SEC-1331: Modify namespace to allow omission of user passwords in user-service element and generate random ones internally, preventing authentication against the data..

This commit is contained in:
Luke Taylor 2009-12-18 15:39:13 +00:00
parent fabe03ba33
commit 85a58fd473
5 changed files with 45 additions and 12 deletions

View File

@ -14,6 +14,8 @@ import org.springframework.util.CollectionUtils;
import org.springframework.util.xml.DomUtils; import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.List; import java.util.List;
import java.util.Iterator; import java.util.Iterator;
@ -32,6 +34,8 @@ public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceB
static final String ATT_DISABLED = "disabled"; static final String ATT_DISABLED = "disabled";
static final String ATT_LOCKED = "locked"; static final String ATT_LOCKED = "locked";
private SecureRandom random;
protected String getBeanClassName(Element element) { protected String getBeanClassName(Element element) {
return "org.springframework.security.core.userdetails.memory.InMemoryDaoImpl"; return "org.springframework.security.core.userdetails.memory.InMemoryDaoImpl";
} }
@ -65,6 +69,11 @@ public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceB
Element userElt = (Element) i.next(); Element userElt = (Element) i.next();
String userName = userElt.getAttribute(ATT_NAME); String userName = userElt.getAttribute(ATT_NAME);
String password = userElt.getAttribute(ATT_PASSWORD); String password = userElt.getAttribute(ATT_PASSWORD);
if (!StringUtils.hasLength(password)) {
password = generateRandomPassword();
}
boolean locked = "true".equals(userElt.getAttribute(ATT_LOCKED)); boolean locked = "true".equals(userElt.getAttribute(ATT_LOCKED));
boolean disabled = "true".equals(userElt.getAttribute(ATT_DISABLED)); boolean disabled = "true".equals(userElt.getAttribute(ATT_DISABLED));
@ -74,4 +83,16 @@ public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceB
builder.addPropertyValue("userMap", users); builder.addPropertyValue("userMap", users);
} }
private String generateRandomPassword() {
if (random == null) {
try {
random = SecureRandom.getInstance("SHA1PRNG");
} catch (NoSuchAlgorithmException e) {
// Shouldn't happen...
throw new RuntimeException("Failed find SHA1PRNG algorithm!");
}
}
return Long.toString(random.nextLong());
}
} }

View File

@ -533,7 +533,7 @@ x509.attlist &=
user-service-ref? user-service-ref?
authentication-manager = authentication-manager =
## Registers the AuthenticationManager instance and allows its list of AuthenticationProviders to be defined. should use. Also allows you to define an alias to allow you to reference the AuthenticationManager in your own beans. ## Registers the AuthenticationManager instance and allows its list of AuthenticationProviders to be defined. Also allows you to define an alias to allow you to reference the AuthenticationManager in your own beans.
element authentication-manager {authman.attlist & authentication-provider* & ldap-authentication-provider*} element authentication-manager {authman.attlist & authentication-provider* & ldap-authentication-provider*}
authman.attlist &= authman.attlist &=
## The alias you wish to use for the AuthenticationManager bean ## The alias you wish to use for the AuthenticationManager bean
@ -562,8 +562,8 @@ user.attlist &=
## The username assigned to the user. ## The username assigned to the user.
attribute name {xsd:token} attribute name {xsd:token}
user.attlist &= user.attlist &=
## The password assigned to the user. This may be hashed if the corresponding authentication provider supports hashing (remember to set the "hash" attribute of the "user-service" element). ## The password assigned to the user. This may be hashed if the corresponding authentication provider supports hashing (remember to set the "hash" attribute of the "user-service" element). This attribute be omitted in the case where the data will not be used for authentication, but only for accessing authorities. If omitted, the namespace will generate a random value, preventing its accidental use for authentication. Cannot be empty.
attribute password {xsd:string} attribute password {xsd:string}?
user.attlist &= user.attlist &=
## One of more authorities granted to the user. Separate authorities with a comma (but no space). For example, "ROLE_USER,ROLE_ADMINISTRATOR" ## One of more authorities granted to the user. Separate authorities with a comma (but no space). For example, "ROLE_USER,ROLE_ADMINISTRATOR"
attribute authorities {xsd:token} attribute authorities {xsd:token}

View File

