View Javadoc

1   package org.springframework.security.config;
2   
3   import javax.naming.directory.Attribute;
4   import javax.naming.directory.Attributes;
5   import javax.naming.directory.BasicAttribute;
6   import javax.naming.directory.BasicAttributes;
7   
8   import org.springframework.beans.factory.xml.BeanDefinitionParser;
9   import org.springframework.beans.factory.xml.ParserContext;
10  import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
11  import org.springframework.beans.factory.config.BeanDefinition;
12  import org.springframework.beans.factory.support.RootBeanDefinition;
13  import org.springframework.beans.factory.support.BeanDefinitionBuilder;
14  import org.springframework.beans.factory.support.ManagedSet;
15  import org.springframework.util.StringUtils;
16  
17  import org.w3c.dom.Element;
18  import org.apache.commons.logging.Log;
19  import org.apache.commons.logging.LogFactory;
20  
21  /**
22   * @author Luke Taylor
23   * @version $Id: LdapServerBeanDefinitionParser.java 3068 2008-05-15 14:33:42Z luke_t $
24   */
25  public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
26      private static final String CONTEXT_SOURCE_CLASS="org.springframework.security.ldap.DefaultSpringSecurityContextSource";
27      
28      private final Log logger = LogFactory.getLog(getClass());
29  
30      /** Defines the Url of the ldap server to use. If not specified, an embedded apache DS instance will be created */
31      private static final String ATT_URL = "url";
32  
33      private static final String ATT_PRINCIPAL = "manager-dn";
34      private static final String ATT_PASSWORD = "manager-password";
35  
36      // Properties which apply to embedded server only - when no Url is set
37  
38      /** sets the configuration suffix (default is "dc=springframework,dc=org"). */
39      public static final String ATT_ROOT_SUFFIX = "root";
40      private static final String OPT_DEFAULT_ROOT_SUFFIX = "dc=springframework,dc=org";
41      /**
42       * Optionally defines an ldif resource to be loaded. Otherwise an attempt will be made to load all ldif files
43       * found on the classpath.
44       */
45      public static final String ATT_LDIF_FILE = "ldif";
46      private static final String OPT_DEFAULT_LDIF_FILE = "classpath*:*.ldif";
47  
48      /** Defines the port the LDAP_PROVIDER server should run on */
49      public static final String ATT_PORT = "port";
50      public static final String OPT_DEFAULT_PORT = "33389";
51  
52  
53      public BeanDefinition parse(Element elt, ParserContext parserContext) {
54          String url = elt.getAttribute(ATT_URL);
55  
56          RootBeanDefinition contextSource;
57  
58          if (!StringUtils.hasText(url)) {
59              contextSource = createEmbeddedServer(elt, parserContext);
60          } else {
61              contextSource = new RootBeanDefinition();
62              contextSource.setBeanClassName(CONTEXT_SOURCE_CLASS);
63              contextSource.getConstructorArgumentValues().addIndexedArgumentValue(0, url);
64          }
65  
66          contextSource.setSource(parserContext.extractSource(elt));
67  
68          String managerDn = elt.getAttribute(ATT_PRINCIPAL);
69          String managerPassword = elt.getAttribute(ATT_PASSWORD);
70  
71          if (StringUtils.hasText(managerDn)) {
72              if(!StringUtils.hasText(managerPassword)) {
73                  parserContext.getReaderContext().error("You must specify the " + ATT_PASSWORD +
74                          " if you supply a " + managerDn, elt);
75              }
76  
77              contextSource.getPropertyValues().addPropertyValue("userDn", managerDn);
78              contextSource.getPropertyValues().addPropertyValue("password", managerPassword);
79          }
80  
81          String id = elt.getAttribute(AbstractBeanDefinitionParser.ID_ATTRIBUTE);
82  
83          String contextSourceId = StringUtils.hasText(id) ? id : BeanIds.CONTEXT_SOURCE;
84  
85          parserContext.getRegistry().registerBeanDefinition(contextSourceId, contextSource);
86  
87          return null;
88      }
89  
90      /**
91       * Will be called if no url attribute is supplied.
92       *
93       * Registers beans to create an embedded apache directory server.
94       *
95       * @return the BeanDefinition for the ContextSource for the embedded server.
96       *
97       * @see ApacheDSContainer
98       */
99      private RootBeanDefinition createEmbeddedServer(Element element, ParserContext parserContext) {
100         Object source = parserContext.extractSource(element);
101         BeanDefinitionBuilder configuration = 
102             BeanDefinitionBuilder.rootBeanDefinition("org.apache.directory.server.configuration.MutableServerStartupConfiguration");
103         BeanDefinitionBuilder partition = 
104             BeanDefinitionBuilder.rootBeanDefinition("org.apache.directory.server.core.partition.impl.btree.MutableBTreePartitionConfiguration");
105         configuration.setSource(source);
106         partition.setSource(source);
107         
108         Attributes rootAttributes = new BasicAttributes("dc", "springsecurity");
109         Attribute a = new BasicAttribute("objectClass");
110         a.add("top");
111         a.add("domain");
112         a.add("extensibleObject");
113         rootAttributes.put(a);
114 
115         partition.addPropertyValue("name", "springsecurity");
116         partition.addPropertyValue("contextEntry", rootAttributes);
117 
118         String suffix = element.getAttribute(ATT_ROOT_SUFFIX);
119 
120         if (!StringUtils.hasText(suffix)) {
121             suffix = OPT_DEFAULT_ROOT_SUFFIX;
122         }
123 
124         partition.addPropertyValue("suffix", suffix);
125 
126         ManagedSet partitions = new ManagedSet(1);
127         partitions.add(partition.getBeanDefinition());
128 
129         String port = element.getAttribute(ATT_PORT);
130 
131         if (!StringUtils.hasText(port)) {
132             port = OPT_DEFAULT_PORT;
133         }
134 
135         configuration.addPropertyValue("ldapPort", port);
136 
137         // We shut down the server ourself when the app context is closed so we don't need
138         // the extra shutdown hook from apache DS itself.
139         configuration.addPropertyValue("shutdownHookEnabled", Boolean.FALSE);
140         configuration.addPropertyValue("exitVmOnShutdown", Boolean.FALSE);
141         configuration.addPropertyValue("contextPartitionConfigurations", partitions);
142 
143         String url = "ldap://127.0.0.1:" + port + "/" + suffix;
144 
145         BeanDefinitionBuilder contextSource = BeanDefinitionBuilder.rootBeanDefinition(CONTEXT_SOURCE_CLASS);
146         contextSource.addConstructorArg(url);
147         contextSource.addPropertyValue("userDn", "uid=admin,ou=system");
148         contextSource.addPropertyValue("password", "secret");
149 
150         RootBeanDefinition apacheContainer = new RootBeanDefinition("org.springframework.security.config.ApacheDSContainer", null, null);
151         apacheContainer.setSource(source);
152         apacheContainer.getConstructorArgumentValues().addGenericArgumentValue(configuration.getBeanDefinition());
153         apacheContainer.getConstructorArgumentValues().addGenericArgumentValue(contextSource.getBeanDefinition());
154 
155         String ldifs = element.getAttribute(ATT_LDIF_FILE);
156         if (!StringUtils.hasText(ldifs)) {
157             ldifs = OPT_DEFAULT_LDIF_FILE;
158         }
159 
160         apacheContainer.getConstructorArgumentValues().addGenericArgumentValue(ldifs);
161 
162         logger.info("Embedded LDAP server bean created for URL: " + url);
163 
164         if (parserContext.getRegistry().containsBeanDefinition(BeanIds.EMBEDDED_APACHE_DS)) {
165             parserContext.getReaderContext().error("Only one embedded server bean is allowed per application context",
166                     element);
167         }
168 
169         parserContext.getRegistry().registerBeanDefinition(BeanIds.EMBEDDED_APACHE_DS, apacheContainer);
170 
171         return (RootBeanDefinition) contextSource.getBeanDefinition();
172     }
173 }