From f7ae070b2f5a656980247a56a95d6920084bdf99 Mon Sep 17 00:00:00 2001 From: Luke Taylor Date: Sun, 9 Mar 2008 19:26:34 +0000 Subject: [PATCH] SEC-705: Extend ldap-authentication-provider namespace elt to support user searches and multiple authentication strategies http://jira.springframework.org/browse/SEC-705 --- .../security/config/Elements.java | 1 + .../LdapProviderBeanDefinitionParser.java | 86 ++++++++----- .../LdapUserServiceBeanDefinitionParser.java | 81 ++++++++---- .../config/PasswordEncoderParser.java | 3 + .../security/config/spring-security-2.0.rnc | 68 ++++++++--- .../security/config/spring-security-2.0.xsd | 115 ++++++++++++++++-- ...LdapProviderBeanDefinitionParserTests.java | 42 +++++-- ...pUserServiceBeanDefinitionParserTests.java | 23 +++- 8 files changed, 329 insertions(+), 90 deletions(-) diff --git a/core/src/main/java/org/springframework/security/config/Elements.java b/core/src/main/java/org/springframework/security/config/Elements.java index 9b7ec7b5e6..c361394427 100644 --- a/core/src/main/java/org/springframework/security/config/Elements.java +++ b/core/src/main/java/org/springframework/security/config/Elements.java @@ -35,4 +35,5 @@ abstract class Elements { public static final String CUSTOM_AUTH_RPOVIDER = "custom-authentication-provider"; public static final String X509 = "x509"; public static final String FILTER_INVOCATION_DEFINITION_SOURCE = "filter-invocation-definition-source"; + public static final String LDAP_PASSWORD_COMPARE = "password-compare"; } diff --git a/core/src/main/java/org/springframework/security/config/LdapProviderBeanDefinitionParser.java b/core/src/main/java/org/springframework/security/config/LdapProviderBeanDefinitionParser.java index 09b15ec3a0..7cf2d56b42 100644 --- a/core/src/main/java/org/springframework/security/config/LdapProviderBeanDefinitionParser.java +++ b/core/src/main/java/org/springframework/security/config/LdapProviderBeanDefinitionParser.java @@ -1,21 +1,23 @@ package org.springframework.security.config; -import org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator; +import org.springframework.security.ldap.search.FilterBasedLdapUserSearch; import org.springframework.security.providers.ldap.LdapAuthenticationProvider; import org.springframework.security.providers.ldap.authenticator.BindAuthenticator; +import org.springframework.security.providers.ldap.authenticator.PasswordComparisonAuthenticator; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.util.StringUtils; +import org.springframework.util.xml.DomUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.w3c.dom.Element; /** - * Experimental "security:ldap" namespace configuration. + * Ldap authentication provider namespace configuration. * * @author Luke Taylor * @version $Id$ @@ -23,36 +25,64 @@ import org.w3c.dom.Element; */ public class LdapProviderBeanDefinitionParser implements BeanDefinitionParser { private Log logger = LogFactory.getLog(getClass()); - - private static final String ATT_AUTH_TYPE = "auth-type"; - private static final String ATT_SERVER = "server-ref"; - - private static final String OPT_DEFAULT_DN_PATTERN = "uid={0},ou=people"; - private static final String DEF_GROUP_CONTEXT = "ou=groups"; - private static final String DEF_GROUP_SEARCH_FILTER = "(uniqueMember={0})"; - + + private static final String ATT_USER_DN_PATTERN = "user-dn-pattern"; + private static final String ATT_USER_PASSWORD= "password-attribute"; + + private static final String DEF_USER_SEARCH_FILTER="uid={0}"; public BeanDefinition parse(Element elt, ParserContext parserContext) { - String server = elt.getAttribute(ATT_SERVER); - - if (!StringUtils.hasText(server)) { - server = BeanIds.CONTEXT_SOURCE; + RuntimeBeanReference contextSource = LdapUserServiceBeanDefinitionParser.parseServerReference(elt, parserContext); + + RootBeanDefinition searchBean = LdapUserServiceBeanDefinitionParser.parseSearchBean(elt, parserContext); + String userDnPattern = elt.getAttribute(ATT_USER_DN_PATTERN); + + String[] userDnPatternArray = new String[0]; + + if (StringUtils.hasText(userDnPattern)) { + userDnPatternArray = new String[] {userDnPattern}; + // TODO: Validate the pattern and make sure it is a valid DN. + } else if (searchBean == null) { + logger.info("No search information or DN pattern specified. Using default search filter '" + DEF_USER_SEARCH_FILTER + "'"); + searchBean = new RootBeanDefinition(FilterBasedLdapUserSearch.class); + searchBean.setSource(elt); + searchBean.getConstructorArgumentValues().addIndexedArgumentValue(0, ""); + searchBean.getConstructorArgumentValues().addIndexedArgumentValue(1, DEF_USER_SEARCH_FILTER); + searchBean.getConstructorArgumentValues().addIndexedArgumentValue(2, contextSource); } - - RuntimeBeanReference contextSource = new RuntimeBeanReference(server); - - RootBeanDefinition bindAuthenticator = new RootBeanDefinition(BindAuthenticator.class); - bindAuthenticator.getConstructorArgumentValues().addGenericArgumentValue(contextSource); - bindAuthenticator.getPropertyValues().addPropertyValue("userDnPatterns", new String[] {OPT_DEFAULT_DN_PATTERN}); - RootBeanDefinition authoritiesPopulator = new RootBeanDefinition(DefaultLdapAuthoritiesPopulator.class); - authoritiesPopulator.getConstructorArgumentValues().addGenericArgumentValue(contextSource); - authoritiesPopulator.getConstructorArgumentValues().addGenericArgumentValue(DEF_GROUP_CONTEXT); - // TODO: Change to using uniqueMember as default -// authoritiesPopulator.getPropertyValues().addPropertyValue("groupSearchFilter", DEF_GROUP_SEARCH_FILTER); - + + RootBeanDefinition authenticator = new RootBeanDefinition(BindAuthenticator.class); + Element passwordCompareElt = DomUtils.getChildElementByTagName(elt, Elements.LDAP_PASSWORD_COMPARE); + if (passwordCompareElt != null) { + authenticator = new RootBeanDefinition(PasswordComparisonAuthenticator.class); + + String passwordAttribute = passwordCompareElt.getAttribute(ATT_USER_PASSWORD); + if (StringUtils.hasText(passwordAttribute)) { + authenticator.getPropertyValues().addPropertyValue("passwordAttributeName", passwordAttribute); + } + + Element passwordEncoderElement = DomUtils.getChildElementByTagName(passwordCompareElt, Elements.PASSWORD_ENCODER); + + if (passwordEncoderElement != null) { + PasswordEncoderParser pep = new PasswordEncoderParser(passwordEncoderElement, parserContext); + authenticator.getPropertyValues().addPropertyValue("passwordEncoder", pep.getPasswordEncoder()); + + if (pep.getSaltSource() != null) { + parserContext.getReaderContext().warning("Salt source information isn't valid when used with LDAP", passwordEncoderElement); + } + } + } + + authenticator.getConstructorArgumentValues().addGenericArgumentValue(contextSource); + authenticator.getPropertyValues().addPropertyValue("userDnPatterns", userDnPatternArray); + + if (searchBean != null) { + authenticator.getPropertyValues().addPropertyValue("userSearch", searchBean); + } + RootBeanDefinition ldapProvider = new RootBeanDefinition(LdapAuthenticationProvider.class); - ldapProvider.getConstructorArgumentValues().addGenericArgumentValue(bindAuthenticator); - ldapProvider.getConstructorArgumentValues().addGenericArgumentValue(authoritiesPopulator); + ldapProvider.getConstructorArgumentValues().addGenericArgumentValue(authenticator); + ldapProvider.getConstructorArgumentValues().addGenericArgumentValue(LdapUserServiceBeanDefinitionParser.parseAuthoritiesPopulator(elt, parserContext)); LdapConfigUtils.registerPostProcessorIfNecessary(parserContext.getRegistry()); diff --git a/core/src/main/java/org/springframework/security/config/LdapUserServiceBeanDefinitionParser.java b/core/src/main/java/org/springframework/security/config/LdapUserServiceBeanDefinitionParser.java index 1673f8d63b..54f8734980 100644 --- a/core/src/main/java/org/springframework/security/config/LdapUserServiceBeanDefinitionParser.java +++ b/core/src/main/java/org/springframework/security/config/LdapUserServiceBeanDefinitionParser.java @@ -17,13 +17,14 @@ import org.w3c.dom.Element; * @since 2.0 */ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServiceBeanDefinitionParser { - private static final String ATT_SERVER = "server-ref"; + public static final String ATT_SERVER = "server-ref"; public static final String ATT_USER_SEARCH_FILTER = "user-search-filter"; public static final String ATT_USER_SEARCH_BASE = "user-search-base"; public static final String DEF_USER_SEARCH_BASE = ""; public static final String ATT_GROUP_SEARCH_FILTER = "group-search-filter"; public static final String ATT_GROUP_SEARCH_BASE = "group-search-base"; + public static final String ATT_GROUP_ROLE_ATTRIBUTE = "group-role-attribute"; public static final String DEF_GROUP_SEARCH_FILTER = "(uniqueMember={0})"; public static final String DEF_GROUP_SEARCH_BASE = "ou=groups"; @@ -32,26 +33,60 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ } protected void doParse(Element elt, ParserContext parserContext, BeanDefinitionBuilder builder) { - String server = elt.getAttribute(ATT_SERVER); - if (!StringUtils.hasText(server)) { - server = BeanIds.CONTEXT_SOURCE; + if (!StringUtils.hasText(elt.getAttribute(ATT_USER_SEARCH_FILTER))) { + parserContext.getReaderContext().error("User search filter must be supplied", elt); } + + builder.addConstructorArg(parseSearchBean(elt, parserContext)); + builder.addConstructorArg(parseAuthoritiesPopulator(elt, parserContext)); + LdapConfigUtils.registerPostProcessorIfNecessary(parserContext.getRegistry()); + } + + static RootBeanDefinition parseSearchBean(Element elt, ParserContext parserContext) { String userSearchFilter = elt.getAttribute(ATT_USER_SEARCH_FILTER); - + String userSearchBase = elt.getAttribute(ATT_USER_SEARCH_BASE); + Object source = parserContext.extractSource(elt); + + if (StringUtils.hasText(userSearchBase)) { + if(!StringUtils.hasText(userSearchFilter)) { + parserContext.getReaderContext().error(ATT_USER_SEARCH_BASE + " cannot be used without a " + ATT_USER_SEARCH_FILTER, source); + } + } else { + userSearchBase = DEF_USER_SEARCH_BASE; + } + if (!StringUtils.hasText(userSearchFilter)) { - parserContext.getReaderContext().error("User search filter must be supplied", elt); + return null; } + + RootBeanDefinition search = new RootBeanDefinition(FilterBasedLdapUserSearch.class); + search.setSource(source); + search.getConstructorArgumentValues().addIndexedArgumentValue(0, userSearchBase); + search.getConstructorArgumentValues().addIndexedArgumentValue(1, userSearchFilter); + search.getConstructorArgumentValues().addIndexedArgumentValue(2, parseServerReference(elt, parserContext)); + + return search; + } + + static RuntimeBeanReference parseServerReference(Element elt, ParserContext parserContext) { + String server = elt.getAttribute(ATT_SERVER); - String userSearchBase = elt.getAttribute(ATT_USER_SEARCH_BASE); - - if (!StringUtils.hasText(userSearchBase)) { - userSearchBase = DEF_USER_SEARCH_BASE; + if (!StringUtils.hasText(server)) { + server = BeanIds.CONTEXT_SOURCE; } + RuntimeBeanReference contextSource = new RuntimeBeanReference(server); + contextSource.setSource(parserContext.extractSource(elt)); + + return contextSource; + } + + static RootBeanDefinition parseAuthoritiesPopulator(Element elt, ParserContext parserContext) { String groupSearchFilter = elt.getAttribute(ATT_GROUP_SEARCH_FILTER); String groupSearchBase = elt.getAttribute(ATT_GROUP_SEARCH_BASE); + String groupRoleAttribute = elt.getAttribute(ATT_GROUP_ROLE_ATTRIBUTE); if (!StringUtils.hasText(groupSearchFilter)) { groupSearchFilter = DEF_GROUP_SEARCH_FILTER; @@ -60,25 +95,17 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ if (!StringUtils.hasText(groupSearchBase)) { groupSearchBase = DEF_GROUP_SEARCH_BASE; } - - Object source = parserContext.extractSource(elt); - - RuntimeBeanReference contextSource = new RuntimeBeanReference(server); - RootBeanDefinition search = new RootBeanDefinition(FilterBasedLdapUserSearch.class); - search.setSource(source); - search.getConstructorArgumentValues().addIndexedArgumentValue(0, userSearchBase); - search.getConstructorArgumentValues().addIndexedArgumentValue(1, userSearchFilter); - search.getConstructorArgumentValues().addIndexedArgumentValue(2, contextSource); - + RootBeanDefinition populator = new RootBeanDefinition(DefaultLdapAuthoritiesPopulator.class); - populator.setSource(source); - populator.getConstructorArgumentValues().addIndexedArgumentValue(0, contextSource); + populator.setSource(parserContext.extractSource(elt)); + populator.getConstructorArgumentValues().addIndexedArgumentValue(0, parseServerReference(elt, parserContext)); populator.getConstructorArgumentValues().addIndexedArgumentValue(1, groupSearchBase); populator.getPropertyValues().addPropertyValue("groupSearchFilter", groupSearchFilter); - - builder.addConstructorArg(search); - builder.addConstructorArg(populator); - - LdapConfigUtils.registerPostProcessorIfNecessary(parserContext.getRegistry()); + + if (StringUtils.hasLength(groupRoleAttribute)) { + populator.getPropertyValues().addPropertyValue("groupRoleAttribute", groupRoleAttribute); + } + + return populator; } } diff --git a/core/src/main/java/org/springframework/security/config/PasswordEncoderParser.java b/core/src/main/java/org/springframework/security/config/PasswordEncoderParser.java index b9052009e0..2bedf5d510 100644 --- a/core/src/main/java/org/springframework/security/config/PasswordEncoderParser.java +++ b/core/src/main/java/org/springframework/security/config/PasswordEncoderParser.java @@ -2,6 +2,7 @@ package org.springframework.security.config; import org.springframework.security.providers.encoding.Md4PasswordEncoder; import org.springframework.security.providers.encoding.Md5PasswordEncoder; +import org.springframework.security.providers.encoding.PlaintextPasswordEncoder; import org.springframework.security.providers.encoding.ShaPasswordEncoder; import org.springframework.security.providers.encoding.BaseDigestPasswordEncoder; import org.springframework.security.providers.ldap.authenticator.LdapShaPasswordEncoder; @@ -32,6 +33,7 @@ public class PasswordEncoderParser { static final String ATT_REF = "ref"; static final String ATT_HASH = "hash"; static final String ATT_BASE_64 = "base64"; + static final String OPT_HASH_PLAINTEXT = "plaintext"; static final String OPT_HASH_SHA = "sha"; static final String OPT_HASH_MD4 = "md4"; static final String OPT_HASH_MD5 = "md5"; @@ -41,6 +43,7 @@ public class PasswordEncoderParser { static { ENCODER_CLASSES = new HashMap(); + ENCODER_CLASSES.put(OPT_HASH_PLAINTEXT, PlaintextPasswordEncoder.class); ENCODER_CLASSES.put(OPT_HASH_SHA, ShaPasswordEncoder.class); ENCODER_CLASSES.put(OPT_HASH_MD4, Md4PasswordEncoder.class); ENCODER_CLASSES.put(OPT_HASH_MD5, Md5PasswordEncoder.class); diff --git a/core/src/main/resources/org/springframework/security/config/spring-security-2.0.rnc b/core/src/main/resources/org/springframework/security/config/spring-security-2.0.rnc index e050cf91ae..257d5d30fc 100644 --- a/core/src/main/resources/org/springframework/security/config/spring-security-2.0.rnc +++ b/core/src/main/resources/org/springframework/security/config/spring-security-2.0.rnc @@ -10,7 +10,7 @@ start = http | ldap-server | authentication-provider | ldap-authentication-provi hash = ## Defines the hashing algorithm used on user passwords. We recommend strongly against using MD4, as it is a very weak hashing algorithm. - attribute hash {"sha" | "md5" | "md4" | "{sha}" | "{ssha}"} + attribute hash {"plaintext" | "sha" | "md5" | "md4" | "{sha}" | "{ssha}"} base64 = ## Whether a string should be base64 encoded attribute base64 {"true" | "false"} @@ -66,33 +66,71 @@ ldap-server.attlist &= ## Optional root suffix for the embedded LDAP server. Default is "dc=springframework,dc=org" attribute root { xsd:string }? +ldap-server-ref-attribute = + ## The optional server to use. If omitted, and a default LDAP server is registered (using with no Id), that server will be used. + attribute server-ref {xsd:string} + + +group-search-filter-attribute = + ## Group search filter. Defaults to (uniqueMember={0}). The substituted parameter is the DN of the user. + attribute group-search-filter {xsd:string} +group-search-base-attribute = + ## Search base for group membership searches. Defaults to "ou=groups". + attribute group-search-base {xsd:string} +user-search-filter-attribute = + attribute user-search-filter {xsd:string} +user-search-base-attribute = + ## Search base for user searches. Defaults to "". + attribute user-search-base {xsd:string}? +group-role-attribute-attribute = + ## The LDAP attribute name which contains the role name which will be used within Spring Security. Defaults to "cn". + attribute group-role-attribute {xsd:string} + + ldap-user-service = element ldap-user-service {ldap-us.attlist} ldap-us.attlist &= id? ldap-us.attlist &= - ## The optional server to use. If omitted, and a default LDAP server is registered (using with no Id), that server will be used. - attribute server-ref {xsd:string}? + ldap-server-ref-attribute? ldap-us.attlist &= - attribute user-search-filter {xsd:string} + user-search-filter-attribute? ldap-us.attlist &= - ## Search base for user searches. Defaults to "". - attribute user-search-base {xsd:string}? + user-search-base-attribute? ldap-us.attlist &= - ## Group search filter. Defaults to (uniqueMember={0}). - attribute group-search-filter {xsd:string}? + group-search-filter-attribute? ldap-us.attlist &= - ## Search base for group membership searches. Defaults to "ou=groups". - attribute group-search-base {xsd:string}? - - + group-search-base-attribute? +ldap-us.attlist &= + group-role-attribute-attribute? ldap-authentication-provider = ## Sets up an ldap authentication provider - element ldap-authentication-provider {ldap-ap.attlist, empty} + element ldap-authentication-provider {ldap-ap.attlist, password-compare-element?} +ldap-ap.attlist &= + ldap-server-ref-attribute? ldap-ap.attlist &= - ## The server to authenticate against. - attribute server-ref {xsd:string}? + user-search-base-attribute? +ldap-ap.attlist &= + user-search-filter-attribute? +ldap-ap.attlist &= + group-search-base-attribute? +ldap-ap.attlist &= + group-search-filter-attribute? +ldap-ap.attlist &= + group-role-attribute-attribute? +ldap-ap.attlist &= + ## A specific pattern used to build the user's DN, for example "uid={0},ou=people". The key "{0}" must be present and will be substituted with the username. + attribute user-dn-pattern {xsd:string}? +password-compare-element = + ## Specifies that an LDAP provider should use an LDAP compare operation of the user's password to authenticate the user + element password-compare {password-compare.attlist, password-encoder?} + +password-compare.attlist &= + ## The attribute in the directory which contains the user password. Defaults to "userPassword". + attribute password-attribute {xsd:string}? +password-compare.attlist &= + hash? intercept-methods = ## Can be used inside a bean definition to add a security interceptor to the bean and set up access configuration attributes for the bean's methods diff --git a/core/src/main/resources/org/springframework/security/config/spring-security-2.0.xsd b/core/src/main/resources/org/springframework/security/config/spring-security-2.0.xsd index a30ebe7495..2d808b9565 100644 --- a/core/src/main/resources/org/springframework/security/config/spring-security-2.0.xsd +++ b/core/src/main/resources/org/springframework/security/config/spring-security-2.0.xsd @@ -7,6 +7,7 @@ + @@ -96,6 +97,7 @@ + @@ -186,6 +188,44 @@ + + + + The optional server to use. If omitted, and a default LDAP server is registered (using <ldap-server> with no Id), that server will be used. + + + + + + + Group search filter. Defaults to (uniqueMember={0}). The substituted parameter is the DN of the user. + + + + + + + Search base for group membership searches. Defaults to "ou=groups". + + + + + + + + + + Search base for user searches. Defaults to "". + + + + + + + The LDAP attribute name which contains the role name which will be used within Spring Security. Defaults to "cn". + + + @@ -202,15 +242,11 @@ The optional server to use. If omitted, and a default LDAP server is registered (using <ldap-server> with no Id), that server will be used. - - - - Search base for user searches. Defaults to "". - - + + - Group search filter. Defaults to (uniqueMember={0}). + Group search filter. Defaults to (uniqueMember={0}). The substituted parameter is the DN of the user. @@ -218,21 +254,84 @@ Search base for group membership searches. Defaults to "ou=groups". + + + The LDAP attribute name which contains the role name which will be used within Spring Security. Defaults to "cn". + + Sets up an ldap authentication provider + + + - The server to authenticate against. + The optional server to use. If omitted, and a default LDAP server is registered (using <ldap-server> with no Id), that server will be used. + + + + + Search base for group membership searches. Defaults to "ou=groups". + + + + + Group search filter. Defaults to (uniqueMember={0}). The substituted parameter is the DN of the user. + + + + + The LDAP attribute name which contains the role name which will be used within Spring Security. Defaults to "cn". + + + + + A specific pattern used to build the user's DN, for example "uid={0},ou=people". The key "{0}" must be present and will be substituted with the username. + + + + + + Specifies that an LDAP provider should use an LDAP compare operation of the user's password to authenticate the user + + + + + + + + + + + + The attribute in the directory which contains the user password. Defaults to "userPassword". + + + + + Defines the hashing algorithm used on user passwords. We recommend strongly against using MD4, as it is a very weak hashing algorithm. + + + + + + + + + + + + diff --git a/core/src/test/java/org/springframework/security/config/LdapProviderBeanDefinitionParserTests.java b/core/src/test/java/org/springframework/security/config/LdapProviderBeanDefinitionParserTests.java index 38d79cee80..effe1e53bb 100644 --- a/core/src/test/java/org/springframework/security/config/LdapProviderBeanDefinitionParserTests.java +++ b/core/src/test/java/org/springframework/security/config/LdapProviderBeanDefinitionParserTests.java @@ -1,5 +1,6 @@ package org.springframework.security.config; +import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; import org.springframework.security.providers.ProviderManager; import org.springframework.security.providers.UsernamePasswordAuthenticationToken; import org.springframework.security.providers.ldap.LdapAuthenticationProvider; @@ -12,7 +13,7 @@ import org.junit.After; /** - * @author luke + * @author Luke Taylor * @version $Id$ */ public class LdapProviderBeanDefinitionParserTests { @@ -28,22 +29,43 @@ public class LdapProviderBeanDefinitionParserTests { @Test public void simpleProviderAuthenticatesCorrectly() { - appCtx = new InMemoryXmlApplicationContext(" "); + setContext(" "); - ProviderManager authManager = (ProviderManager) appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER); - - assertEquals(1, authManager.getProviders().size()); - - LdapAuthenticationProvider provider = (LdapAuthenticationProvider) authManager.getProviders().get(0); + LdapAuthenticationProvider provider = getProvider(); Authentication auth = provider.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword")); LdapUserDetailsImpl ben = (LdapUserDetailsImpl) auth.getPrincipal(); assertEquals(2, ben.getAuthorities().length); - } - + } + @Test(expected = SecurityConfigurationException.class) public void missingServerEltCausesConfigException() { - appCtx = new InMemoryXmlApplicationContext(""); + setContext(""); + } + + @Test + public void supportsPasswordComparisonAuthentication() { + setContext(" " + + "" + + " " + + " " + + " " + + ""); + LdapAuthenticationProvider provider = getProvider(); + provider.authenticate(new UsernamePasswordAuthenticationToken("ben", "ben")); } + private void setContext(String context) { + appCtx = new InMemoryXmlApplicationContext(context); + } + + + private LdapAuthenticationProvider getProvider() { + ProviderManager authManager = (ProviderManager) appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER); + + assertEquals(1, authManager.getProviders().size()); + + LdapAuthenticationProvider provider = (LdapAuthenticationProvider) authManager.getProviders().get(0); + return provider; + } } diff --git a/core/src/test/java/org/springframework/security/config/LdapUserServiceBeanDefinitionParserTests.java b/core/src/test/java/org/springframework/security/config/LdapUserServiceBeanDefinitionParserTests.java index 005ffd7a6b..196612c2b1 100644 --- a/core/src/test/java/org/springframework/security/config/LdapUserServiceBeanDefinitionParserTests.java +++ b/core/src/test/java/org/springframework/security/config/LdapUserServiceBeanDefinitionParserTests.java @@ -1,12 +1,16 @@ package org.springframework.security.config; +import java.util.Set; + +import org.springframework.security.GrantedAuthorityImpl; +import org.springframework.security.util.AuthorityUtils; import org.springframework.security.util.InMemoryXmlApplicationContext; import org.springframework.security.userdetails.UserDetailsService; import org.springframework.security.userdetails.UserDetails; import org.junit.Test; import org.junit.After; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; /** * @author Luke Taylor @@ -35,7 +39,9 @@ public class LdapUserServiceBeanDefinitionParserTests { UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS"); UserDetails ben = uds.loadUserByUsername("ben"); - assertEquals(2, ben.getAuthorities().length); + Set authorities = AuthorityUtils.authorityArrayToSet(ben.getAuthorities()); + assertEquals(2, authorities.size()); + assertTrue(authorities.contains(new GrantedAuthorityImpl("ROLE_DEVELOPERS"))); } @Test @@ -48,6 +54,19 @@ public class LdapUserServiceBeanDefinitionParserTests { assertEquals("Joe Smeth", joe.getUsername()); } + @Test + public void differentGroupRoleAttributeWorksAsExpected() throws Exception { + setContext(""); + + UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS"); + UserDetails ben = uds.loadUserByUsername("ben"); + + Set authorities = AuthorityUtils.authorityArrayToSet(ben.getAuthorities()); + assertEquals(2, authorities.size()); + assertTrue(authorities.contains(new GrantedAuthorityImpl("ROLE_DEVELOPER"))); + + } + @Test public void isSupportedByAuthenticationProviderElement() { setContext(