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,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;

View File

@ -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);

View File

@ -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

View File

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