From e4b32b8d29c5bdd4a13f55e13e1d6a1a8b63ab36 Mon Sep 17 00:00:00 2001 From: Luke Taylor Date: Tue, 29 Apr 2008 16:53:24 +0000 Subject: [PATCH] OPEN - issue SEC-807: Allow mapping to a standard Ldap UserDetails through the namespace http://jira.springframework.org/browse/SEC-807. Added support for user-details-class attribute to ldap-authentication-provider and ldap-user-service. --- .../LdapProviderBeanDefinitionParser.java | 4 +- .../LdapUserServiceBeanDefinitionParser.java | 22 +++++++- .../security/config/spring-security-2.0.rnc | 9 ++- .../security/config/spring-security-2.0.xsd | 55 ++++++++++++++++++- ...pUserServiceBeanDefinitionParserTests.java | 25 ++++++++- 5 files changed, 107 insertions(+), 8 deletions(-) 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 9cd00e1a66..099270d518 100644 --- a/core/src/main/java/org/springframework/security/config/LdapProviderBeanDefinitionParser.java +++ b/core/src/main/java/org/springframework/security/config/LdapProviderBeanDefinitionParser.java @@ -93,7 +93,9 @@ public class LdapProviderBeanDefinitionParser implements BeanDefinitionParser { RootBeanDefinition ldapProvider = new RootBeanDefinition(LdapAuthenticationProvider.class); ldapProvider.getConstructorArgumentValues().addGenericArgumentValue(authenticator); ldapProvider.getConstructorArgumentValues().addGenericArgumentValue(LdapUserServiceBeanDefinitionParser.parseAuthoritiesPopulator(elt, parserContext)); - + ldapProvider.getPropertyValues().addPropertyValue("userDetailsContextMapper", + LdapUserServiceBeanDefinitionParser.parseUserDetailsClass(elt, parserContext)); + ConfigUtils.getRegisteredProviders(parserContext).add(ldapProvider); return null; 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 fe2f304e39..cc07f5a465 100644 --- a/core/src/main/java/org/springframework/security/config/LdapUserServiceBeanDefinitionParser.java +++ b/core/src/main/java/org/springframework/security/config/LdapUserServiceBeanDefinitionParser.java @@ -1,6 +1,9 @@ package org.springframework.security.config; +import org.springframework.security.userdetails.ldap.InetOrgPersonContextMapper; +import org.springframework.security.userdetails.ldap.LdapUserDetailsMapper; import org.springframework.security.userdetails.ldap.LdapUserDetailsService; +import org.springframework.security.userdetails.ldap.PersonContextMapper; import org.springframework.security.ldap.search.FilterBasedLdapUserSearch; import org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator; import org.springframework.beans.factory.xml.ParserContext; @@ -17,7 +20,7 @@ import org.w3c.dom.Element; * @since 2.0 */ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServiceBeanDefinitionParser { - public 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 = ""; @@ -28,7 +31,10 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ public static final String DEF_GROUP_SEARCH_FILTER = "(uniqueMember={0})"; public static final String DEF_GROUP_SEARCH_BASE = "ou=groups"; - static final String ATT_ROLE_PREFIX = "role-prefix"; + static final String ATT_ROLE_PREFIX = "role-prefix"; + static final String ATT_USER_CLASS = "user-details-class"; + static final String OPT_PERSON = "person"; + static final String OPT_INETORGPERSON = "inetOrgPerson"; protected Class getBeanClass(Element element) { return LdapUserDetailsService.class; @@ -42,6 +48,7 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ builder.addConstructorArg(parseSearchBean(elt, parserContext)); builder.addConstructorArg(parseAuthoritiesPopulator(elt, parserContext)); + builder.addPropertyValue("userDetailsMapper", parseUserDetailsClass(elt, parserContext)); } static RootBeanDefinition parseSearchBean(Element elt, ParserContext parserContext) { @@ -86,6 +93,17 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ return contextSource; } + static RootBeanDefinition parseUserDetailsClass(Element elt, ParserContext parserContext) { + String userDetailsClass = elt.getAttribute(ATT_USER_CLASS); + + if(OPT_PERSON.equals(userDetailsClass)) { + return new RootBeanDefinition(PersonContextMapper.class); + } else if (OPT_INETORGPERSON.equals(userDetailsClass)) { + return new RootBeanDefinition(InetOrgPersonContextMapper.class); + } + return new RootBeanDefinition(LdapUserDetailsMapper.class); + } + static RootBeanDefinition parseAuthoritiesPopulator(Element elt, ParserContext parserContext) { String groupSearchFilter = elt.getAttribute(ATT_GROUP_SEARCH_FILTER); String groupSearchBase = elt.getAttribute(ATT_GROUP_SEARCH_BASE); 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 a31912b117..ea569296ba 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 @@ -90,10 +90,13 @@ 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}? + 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} +user-details-class-attribute = + ## Allows the objectClass of the user entry to be specified. If set, the framework will attempt to load standard attributes for the defined class into the returned UserDetails object + attribute user-details-class {"person" | "inetOrgPerson"} ldap-user-service = @@ -115,6 +118,8 @@ ldap-us.attlist &= cache-ref? ldap-us.attlist &= role-prefix? +ldap-us.attlist &= + user-details-class-attribute? ldap-authentication-provider = ## Sets up an ldap authentication provider @@ -136,6 +141,8 @@ ldap-ap.attlist &= attribute user-dn-pattern {xsd:string}? ldap-ap.attlist &= role-prefix? +ldap-ap.attlist &= + user-details-class-attribute? password-compare-element = ## Specifies that an LDAP provider should use an LDAP compare operation of the user's password to authenticate the user 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 a7b2a0a579..1d8830a073 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 @@ -238,7 +238,7 @@ - + Search base for user searches. Defaults to "". @@ -252,6 +252,21 @@ + + + + Allows the objectClass of the user entry to be specified. If set, the + framework will attempt to load standard attributes for the defined class into the returned + UserDetails object + + + + + + + + + @@ -272,7 +287,11 @@ - + + + Search base for user searches. Defaults to "". + + Group search filter. Defaults to (uniqueMember={0}). The substituted @@ -303,6 +322,19 @@ persistent storage (e.g. "ROLE_"). + + + Allows the objectClass of the user entry to be specified. If set, the + framework will attempt to load standard attributes for the defined class into the returned + UserDetails object + + + + + + + + @@ -362,7 +394,11 @@ - + + + Search base for user searches. Defaults to "". + + @@ -395,6 +431,19 @@ persistent storage (e.g. "ROLE_"). + + + Allows the objectClass of the user entry to be specified. If set, the + framework will attempt to load standard attributes for the defined class into the returned + UserDetails object + + + + + + + + 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 3221044d51..3ed6a93ce9 100644 --- a/core/src/test/java/org/springframework/security/config/LdapUserServiceBeanDefinitionParserTests.java +++ b/core/src/test/java/org/springframework/security/config/LdapUserServiceBeanDefinitionParserTests.java @@ -7,6 +7,8 @@ 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.springframework.security.userdetails.ldap.InetOrgPerson; +import org.springframework.security.userdetails.ldap.Person; import org.junit.Test; import org.junit.After; @@ -99,7 +101,28 @@ public class LdapUserServiceBeanDefinitionParserTests { " " + ""); } - + + @Test + public void personContextMapperIsSupported() { + setContext( + "" + + ""); + UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS"); + UserDetails ben = uds.loadUserByUsername("ben"); + assertTrue(ben instanceof Person); + } + + @Test + public void inetOrgContextMapperIsSupported() { + setContext( + "" + + ""); + UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS"); + UserDetails ben = uds.loadUserByUsername("ben"); + assertTrue(ben instanceof InetOrgPerson); + } + + private void setContext(String context) { appCtx = new InMemoryXmlApplicationContext(context); }