mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-07-16 15:23:31 +00:00
SEC-1137: Added support for an external UserDetailsContextMapper using the attribute user-context-mapper-ref.
This commit is contained in:
parent
bfa2806034
commit
0473cfbfc0
@ -97,7 +97,7 @@ public class LdapProviderBeanDefinitionParser implements BeanDefinitionParser {
|
||||
ldapProvider.addConstructorArgValue(authenticatorBuilder.getBeanDefinition());
|
||||
ldapProvider.addConstructorArgValue(LdapUserServiceBeanDefinitionParser.parseAuthoritiesPopulator(elt, parserContext));
|
||||
ldapProvider.addPropertyValue("userDetailsContextMapper",
|
||||
LdapUserServiceBeanDefinitionParser.parseUserDetailsClass(elt, parserContext));
|
||||
LdapUserServiceBeanDefinitionParser.parseUserDetailsClassOrUserMapperRef(elt, parserContext));
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.LDAP_AUTHENTICATION_PROVIDER, ldapProvider.getBeanDefinition());
|
||||
|
||||
ConfigUtils.addAuthenticationProvider(parserContext, BeanIds.LDAP_AUTHENTICATION_PROVIDER);
|
||||
|
@ -1,5 +1,6 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
@ -29,6 +30,7 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
|
||||
|
||||
static final String ATT_ROLE_PREFIX = "role-prefix";
|
||||
static final String ATT_USER_CLASS = "user-details-class";
|
||||
static final String ATT_USER_CONTEXT_MAPPER_REF = "user-context-mapper-ref";
|
||||
static final String OPT_PERSON = "person";
|
||||
static final String OPT_INETORGPERSON = "inetOrgPerson";
|
||||
|
||||
@ -49,8 +51,9 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
|
||||
}
|
||||
|
||||
builder.addConstructorArgValue(parseSearchBean(elt, parserContext));
|
||||
builder.getRawBeanDefinition().setSource(parserContext.extractSource(elt));
|
||||
builder.addConstructorArgValue(parseAuthoritiesPopulator(elt, parserContext));
|
||||
builder.addPropertyValue("userDetailsMapper", parseUserDetailsClass(elt, parserContext));
|
||||
builder.addPropertyValue("userDetailsMapper", parseUserDetailsClassOrUserMapperRef(elt, parserContext));
|
||||
}
|
||||
|
||||
static RootBeanDefinition parseSearchBean(Element elt, ParserContext parserContext) {
|
||||
@ -109,15 +112,32 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
|
||||
registry.registerBeanDefinition(BeanIds.CONTEXT_SOURCE_SETTING_POST_PROCESSOR, bdb.getBeanDefinition());
|
||||
}
|
||||
|
||||
static RootBeanDefinition parseUserDetailsClass(Element elt, ParserContext parserContext) {
|
||||
static BeanMetadataElement parseUserDetailsClassOrUserMapperRef(Element elt, ParserContext parserContext) {
|
||||
String userDetailsClass = elt.getAttribute(ATT_USER_CLASS);
|
||||
String userMapperRef = elt.getAttribute(ATT_USER_CONTEXT_MAPPER_REF);
|
||||
|
||||
if (StringUtils.hasText(userDetailsClass) && StringUtils.hasText(userMapperRef)) {
|
||||
parserContext.getReaderContext().error("Attributes " + ATT_USER_CLASS + " and " + ATT_USER_CONTEXT_MAPPER_REF
|
||||
+ " cannot be used together.", parserContext.extractSource(elt));
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(userMapperRef)) {
|
||||
return new RuntimeBeanReference(userMapperRef);
|
||||
}
|
||||
|
||||
RootBeanDefinition mapper;
|
||||
|
||||
if (OPT_PERSON.equals(userDetailsClass)) {
|
||||
return new RootBeanDefinition(PERSON_MAPPER_CLASS, null, null);
|
||||
mapper = new RootBeanDefinition(PERSON_MAPPER_CLASS, null, null);
|
||||
} else if (OPT_INETORGPERSON.equals(userDetailsClass)) {
|
||||
return new RootBeanDefinition(INET_ORG_PERSON_MAPPER_CLASS, null, null);
|
||||
mapper = new RootBeanDefinition(INET_ORG_PERSON_MAPPER_CLASS, null, null);
|
||||
} else {
|
||||
mapper = new RootBeanDefinition(LDAP_USER_MAPPER_CLASS, null, null);
|
||||
}
|
||||
return new RootBeanDefinition(LDAP_USER_MAPPER_CLASS, null, null);
|
||||
|
||||
mapper.setSource(parserContext.extractSource(elt));
|
||||
|
||||
return mapper;
|
||||
}
|
||||
|
||||
static RootBeanDefinition parseAuthoritiesPopulator(Element elt, ParserContext parserContext) {
|
||||
|
@ -106,6 +106,9 @@ group-role-attribute-attribute =
|
||||
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"}
|
||||
user-context-mapper-attribute =
|
||||
## Allows explicit customization of the loaded user object by specifying a UserDetailsContextMapper bean which will be called with the context information from the user's directory entry
|
||||
attribute user-context-mapper-ref {xsd:token}
|
||||
|
||||
|
||||
ldap-user-service =
|
||||
@ -128,7 +131,7 @@ ldap-us.attlist &=
|
||||
ldap-us.attlist &=
|
||||
role-prefix?
|
||||
ldap-us.attlist &=
|
||||
user-details-class-attribute?
|
||||
(user-details-class-attribute | user-context-mapper-attribute)?
|
||||
|
||||
ldap-authentication-provider =
|
||||
## Sets up an ldap authentication provider
|
||||
@ -151,7 +154,7 @@ ldap-ap.attlist &=
|
||||
ldap-ap.attlist &=
|
||||
role-prefix?
|
||||
ldap-ap.attlist &=
|
||||
user-details-class-attribute?
|
||||
(user-details-class-attribute | user-context-mapper-attribute)?
|
||||
|
||||
password-compare-element =
|
||||
## Specifies that an LDAP provider should use an LDAP compare operation of the user's password to authenticate the user
|
||||
|
@ -301,6 +301,15 @@
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
<xs:attributeGroup name="user-context-mapper-attribute">
|
||||
<xs:attribute name="user-context-mapper-ref" use="required" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Allows explicit customization of the loaded user object by specifying
|
||||
a UserDetailsContextMapper bean which will be called with the context information
|
||||
from the user's directory entry</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="ldap-user-service" substitutionGroup="security:any-user-service">
|
||||
<xs:complexType>
|
||||
<xs:attributeGroup ref="security:ldap-us.attlist"/>
|
||||
@ -376,6 +385,13 @@
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="user-context-mapper-ref" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Allows explicit customization of the loaded user object by specifying
|
||||
a UserDetailsContextMapper bean which will be called with the context information
|
||||
from the user's directory entry</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="ldap-authentication-provider">
|
||||
<xs:annotation>
|
||||
@ -504,6 +520,13 @@
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="user-context-mapper-ref" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Allows explicit customization of the loaded user object by specifying
|
||||
a UserDetailsContextMapper bean which will be called with the context information
|
||||
from the user's directory entry</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
<xs:attributeGroup name="password-compare.attlist">
|
||||
<xs:attribute name="password-attribute" type="xs:token">
|
||||
@ -623,7 +646,16 @@
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element ref="security:expression-handler"/>
|
||||
<xs:element name="expression-handler">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Defines the SecurityExpressionHandler instance which will be
|
||||
used if expression-based access-control is enabled. A default implementation
|
||||
(with no ACL support) will be used if not supplied.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:attributeGroup ref="security:ref"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:choice>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" name="protect-pointcut">
|
||||
<xs:annotation>
|
||||
@ -693,16 +725,6 @@
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="expression-handler">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Defines the SecurityExpressionHandler instance which will be used if
|
||||
expression-based access-control is enabled. A default implementation (with no ACL
|
||||
support) will be used if not supplied.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:attributeGroup ref="security:ref"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="custom-after-invocation-provider">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to decorate an AfterInvocationProvider to specify that it should be
|
||||
@ -759,7 +781,21 @@
|
||||
<xs:attributeGroup ref="security:form-login.attlist"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element ref="security:openid-login"/>
|
||||
<xs:element name="openid-login">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Sets up form login for authentication with an Open ID
|
||||
identity</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:attributeGroup ref="security:form-login.attlist"/>
|
||||
<xs:attribute name="user-service-ref" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A reference to a user-service (or UserDetailsService bean)
|
||||
Id</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="x509">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Adds support for X.509 client authentication.</xs:documentation>
|
||||
@ -823,7 +859,12 @@
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element maxOccurs="unbounded" ref="security:port-mapping"/>
|
||||
<xs:element maxOccurs="unbounded" name="port-mapping">
|
||||
<xs:complexType>
|
||||
<xs:attributeGroup ref="security:http-port"/>
|
||||
<xs:attributeGroup ref="security:https-port"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
@ -1108,21 +1149,6 @@
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="openid-login">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Sets up form login for authentication with an Open ID
|
||||
identity</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:attributeGroup ref="security:form-login.attlist"/>
|
||||
<xs:attribute name="user-service-ref" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A reference to a user-service (or UserDetailsService bean)
|
||||
Id</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="filter-chain-map">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to explicitly configure a FilterChainProxy instance with a
|
||||
@ -1348,12 +1374,6 @@
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="port-mapping">
|
||||
<xs:complexType>
|
||||
<xs:attributeGroup ref="security:http-port"/>
|
||||
<xs:attributeGroup ref="security:https-port"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:attributeGroup name="http-port">
|
||||
<xs:attribute name="http" use="required" type="xs:token"/>
|
||||
</xs:attributeGroup>
|
||||
@ -1474,7 +1494,14 @@
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" ref="security:user"/>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" name="user">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Represents a user in the application.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:attributeGroup ref="security:user.attlist"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="id" type="xs:ID">
|
||||
<xs:annotation>
|
||||
@ -1488,14 +1515,6 @@
|
||||
<xs:attributeGroup name="properties-file">
|
||||
<xs:attribute name="properties" type="xs:token"/>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="user">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Represents a user in the application.</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:attributeGroup ref="security:user.attlist"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:attributeGroup name="user.attlist">
|
||||
<xs:attribute name="name" use="required" type="xs:token">
|
||||
<xs:annotation>
|
||||
|
@ -141,6 +141,18 @@ public class LdapUserServiceBeanDefinitionParserTests {
|
||||
assertTrue(ben instanceof InetOrgPerson);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void externalContextMapperIsSupported() {
|
||||
setContext(
|
||||
"<ldap-server id='someServer'/>" +
|
||||
"<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' user-context-mapper-ref='mapper'/>" +
|
||||
"<b:bean id='mapper' class='"+ InetOrgPersonContextMapper.class.getName() +"'/>");
|
||||
|
||||
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
|
||||
UserDetails ben = uds.loadUserByUsername("ben");
|
||||
assertTrue(ben instanceof InetOrgPerson);
|
||||
}
|
||||
|
||||
|
||||
private void setContext(String context) {
|
||||
appCtx = new InMemoryXmlApplicationContext(context);
|
||||
|
Loading…
x
Reference in New Issue
Block a user