diff --git a/config/pom.xml b/config/pom.xml
index 91c7ef7170..5692a875e0 100644
--- a/config/pom.xml
+++ b/config/pom.xml
@@ -59,6 +59,19 @@
org.springframework
spring-web
+
+ org.apache.directory.server
+ apacheds-core
+ 1.5.5
+ true
+
+
+ org.apache.directory.server
+ apacheds-server-jndi
+ 1.5.5
+ true
+
+
org.slf4j
slf4j-log4j12
diff --git a/config/src/main/java/org/springframework/security/config/ldap/LdapServerBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/ldap/LdapServerBeanDefinitionParser.java
index 59856f5039..103108434f 100644
--- a/config/src/main/java/org/springframework/security/config/ldap/LdapServerBeanDefinitionParser.java
+++ b/config/src/main/java/org/springframework/security/config/ldap/LdapServerBeanDefinitionParser.java
@@ -1,23 +1,16 @@
package org.springframework.security.config.ldap;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.BasicAttribute;
-import javax.naming.directory.BasicAttributes;
-
-import org.springframework.beans.factory.xml.BeanDefinitionParser;
-import org.springframework.beans.factory.xml.ParserContext;
-import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
-import org.springframework.beans.factory.config.BeanDefinition;
-import org.springframework.beans.factory.support.RootBeanDefinition;
-import org.springframework.beans.factory.support.BeanDefinitionBuilder;
-import org.springframework.beans.factory.support.ManagedSet;
-import org.springframework.security.config.BeanIds;
-import org.springframework.util.StringUtils;
-
-import org.w3c.dom.Element;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
+import org.springframework.beans.factory.xml.BeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.security.config.BeanIds;
+import org.springframework.util.StringUtils;
+import org.w3c.dom.Element;
/**
* @author Luke Taylor
@@ -97,25 +90,8 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
*
* @see ApacheDSContainer
*/
- @SuppressWarnings("unchecked")
private RootBeanDefinition createEmbeddedServer(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
- BeanDefinitionBuilder configuration =
- BeanDefinitionBuilder.rootBeanDefinition("org.apache.directory.server.configuration.MutableServerStartupConfiguration");
- BeanDefinitionBuilder partition =
- BeanDefinitionBuilder.rootBeanDefinition("org.apache.directory.server.core.partition.impl.btree.MutableBTreePartitionConfiguration");
- configuration.getRawBeanDefinition().setSource(source);
- partition.getRawBeanDefinition().setSource(source);
-
- Attributes rootAttributes = new BasicAttributes("dc", "springsecurity");
- Attribute a = new BasicAttribute("objectClass");
- a.add("top");
- a.add("domain");
- a.add("extensibleObject");
- rootAttributes.put(a);
-
- partition.addPropertyValue("name", "springsecurity");
- partition.addPropertyValue("contextEntry", rootAttributes);
String suffix = element.getAttribute(ATT_ROOT_SUFFIX);
@@ -123,25 +99,12 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
suffix = OPT_DEFAULT_ROOT_SUFFIX;
}
- partition.addPropertyValue("suffix", suffix);
-
- ManagedSet partitions = new ManagedSet(1);
- partitions.add(partition.getBeanDefinition());
-
String port = element.getAttribute(ATT_PORT);
if (!StringUtils.hasText(port)) {
port = OPT_DEFAULT_PORT;
}
- configuration.addPropertyValue("ldapPort", port);
-
- // We shut down the server ourself when the app context is closed so we don't need
- // the extra shutdown hook from apache DS itself.
- configuration.addPropertyValue("shutdownHookEnabled", Boolean.FALSE);
- configuration.addPropertyValue("exitVmOnShutdown", Boolean.FALSE);
- configuration.addPropertyValue("contextPartitionConfigurations", partitions);
-
String url = "ldap://127.0.0.1:" + port + "/" + suffix;
BeanDefinitionBuilder contextSource = BeanDefinitionBuilder.rootBeanDefinition(CONTEXT_SOURCE_CLASS);
@@ -151,8 +114,7 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
RootBeanDefinition apacheContainer = new RootBeanDefinition("org.springframework.security.ldap.server.ApacheDSContainer", null, null);
apacheContainer.setSource(source);
- apacheContainer.getConstructorArgumentValues().addGenericArgumentValue(configuration.getBeanDefinition());
- apacheContainer.getConstructorArgumentValues().addGenericArgumentValue(contextSource.getBeanDefinition());
+ apacheContainer.getConstructorArgumentValues().addGenericArgumentValue(suffix);
String ldifs = element.getAttribute(ATT_LDIF_FILE);
if (!StringUtils.hasText(ldifs)) {
@@ -160,6 +122,7 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
}
apacheContainer.getConstructorArgumentValues().addGenericArgumentValue(ldifs);
+ apacheContainer.getPropertyValues().addPropertyValue("port", port);
logger.info("Embedded LDAP server bean created for URL: " + url);
diff --git a/ldap/pom.xml b/ldap/pom.xml
index 095939e923..2757bd1df5 100644
--- a/ldap/pom.xml
+++ b/ldap/pom.xml
@@ -28,21 +28,30 @@
ldapsdk
4.1
true
-
+
+
org.apache.directory.server
apacheds-core
- 1.0.2
+ 1.5.5
compile
true
org.apache.directory.server
apacheds-server-jndi
- 1.0.2
+ 1.5.5
compile
true
+
org.slf4j
slf4j-log4j12
diff --git a/ldap/src/main/java/org/springframework/security/ldap/server/ApacheDSContainer.java b/ldap/src/main/java/org/springframework/security/ldap/server/ApacheDSContainer.java
index 525bb88b13..9b0baddd74 100644
--- a/ldap/src/main/java/org/springframework/security/ldap/server/ApacheDSContainer.java
+++ b/ldap/src/main/java/org/springframework/security/ldap/server/ApacheDSContainer.java
@@ -1,31 +1,26 @@
package org.springframework.security.ldap.server;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.beans.factory.DisposableBean;
+import java.io.File;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.directory.server.core.DefaultDirectoryService;
+import org.apache.directory.server.core.entry.ServerEntry;
+import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmPartition;
+import org.apache.directory.server.ldap.LdapServer;
+import org.apache.directory.server.protocol.shared.store.LdifFileLoader;
+import org.apache.directory.server.protocol.shared.transport.TcpTransport;
+import org.apache.directory.shared.ldap.exception.LdapNameNotFoundException;
+import org.apache.directory.shared.ldap.name.LdapDN;
import org.springframework.beans.BeansException;
-import org.springframework.context.ApplicationContextAware;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
import org.springframework.context.Lifecycle;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
-import org.springframework.ldap.core.ContextSource;
import org.springframework.util.Assert;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.directory.server.configuration.MutableServerStartupConfiguration;
-import org.apache.directory.server.jndi.ServerContextFactory;
-import org.apache.directory.server.protocol.shared.store.LdifFileLoader;
-import org.apache.directory.server.core.configuration.ShutdownConfiguration;
-import org.apache.directory.server.core.DirectoryService;
-
-import javax.naming.Context;
-import javax.naming.InitialContext;
-import javax.naming.NamingException;
-import javax.naming.directory.DirContext;
-import javax.naming.directory.InitialDirContext;
-import java.util.Properties;
-import java.io.File;
-import java.io.IOException;
/**
* Provides lifecycle services for the embedded apacheDS server defined by the supplied configuration.
@@ -49,18 +44,30 @@ import java.io.IOException;
public class ApacheDSContainer implements InitializingBean, DisposableBean, Lifecycle, ApplicationContextAware {
private Log logger = LogFactory.getLog(getClass());
- private MutableServerStartupConfiguration configuration;
+ DefaultDirectoryService service;
+ LdapServer server;
+
private ApplicationContext ctxt;
private File workingDir;
- private ContextSource contextSource;
private boolean running;
private String ldifResources;
+ private JdbmPartition partition;
+ private String root;
+ private int port = 53389;
- public ApacheDSContainer(MutableServerStartupConfiguration config, ContextSource contextSource, String ldifs) {
- this.configuration = config;
- this.contextSource = contextSource;
+ public ApacheDSContainer(String root, String ldifs) throws Exception {
this.ldifResources = ldifs;
+ service = new DefaultDirectoryService();
+ partition = new JdbmPartition();
+ partition.setId("rootPartition");
+ partition.setSuffix(root);
+ this.root = root;
+ service.addPartition(partition);
+ service.setExitVmOnShutdown(false);
+ service.setShutdownHookEnabled(false);
+ service.getChangeLog().setEnabled(false);
+ service.setDenormalizeOpAttrsEnabled(true);
}
public void afterPropertiesSet() throws Exception {
@@ -73,6 +80,10 @@ public class ApacheDSContainer implements InitializingBean, DisposableBean, Life
setWorkingDirectory(new File(apacheWorkDir));
}
+
+ server = new LdapServer();
+ server.setDirectoryService(service);
+ server.setTransports(new TcpTransport(port));
start();
}
@@ -84,20 +95,6 @@ public class ApacheDSContainer implements InitializingBean, DisposableBean, Life
ctxt = applicationContext;
}
- private boolean deleteDir(File dir) {
- if (dir.isDirectory()) {
- String[] children = dir.list();
- for (int i=0; i < children.length; i++) {
- boolean success = deleteDir(new File(dir, children[i]));
- if (!success) {
- return false;
- }
- }
- }
-
- return dir.delete();
- }
-
public void setWorkingDirectory(File workingDir) {
Assert.notNull(workingDir);
@@ -112,35 +109,52 @@ public class ApacheDSContainer implements InitializingBean, DisposableBean, Life
this.workingDir = workingDir;
- configuration.setWorkingDirectory(workingDir);
+ service.setWorkingDirectory(workingDir);
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ public DefaultDirectoryService getService() {
+ return service;
}
- @SuppressWarnings("unchecked")
public void start() {
if (isRunning()) {
return;
}
- DirectoryService ds = DirectoryService.getInstance(configuration.getInstanceId());
-
- if (ds.isStarted()) {
- throw new IllegalStateException("A DirectoryService with Id '" + configuration.getInstanceId() + "' is already running.");
+ if (service.isStarted()) {
+ throw new IllegalStateException("DirectoryService is already running.");
}
- logger.info("Starting directory server with Id '" + configuration.getInstanceId() + "'");
- Properties env = new Properties();
-
- env.setProperty(Context.INITIAL_CONTEXT_FACTORY, ServerContextFactory.class.getName());
- env.setProperty(Context.SECURITY_AUTHENTICATION, "simple");
- env.setProperty(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system");
- env.setProperty(Context.SECURITY_CREDENTIALS, "secret");
- env.putAll(configuration.toJndiEnvironment());
+ logger.info("Starting directory server...");
+ try {
+ service.startup();
+ server.start();
+ } catch (Exception e) {
+ logger.error("Server startup failed ", e);
+ return;
+ }
try {
- new InitialDirContext(env);
- } catch (NamingException e) {
- logger.error("Failed to start directory service", e);
- return;
+ service.getAdminSession().lookup(partition.getSuffixDn());
+ }
+ catch (LdapNameNotFoundException e) {
+ try {
+ LdapDN dn = new LdapDN(root);
+ Assert.isTrue(root.startsWith("dc="));
+ String dc = root.substring(3,root.indexOf(','));
+ ServerEntry entry = service.newEntry(dn);
+ entry.add("objectClass", "top", "domain", "extensibleObject");
+ entry.add("dc",dc);
+ service.getAdminSession().add( entry );
+ } catch (Exception e1) {
+ logger.error("Failed to create dc entry", e1);
+ }
+ } catch (Exception e) {
+ logger.error("Lookup failed", e);
}
running = true;
@@ -152,7 +166,29 @@ public class ApacheDSContainer implements InitializingBean, DisposableBean, Life
}
}
- private void importLdifs() throws IOException, NamingException {
+ public void stop() {
+ if (!isRunning()) {
+ return;
+ }
+
+ logger.info("Shutting down directory server ...");
+ try {
+ server.stop();
+ service.shutdown();
+ } catch (Exception e) {
+ logger.error("Shutdown failed", e);
+ return;
+ }
+
+ running = false;
+
+ if (workingDir.exists()) {
+ logger.info("Deleting working directory " + workingDir.getAbsolutePath());
+ deleteDir(workingDir);
+ }
+ }
+
+ private void importLdifs() throws Exception {
// Import any ldif files
Resource[] ldifs;
@@ -166,51 +202,28 @@ public class ApacheDSContainer implements InitializingBean, DisposableBean, Life
// Note that we can't just import using the ServerContext returned
// from starting Apace DS, apparently because of the long-running issue DIRSERVER-169.
// We need a standard context.
- DirContext dirContext = contextSource.getReadWriteContext();
+ //DirContext dirContext = contextSource.getReadWriteContext();
if(ldifs != null && ldifs.length > 0) {
- try {
- String ldifFile = ldifs[0].getFile().getAbsolutePath();
- logger.info("Loading LDIF file: " + ldifFile);
- LdifFileLoader loader = new LdifFileLoader(dirContext, ldifFile);
- loader.execute();
- } finally {
- dirContext.close();
+ String ldifFile = ldifs[0].getFile().getAbsolutePath();
+ logger.info("Loading LDIF file: " + ldifFile);
+ LdifFileLoader loader = new LdifFileLoader(service.getAdminSession(), ldifFile);
+ loader.execute();
+ }
+ }
+
+ private boolean deleteDir(File dir) {
+ if (dir.isDirectory()) {
+ String[] children = dir.list();
+ for (int i=0; i < children.length; i++) {
+ boolean success = deleteDir(new File(dir, children[i]));
+ if (!success) {
+ return false;
+ }
}
}
- }
-
- @SuppressWarnings("unchecked")
- public void stop() {
- if (!isRunning()) {
- return;
- }
-
- Properties env = new Properties();
- env.setProperty(Context.INITIAL_CONTEXT_FACTORY, ServerContextFactory.class.getName());
- env.setProperty(Context.SECURITY_AUTHENTICATION, "simple");
- env.setProperty(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system");
- env.setProperty(Context.SECURITY_CREDENTIALS, "secret");
-
- ShutdownConfiguration shutdown = new ShutdownConfiguration(configuration.getInstanceId());
- env.putAll(shutdown.toJndiEnvironment());
-
- logger.info("Shutting down directory server with Id '" + configuration.getInstanceId() + "'");
-
- try {
- new InitialContext(env);
- } catch (NamingException e) {
- logger.error("Failed to shutdown directory server", e);
- return;
- }
-
- running = false;
-
- if (workingDir.exists()) {
- logger.info("Deleting working directory " + workingDir.getAbsolutePath());
- deleteDir(workingDir);
- }
+ return dir.delete();
}
public boolean isRunning() {
diff --git a/ldap/src/test/java/org/springframework/security/ldap/AbstractLdapIntegrationTests.java b/ldap/src/test/java/org/springframework/security/ldap/AbstractLdapIntegrationTests.java
index e9f6ce4cee..b22dda91c3 100644
--- a/ldap/src/test/java/org/springframework/security/ldap/AbstractLdapIntegrationTests.java
+++ b/ldap/src/test/java/org/springframework/security/ldap/AbstractLdapIntegrationTests.java
@@ -14,24 +14,14 @@
*/
package org.springframework.security.ldap;
-import java.util.HashSet;
-import java.util.Set;
-
import javax.naming.Binding;
import javax.naming.ContextNotEmptyException;
import javax.naming.Name;
import javax.naming.NameNotFoundException;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.BasicAttribute;
-import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
-import org.apache.directory.server.configuration.MutableServerStartupConfiguration;
-import org.apache.directory.server.core.DirectoryService;
-import org.apache.directory.server.core.partition.impl.btree.MutableBTreePartitionConfiguration;
import org.apache.directory.server.protocol.shared.store.LdifFileLoader;
import org.junit.After;
import org.junit.AfterClass;
@@ -56,35 +46,11 @@ public abstract class AbstractLdapIntegrationTests {
protected AbstractLdapIntegrationTests() {
}
- @SuppressWarnings("unchecked")
@BeforeClass
public static void startServer() throws Exception {
- shutdownRunningServers();
- MutableBTreePartitionConfiguration partition = new MutableBTreePartitionConfiguration();
- partition.setName("springsecurity");
-
- Attributes rootAttributes = new BasicAttributes("dc", "springsecurity");
- Attribute a = new BasicAttribute("objectClass");
- a.add("top");
- a.add("domain");
- a.add("extensibleObject");
- rootAttributes.put(a);
-
- partition.setContextEntry(rootAttributes);
- partition.setSuffix("dc=springframework,dc=org");
-
- Set partitions = new HashSet();
- partitions.add(partition);
-
- MutableServerStartupConfiguration cfg = new MutableServerStartupConfiguration();
- cfg.setLdapPort(53389);
- cfg.setShutdownHookEnabled(false);
- cfg.setExitVmOnShutdown(false);
- cfg.setContextPartitionConfigurations(partitions);
-
contextSource = new DefaultSpringSecurityContextSource("ldap://127.0.0.1:53389/dc=springframework,dc=org");
((DefaultSpringSecurityContextSource)contextSource).afterPropertiesSet();
- server = new ApacheDSContainer(cfg, contextSource, "classpath:test-server.ldif");
+ server = new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif");
server.afterPropertiesSet();
}
@@ -93,20 +59,8 @@ public abstract class AbstractLdapIntegrationTests {
if (server != null) {
server.stop();
}
- shutdownRunningServers();
}
- private static void shutdownRunningServers() throws NamingException {
- DirectoryService ds = DirectoryService.getInstance();
-
- if (ds.isStarted()) {
- System.out.println("WARNING: Discovered running DirectoryService with configuration: " + ds.getConfiguration().getStartupConfiguration().toString());
- System.out.println("Shutting it down...");
- ds.shutdown();
- }
- }
-
-
@Before
public void onSetUp() throws Exception {
}
@@ -127,7 +81,7 @@ public abstract class AbstractLdapIntegrationTests {
try {
clearSubContexts(ctx, startingPoint);
- LdifFileLoader loader = new LdifFileLoader(ctx, ldifs.getFile().getAbsolutePath());
+ LdifFileLoader loader = new LdifFileLoader(server.getService().getAdminSession(), ldifs.getFile().getAbsolutePath());
loader.execute();
} finally {
ctx.close();
diff --git a/ldap/src/test/java/org/springframework/security/ldap/server/ApacheDSContainerTests.java b/ldap/src/test/java/org/springframework/security/ldap/server/ApacheDSContainerTests.java
new file mode 100644
index 0000000000..f849b30702
--- /dev/null
+++ b/ldap/src/test/java/org/springframework/security/ldap/server/ApacheDSContainerTests.java
@@ -0,0 +1,27 @@
+package org.springframework.security.ldap.server;
+
+import org.apache.directory.shared.ldap.name.LdapDN;
+import org.junit.Test;
+
+/**
+ * Useful for debugging the container by itself.
+ *
+ * @author Luke Taylor
+ * @version $Id$
+ * @since 3.0
+ */
+public class ApacheDSContainerTests {
+
+ @Test
+ public void successfulStartupAndShutdown() throws Exception {
+ LdapDN people = new LdapDN("ou=people,dc=springframework,dc=org");
+ people.toString();
+
+// ApacheDSContainer server = new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif");
+// server.afterPropertiesSet();
+//
+// server.getService().getAdminSession().lookup(people);
+//
+// server.stop();
+ }
+}
diff --git a/ldap/src/test/resources/log4j.properties b/ldap/src/test/resources/log4j.properties
index 63f39ae846..9900ef07b4 100644
--- a/ldap/src/test/resources/log4j.properties
+++ b/ldap/src/test/resources/log4j.properties
@@ -11,4 +11,4 @@ log4j.appender.stdout.layout.ConversionPattern=%p %c{1} - %m%n
log4j.logger.org.springframework.security=DEBUG
log4j.logger.org.springframework.ldap=DEBUG
-log4j.logger.org.apache.directory=ERROR
+log4j.logger.org.apache.directory=INFO
diff --git a/ldap/template.mf b/ldap/template.mf
index 7bca39354e..834b107695 100644
--- a/ldap/template.mf
+++ b/ldap/template.mf
@@ -9,6 +9,7 @@ Ignored-Existing-Headers:
Import-Template:
org.apache.commons.logging.*;version="[1.0.4, 2.0.0)",
org.apache.directory.server.*;version="[1.0.2, 1.5)";resolution:=optional,
+ org.apache.directory.shared.ldap.*;version="[1.5.5,1.6)";resolution:=optional,
org.springframework.ldap.*;version="[1.3.0,1.4.0)",
org.springframework.security.core.*;version="[${version}, 3.1.0)",
org.springframework.security.authentication.*;version="[${version}, 3.1.0)",