@ -1096,7 +1096,7 @@
</xs:attribute> </xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:element name="authentication-manager"><xs:annotation> <xs:element name="authentication-manager"><xs:annotation>
<xs:documentation>Registers the AuthenticationManager instance and allows its list of AuthenticationProviders to be defined. should use. Also allows you to define an alias to allow you to reference the AuthenticationManager in your own beans. </xs:documentation> <xs:documentation>Registers the AuthenticationManager instance and allows its list of AuthenticationProviders to be defined. Also allows you to define an alias to allow you to reference the AuthenticationManager in your own beans. </xs:documentation>
</xs:annotation><xs:complexType> </xs:annotation><xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="authentication-provider"><xs:annotation> <xs:element name="authentication-provider"><xs:annotation>
@ -1223,9 +1223,9 @@
<xs:documentation>The username assigned to the user.</xs:documentation> <xs:documentation>The username assigned to the user.</xs:documentation>
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
<xs:attribute name="password" use="required" type="xs:string"> <xs:attribute name="password" type="xs:string">
<xs:annotation> <xs:annotation>
<xs:documentation>The password assigned to the user. This may be hashed if the corresponding authentication provider supports hashing (remember to set the "hash" attribute of the "user-service" element).</xs:documentation> <xs:documentation>The password assigned to the user. This may be hashed if the corresponding authentication provider supports hashing (remember to set the "hash" attribute of the "user-service" element). This attribute be omitted in the case where the data will not be used for authentication, but only for accessing authorities. If omitted, the namespace will generate a random value, preventing its accidental use for authentication. Cannot be empty.</xs:documentation>
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
<xs:attribute name="authorities" use="required" type="xs:token"> <xs:attribute name="authorities" use="required" type="xs:token">

View File

@ -45,6 +45,18 @@ public class UserServiceBeanDefinitionParserTests {
userService.loadUserByUsername("joe"); userService.loadUserByUsername("joe");
} }
@Test
public void embeddedUsersWithNoPasswordIsGivenGeneratedValue() {
setContext(
"<user-service id='service'>" +
" <user name='joe' authorities='ROLE_A'/>" +
"</user-service>");
UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
UserDetails joe = userService.loadUserByUsername("joe");
assertTrue(joe.getPassword().length() > 0);
Long.parseLong(joe.getPassword());
}
@Test @Test
public void disabledAndEmbeddedFlagsAreSupported() { public void disabledAndEmbeddedFlagsAreSupported() {
setContext( setContext(
@ -58,8 +70,8 @@ public class UserServiceBeanDefinitionParserTests {
UserDetails bob = userService.loadUserByUsername("bob"); UserDetails bob = userService.loadUserByUsername("bob");
assertFalse(bob.isEnabled()); assertFalse(bob.isEnabled());
} }
@Test(expected=FatalBeanException.class) @Test(expected=FatalBeanException.class)
public void userWithBothPropertiesAndEmbeddedUsersThrowsException() { public void userWithBothPropertiesAndEmbeddedUsersThrowsException() {
setContext( setContext(

View File

@ -27,10 +27,10 @@
<authentication-manager alias="authenticationManager"/> <authentication-manager alias="authenticationManager"/>
<user-service id="userService"> <user-service id="userService">
<user name="http://luke.taylor.myopenid.com/" password="notused" authorities="ROLE_SUPERVISOR,ROLE_USER" /> <user name="http://luke.taylor.myopenid.com/" authorities="ROLE_SUPERVISOR,ROLE_USER" />
<user name="http://luke.taylor.openid.cn/" password="notused" authorities="ROLE_SUPERVISOR,ROLE_USER" /> <user name="http://luke.taylor.openid.cn/" authorities="ROLE_SUPERVISOR,ROLE_USER" />
<user name="http://raykrueger.blogspot.com/" password="notused" authorities="ROLE_SUPERVISOR,ROLE_USER" /> <user name="http://raykrueger.blogspot.com/" authorities="ROLE_SUPERVISOR,ROLE_USER" />
<user name="http://spring.security.test.myopenid.com/" password="password" authorities="ROLE_SUPERVISOR,ROLE_USER" /> <user name="http://spring.security.test.myopenid.com/" authorities="ROLE_SUPERVISOR,ROLE_USER" />
</user-service> </user-service>
</b:beans> </b:beans>