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.
This commit is contained in:
Luke Taylor 2008-04-29 16:53:24 +00:00
parent 104716fedb
commit e4b32b8d29
5 changed files with 107 additions and 8 deletions

View File

@ -93,6 +93,8 @@ public class LdapProviderBeanDefinitionParser implements BeanDefinitionParser {
RootBeanDefinition ldapProvider = new RootBeanDefinition(LdapAuthenticationProvider.class); RootBeanDefinition ldapProvider = new RootBeanDefinition(LdapAuthenticationProvider.class);
ldapProvider.getConstructorArgumentValues().addGenericArgumentValue(authenticator); ldapProvider.getConstructorArgumentValues().addGenericArgumentValue(authenticator);
ldapProvider.getConstructorArgumentValues().addGenericArgumentValue(LdapUserServiceBeanDefinitionParser.parseAuthoritiesPopulator(elt, parserContext)); ldapProvider.getConstructorArgumentValues().addGenericArgumentValue(LdapUserServiceBeanDefinitionParser.parseAuthoritiesPopulator(elt, parserContext));
ldapProvider.getPropertyValues().addPropertyValue("userDetailsContextMapper",
LdapUserServiceBeanDefinitionParser.parseUserDetailsClass(elt, parserContext));
ConfigUtils.getRegisteredProviders(parserContext).add(ldapProvider); ConfigUtils.getRegisteredProviders(parserContext).add(ldapProvider);

View File

@ -1,6 +1,9 @@
package org.springframework.security.config; 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.LdapUserDetailsService;
import org.springframework.security.userdetails.ldap.PersonContextMapper;
import org.springframework.security.ldap.search.FilterBasedLdapUserSearch; import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
import org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator; import org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator;
import org.springframework.beans.factory.xml.ParserContext; import org.springframework.beans.factory.xml.ParserContext;
@ -29,6 +32,9 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
public static final String DEF_GROUP_SEARCH_BASE = "ou=groups"; 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) { protected Class getBeanClass(Element element) {
return LdapUserDetailsService.class; return LdapUserDetailsService.class;
@ -42,6 +48,7 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
builder.addConstructorArg(parseSearchBean(elt, parserContext)); builder.addConstructorArg(parseSearchBean(elt, parserContext));
builder.addConstructorArg(parseAuthoritiesPopulator(elt, parserContext)); builder.addConstructorArg(parseAuthoritiesPopulator(elt, parserContext));
builder.addPropertyValue("userDetailsMapper", parseUserDetailsClass(elt, parserContext));
} }
static RootBeanDefinition parseSearchBean(Element elt, ParserContext parserContext) { static RootBeanDefinition parseSearchBean(Element elt, ParserContext parserContext) {
@ -86,6 +93,17 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
return contextSource; 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) { static RootBeanDefinition parseAuthoritiesPopulator(Element elt, ParserContext parserContext) {
String groupSearchFilter = elt.getAttribute(ATT_GROUP_SEARCH_FILTER); String groupSearchFilter = elt.getAttribute(ATT_GROUP_SEARCH_FILTER);
String groupSearchBase = elt.getAttribute(ATT_GROUP_SEARCH_BASE); String groupSearchBase = elt.getAttribute(ATT_GROUP_SEARCH_BASE);

View File

@ -90,10 +90,13 @@ user-search-filter-attribute =
attribute user-search-filter {xsd:string} attribute user-search-filter {xsd:string}
user-search-base-attribute = user-search-base-attribute =
## Search base for user searches. Defaults to "". ## Search base for user searches. Defaults to "".
attribute user-search-base {xsd:string}? attribute user-search-base {xsd:string}
group-role-attribute-attribute = group-role-attribute-attribute =
## The LDAP attribute name which contains the role name which will be used within Spring Security. Defaults to "cn". ## 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} 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 = ldap-user-service =
@ -115,6 +118,8 @@ ldap-us.attlist &=
cache-ref? cache-ref?
ldap-us.attlist &= ldap-us.attlist &=
role-prefix? role-prefix?
ldap-us.attlist &=
user-details-class-attribute?
ldap-authentication-provider = ldap-authentication-provider =
## Sets up an ldap authentication provider ## Sets up an ldap authentication provider
@ -136,6 +141,8 @@ ldap-ap.attlist &=
attribute user-dn-pattern {xsd:string}? attribute user-dn-pattern {xsd:string}?
ldap-ap.attlist &= ldap-ap.attlist &=
role-prefix? role-prefix?
ldap-ap.attlist &=
user-details-class-attribute?
password-compare-element = password-compare-element =
## Specifies that an LDAP provider should use an LDAP compare operation of the user's password to authenticate the user ## Specifies that an LDAP provider should use an LDAP compare operation of the user's password to authenticate the user

View File

@ -238,7 +238,7 @@
<xs:attribute name="user-search-filter" use="required" type="xs:string"/> <xs:attribute name="user-search-filter" use="required" type="xs:string"/>
</xs:attributeGroup> </xs:attributeGroup>
<xs:attributeGroup name="user-search-base-attribute"> <xs:attributeGroup name="user-search-base-attribute">
<xs:attribute name="user-search-base" type="xs:string"> <xs:attribute name="user-search-base" use="required" type="xs:string">
<xs:annotation> <xs:annotation>
<xs:documentation>Search base for user searches. Defaults to "".</xs:documentation> <xs:documentation>Search base for user searches. Defaults to "".</xs:documentation>
</xs:annotation> </xs:annotation>
@ -252,6 +252,21 @@
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:attributeGroup name="user-details-class-attribute">
<xs:attribute name="user-details-class" use="required">
<xs:annotation>
<xs:documentation>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</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="person"/>
<xs:enumeration value="inetOrgPerson"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:attributeGroup>
<xs:element name="ldap-user-service" substitutionGroup="security:any-user-service"> <xs:element name="ldap-user-service" substitutionGroup="security:any-user-service">
<xs:complexType> <xs:complexType>
<xs:attributeGroup ref="security:ldap-us.attlist"/> <xs:attributeGroup ref="security:ldap-us.attlist"/>
@ -272,7 +287,11 @@
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
<xs:attribute name="user-search-filter" type="xs:string"/> <xs:attribute name="user-search-filter" type="xs:string"/>
<xs:attributeGroup ref="security:user-search-base-attribute"/> <xs:attribute name="user-search-base" type="xs:string">
<xs:annotation>
<xs:documentation>Search base for user searches. Defaults to "".</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="group-search-filter" type="xs:string"> <xs:attribute name="group-search-filter" type="xs:string">
<xs:annotation> <xs:annotation>
<xs:documentation>Group search filter. Defaults to (uniqueMember={0}). The substituted <xs:documentation>Group search filter. Defaults to (uniqueMember={0}). The substituted
@ -303,6 +322,19 @@
persistent storage (e.g. "ROLE_").</xs:documentation> persistent storage (e.g. "ROLE_").</xs:documentation>
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
<xs:attribute name="user-details-class">
<xs:annotation>
<xs:documentation>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</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="person"/>
<xs:enumeration value="inetOrgPerson"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:element name="ldap-authentication-provider"> <xs:element name="ldap-authentication-provider">
<xs:annotation> <xs:annotation>
@ -362,7 +394,11 @@
</xs:documentation> </xs:documentation>
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
<xs:attributeGroup ref="security:user-search-base-attribute"/> <xs:attribute name="user-search-base" type="xs:string">
<xs:annotation>
<xs:documentation>Search base for user searches. Defaults to "".</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="user-search-filter" type="xs:string"/> <xs:attribute name="user-search-filter" type="xs:string"/>
<xs:attribute name="group-search-base" type="xs:string"> <xs:attribute name="group-search-base" type="xs:string">
<xs:annotation> <xs:annotation>
@ -395,6 +431,19 @@
persistent storage (e.g. "ROLE_").</xs:documentation> persistent storage (e.g. "ROLE_").</xs:documentation>
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
<xs:attribute name="user-details-class">
<xs:annotation>
<xs:documentation>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</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="person"/>
<xs:enumeration value="inetOrgPerson"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:attributeGroup name="password-compare.attlist"> <xs:attributeGroup name="password-compare.attlist">
<xs:attribute name="password-attribute" type="xs:string"> <xs:attribute name="password-attribute" type="xs:string">

View File

@ -7,6 +7,8 @@ import org.springframework.security.util.AuthorityUtils;
import org.springframework.security.util.InMemoryXmlApplicationContext; import org.springframework.security.util.InMemoryXmlApplicationContext;
import org.springframework.security.userdetails.UserDetailsService; import org.springframework.security.userdetails.UserDetailsService;
import org.springframework.security.userdetails.UserDetails; 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.Test;
import org.junit.After; import org.junit.After;
@ -100,6 +102,27 @@ public class LdapUserServiceBeanDefinitionParserTests {
"</authentication-provider>"); "</authentication-provider>");
} }
@Test
public void personContextMapperIsSupported() {
setContext(
"<ldap-server />" +
"<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' user-details-class='person'/>");
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
UserDetails ben = uds.loadUserByUsername("ben");
assertTrue(ben instanceof Person);
}
@Test
public void inetOrgContextMapperIsSupported() {
setContext(
"<ldap-server id='someServer'/>" +
"<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' user-details-class='inetOrgPerson'/>");
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
UserDetails ben = uds.loadUserByUsername("ben");
assertTrue(ben instanceof InetOrgPerson);
}
private void setContext(String context) { private void setContext(String context) {
appCtx = new InMemoryXmlApplicationContext(context); appCtx = new InMemoryXmlApplicationContext(context);
} }