From 5e0cb21c8d476ecab6456e2ff3383a3c39c5f10c Mon Sep 17 00:00:00 2001 From: Luke Taylor Date: Sun, 9 Dec 2007 18:40:28 +0000 Subject: [PATCH] SEC-619: Added test class for LdapUserDetailsService. The LdapAuthoritiesPopulator interface and also implementations have been moved to the org.springframework.security.ldap package since they are now used by both the ldap provider and the user service. --- .../config/LdapBeanDefinitionParser.java | 2 +- .../ldap/LdapAuthoritiesPopulator.java | 2 +- .../DefaultLdapAuthoritiesPopulator.java | 29 +++++----- .../ldap/populator/package.html | 2 +- .../ldap/LdapAuthenticationProvider.java | 6 +- .../userdetails/ldap/InetOrgPerson.java | 1 - .../ldap/LdapUserDetailsService.java | 2 +- .../ldap/MockSpringSecurityContextSource.java | 3 + .../DefaultLdapAuthoritiesPopulatorTests.java | 3 +- .../ldap/LdapAuthenticationProviderTests.java | 11 ++-- .../ldap/authenticator/MockUserSearch.java | 3 + .../ldap/LdapUserDetailsServiceTests.java | 56 +++++++++++++++++++ ...applicationContext-acegi-security-ldap.xml | 2 +- src/docbkx/springsecurity.xml | 4 +- 14 files changed, 94 insertions(+), 32 deletions(-) rename core/src/main/java/org/springframework/security/{providers => }/ldap/LdapAuthoritiesPopulator.java (96%) rename core/src/main/java/org/springframework/security/{providers => }/ldap/populator/DefaultLdapAuthoritiesPopulator.java (95%) rename core/src/main/java/org/springframework/security/{providers => }/ldap/populator/package.html (88%) rename core/src/test/java/org/springframework/security/{providers => }/ldap/populator/DefaultLdapAuthoritiesPopulatorTests.java (97%) create mode 100644 core/src/test/java/org/springframework/security/userdetails/ldap/LdapUserDetailsServiceTests.java diff --git a/core/src/main/java/org/springframework/security/config/LdapBeanDefinitionParser.java b/core/src/main/java/org/springframework/security/config/LdapBeanDefinitionParser.java index b7cbf1fe8d..47e8e596ec 100644 --- a/core/src/main/java/org/springframework/security/config/LdapBeanDefinitionParser.java +++ b/core/src/main/java/org/springframework/security/config/LdapBeanDefinitionParser.java @@ -1,9 +1,9 @@ package org.springframework.security.config; import org.springframework.security.ldap.DefaultSpringSecurityContextSource; +import org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator; import org.springframework.security.providers.ldap.LdapAuthenticationProvider; import org.springframework.security.providers.ldap.authenticator.BindAuthenticator; -import org.springframework.security.providers.ldap.populator.DefaultLdapAuthoritiesPopulator; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; diff --git a/core/src/main/java/org/springframework/security/providers/ldap/LdapAuthoritiesPopulator.java b/core/src/main/java/org/springframework/security/ldap/LdapAuthoritiesPopulator.java similarity index 96% rename from core/src/main/java/org/springframework/security/providers/ldap/LdapAuthoritiesPopulator.java rename to core/src/main/java/org/springframework/security/ldap/LdapAuthoritiesPopulator.java index e30a0391d4..4e7c48fa04 100644 --- a/core/src/main/java/org/springframework/security/providers/ldap/LdapAuthoritiesPopulator.java +++ b/core/src/main/java/org/springframework/security/ldap/LdapAuthoritiesPopulator.java @@ -13,7 +13,7 @@ * limitations under the License. */ -package org.springframework.security.providers.ldap; +package org.springframework.security.ldap; import org.springframework.security.GrantedAuthority; diff --git a/core/src/main/java/org/springframework/security/providers/ldap/populator/DefaultLdapAuthoritiesPopulator.java b/core/src/main/java/org/springframework/security/ldap/populator/DefaultLdapAuthoritiesPopulator.java similarity index 95% rename from core/src/main/java/org/springframework/security/providers/ldap/populator/DefaultLdapAuthoritiesPopulator.java rename to core/src/main/java/org/springframework/security/ldap/populator/DefaultLdapAuthoritiesPopulator.java index 2fba78fa83..d460cbd2d6 100644 --- a/core/src/main/java/org/springframework/security/providers/ldap/populator/DefaultLdapAuthoritiesPopulator.java +++ b/core/src/main/java/org/springframework/security/ldap/populator/DefaultLdapAuthoritiesPopulator.java @@ -13,12 +13,12 @@ * limitations under the License. */ -package org.springframework.security.providers.ldap.populator; +package org.springframework.security.ldap.populator; import org.springframework.security.GrantedAuthority; import org.springframework.security.GrantedAuthorityImpl; import org.springframework.security.ldap.SpringSecurityLdapTemplate; -import org.springframework.security.providers.ldap.LdapAuthoritiesPopulator; +import org.springframework.security.ldap.LdapAuthoritiesPopulator; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.DirContextOperations; import org.springframework.util.Assert; @@ -34,8 +34,9 @@ import java.util.Set; /** * The default strategy for obtaining user role information from the directory. - *

It obtains roles by performing a search for "groups" the user is a member of.

- *

+ *

+ * It obtains roles by performing a search for "groups" the user is a member of. + *

* A typical group search scenario would be where each group/role is specified using the groupOfNames * (or groupOfUniqueNames) LDAP objectClass and the user's DN is listed in the member (or * uniqueMember) attribute to indicate that they should be assigned that role. The following LDIF sample has @@ -48,7 +49,7 @@ import java.util.Set; * ou: groups * * dn: cn=developers,ou=groups,dc=springframework,dc=org - * objectClass: groupOfNameso + * objectClass: groupOfNames * objectClass: top * cn: developers * description: Spring Security Developers @@ -56,16 +57,15 @@ import java.util.Set; * member: uid=luke,ou=people,dc=springframework,dc=org * ou: developer * - *

- *

+ *

* The group search is performed within a DN specified by the groupSearchBase property, which should * be relative to the root DN of its InitialDirContextFactory. If the search base is null, group searching is * disabled. The filter used in the search is defined by the groupSearchFilter property, with the filter * argument {0} being the full DN of the user. You can also optionally use the parameter {1}, which will be substituted * with the username. You can also specify which attribute defines the role name by setting - * the groupRoleAttribute property (the default is "cn").

- *

- *

The configuration below shows how the group search might be performed with the above schema. + * the groupRoleAttribute property (the default is "cn"). + *

+ * The configuration below shows how the group search might be performed with the above schema. *

  * <bean id="ldapAuthoritiesPopulator"
  *       class="org.springframework.security.providers.ldap.populator.DefaultLdapAuthoritiesPopulator">
@@ -80,8 +80,7 @@ import java.util.Set;
  * 
* A search for roles for user "uid=ben,ou=people,dc=springframework,dc=org" would return the single granted authority * "ROLE_DEVELOPER". - *

- *

+ *

* The single-level search is performed by default. Setting the searchSubTree property to true will enable * a search of the entire subtree under groupSearchBase. * @@ -98,9 +97,9 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator /** * A default role which will be assigned to all authenticated users if set */ - private GrantedAuthority defaultRole = null; + private GrantedAuthority defaultRole; - private ContextSource contextSource = null; + private ContextSource contextSource; private SpringSecurityLdapTemplate ldapTemplate; @@ -118,7 +117,7 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator /** * The base DN from which the search for group membership should be performed */ - private String groupSearchBase = null; + private String groupSearchBase; /** * The pattern to be used for the user search. {0} is the user's DN diff --git a/core/src/main/java/org/springframework/security/providers/ldap/populator/package.html b/core/src/main/java/org/springframework/security/ldap/populator/package.html similarity index 88% rename from core/src/main/java/org/springframework/security/providers/ldap/populator/package.html rename to core/src/main/java/org/springframework/security/ldap/populator/package.html index 2571b3e762..492914683e 100644 --- a/core/src/main/java/org/springframework/security/providers/ldap/populator/package.html +++ b/core/src/main/java/org/springframework/security/ldap/populator/package.html @@ -2,4 +2,4 @@ LdapAuthoritiesPopulator implementations. - + \ No newline at end of file diff --git a/core/src/main/java/org/springframework/security/providers/ldap/LdapAuthenticationProvider.java b/core/src/main/java/org/springframework/security/providers/ldap/LdapAuthenticationProvider.java index d49c2af204..c7f2fcc4f0 100644 --- a/core/src/main/java/org/springframework/security/providers/ldap/LdapAuthenticationProvider.java +++ b/core/src/main/java/org/springframework/security/providers/ldap/LdapAuthenticationProvider.java @@ -21,6 +21,8 @@ import org.springframework.security.AuthenticationServiceException; import org.springframework.security.BadCredentialsException; import org.springframework.security.GrantedAuthority; import org.springframework.security.SpringSecurityMessageSource; +import org.springframework.security.ldap.LdapAuthoritiesPopulator; +import org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator; import org.springframework.security.providers.AuthenticationProvider; import org.springframework.security.providers.UsernamePasswordAuthenticationToken; import org.springframework.security.userdetails.UserDetails; @@ -60,7 +62,7 @@ import org.apache.commons.logging.LogFactory; *

LdapAuthoritiesPopulator

* Once the user has been authenticated, this interface is called to obtain the set of granted authorities for the * user. - * The {@link org.springframework.security.providers.ldap.populator.DefaultLdapAuthoritiesPopulator DefaultLdapAuthoritiesPopulator} + * The {@link DefaultLdapAuthoritiesPopulator DefaultLdapAuthoritiesPopulator} * can be configured to obtain user role information from the user's attributes and/or to perform a search for * "groups" that the user is a member of and map these to roles. * @@ -114,7 +116,7 @@ import org.apache.commons.logging.LogFactory; * @version $Id$ * * @see org.springframework.security.providers.ldap.authenticator.BindAuthenticator - * @see org.springframework.security.providers.ldap.populator.DefaultLdapAuthoritiesPopulator + * @see DefaultLdapAuthoritiesPopulator */ public class LdapAuthenticationProvider implements AuthenticationProvider { //~ Static fields/initializers ===================================================================================== diff --git a/core/src/main/java/org/springframework/security/userdetails/ldap/InetOrgPerson.java b/core/src/main/java/org/springframework/security/userdetails/ldap/InetOrgPerson.java index bdb53ac928..36f759e0d9 100644 --- a/core/src/main/java/org/springframework/security/userdetails/ldap/InetOrgPerson.java +++ b/core/src/main/java/org/springframework/security/userdetails/ldap/InetOrgPerson.java @@ -24,7 +24,6 @@ import org.springframework.ldap.core.DirContextOperations; * *

* The username will be mapped from the uid attribute by default. - *

* * @author Luke * @version $Id$ diff --git a/core/src/main/java/org/springframework/security/userdetails/ldap/LdapUserDetailsService.java b/core/src/main/java/org/springframework/security/userdetails/ldap/LdapUserDetailsService.java index e07cc5206c..ba2ff00b06 100644 --- a/core/src/main/java/org/springframework/security/userdetails/ldap/LdapUserDetailsService.java +++ b/core/src/main/java/org/springframework/security/userdetails/ldap/LdapUserDetailsService.java @@ -2,7 +2,7 @@ package org.springframework.security.userdetails.ldap; import org.springframework.security.GrantedAuthority; import org.springframework.security.ldap.LdapUserSearch; -import org.springframework.security.providers.ldap.LdapAuthoritiesPopulator; +import org.springframework.security.ldap.LdapAuthoritiesPopulator; import org.springframework.security.userdetails.UserDetails; import org.springframework.security.userdetails.UserDetailsService; import org.springframework.security.userdetails.UsernameNotFoundException; diff --git a/core/src/test/java/org/springframework/security/ldap/MockSpringSecurityContextSource.java b/core/src/test/java/org/springframework/security/ldap/MockSpringSecurityContextSource.java index 7a7ed644e0..8a0276857c 100644 --- a/core/src/test/java/org/springframework/security/ldap/MockSpringSecurityContextSource.java +++ b/core/src/test/java/org/springframework/security/ldap/MockSpringSecurityContextSource.java @@ -34,6 +34,9 @@ public class MockSpringSecurityContextSource implements SpringSecurityContextSou //~ Constructors =================================================================================================== + public MockSpringSecurityContextSource() { + } + public MockSpringSecurityContextSource(DirContext ctx, String baseDn) { this.baseDn = baseDn; this.ctx = ctx; diff --git a/core/src/test/java/org/springframework/security/providers/ldap/populator/DefaultLdapAuthoritiesPopulatorTests.java b/core/src/test/java/org/springframework/security/ldap/populator/DefaultLdapAuthoritiesPopulatorTests.java similarity index 97% rename from core/src/test/java/org/springframework/security/providers/ldap/populator/DefaultLdapAuthoritiesPopulatorTests.java rename to core/src/test/java/org/springframework/security/ldap/populator/DefaultLdapAuthoritiesPopulatorTests.java index 636bc9db68..2a28674427 100644 --- a/core/src/test/java/org/springframework/security/providers/ldap/populator/DefaultLdapAuthoritiesPopulatorTests.java +++ b/core/src/test/java/org/springframework/security/ldap/populator/DefaultLdapAuthoritiesPopulatorTests.java @@ -13,11 +13,12 @@ * limitations under the License. */ -package org.springframework.security.providers.ldap.populator; +package org.springframework.security.ldap.populator; import org.springframework.security.GrantedAuthority; import org.springframework.security.ldap.AbstractLdapIntegrationTests; +import org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator; import org.springframework.ldap.core.DirContextAdapter; import org.springframework.ldap.core.DistinguishedName; diff --git a/core/src/test/java/org/springframework/security/providers/ldap/LdapAuthenticationProviderTests.java b/core/src/test/java/org/springframework/security/providers/ldap/LdapAuthenticationProviderTests.java index 814b206888..eed4182e5d 100644 --- a/core/src/test/java/org/springframework/security/providers/ldap/LdapAuthenticationProviderTests.java +++ b/core/src/test/java/org/springframework/security/providers/ldap/LdapAuthenticationProviderTests.java @@ -15,21 +15,20 @@ package org.springframework.security.providers.ldap; -import junit.framework.TestCase; - +import org.springframework.security.Authentication; import org.springframework.security.BadCredentialsException; import org.springframework.security.GrantedAuthority; import org.springframework.security.GrantedAuthorityImpl; -import org.springframework.security.Authentication; - +import org.springframework.security.ldap.LdapAuthoritiesPopulator; import org.springframework.security.providers.UsernamePasswordAuthenticationToken; - import org.springframework.security.userdetails.UserDetails; import org.springframework.security.userdetails.ldap.LdapUserDetailsMapper; -import org.springframework.ldap.core.DirContextOperations; import org.springframework.ldap.core.DirContextAdapter; +import org.springframework.ldap.core.DirContextOperations; import org.springframework.ldap.core.DistinguishedName; +import junit.framework.TestCase; + import java.util.ArrayList; diff --git a/core/src/test/java/org/springframework/security/providers/ldap/authenticator/MockUserSearch.java b/core/src/test/java/org/springframework/security/providers/ldap/authenticator/MockUserSearch.java index 6e7d6ddad9..51f310df9b 100644 --- a/core/src/test/java/org/springframework/security/providers/ldap/authenticator/MockUserSearch.java +++ b/core/src/test/java/org/springframework/security/providers/ldap/authenticator/MockUserSearch.java @@ -33,6 +33,9 @@ public class MockUserSearch implements LdapUserSearch { //~ Constructors =================================================================================================== + public MockUserSearch() { + } + public MockUserSearch(DirContextOperations user) { this.user = user; } diff --git a/core/src/test/java/org/springframework/security/userdetails/ldap/LdapUserDetailsServiceTests.java b/core/src/test/java/org/springframework/security/userdetails/ldap/LdapUserDetailsServiceTests.java new file mode 100644 index 0000000000..d997a3a36e --- /dev/null +++ b/core/src/test/java/org/springframework/security/userdetails/ldap/LdapUserDetailsServiceTests.java @@ -0,0 +1,56 @@ +package org.springframework.security.userdetails.ldap; + +import org.springframework.security.GrantedAuthority; +import org.springframework.security.GrantedAuthorityImpl; +import org.springframework.security.ldap.LdapAuthoritiesPopulator; +import org.springframework.security.providers.ldap.authenticator.MockUserSearch; +import org.springframework.security.userdetails.UserDetails; +import org.springframework.security.util.AuthorityUtils; +import org.springframework.ldap.core.DirContextAdapter; +import org.springframework.ldap.core.DirContextOperations; +import org.springframework.ldap.core.DistinguishedName; + +import static org.junit.Assert.*; +import org.junit.Test; + +import java.util.Set; + +/** + * Tests for {@link LdapUserDetailsService} + * + * @author Luke Taylor + * @version $Id$ + */ +public class LdapUserDetailsServiceTests { + + @Test(expected = IllegalArgumentException.class) + public void rejectsNullSearchObject() { + new LdapUserDetailsService(null, new MockAuthoritiesPopulator()); + } + + @Test(expected = IllegalArgumentException.class) + public void rejectsNullAuthoritiesPopulator() { + new LdapUserDetailsService(new MockUserSearch(), null); + } + + @Test + public void correctAuthoritiesAreReturned() { + DirContextAdapter userData = new DirContextAdapter(new DistinguishedName("uid=joe")); + + LdapUserDetailsService service = + new LdapUserDetailsService(new MockUserSearch(userData), new MockAuthoritiesPopulator()); + service.setUserDetailsMapper(new LdapUserDetailsMapper()); + + UserDetails user = service.loadUserByUsername("doesntmatterwegetjoeanyway"); + + Set authorities = AuthorityUtils.authorityArrayToSet(user.getAuthorities()); + assertEquals(1, authorities.size()); + assertTrue(authorities.contains("ROLE_FROM_POPULATOR")); + } + + class MockAuthoritiesPopulator implements LdapAuthoritiesPopulator { + public GrantedAuthority[] getGrantedAuthorities(DirContextOperations userCtx, String username) { + return new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_FROM_POPULATOR")}; + } + } +} diff --git a/samples/contacts/src/main/webapp/WEB-INF/applicationContext-acegi-security-ldap.xml b/samples/contacts/src/main/webapp/WEB-INF/applicationContext-acegi-security-ldap.xml index 0343d64980..38911d41ed 100644 --- a/samples/contacts/src/main/webapp/WEB-INF/applicationContext-acegi-security-ldap.xml +++ b/samples/contacts/src/main/webapp/WEB-INF/applicationContext-acegi-security-ldap.xml @@ -50,7 +50,7 @@ - + ou=groups ou diff --git a/src/docbkx/springsecurity.xml b/src/docbkx/springsecurity.xml index d8d8a985c1..004546a61c 100644 --- a/src/docbkx/springsecurity.xml +++ b/src/docbkx/springsecurity.xml @@ -1462,7 +1462,7 @@ if (obj instanceof UserDetails) { Note that when using the tags, you should include the taglib reference in your JSP: <%@ taglib prefix='security' uri='http://www.springframework.org/security/tags' %> - + @@ -3265,7 +3265,7 @@ key: A private key to prevent modification of the remember-me token </bean> </constructor-arg> <constructor-arg> - <bean class="org.springframework.security.providers.ldap.populator.DefaultLdapAuthoritiesPopulator"> + <bean class="org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator"> <constructor-arg><ref local="initialDirContextFactory"/></constructor-arg> <constructor-arg><value>ou=groups</value></constructor-arg> <property name="groupRoleAttribute"><value>ou</value></property>