package net.detailedbalance.ladle;
import org.apache.commons.io.FileUtils;
import org.apache.directory.server.configuration.MutableServerStartupConfiguration;
import org.apache.directory.server.core.configuration.Configuration;
import org.apache.directory.server.core.configuration.MutablePartitionConfiguration;
import org.apache.directory.server.core.configuration.ShutdownConfiguration;
import org.apache.log4j.Logger;
import javax.naming.Context;
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.InitialDirContext;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Set;
import java.util.UUID;
/**
* The class that creates and controls an embedded ApacheDS instance. This runner is not designed
* for thread-safety or even to be used in the same JVM as anything else -- it's intended to be run
* in its own process to provide LDAP access over TCP.
*
* The idea of using ApacheDS for this was from Spring Security's LDAP test support. The details
* are from the ApacheDS embedding and unit testing documentation.
*/
public class Server {
private final Logger log = Logger.getLogger(getClass());
private final int port;
private final String domainComponent;
private final boolean allowAnonymous;
private final File tempDir;
private final File ldifDir;
private boolean running = false;
public Server(
int port, String domainComponent, File ldifFile, File tempDirBase, boolean allowAnonymous
) {
this.port = port;
this.domainComponent = domainComponent;
this.allowAnonymous = allowAnonymous;
this.tempDir = createTempDir(tempDirBase);
this.ldifDir = prepareLdif(ldifFile);
}
////// SETUP
private File createTempDir(File tempDirBase) {
File temp = new File(tempDirBase, "ladle-server-" + UUID.randomUUID());
if (temp.mkdir()) {
return temp;
} else {
throw new LadleFatalException("Could not create temporary directory " + temp);
}
}
private static Hashtable baseEnvironment() {
Hashtable env = new Hashtable();
env.put(Context.PROVIDER_URL, "");
env.put(Context.INITIAL_CONTEXT_FACTORY,
"org.apache.directory.server.jndi.ServerContextFactory");
// these values are apparently hardcoded in ApacheDS
env.put(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system");
env.put(Context.SECURITY_CREDENTIALS, "secret");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
return env;
}
private File prepareLdif(File ldifFile) {
File dir = new File(tempDir, "ldif");
if (!dir.mkdir()) {
throw new LadleFatalException("Could not create LDIF directory " + dir);
}
try {
FileUtils.copyFileToDirectory(ldifFile, dir);
} catch (IOException e) {
throw new LadleFatalException("Copying " + ldifFile + " to " + dir + " failed.", e);
}
return dir;
}
////// RUNNING
public void start() {
if (running) return;
try {
MutableServerStartupConfiguration cfg = new MutableServerStartupConfiguration();
cfg.setWorkingDirectory(tempDir);
cfg.setLdifDirectory(ldifDir);
cfg.setEnableNetworking(true);
cfg.setLdapPort(port);
cfg.setAllowAnonymousAccess(allowAnonymous);
cfg.setAccessControlEnabled(false);
cfg.setShutdownHookEnabled(false);
cfg.setContextPartitionConfigurations(
Collections.singleton(createPartitionConfiguration()));
new InitialDirContext(createJndiEnvironment(cfg));
} catch (NamingException e) {
throw new LadleFatalException("Startup failed", e);
}
running = true;
}
// Derived from http://directory.apache.org/apacheds/1.0/using-apacheds-for-unit-tests.html
private MutablePartitionConfiguration createPartitionConfiguration() throws NamingException {
MutablePartitionConfiguration pCfg = new MutablePartitionConfiguration();
pCfg.setName("ladle");
pCfg.setSuffix(domainComponent);
Set indexedAttrs = new HashSet();
indexedAttrs.add("objectClass");
indexedAttrs.add("dc");
indexedAttrs.add("uid");
pCfg.setIndexedAttributes( indexedAttrs );
// Create the root entry
{
Attributes attrs = new BasicAttributes(true);
Attribute attr = new BasicAttribute("objectClass");
attr.add("top");
attr.add("domain");
attrs.put(attr);
attr = new BasicAttribute("dc");
attr.add(domainComponent.split(",")[0].substring(3));
attrs.put(attr);
pCfg.setContextEntry(attrs);
}
return pCfg;
}
@SuppressWarnings({ "unchecked" })
private Hashtable createJndiEnvironment(Configuration cfg) {
Hashtable env = baseEnvironment();
env.putAll(cfg.toJndiEnvironment());
return env;
}
public void stop() {
if (!running) return;
try {
new InitialDirContext(createJndiEnvironment(new ShutdownConfiguration()));
} catch (NamingException e) {
throw new LadleFatalException("Shutdown failed", e);
}
running = false;
if (tempDir.exists()) {
try {
FileUtils.deleteDirectory(tempDir);
} catch (IOException e) {
log.error("Deleting the temporary directory " + tempDir + " failed", e);
}
}
}
}