1 package org.springframework.security.config;
2
3 import org.springframework.beans.factory.config.BeanDefinition;
4 import org.springframework.beans.factory.config.RuntimeBeanReference;
5 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
6 import org.springframework.beans.factory.support.RootBeanDefinition;
7 import org.springframework.beans.factory.xml.BeanDefinitionParser;
8 import org.springframework.beans.factory.xml.ParserContext;
9 import org.springframework.util.StringUtils;
10 import org.springframework.util.xml.DomUtils;
11
12 import org.apache.commons.logging.Log;
13 import org.apache.commons.logging.LogFactory;
14 import org.w3c.dom.Element;
15
16
17
18
19
20
21
22
23 public class LdapProviderBeanDefinitionParser implements BeanDefinitionParser {
24 private Log logger = LogFactory.getLog(getClass());
25
26 private static final String ATT_USER_DN_PATTERN = "user-dn-pattern";
27 private static final String ATT_USER_PASSWORD = "password-attribute";
28 private static final String ATT_HASH = PasswordEncoderParser.ATT_HASH;
29
30 private static final String DEF_USER_SEARCH_FILTER = "uid={0}";
31
32 private static final String PROVIDER_CLASS = "org.springframework.security.providers.ldap.LdapAuthenticationProvider";
33 private static final String BIND_AUTH_CLASS = "org.springframework.security.providers.ldap.authenticator.BindAuthenticator";
34 private static final String PASSWD_AUTH_CLASS = "org.springframework.security.providers.ldap.authenticator.PasswordComparisonAuthenticator";
35
36 public BeanDefinition parse(Element elt, ParserContext parserContext) {
37 RuntimeBeanReference contextSource = LdapUserServiceBeanDefinitionParser.parseServerReference(elt, parserContext);
38
39 BeanDefinition searchBean = LdapUserServiceBeanDefinitionParser.parseSearchBean(elt, parserContext);
40 String userDnPattern = elt.getAttribute(ATT_USER_DN_PATTERN);
41
42 String[] userDnPatternArray = new String[0];
43
44 if (StringUtils.hasText(userDnPattern)) {
45 userDnPatternArray = new String[] {userDnPattern};
46
47 } else if (searchBean == null) {
48 logger.info("No search information or DN pattern specified. Using default search filter '" + DEF_USER_SEARCH_FILTER + "'");
49 BeanDefinitionBuilder searchBeanBuilder = BeanDefinitionBuilder.rootBeanDefinition(LdapUserServiceBeanDefinitionParser.LDAP_SEARCH_CLASS);
50 searchBeanBuilder.setSource(elt);
51 searchBeanBuilder.addConstructorArg("");
52 searchBeanBuilder.addConstructorArg(DEF_USER_SEARCH_FILTER);
53 searchBeanBuilder.addConstructorArg(contextSource);
54 searchBean = searchBeanBuilder.getBeanDefinition();
55 }
56
57 BeanDefinitionBuilder authenticatorBuilder =
58 BeanDefinitionBuilder.rootBeanDefinition(BIND_AUTH_CLASS);
59 Element passwordCompareElt = DomUtils.getChildElementByTagName(elt, Elements.LDAP_PASSWORD_COMPARE);
60
61 if (passwordCompareElt != null) {
62 authenticatorBuilder =
63 BeanDefinitionBuilder.rootBeanDefinition(PASSWD_AUTH_CLASS);
64
65 String passwordAttribute = passwordCompareElt.getAttribute(ATT_USER_PASSWORD);
66 if (StringUtils.hasText(passwordAttribute)) {
67 authenticatorBuilder.addPropertyValue("passwordAttributeName", passwordAttribute);
68 }
69
70 Element passwordEncoderElement = DomUtils.getChildElementByTagName(passwordCompareElt, Elements.PASSWORD_ENCODER);
71 String hash = passwordCompareElt.getAttribute(ATT_HASH);
72
73 if (passwordEncoderElement != null) {
74 if (StringUtils.hasText(hash)) {
75 parserContext.getReaderContext().warning("Attribute 'hash' cannot be used with 'password-encoder' and " +
76 "will be ignored.", parserContext.extractSource(elt));
77 }
78 PasswordEncoderParser pep = new PasswordEncoderParser(passwordEncoderElement, parserContext);
79 authenticatorBuilder.addPropertyValue("passwordEncoder", pep.getPasswordEncoder());
80
81 if (pep.getSaltSource() != null) {
82 parserContext.getReaderContext().warning("Salt source information isn't valid when used with LDAP",
83 passwordEncoderElement);
84 }
85 } else if (StringUtils.hasText(hash)) {
86 Class encoderClass = (Class) PasswordEncoderParser.ENCODER_CLASSES.get(hash);
87 authenticatorBuilder.addPropertyValue("passwordEncoder", new RootBeanDefinition(encoderClass));
88 }
89 }
90
91 authenticatorBuilder.addConstructorArg(contextSource);
92 authenticatorBuilder.addPropertyValue("userDnPatterns", userDnPatternArray);
93
94 if (searchBean != null) {
95 authenticatorBuilder.addPropertyValue("userSearch", searchBean);
96 }
97
98 BeanDefinitionBuilder ldapProvider = BeanDefinitionBuilder.rootBeanDefinition(PROVIDER_CLASS);
99 ldapProvider.addConstructorArg(authenticatorBuilder.getBeanDefinition());
100 ldapProvider.addConstructorArg(LdapUserServiceBeanDefinitionParser.parseAuthoritiesPopulator(elt, parserContext));
101 ldapProvider.addPropertyValue("userDetailsContextMapper",
102 LdapUserServiceBeanDefinitionParser.parseUserDetailsClass(elt, parserContext));
103 parserContext.getRegistry().registerBeanDefinition(BeanIds.LDAP_AUTHENTICATION_PROVIDER, ldapProvider.getBeanDefinition());
104
105 ConfigUtils.addAuthenticationProvider(parserContext, BeanIds.LDAP_AUTHENTICATION_PROVIDER);
106
107 return null;
108 }
109 }