1 package org.springframework.security.config;
2
3 import org.springframework.beans.factory.xml.ParserContext;
4 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
5 import org.springframework.beans.factory.support.RootBeanDefinition;
6 import org.springframework.beans.factory.config.RuntimeBeanReference;
7 import org.springframework.util.StringUtils;
8
9 import org.w3c.dom.Element;
10
11
12
13
14
15
16 public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServiceBeanDefinitionParser {
17 public static final String ATT_SERVER = "server-ref";
18 public static final String ATT_USER_SEARCH_FILTER = "user-search-filter";
19 public static final String ATT_USER_SEARCH_BASE = "user-search-base";
20 public static final String DEF_USER_SEARCH_BASE = "";
21
22 public static final String ATT_GROUP_SEARCH_FILTER = "group-search-filter";
23 public static final String ATT_GROUP_SEARCH_BASE = "group-search-base";
24 public static final String ATT_GROUP_ROLE_ATTRIBUTE = "group-role-attribute";
25 public static final String DEF_GROUP_SEARCH_FILTER = "(uniqueMember={0})";
26 public static final String DEF_GROUP_SEARCH_BASE = "";
27
28 static final String ATT_ROLE_PREFIX = "role-prefix";
29 static final String ATT_USER_CLASS = "user-details-class";
30 static final String OPT_PERSON = "person";
31 static final String OPT_INETORGPERSON = "inetOrgPerson";
32
33 public static final String LDAP_SEARCH_CLASS = "org.springframework.security.ldap.search.FilterBasedLdapUserSearch";
34 public static final String PERSON_MAPPER_CLASS = "org.springframework.security.userdetails.ldap.PersonContextMapper";
35 public static final String INET_ORG_PERSON_MAPPER_CLASS = "org.springframework.security.userdetails.ldap.InetOrgPersonContextMapper";
36 public static final String LDAP_USER_MAPPER_CLASS = "org.springframework.security.userdetails.ldap.LdapUserDetailsMapper";
37 public static final String LDAP_AUTHORITIES_POPULATOR_CLASS = "org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator";
38
39 protected String getBeanClassName(Element element) {
40 return "org.springframework.security.userdetails.ldap.LdapUserDetailsService";
41 }
42
43 protected void doParse(Element elt, ParserContext parserContext, BeanDefinitionBuilder builder) {
44
45 if (!StringUtils.hasText(elt.getAttribute(ATT_USER_SEARCH_FILTER))) {
46 parserContext.getReaderContext().error("User search filter must be supplied", elt);
47 }
48
49 builder.addConstructorArg(parseSearchBean(elt, parserContext));
50 builder.addConstructorArg(parseAuthoritiesPopulator(elt, parserContext));
51 builder.addPropertyValue("userDetailsMapper", parseUserDetailsClass(elt, parserContext));
52 }
53
54 static RootBeanDefinition parseSearchBean(Element elt, ParserContext parserContext) {
55 String userSearchFilter = elt.getAttribute(ATT_USER_SEARCH_FILTER);
56 String userSearchBase = elt.getAttribute(ATT_USER_SEARCH_BASE);
57 Object source = parserContext.extractSource(elt);
58
59 if (StringUtils.hasText(userSearchBase)) {
60 if(!StringUtils.hasText(userSearchFilter)) {
61 parserContext.getReaderContext().error(ATT_USER_SEARCH_BASE + " cannot be used without a " + ATT_USER_SEARCH_FILTER, source);
62 }
63 } else {
64 userSearchBase = DEF_USER_SEARCH_BASE;
65 }
66
67 if (!StringUtils.hasText(userSearchFilter)) {
68 return null;
69 }
70
71 BeanDefinitionBuilder searchBuilder = BeanDefinitionBuilder.rootBeanDefinition(LDAP_SEARCH_CLASS);
72 searchBuilder.setSource(source);
73 searchBuilder.addConstructorArg(userSearchBase);
74 searchBuilder.addConstructorArg(userSearchFilter);
75 searchBuilder.addConstructorArg(parseServerReference(elt, parserContext));
76
77 return (RootBeanDefinition) searchBuilder.getBeanDefinition();
78 }
79
80 static RuntimeBeanReference parseServerReference(Element elt, ParserContext parserContext) {
81 String server = elt.getAttribute(ATT_SERVER);
82 boolean requiresDefaultName = false;
83
84 if (!StringUtils.hasText(server)) {
85 server = BeanIds.CONTEXT_SOURCE;
86 requiresDefaultName = true;
87 }
88
89 RuntimeBeanReference contextSource = new RuntimeBeanReference(server);
90 contextSource.setSource(parserContext.extractSource(elt));
91 LdapConfigUtils.registerPostProcessorIfNecessary(parserContext.getRegistry(), requiresDefaultName);
92
93 return contextSource;
94 }
95
96 static RootBeanDefinition parseUserDetailsClass(Element elt, ParserContext parserContext) {
97 String userDetailsClass = elt.getAttribute(ATT_USER_CLASS);
98
99 if (OPT_PERSON.equals(userDetailsClass)) {
100 return new RootBeanDefinition(PERSON_MAPPER_CLASS, null, null);
101 } else if (OPT_INETORGPERSON.equals(userDetailsClass)) {
102 return new RootBeanDefinition(INET_ORG_PERSON_MAPPER_CLASS, null, null);
103 }
104 return new RootBeanDefinition(LDAP_USER_MAPPER_CLASS, null, null);
105 }
106
107 static RootBeanDefinition parseAuthoritiesPopulator(Element elt, ParserContext parserContext) {
108 String groupSearchFilter = elt.getAttribute(ATT_GROUP_SEARCH_FILTER);
109 String groupSearchBase = elt.getAttribute(ATT_GROUP_SEARCH_BASE);
110 String groupRoleAttribute = elt.getAttribute(ATT_GROUP_ROLE_ATTRIBUTE);
111 String rolePrefix = elt.getAttribute(ATT_ROLE_PREFIX);
112
113 if (!StringUtils.hasText(groupSearchFilter)) {
114 groupSearchFilter = DEF_GROUP_SEARCH_FILTER;
115 }
116
117 if (!StringUtils.hasText(groupSearchBase)) {
118 groupSearchBase = DEF_GROUP_SEARCH_BASE;
119 }
120
121 BeanDefinitionBuilder populator = BeanDefinitionBuilder.rootBeanDefinition(LDAP_AUTHORITIES_POPULATOR_CLASS);
122 populator.setSource(parserContext.extractSource(elt));
123 populator.addConstructorArg(parseServerReference(elt, parserContext));
124 populator.addConstructorArg(groupSearchBase);
125 populator.addPropertyValue("groupSearchFilter", groupSearchFilter);
126 populator.addPropertyValue("searchSubtree", Boolean.TRUE);
127
128 if (StringUtils.hasText(rolePrefix)) {
129 if ("none".equals(rolePrefix)) {
130 rolePrefix = "";
131 }
132 populator.addPropertyValue("rolePrefix", rolePrefix);
133 }
134
135 if (StringUtils.hasLength(groupRoleAttribute)) {
136 populator.addPropertyValue("groupRoleAttribute", groupRoleAttribute);
137 }
138
139 return (RootBeanDefinition) populator.getBeanDefinition();
140 }
141 }