All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.nimbusds.common.ldap.SampleDirectory Maven / Gradle / Ivy

There is a newer version: 3.4
Show newest version
package com.nimbusds.common.ldap;


import com.nimbusds.common.servlet.ResourceRetriever;
import com.thetransactioncompany.util.PropertyParseException;
import com.thetransactioncompany.util.PropertyRetriever;
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import com.unboundid.ldap.listener.InMemoryListenerConfig;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.OperationType;
import com.unboundid.ldap.sdk.schema.Schema;
import com.unboundid.ldif.LDIFException;
import com.unboundid.ldif.LDIFReader;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;


/**
 * Sample in-memory LDAP directory server for demonstration and testing
 * purposes. Access is limited to read and bind (authenticate) only.
 *
 * 

The directory server is configured by a set of "sampleDirectoryServer.*" * properties which can be overridden with Java system properties, see * {@link Configuration}. * *

The sample directory implements {@code ServletContextListener}. This * enables its automatic startup and shutdown in a servlet container (Java web * server), such as Apache Tomcat. When started from a servlet container the * directory configuration is obtained from a properties file specified by a * context parameter named {@code sampleDirectoryServer.configurationFile}. */ public class SampleDirectory implements ServletContextListener { /** * The sample directory server configuration. */ public static class Configuration { /** * If {@code true} the sample directory server must be * enabled. * *

Property key: sampleDirectoryServer.enable */ public final boolean enable; /** * The default enable policy. */ public static final boolean DEFAULT_ENABLE = false; /** * The port number on which the sample directory server * must accept LDAP client connections. * *

Property key: sampleDirectoryServer.port */ public final int port; /** * The default port number. */ public static final int DEFAULT_PORT = 10389; /** * Specifies the permitted LDAP operations. * *

Property key: sampleDirectoryServer.operations */ public final Set operations; /** * The default permitted LDAP operations. */ public static final Set DEFAULT_OPERATIONS = new HashSet<>( Arrays.asList(OperationType.BIND, OperationType.COMPARE, OperationType.SEARCH, OperationType.EXTENDED)); /** * Specifies an alternative schema for the sample directory + * server, supplied in a single LDIF file. If {@code null} the * default built-in server schema must be used. * *

Property key: sampleDirectoryServer.schema */ public final String schema; /** * The base distinguished name (DN) of the directory information * tree. * *

Property key: sampleDirectoryServer.baseDN */ public final String baseDN; /** * The initial directory information tree, supplied in a single * LDIF file. If {@code null} the directory will be left * empty. * *

Property key: sampleDirectoryServer.content */ public final String content; /** * Creates a new sample directory server configuration from the * specified properties. * * @param props The configuration properties. Must not be * {@code null}. * * @throws PropertyParseException On a missing or invalid * property. */ public Configuration(final Properties props) throws PropertyParseException { var pr = new PropertyRetriever(props, true); enable = pr.getOptBoolean("sampleDirectoryServer.enable", DEFAULT_ENABLE); if (! enable) { port = DEFAULT_PORT; operations = DEFAULT_OPERATIONS; schema = null; baseDN = null; content = null; return; } // We're okay to read rest of config port = pr.getOptInt("sampleDirectoryServer.port", DEFAULT_PORT); String s = pr.getOptString("sampleDirectoryServer.operations", null); if (s != null && ! s.trim().isEmpty()) { String[] tokens = s.split("[\\s,]+"); Set ops = new HashSet<>(); for (String t: tokens) { try { ops.add(OperationType.valueOf(t.toUpperCase())); } catch (Exception e) { throw new PropertyParseException("Invalid LDAP operation: " + t, "sampleDirectoryServer.operations", s); } } operations = Collections.unmodifiableSet(ops); } else { operations = DEFAULT_OPERATIONS; } s = pr.getOptString("sampleDirectoryServer.schema", null); if (s == null || s.isEmpty()) schema = null; else schema = s; baseDN = pr.getString("sampleDirectoryServer.baseDN"); s = pr.getOptString("sampleDirectoryServer.content", null); if (s == null || s.isEmpty()) content = null; else content = s; } } /** * The sample in-memory directory server. */ private InMemoryDirectoryServer ds = null; /** * The servlet context. */ private ServletContext servletContext; /** * The logger. */ private final Logger log = LogManager.getLogger("MAIN"); /** * Starts the sample in-memory directory server. * * @param config The sample directory server configuration. Must not * be {@code null}. * * @throws LDAPException If the in-memory directory server couldn't be * started or its initialisation failed. * @throws IOException If a schema file was specified and it couldn't * be read. * @throws LDIFException If a schema file was specified that is not * valid LDIF. */ public void start(final Configuration config) throws LDAPException, IOException, LDIFException { if (! config.enable) { log.info("Sample directory server: disabled"); return; } InMemoryListenerConfig listenerConfig = InMemoryListenerConfig.createLDAPConfig("sample-ds", config.port); // Get alternative schema, if any Schema schema = null; if (config.schema != null) { InputStream ldifInput; if (servletContext != null) { ldifInput = servletContext.getResourceAsStream(config.schema); } else { ldifInput = new FileInputStream(config.schema); } if (ldifInput == null) { throw new IOException("Couldn't find schema LDIF file: " + config.schema); } LDIFReader ldifReader = new LDIFReader(ldifInput); schema = new Schema(ldifReader.readEntry()); log.info("Sample directory server: Schema LDIF file: {}", config.schema); } InMemoryDirectoryServerConfig dsConfig = new InMemoryDirectoryServerConfig(config.baseDN); log.info("Sample directory server: Base DN: {}", config.baseDN); dsConfig.setSchema(schema); dsConfig.setListenerConfigs(listenerConfig); // Set the allowed LDAP operations dsConfig.setAllowedOperationTypes(config.operations); // Start server ds = new InMemoryDirectoryServer(dsConfig); // Populate directory with LDIF, if any if (config.content != null) { InputStream ldifInput; if (servletContext != null) { ldifInput = servletContext.getResourceAsStream(config.content); } else { ldifInput = new FileInputStream(config.content); } if (ldifInput == null) { throw new IOException("Couldn't find directory content LDIF file: " + config.content); } ds.importFromLDIF(true, new LDIFReader(ldifInput)); ldifInput.close(); log.info("Sample directory server: Populated from LDIF file {}", config.content); } // Start listening on selected port ds.startListening(); log.info("Sample directory server: Started on port {}", ds.getListenPort()); } /** * Stops the sample in-memory directory server (if previously started). * Information and status messages are logged at INFO level. */ public void stop() { if (ds == null) return; // Clean all connections and stop server ds.shutDown(true); log.info("Sample directory server: Shut down"); } /** * Handler for servlet context startup events. Launches the sample * in-memory directory server (if enabled per configuration). Exceptions * are logged at ERROR level, information and status messages at INFO * level. * *

The sample directory server configuration is retrieved from a * properties file which location is specified by a servlet context * parameter named {@code sampleDirectory.configurationFile}. * * @param sce A servlet context event. */ @Override public void contextInitialized(final ServletContextEvent sce) { servletContext = sce.getServletContext(); // Read configuration Configuration config; try { Properties props = ResourceRetriever.getProperties(servletContext, "sampleDirectory.configurationFile", log); config = new Configuration(props); } catch (Exception e) { log.error("Couldn't configure sample directory server: {}", e.getMessage()); return; } // Start server try { start(config); } catch (LDAPException e) { log.error("Couldn't start sample directory server: {}", e.getMessage()); } catch (IOException | LDIFException e) { log.error("Couldn't read schema file: {}", e.getMessage()); } } /** * Handler for servlet context shutdown events. Stops the sample * in-memory directory server (if previously started). * * @param sce A servlet context event. */ @Override public void contextDestroyed(final ServletContextEvent sce) { stop(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy