From 464f6dd52a1eeeef0f7b38d4dc1840501818a36f Mon Sep 17 00:00:00 2001
From: Yannick Lecaillez <yannick.lecaillez@forgerock.com>
Date: Mon, 07 Nov 2016 13:59:40 +0000
Subject: [PATCH] OPENDJ-3179: Migrate LDAP Connection Handler to SDK Grizzly transport
---
opendj-server-legacy/src/main/java/org/forgerock/opendj/reactive/LDAPConnectionHandler2.java | 1742 ++++++++++++++++++++++++++-------------------------------
1 files changed, 788 insertions(+), 954 deletions(-)
diff --git a/opendj-server-legacy/src/main/java/org/forgerock/opendj/reactive/LDAPConnectionHandler2.java b/opendj-server-legacy/src/main/java/org/forgerock/opendj/reactive/LDAPConnectionHandler2.java
index 5e71d6c..753c8da 100644
--- a/opendj-server-legacy/src/main/java/org/forgerock/opendj/reactive/LDAPConnectionHandler2.java
+++ b/opendj-server-legacy/src/main/java/org/forgerock/opendj/reactive/LDAPConnectionHandler2.java
@@ -92,1025 +92,859 @@
import com.forgerock.reactive.Stream;
/**
- * This class defines a connection handler that will be used for communicating
- * with clients over LDAP. It is actually implemented in two parts: as a
- * connection handler and one or more request handlers. The connection handler
- * is responsible for accepting new connections and registering each of them
- * with a request handler. The request handlers then are responsible for reading
- * requests from the clients and parsing them as operations. A single request
- * handler may be used, but having multiple handlers might provide better
- * performance in a multi-CPU system.
+ * This class defines a connection handler that will be used for communicating with clients over LDAP. It is actually
+ * implemented in two parts: as a connection handler and one or more request handlers. The connection handler is
+ * responsible for accepting new connections and registering each of them with a request handler. The request handlers
+ * then are responsible for reading requests from the clients and parsing them as operations. A single request handler
+ * may be used, but having multiple handlers might provide better performance in a multi-CPU system.
*/
-public final class LDAPConnectionHandler2 extends
- ConnectionHandler<LDAPConnectionHandlerCfg> implements
- ConfigurationChangeListener<LDAPConnectionHandlerCfg>,
- ServerShutdownListener, AlertGenerator
-{
- /** Task run periodically by the connection finalizer. */
- private final class ConnectionFinalizerRunnable implements Runnable
- {
+public final class LDAPConnectionHandler2 extends ConnectionHandler<LDAPConnectionHandlerCfg> implements
+ ConfigurationChangeListener<LDAPConnectionHandlerCfg>, ServerShutdownListener, AlertGenerator {
+ /** Task run periodically by the connection finalizer. */
+ private final class ConnectionFinalizerRunnable implements Runnable {
+ @Override
+ public void run() {
+ if (!connectionFinalizerActiveJobQueue.isEmpty()) {
+ for (Runnable r : connectionFinalizerActiveJobQueue) {
+ r.run();
+ }
+ connectionFinalizerActiveJobQueue.clear();
+ }
+
+ // Switch the lists.
+ synchronized (connectionFinalizerLock) {
+ List<Runnable> tmp = connectionFinalizerActiveJobQueue;
+ connectionFinalizerActiveJobQueue = connectionFinalizerPendingJobQueue;
+ connectionFinalizerPendingJobQueue = tmp;
+ }
+ }
+ }
+
+ private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
+
+ /** Default friendly name for the LDAP connection handler. */
+ private static final String DEFAULT_FRIENDLY_NAME = "LDAP Connection Handler";
+
+ /** SSL instance name used in context creation. */
+ private static final String SSL_CONTEXT_INSTANCE_NAME = "TLS";
+
+ private GrizzlyLDAPListener listener;
+
+ /** The current configuration state. */
+ private LDAPConnectionHandlerCfg currentConfig;
+
+ /* Properties that cannot be modified dynamically */
+
+ /** The set of addresses on which to listen for new connections. */
+ private Set<InetSocketAddress> listenAddresses;
+
+ /** The SSL client auth policy used by this connection handler. */
+ private SSLClientAuthPolicy sslClientAuthPolicy;
+
+ /** The backlog that will be used for the accept queue. */
+ private int backlog;
+
+ /** Indicates whether to allow the reuse address socket option. */
+ private boolean allowReuseAddress;
+
+ /** Indicates whether the Directory Server is in the process of shutting down. */
+ private volatile boolean shutdownRequested;
+
+ /* Internal LDAP connection handler state */
+
+ /** Indicates whether this connection handler is enabled. */
+ private boolean enabled;
+
+ /** The set of clients that are explicitly allowed access to the server. */
+ private Collection<AddressMask> allowedClients;
+
+ /** The set of clients that have been explicitly denied access to the server. */
+ private Collection<AddressMask> deniedClients;
+
+ /** The set of listeners for this connection handler. */
+ private List<HostPort> listeners;
+
+ /** The set of statistics collected for this connection handler. */
+ private LDAPStatistics statTracker;
+
+ /** The client connection monitor provider associated with this connection handler. */
+ private ClientConnectionMonitorProvider connMonitor;
+
+ /** The unique name assigned to this connection handler. */
+ private String handlerName;
+
+ /** The protocol used by this connection handler. */
+ private String protocol;
+
+ /** Queueing strategy. */
+ private final QueueingStrategy queueingStrategy;
+
+ /**
+ * The condition variable that will be used by the start method to wait for the socket port to be opened and ready
+ * to process requests before returning.
+ */
+ private final Object waitListen = new Object();
+
+ /** The friendly name of this connection handler. */
+ private String friendlyName;
+
+ /**
+ * SSL context.
+ *
+ * @see LDAPConnectionHandler2#sslEngine
+ */
+ private SSLContext sslContext;
+
+ /** The SSL engine is used for obtaining default SSL parameters. */
+ private SSLEngine sslEngine;
+
+ /**
+ * Connection finalizer thread.
+ * <p>
+ * This thread is defers closing clients for approximately 100ms. This gives the client a chance to close the
+ * connection themselves before the server thus avoiding leaving the server side in the TIME WAIT state.
+ */
+ private final Object connectionFinalizerLock = new Object();
+ private ScheduledExecutorService connectionFinalizer;
+ private List<Runnable> connectionFinalizerActiveJobQueue;
+ private List<Runnable> connectionFinalizerPendingJobQueue;
+
+ private final List<ClientConnection> connectionList = Collections
+ .synchronizedList(new ArrayList<ClientConnection>());
+
+ /**
+ * Creates a new instance of this LDAP connection handler. It must be initialized before it may be used.
+ */
+ public LDAPConnectionHandler2() {
+ this(new WorkQueueStrategy(), null); // Use name from configuration.
+ }
+
+ /**
+ * Creates a new instance of this LDAP connection handler, using a queueing strategy. It must be initialized before
+ * it may be used.
+ *
+ * @param strategy
+ * Request handling strategy.
+ * @param friendlyName
+ * The name of of this connection handler, or {@code null} if the name should be taken from the
+ * configuration.
+ */
+ public LDAPConnectionHandler2(QueueingStrategy strategy, String friendlyName) {
+ super(friendlyName != null ? friendlyName : DEFAULT_FRIENDLY_NAME + " Thread");
+
+ this.friendlyName = friendlyName;
+ this.queueingStrategy = strategy;
+ }
+
+ /**
+ * Indicates whether this connection handler should allow interaction with LDAPv2 clients.
+ *
+ * @return <CODE>true</CODE> if LDAPv2 is allowed, or <CODE>false</CODE> if not.
+ */
+ public boolean allowLDAPv2() {
+ return currentConfig.isAllowLDAPV2();
+ }
+
+ /**
+ * Indicates whether this connection handler should allow the use of the StartTLS extended operation.
+ *
+ * @return <CODE>true</CODE> if StartTLS is allowed, or <CODE>false</CODE> if not.
+ */
+ public boolean allowStartTLS() {
+ return currentConfig.isAllowStartTLS() && !currentConfig.isUseSSL();
+ }
+
@Override
- public void run()
- {
- if (!connectionFinalizerActiveJobQueue.isEmpty())
- {
- for (Runnable r : connectionFinalizerActiveJobQueue)
- {
- r.run();
+ public ConfigChangeResult applyConfigurationChange(LDAPConnectionHandlerCfg config) {
+ final ConfigChangeResult ccr = new ConfigChangeResult();
+
+ // Note that the following properties cannot be modified:
+ // * listen port and addresses
+ // * use ssl
+ // * ssl policy
+ // * ssl cert nickname
+ // * accept backlog
+ // * tcp reuse address
+ // * num request handler
+
+ // Clear the stat tracker if LDAPv2 is being enabled.
+ if (currentConfig.isAllowLDAPV2() != config.isAllowLDAPV2() && config.isAllowLDAPV2()) {
+ statTracker.clearStatistics();
}
- connectionFinalizerActiveJobQueue.clear();
- }
- // Switch the lists.
- synchronized (connectionFinalizerLock)
- {
- List<Runnable> tmp = connectionFinalizerActiveJobQueue;
- connectionFinalizerActiveJobQueue = connectionFinalizerPendingJobQueue;
- connectionFinalizerPendingJobQueue = tmp;
- }
- }
- }
- private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
+ // Apply the changes.
+ currentConfig = config;
+ enabled = config.isEnabled();
+ allowedClients = config.getAllowedClient();
+ deniedClients = config.getDeniedClient();
- /** Default friendly name for the LDAP connection handler. */
- private static final String DEFAULT_FRIENDLY_NAME = "LDAP Connection Handler";
+ // Reconfigure SSL if needed.
+ try {
+ configureSSL(config);
+ } catch (DirectoryException e) {
+ logger.traceException(e);
+ ccr.setResultCode(e.getResultCode());
+ ccr.addMessage(e.getMessageObject());
+ return ccr;
+ }
- /** SSL instance name used in context creation. */
- private static final String SSL_CONTEXT_INSTANCE_NAME = "TLS";
+ if (config.isAllowLDAPV2()) {
+ DirectoryServer.registerSupportedLDAPVersion(2, this);
+ } else {
+ DirectoryServer.deregisterSupportedLDAPVersion(2, this);
+ }
- private GrizzlyLDAPListener listener;
-
- /** The current configuration state. */
- private LDAPConnectionHandlerCfg currentConfig;
-
- /* Properties that cannot be modified dynamically */
-
- /** The set of addresses on which to listen for new connections. */
- private Set<InetSocketAddress> listenAddresses;
-
- /** The SSL client auth policy used by this connection handler. */
- private SSLClientAuthPolicy sslClientAuthPolicy;
-
- /** The backlog that will be used for the accept queue. */
- private int backlog;
-
- /** Indicates whether to allow the reuse address socket option. */
- private boolean allowReuseAddress;
-
- /** Indicates whether the Directory Server is in the process of shutting down. */
- private volatile boolean shutdownRequested;
-
- /* Internal LDAP connection handler state */
-
- /** Indicates whether this connection handler is enabled. */
- private boolean enabled;
-
- /** The set of clients that are explicitly allowed access to the server. */
- private Collection<AddressMask> allowedClients;
-
- /** The set of clients that have been explicitly denied access to the server. */
- private Collection<AddressMask> deniedClients;
-
- /** The set of listeners for this connection handler. */
- private List<HostPort> listeners;
-
- /** The set of statistics collected for this connection handler. */
- private LDAPStatistics statTracker;
-
- /** The client connection monitor provider associated with this connection handler. */
- private ClientConnectionMonitorProvider connMonitor;
-
- /** The unique name assigned to this connection handler. */
- private String handlerName;
-
- /** The protocol used by this connection handler. */
- private String protocol;
-
- /** Queueing strategy. */
- private final QueueingStrategy queueingStrategy;
-
- /**
- * The condition variable that will be used by the start method to wait for
- * the socket port to be opened and ready to process requests before
- * returning.
- */
- private final Object waitListen = new Object();
-
- /** The friendly name of this connection handler. */
- private String friendlyName;
-
- /**
- * SSL context.
- *
- * @see LDAPConnectionHandler2#sslEngine
- */
- private SSLContext sslContext;
-
- /** The SSL engine is used for obtaining default SSL parameters. */
- private SSLEngine sslEngine;
-
- /**
- * Connection finalizer thread.
- * <p>
- * This thread is defers closing clients for approximately 100ms. This gives
- * the client a chance to close the connection themselves before the server
- * thus avoiding leaving the server side in the TIME WAIT state.
- */
- private final Object connectionFinalizerLock = new Object();
- private ScheduledExecutorService connectionFinalizer;
- private List<Runnable> connectionFinalizerActiveJobQueue;
- private List<Runnable> connectionFinalizerPendingJobQueue;
-
- private final List<ClientConnection> connectionList = Collections.synchronizedList(new ArrayList<ClientConnection>());
-
- /**
- * Creates a new instance of this LDAP connection handler. It must be
- * initialized before it may be used.
- */
- public LDAPConnectionHandler2()
- {
- this(new WorkQueueStrategy(), null); // Use name from configuration.
- }
-
- /**
- * Creates a new instance of this LDAP connection handler, using a queueing
- * strategy. It must be initialized before it may be used.
- *
- * @param strategy
- * Request handling strategy.
- * @param friendlyName
- * The name of of this connection handler, or {@code null} if the
- * name should be taken from the configuration.
- */
- public LDAPConnectionHandler2(QueueingStrategy strategy, String friendlyName)
- {
- super(friendlyName != null ? friendlyName : DEFAULT_FRIENDLY_NAME + " Thread");
-
- this.friendlyName = friendlyName;
- this.queueingStrategy = strategy;
- }
-
- /**
- * Indicates whether this connection handler should allow interaction with
- * LDAPv2 clients.
- *
- * @return <CODE>true</CODE> if LDAPv2 is allowed, or <CODE>false</CODE> if
- * not.
- */
- public boolean allowLDAPv2()
- {
- return currentConfig.isAllowLDAPV2();
- }
-
- /**
- * Indicates whether this connection handler should allow the use of the
- * StartTLS extended operation.
- *
- * @return <CODE>true</CODE> if StartTLS is allowed, or <CODE>false</CODE> if
- * not.
- */
- public boolean allowStartTLS()
- {
- return currentConfig.isAllowStartTLS() && !currentConfig.isUseSSL();
- }
-
- @Override
- public ConfigChangeResult applyConfigurationChange(
- LDAPConnectionHandlerCfg config)
- {
- final ConfigChangeResult ccr = new ConfigChangeResult();
-
- // Note that the following properties cannot be modified:
- // * listen port and addresses
- // * use ssl
- // * ssl policy
- // * ssl cert nickname
- // * accept backlog
- // * tcp reuse address
- // * num request handler
-
- // Clear the stat tracker if LDAPv2 is being enabled.
- if (currentConfig.isAllowLDAPV2() != config.isAllowLDAPV2()
- && config.isAllowLDAPV2())
- {
- statTracker.clearStatistics();
+ return ccr;
}
- // Apply the changes.
- currentConfig = config;
- enabled = config.isEnabled();
- allowedClients = config.getAllowedClient();
- deniedClients = config.getDeniedClient();
-
- // Reconfigure SSL if needed.
- try
- {
- configureSSL(config);
- }
- catch (DirectoryException e)
- {
- logger.traceException(e);
- ccr.setResultCode(e.getResultCode());
- ccr.addMessage(e.getMessageObject());
- return ccr;
+ private void configureSSL(LDAPConnectionHandlerCfg config) throws DirectoryException {
+ protocol = config.isUseSSL() ? "LDAPS" : "LDAP";
+ if (config.isUseSSL() || config.isAllowStartTLS()) {
+ sslContext = createSSLContext(config);
+ sslEngine = createSSLEngine(config, sslContext);
+ } else {
+ sslContext = null;
+ sslEngine = null;
+ }
}
- if (config.isAllowLDAPV2())
- {
- DirectoryServer.registerSupportedLDAPVersion(2, this);
- }
- else
- {
- DirectoryServer.deregisterSupportedLDAPVersion(2, this);
+ @Override
+ public void finalizeConnectionHandler(LocalizableMessage finalizeReason) {
+ shutdownRequested = true;
+ currentConfig.removeLDAPChangeListener(this);
+
+ if (connMonitor != null) {
+ DirectoryServer.deregisterMonitorProvider(connMonitor);
+ }
+
+ if (statTracker != null) {
+ DirectoryServer.deregisterMonitorProvider(statTracker);
+ }
+
+ DirectoryServer.deregisterSupportedLDAPVersion(2, this);
+ DirectoryServer.deregisterSupportedLDAPVersion(3, this);
+
+ // Shutdown the connection finalizer and ensure that any pending
+ // unclosed connections are closed.
+ synchronized (connectionFinalizerLock) {
+ connectionFinalizer.shutdown();
+ connectionFinalizer = null;
+
+ Runnable r = new ConnectionFinalizerRunnable();
+ r.run(); // Flush active queue.
+ r.run(); // Flush pending queue.
+ }
}
- return ccr;
- }
+ /**
+ * Retrieves information about the set of alerts that this generator may produce. The map returned should be between
+ * the notification type for a particular notification and the human-readable description for that notification.
+ * This alert generator must not generate any alerts with types that are not contained in this list.
+ *
+ * @return Information about the set of alerts that this generator may produce.
+ */
+ @Override
+ public Map<String, String> getAlerts() {
+ Map<String, String> alerts = new LinkedHashMap<>();
- private void configureSSL(LDAPConnectionHandlerCfg config)
- throws DirectoryException
- {
- protocol = config.isUseSSL() ? "LDAPS" : "LDAP";
- if (config.isUseSSL() || config.isAllowStartTLS())
- {
- sslContext = createSSLContext(config);
- sslEngine = createSSLEngine(config, sslContext);
- }
- else
- {
- sslContext = null;
- sslEngine = null;
- }
- }
+ alerts.put(ALERT_TYPE_LDAP_CONNECTION_HANDLER_CONSECUTIVE_FAILURES,
+ ALERT_DESCRIPTION_LDAP_CONNECTION_HANDLER_CONSECUTIVE_FAILURES);
+ alerts.put(ALERT_TYPE_LDAP_CONNECTION_HANDLER_UNCAUGHT_ERROR,
+ ALERT_DESCRIPTION_LDAP_CONNECTION_HANDLER_UNCAUGHT_ERROR);
- @Override
- public void finalizeConnectionHandler(LocalizableMessage finalizeReason)
- {
- shutdownRequested = true;
- currentConfig.removeLDAPChangeListener(this);
-
- if (connMonitor != null)
- {
- DirectoryServer.deregisterMonitorProvider(connMonitor);
+ return alerts;
}
- if (statTracker != null)
- {
- DirectoryServer.deregisterMonitorProvider(statTracker);
+ /**
+ * Retrieves the fully-qualified name of the Java class for this alert generator implementation.
+ *
+ * @return The fully-qualified name of the Java class for this alert generator implementation.
+ */
+ @Override
+ public String getClassName() {
+ return LDAPConnectionHandler2.class.getName();
}
- DirectoryServer.deregisterSupportedLDAPVersion(2, this);
- DirectoryServer.deregisterSupportedLDAPVersion(3, this);
-
- // Shutdown the connection finalizer and ensure that any pending
- // unclosed connections are closed.
- synchronized (connectionFinalizerLock)
- {
- connectionFinalizer.shutdown();
- connectionFinalizer = null;
-
- Runnable r = new ConnectionFinalizerRunnable();
- r.run(); // Flush active queue.
- r.run(); // Flush pending queue.
- }
- }
-
- /**
- * Retrieves information about the set of alerts that this generator may
- * produce. The map returned should be between the notification type for a
- * particular notification and the human-readable description for that
- * notification. This alert generator must not generate any alerts with types
- * that are not contained in this list.
- *
- * @return Information about the set of alerts that this generator may
- * produce.
- */
- @Override
- public Map<String, String> getAlerts()
- {
- Map<String, String> alerts = new LinkedHashMap<>();
-
- alerts.put(ALERT_TYPE_LDAP_CONNECTION_HANDLER_CONSECUTIVE_FAILURES,
- ALERT_DESCRIPTION_LDAP_CONNECTION_HANDLER_CONSECUTIVE_FAILURES);
- alerts.put(ALERT_TYPE_LDAP_CONNECTION_HANDLER_UNCAUGHT_ERROR,
- ALERT_DESCRIPTION_LDAP_CONNECTION_HANDLER_UNCAUGHT_ERROR);
-
- return alerts;
- }
-
- /**
- * Retrieves the fully-qualified name of the Java class for this alert
- * generator implementation.
- *
- * @return The fully-qualified name of the Java class for this alert generator
- * implementation.
- */
- @Override
- public String getClassName()
- {
- return LDAPConnectionHandler2.class.getName();
- }
-
- /**
- * Retrieves the set of active client connections that have been established
- * through this connection handler.
- *
- * @return The set of active client connections that have been established
- * through this connection handler.
- */
- @Override
- public Collection<ClientConnection> getClientConnections()
- {
- return connectionList;
- }
-
- /**
- * Retrieves the DN of the configuration entry with which this alert generator
- * is associated.
- *
- * @return The DN of the configuration entry with which this alert generator
- * is associated.
- */
- @Override
- public DN getComponentEntryDN()
- {
- return currentConfig.dn();
- }
-
- @Override
- public String getConnectionHandlerName()
- {
- return handlerName;
- }
-
- @Override
- public Collection<String> getEnabledSSLCipherSuites()
- {
- final SSLEngine engine = sslEngine;
- if (engine != null)
- {
- return Arrays.asList(engine.getEnabledCipherSuites());
- }
- return super.getEnabledSSLCipherSuites();
- }
-
- @Override
- public Collection<String> getEnabledSSLProtocols()
- {
- final SSLEngine engine = sslEngine;
- if (engine != null)
- {
- return Arrays.asList(engine.getEnabledProtocols());
- }
- return super.getEnabledSSLProtocols();
- }
-
- @Override
- public Collection<HostPort> getListeners()
- {
- return listeners;
- }
-
- /**
- * Retrieves the maximum length of time in milliseconds that attempts to write
- * to LDAP client connections should be allowed to block.
- *
- * @return The maximum length of time in milliseconds that attempts to write
- * to LDAP client connections should be allowed to block, or zero if
- * there should not be any limit imposed.
- */
- public long getMaxBlockedWriteTimeLimit()
- {
- return currentConfig.getMaxBlockedWriteTimeLimit();
- }
-
- /**
- * Retrieves the maximum ASN.1 element value length that will be allowed by
- * this connection handler.
- *
- * @return The maximum ASN.1 element value length that will be allowed by this
- * connection handler.
- */
- public int getMaxRequestSize()
- {
- return (int) currentConfig.getMaxRequestSize();
- }
-
- /**
- * Retrieves the size in bytes of the LDAP response message write buffer
- * defined for this connection handler.
- *
- * @return The size in bytes of the LDAP response message write buffer.
- */
- public int getBufferSize()
- {
- return (int) currentConfig.getBufferSize();
- }
-
- @Override
- public String getProtocol()
- {
- return protocol;
- }
-
- @Override
- public String getShutdownListenerName()
- {
- return handlerName;
- }
-
- /**
- * Retrieves the SSL client authentication policy for this connection handler.
- *
- * @return The SSL client authentication policy for this connection handler.
- */
- public SSLClientAuthPolicy getSSLClientAuthPolicy()
- {
- return sslClientAuthPolicy;
- }
-
- /**
- * Retrieves the set of statistics maintained by this connection handler.
- *
- * @return The set of statistics maintained by this connection handler.
- */
- public LDAPStatistics getStatTracker()
- {
- return statTracker;
- }
-
- @Override
- public void initializeConnectionHandler(ServerContext serverContext, LDAPConnectionHandlerCfg config)
- throws ConfigException, InitializationException
- {
- if (friendlyName == null)
- {
- friendlyName = config.dn().rdn().getFirstAVA().getAttributeValue().toString();
+ /**
+ * Retrieves the set of active client connections that have been established through this connection handler.
+ *
+ * @return The set of active client connections that have been established through this connection handler.
+ */
+ @Override
+ public Collection<ClientConnection> getClientConnections() {
+ return connectionList;
}
- // Save this configuration for future reference.
- currentConfig = config;
- enabled = config.isEnabled();
- allowedClients = config.getAllowedClient();
- deniedClients = config.getDeniedClient();
-
- // Configure SSL if needed.
- try
- {
- // This call may disable the connector if wrong SSL settings
- configureSSL(config);
- }
- catch (DirectoryException e)
- {
- logger.traceException(e);
- throw new InitializationException(e.getMessageObject());
+ /**
+ * Retrieves the DN of the configuration entry with which this alert generator is associated.
+ *
+ * @return The DN of the configuration entry with which this alert generator is associated.
+ */
+ @Override
+ public DN getComponentEntryDN() {
+ return currentConfig.dn();
}
- // Save properties that cannot be dynamically modified.
- allowReuseAddress = config.isAllowTCPReuseAddress();
- backlog = config.getAcceptBacklog();
- listenAddresses = new HashSet<>();
- for(InetAddress addr :config.getListenAddress()) {
- listenAddresses.add(new InetSocketAddress(addr, config.getListenPort()));
+ @Override
+ public String getConnectionHandlerName() {
+ return handlerName;
}
- // Construct a unique name for this connection handler, and put
- // together the set of listeners.
- listeners = new LinkedList<>();
- StringBuilder nameBuffer = new StringBuilder();
- nameBuffer.append(friendlyName);
- for (InetSocketAddress a : listenAddresses)
- {
- listeners.add(new HostPort(a.getHostName(), a.getPort()));
- nameBuffer.append(" ");
- nameBuffer.append(a.getHostName());
- }
- nameBuffer.append(" port ");
- nameBuffer.append(config.getListenPort());
- handlerName = nameBuffer.toString();
-
- // Attempt to bind to the listen port on all configured addresses to
- // verify whether the connection handler will be able to start.
- LocalizableMessage errorMessage =
- checkAnyListenAddressInUse(config.getListenAddress(), config.getListenPort(),
- allowReuseAddress, config.dn());
- if (errorMessage != null)
- {
- logger.error(errorMessage);
- throw new InitializationException(errorMessage);
+ @Override
+ public Collection<String> getEnabledSSLCipherSuites() {
+ final SSLEngine engine = sslEngine;
+ if (engine != null) {
+ return Arrays.asList(engine.getEnabledCipherSuites());
+ }
+ return super.getEnabledSSLCipherSuites();
}
- // Create a system property to store the LDAP(S) port the server is
- // listening to. This information can be displayed with jinfo.
- System.setProperty(protocol + "_port", String.valueOf(config.getListenPort()));
-
- // Create and start a connection finalizer thread for this
- // connection handler.
- connectionFinalizer = Executors
- .newSingleThreadScheduledExecutor(new DirectoryThread.Factory(
- "LDAP Connection Finalizer for connection handler " + toString()));
-
- connectionFinalizerActiveJobQueue = new ArrayList<>();
- connectionFinalizerPendingJobQueue = new ArrayList<>();
-
- connectionFinalizer.scheduleWithFixedDelay(
- new ConnectionFinalizerRunnable(), 100, 100, TimeUnit.MILLISECONDS);
-
- // Register the set of supported LDAP versions.
- DirectoryServer.registerSupportedLDAPVersion(3, this);
- if (config.isAllowLDAPV2())
- {
- DirectoryServer.registerSupportedLDAPVersion(2, this);
+ @Override
+ public Collection<String> getEnabledSSLProtocols() {
+ final SSLEngine engine = sslEngine;
+ if (engine != null) {
+ return Arrays.asList(engine.getEnabledProtocols());
+ }
+ return super.getEnabledSSLProtocols();
}
- // Create and register monitors.
- statTracker = new LDAPStatistics(handlerName + " Statistics");
- DirectoryServer.registerMonitorProvider(statTracker);
-
- connMonitor = new ClientConnectionMonitorProvider(this);
- DirectoryServer.registerMonitorProvider(connMonitor);
-
- // Register this as a change listener.
- config.addLDAPChangeListener(this);
- }
-
- @Override
- public boolean isConfigurationAcceptable(ConnectionHandlerCfg configuration,
- List<LocalizableMessage> unacceptableReasons)
- {
- LDAPConnectionHandlerCfg config = (LDAPConnectionHandlerCfg) configuration;
-
- if (currentConfig == null
- || (!currentConfig.isEnabled() && config.isEnabled()))
- {
- // Attempt to bind to the listen port on all configured addresses to
- // verify whether the connection handler will be able to start.
- LocalizableMessage errorMessage =
- checkAnyListenAddressInUse(config.getListenAddress(), config
- .getListenPort(), config.isAllowTCPReuseAddress(), config.dn());
- if (errorMessage != null)
- {
- unacceptableReasons.add(errorMessage);
- return false;
- }
+ @Override
+ public Collection<HostPort> getListeners() {
+ return listeners;
}
- if (config.isEnabled()
+ /**
+ * Retrieves the maximum length of time in milliseconds that attempts to write to LDAP client connections should be
+ * allowed to block.
+ *
+ * @return The maximum length of time in milliseconds that attempts to write to LDAP client connections should be
+ * allowed to block, or zero if there should not be any limit imposed.
+ */
+ public long getMaxBlockedWriteTimeLimit() {
+ return currentConfig.getMaxBlockedWriteTimeLimit();
+ }
+
+ /**
+ * Retrieves the maximum ASN.1 element value length that will be allowed by this connection handler.
+ *
+ * @return The maximum ASN.1 element value length that will be allowed by this connection handler.
+ */
+ public int getMaxRequestSize() {
+ return (int) currentConfig.getMaxRequestSize();
+ }
+
+ /**
+ * Retrieves the size in bytes of the LDAP response message write buffer defined for this connection handler.
+ *
+ * @return The size in bytes of the LDAP response message write buffer.
+ */
+ public int getBufferSize() {
+ return (int) currentConfig.getBufferSize();
+ }
+
+ @Override
+ public String getProtocol() {
+ return protocol;
+ }
+
+ @Override
+ public String getShutdownListenerName() {
+ return handlerName;
+ }
+
+ /**
+ * Retrieves the SSL client authentication policy for this connection handler.
+ *
+ * @return The SSL client authentication policy for this connection handler.
+ */
+ public SSLClientAuthPolicy getSSLClientAuthPolicy() {
+ return sslClientAuthPolicy;
+ }
+
+ /**
+ * Retrieves the set of statistics maintained by this connection handler.
+ *
+ * @return The set of statistics maintained by this connection handler.
+ */
+ public LDAPStatistics getStatTracker() {
+ return statTracker;
+ }
+
+ @Override
+ public void initializeConnectionHandler(ServerContext serverContext, LDAPConnectionHandlerCfg config)
+ throws ConfigException, InitializationException {
+ if (friendlyName == null) {
+ friendlyName = config.dn().rdn().getFirstAVA().getAttributeValue().toString();
+ }
+
+ // Save this configuration for future reference.
+ currentConfig = config;
+ enabled = config.isEnabled();
+ allowedClients = config.getAllowedClient();
+ deniedClients = config.getDeniedClient();
+
+ // Configure SSL if needed.
+ try {
+ // This call may disable the connector if wrong SSL settings
+ configureSSL(config);
+ } catch (DirectoryException e) {
+ logger.traceException(e);
+ throw new InitializationException(e.getMessageObject());
+ }
+
+ // Save properties that cannot be dynamically modified.
+ allowReuseAddress = config.isAllowTCPReuseAddress();
+ backlog = config.getAcceptBacklog();
+ listenAddresses = new HashSet<>();
+ for (InetAddress addr : config.getListenAddress()) {
+ listenAddresses.add(new InetSocketAddress(addr, config.getListenPort()));
+ }
+
+ // Construct a unique name for this connection handler, and put
+ // together the set of listeners.
+ listeners = new LinkedList<>();
+ StringBuilder nameBuffer = new StringBuilder();
+ nameBuffer.append(friendlyName);
+ for (InetSocketAddress a : listenAddresses) {
+ listeners.add(new HostPort(a.getHostName(), a.getPort()));
+ nameBuffer.append(" ");
+ nameBuffer.append(a.getHostName());
+ }
+ nameBuffer.append(" port ");
+ nameBuffer.append(config.getListenPort());
+ handlerName = nameBuffer.toString();
+
+ // Attempt to bind to the listen port on all configured addresses to
+ // verify whether the connection handler will be able to start.
+ LocalizableMessage errorMessage = checkAnyListenAddressInUse(config.getListenAddress(), config.getListenPort(),
+ allowReuseAddress, config.dn());
+ if (errorMessage != null) {
+ logger.error(errorMessage);
+ throw new InitializationException(errorMessage);
+ }
+
+ // Create a system property to store the LDAP(S) port the server is
+ // listening to. This information can be displayed with jinfo.
+ System.setProperty(protocol + "_port", String.valueOf(config.getListenPort()));
+
+ // Create and start a connection finalizer thread for this
+ // connection handler.
+ connectionFinalizer = Executors.newSingleThreadScheduledExecutor(new DirectoryThread.Factory(
+ "LDAP Connection Finalizer for connection handler " + toString()));
+
+ connectionFinalizerActiveJobQueue = new ArrayList<>();
+ connectionFinalizerPendingJobQueue = new ArrayList<>();
+
+ connectionFinalizer.scheduleWithFixedDelay(new ConnectionFinalizerRunnable(), 100, 100, TimeUnit.MILLISECONDS);
+
+ // Register the set of supported LDAP versions.
+ DirectoryServer.registerSupportedLDAPVersion(3, this);
+ if (config.isAllowLDAPV2()) {
+ DirectoryServer.registerSupportedLDAPVersion(2, this);
+ }
+
+ // Create and register monitors.
+ statTracker = new LDAPStatistics(handlerName + " Statistics");
+ DirectoryServer.registerMonitorProvider(statTracker);
+
+ connMonitor = new ClientConnectionMonitorProvider(this);
+ DirectoryServer.registerMonitorProvider(connMonitor);
+
+ // Register this as a change listener.
+ config.addLDAPChangeListener(this);
+ }
+
+ @Override
+ public boolean isConfigurationAcceptable(ConnectionHandlerCfg configuration,
+ List<LocalizableMessage> unacceptableReasons) {
+ LDAPConnectionHandlerCfg config = (LDAPConnectionHandlerCfg) configuration;
+
+ if (currentConfig == null || (!currentConfig.isEnabled() && config.isEnabled())) {
+ // Attempt to bind to the listen port on all configured addresses to
+ // verify whether the connection handler will be able to start.
+ LocalizableMessage errorMessage = checkAnyListenAddressInUse(config.getListenAddress(),
+ config.getListenPort(), config.isAllowTCPReuseAddress(), config.dn());
+ if (errorMessage != null) {
+ unacceptableReasons.add(errorMessage);
+ return false;
+ }
+ }
+
+ if (config.isEnabled()
// Check that the SSL configuration is valid.
- && (config.isUseSSL() || config.isAllowStartTLS()))
- {
- try
- {
- createSSLEngine(config, createSSLContext(config));
- }
- catch (DirectoryException e)
- {
- logger.traceException(e);
+ && (config.isUseSSL() || config.isAllowStartTLS())) {
+ try {
+ createSSLEngine(config, createSSLContext(config));
+ } catch (DirectoryException e) {
+ logger.traceException(e);
- unacceptableReasons.add(e.getMessageObject());
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Checks whether any listen address is in use for the given port. The check
- * is performed by binding to each address and port.
- *
- * @param listenAddresses
- * the listen {@link InetAddress} to test
- * @param listenPort
- * the listen port to test
- * @param allowReuseAddress
- * whether addresses can be reused
- * @param configEntryDN
- * the configuration entry DN
- * @return an error message if at least one of the address is already in use,
- * null otherwise.
- */
- private LocalizableMessage checkAnyListenAddressInUse(
- Collection<InetAddress> listenAddresses, int listenPort,
- boolean allowReuseAddress, DN configEntryDN)
- {
- for (InetAddress a : listenAddresses)
- {
- try
- {
- if (StaticUtils.isAddressInUse(a, listenPort, allowReuseAddress))
- {
- throw new IOException(ERR_CONNHANDLER_ADDRESS_INUSE.get().toString());
+ unacceptableReasons.add(e.getMessageObject());
+ return false;
+ }
}
- }
- catch (IOException e)
- {
- logger.traceException(e);
- return ERR_CONNHANDLER_CANNOT_BIND.get("LDAP", configEntryDN, a.getHostAddress(), listenPort,
- getExceptionMessage(e));
- }
+
+ return true;
}
- return null;
- }
- @Override
- public boolean isConfigurationChangeAcceptable(
- LDAPConnectionHandlerCfg config, List<LocalizableMessage> unacceptableReasons)
- {
- return isConfigurationAcceptable(config, unacceptableReasons);
- }
-
- @Override
- public void processServerShutdown(LocalizableMessage reason)
- {
- shutdownRequested = true;
- }
-
- void stopListener()
- {
- if (listener != null)
- {
- listener.close();
- listener = null;
+ /**
+ * Checks whether any listen address is in use for the given port. The check is performed by binding to each address
+ * and port.
+ *
+ * @param listenAddresses
+ * the listen {@link InetAddress} to test
+ * @param listenPort
+ * the listen port to test
+ * @param allowReuseAddress
+ * whether addresses can be reused
+ * @param configEntryDN
+ * the configuration entry DN
+ * @return an error message if at least one of the address is already in use, null otherwise.
+ */
+ private LocalizableMessage checkAnyListenAddressInUse(Collection<InetAddress> listenAddresses, int listenPort,
+ boolean allowReuseAddress, DN configEntryDN) {
+ for (InetAddress a : listenAddresses) {
+ try {
+ if (StaticUtils.isAddressInUse(a, listenPort, allowReuseAddress)) {
+ throw new IOException(ERR_CONNHANDLER_ADDRESS_INUSE.get().toString());
+ }
+ } catch (IOException e) {
+ logger.traceException(e);
+ return ERR_CONNHANDLER_CANNOT_BIND.get("LDAP", configEntryDN, a.getHostAddress(), listenPort,
+ getExceptionMessage(e));
+ }
+ }
+ return null;
}
- }
- private void startListener() throws IOException
- {
- listener = new GrizzlyLDAPListener(
- listenAddresses,
- Options.defaultOptions()
- .set(LDAPListener.CONNECT_MAX_BACKLOG, backlog)
- .set(LDAPListener.REQUEST_MAX_SIZE_IN_BYTES, (int) currentConfig.getMaxRequestSize()),
- new Function<LDAPClientContext,
- ReactiveHandler<LDAPClientContext,LdapRawMessage, Stream<Response>>,
- LdapException>() {
+ @Override
+ public boolean isConfigurationChangeAcceptable(LDAPConnectionHandlerCfg config,
+ List<LocalizableMessage> unacceptableReasons) {
+ return isConfigurationAcceptable(config, unacceptableReasons);
+ }
+
+ @Override
+ public void processServerShutdown(LocalizableMessage reason) {
+ shutdownRequested = true;
+ }
+
+ void stopListener() {
+ if (listener != null) {
+ listener.close();
+ listener = null;
+ }
+ }
+
+ private void startListener() throws IOException {
+ listener = new GrizzlyLDAPListener(
+ listenAddresses,
+ Options.defaultOptions().set(LDAPListener.CONNECT_MAX_BACKLOG, backlog)
+ .set(LDAPListener.REQUEST_MAX_SIZE_IN_BYTES, (int) currentConfig.getMaxRequestSize()),
+ new Function<LDAPClientContext,
+ ReactiveHandler<LDAPClientContext, LdapRawMessage, Stream<Response>>,
+ LdapException>() {
@Override
- public ReactiveHandler<LDAPClientContext, LdapRawMessage, Stream<Response>>
- apply(LDAPClientContext clientContext) throws LdapException {
+ public ReactiveHandler<LDAPClientContext, LdapRawMessage, Stream<Response>> apply(
+ LDAPClientContext clientContext) throws LdapException {
final LDAPClientConnection2 conn = canAccept(clientContext);
return new ReactiveHandler<LDAPClientContext, LdapRawMessage, Stream<Response>>() {
@Override
- public Single<Stream<Response>> handle(LDAPClientContext context,
- LdapRawMessage request) throws Exception {
+ public Single<Stream<Response>> handle(LDAPClientContext context, LdapRawMessage request)
+ throws Exception {
return conn.handle(queueingStrategy, request);
}
};
}
});
- }
+ }
- /**
- * Operates in a loop, accepting new connections and ensuring that requests on
- * those connections are handled properly.
- */
- @Override
- public void run()
- {
- setName(handlerName);
- boolean starting = true;
- setName(handlerName);
+ /**
+ * Operates in a loop, accepting new connections and ensuring that requests on those connections are handled
+ * properly.
+ */
+ @Override
+ public void run() {
+ setName(handlerName);
+ boolean starting = true;
+ setName(handlerName);
- boolean lastIterationFailed = false;
+ boolean lastIterationFailed = false;
- while (!shutdownRequested)
- {
- // If this connection handler is not enabled, then just sleep for a bit and check again.
- if (!this.enabled)
- {
- if (listener != null)
- {
- stopListener();
+ while (!shutdownRequested) {
+ // If this connection handler is not enabled, then just sleep for a bit and check again.
+ if (!this.enabled) {
+ if (listener != null) {
+ stopListener();
+ }
+
+ if (starting) {
+ // This may happen if there was an initialisation error which led to disable the connector.
+ // The main thread is waiting for the connector to listen on its port, which will not occur yet,
+ // so notify here to allow the server startup to complete.
+ synchronized (waitListen) {
+ starting = false;
+ waitListen.notify();
+ }
+ }
+
+ StaticUtils.sleep(1000);
+ continue;
+ }
+
+ if (listener != null) {
+ // If already listening, then sleep for a bit and check again.
+ StaticUtils.sleep(1000);
+ continue;
+ }
+
+ try {
+ // At this point, the connection Handler either started correctly or failed
+ // to start but the start process should be notified and resume its work in any cases.
+ synchronized (waitListen) {
+ waitListen.notify();
+ }
+
+ // If we have gotten here, then we are about to start listening
+ // for the first time since startup or since we were previously disabled.
+ // Start the embedded HTTP server
+ startListener();
+ lastIterationFailed = false;
+ } catch (Exception e) {
+ // Clean up the messed up HTTP server
+ stopListener();
+
+ // Error + alert about the horked config
+ logger.traceException(e);
+ logger.error(ERR_CONNHANDLER_CANNOT_ACCEPT_CONNECTION, friendlyName, currentConfig.dn(),
+ getExceptionMessage(e));
+
+ if (lastIterationFailed) {
+ // The last time through the accept loop we also encountered a failure.
+ // Rather than enter a potential infinite loop of failures,
+ // disable this acceptor and log an error.
+ LocalizableMessage message = ERR_CONNHANDLER_CONSECUTIVE_ACCEPT_FAILURES.get(friendlyName,
+ currentConfig.dn(), stackTraceToSingleLineString(e));
+ logger.error(message);
+
+ DirectoryServer.sendAlertNotification(this,
+ ALERT_TYPE_HTTP_CONNECTION_HANDLER_CONSECUTIVE_FAILURES, message);
+ this.enabled = false;
+ } else {
+ lastIterationFailed = true;
+ }
+ }
}
- if (starting)
- {
- // This may happen if there was an initialisation error which led to disable the connector.
- // The main thread is waiting for the connector to listen on its port, which will not occur yet,
- // so notify here to allow the server startup to complete.
- synchronized (waitListen)
- {
- starting = false;
- waitListen.notify();
- }
- }
-
- StaticUtils.sleep(1000);
- continue;
- }
-
- if (listener != null)
- {
- // If already listening, then sleep for a bit and check again.
- StaticUtils.sleep(1000);
- continue;
- }
-
- try
- {
- // At this point, the connection Handler either started correctly or failed
- // to start but the start process should be notified and resume its work in any cases.
- synchronized (waitListen)
- {
- waitListen.notify();
- }
-
- // If we have gotten here, then we are about to start listening
- // for the first time since startup or since we were previously disabled.
- // Start the embedded HTTP server
- startListener();
- lastIterationFailed = false;
- }
- catch (Exception e)
- {
- // Clean up the messed up HTTP server
+ // Initiate shutdown
stopListener();
+ }
- // Error + alert about the horked config
- logger.traceException(e);
- logger.error(
- ERR_CONNHANDLER_CANNOT_ACCEPT_CONNECTION, friendlyName, currentConfig.dn(), getExceptionMessage(e));
-
- if (lastIterationFailed)
- {
- // The last time through the accept loop we also encountered a failure.
- // Rather than enter a potential infinite loop of failures,
- // disable this acceptor and log an error.
- LocalizableMessage message = ERR_CONNHANDLER_CONSECUTIVE_ACCEPT_FAILURES.get(
- friendlyName, currentConfig.dn(), stackTraceToSingleLineString(e));
- logger.error(message);
-
- DirectoryServer.sendAlertNotification(this, ALERT_TYPE_HTTP_CONNECTION_HANDLER_CONSECUTIVE_FAILURES, message);
- this.enabled = false;
+ private LDAPClientConnection2 canAccept(LDAPClientContext clientContext) throws LdapException {
+ // Check to see if the core server rejected the
+ // connection (e.g., already too many connections
+ // established).
+ final LDAPClientConnection2 clientConnection = new LDAPClientConnection2(this, clientContext, getProtocol(),
+ currentConfig.isKeepStats());
+ if (clientConnection.getConnectionID() < 0) {
+ clientConnection.disconnect(DisconnectReason.ADMIN_LIMIT_EXCEEDED, true,
+ ERR_CONNHANDLER_REJECTED_BY_SERVER.get());
+ throw LdapException.newLdapException(ResultCode.ADMIN_LIMIT_EXCEEDED);
}
- else
- {
- lastIterationFailed = true;
+
+ InetAddress clientAddr = clientConnection.getRemoteAddress();
+ // Check to see if the client is on the denied list.
+ // If so, then reject it immediately.
+ if (!deniedClients.isEmpty() && AddressMask.matchesAny(deniedClients, clientAddr)) {
+ clientConnection.disconnect(
+ DisconnectReason.CONNECTION_REJECTED,
+ currentConfig.isSendRejectionNotice(),
+ ERR_CONNHANDLER_DENIED_CLIENT.get(clientConnection.getClientHostPort(),
+ clientConnection.getServerHostPort()));
+ throw LdapException.newLdapException(ResultCode.CONSTRAINT_VIOLATION);
}
- }
- }
+ // Check to see if there is an allowed list and if
+ // there is whether the client is on that list. If
+ // not, then reject the connection.
+ if (!allowedClients.isEmpty() && !AddressMask.matchesAny(allowedClients, clientAddr)) {
+ clientConnection.disconnect(
+ DisconnectReason.CONNECTION_REJECTED,
+ currentConfig.isSendRejectionNotice(),
+ ERR_CONNHANDLER_DISALLOWED_CLIENT.get(clientConnection.getClientHostPort(),
+ clientConnection.getServerHostPort()));
+ throw LdapException.newLdapException(ResultCode.CONSTRAINT_VIOLATION);
+ }
- // Initiate shutdown
- stopListener();
- }
-
- private LDAPClientConnection2 canAccept(LDAPClientContext clientContext) throws LdapException
- {
- // Check to see if the core server rejected the
- // connection (e.g., already too many connections
- // established).
- final LDAPClientConnection2 clientConnection =
- new LDAPClientConnection2(this, clientContext, getProtocol(), currentConfig.isKeepStats());
- if (clientConnection.getConnectionID() < 0)
- {
- clientConnection.disconnect(
- DisconnectReason.ADMIN_LIMIT_EXCEEDED, true, ERR_CONNHANDLER_REJECTED_BY_SERVER.get());
- throw LdapException.newLdapException(ResultCode.ADMIN_LIMIT_EXCEEDED);
- }
-
- InetAddress clientAddr = clientConnection.getRemoteAddress();
- // Check to see if the client is on the denied list.
- // If so, then reject it immediately.
- if (!deniedClients.isEmpty()
- && AddressMask.matchesAny(deniedClients, clientAddr))
- {
- clientConnection.disconnect(DisconnectReason.CONNECTION_REJECTED,
- currentConfig.isSendRejectionNotice(), ERR_CONNHANDLER_DENIED_CLIENT
- .get(clientConnection.getClientHostPort(), clientConnection
- .getServerHostPort()));
- throw LdapException.newLdapException(ResultCode.CONSTRAINT_VIOLATION);
- }
- // Check to see if there is an allowed list and if
- // there is whether the client is on that list. If
- // not, then reject the connection.
- if (!allowedClients.isEmpty()
- && !AddressMask.matchesAny(allowedClients, clientAddr))
- {
- clientConnection.disconnect(DisconnectReason.CONNECTION_REJECTED,
- currentConfig.isSendRejectionNotice(),
- ERR_CONNHANDLER_DISALLOWED_CLIENT.get(clientConnection
- .getClientHostPort(), clientConnection.getServerHostPort()));
- throw LdapException.newLdapException(ResultCode.CONSTRAINT_VIOLATION);
- }
-
- // If we've gotten here, then we'll take the
- // connection so invoke the post-connect plugins and
- // register the client connection with a request
- // handler.
- try
- {
- PluginConfigManager pluginManager = DirectoryServer
- .getPluginConfigManager();
- PluginResult.PostConnect pluginResult = pluginManager
- .invokePostConnectPlugins(clientConnection);
- if (!pluginResult.continueProcessing())
- {
- clientConnection.disconnect(pluginResult.getDisconnectReason(),
- pluginResult.sendDisconnectNotification(),
- pluginResult.getErrorMessage());
- throw LdapException.newLdapException(ResultCode.CONSTRAINT_VIOLATION);
- }
- }
- catch (Exception e)
- {
- logger.traceException(e);
-
- LocalizableMessage message =
- INFO_CONNHANDLER_UNABLE_TO_REGISTER_CLIENT.get(clientConnection
- .getClientHostPort(), clientConnection.getServerHostPort(),
- getExceptionMessage(e));
- logger.debug(message);
-
- clientConnection.disconnect(DisconnectReason.SERVER_ERROR,
- currentConfig.isSendRejectionNotice(), message);
- throw LdapException.newLdapException(ResultCode.OPERATIONS_ERROR);
- }
-
- if (useSSL()) {
+ // If we've gotten here, then we'll take the
+ // connection so invoke the post-connect plugins and
+ // register the client connection with a request
+ // handler.
try {
- clientContext.enableTLS(createSSLEngine());
- } catch (DirectoryException e) {
- throw LdapException.newLdapException(e.getResultCode(), e);
+ PluginConfigManager pluginManager = DirectoryServer.getPluginConfigManager();
+ PluginResult.PostConnect pluginResult = pluginManager.invokePostConnectPlugins(clientConnection);
+ if (!pluginResult.continueProcessing()) {
+ clientConnection.disconnect(pluginResult.getDisconnectReason(),
+ pluginResult.sendDisconnectNotification(), pluginResult.getErrorMessage());
+ throw LdapException.newLdapException(ResultCode.CONSTRAINT_VIOLATION);
+ }
+ } catch (Exception e) {
+ logger.traceException(e);
+
+ LocalizableMessage message = INFO_CONNHANDLER_UNABLE_TO_REGISTER_CLIENT.get(
+ clientConnection.getClientHostPort(), clientConnection.getServerHostPort(), getExceptionMessage(e));
+ logger.debug(message);
+
+ clientConnection.disconnect(DisconnectReason.SERVER_ERROR, currentConfig.isSendRejectionNotice(), message);
+ throw LdapException.newLdapException(ResultCode.OPERATIONS_ERROR);
+ }
+
+ if (useSSL()) {
+ try {
+ clientContext.enableTLS(createSSLEngine());
+ } catch (DirectoryException e) {
+ throw LdapException.newLdapException(e.getResultCode(), e);
+ }
+ }
+
+ return clientConnection;
+ }
+
+ /**
+ * Appends a string representation of this connection handler to the provided buffer.
+ *
+ * @param buffer
+ * The buffer to which the information should be appended.
+ */
+ @Override
+ public void toString(StringBuilder buffer) {
+ buffer.append(handlerName);
+ }
+
+ /**
+ * Indicates whether this connection handler should use SSL to communicate with clients.
+ *
+ * @return {@code true} if this connection handler should use SSL to communicate with clients, or {@code false} if
+ * not.
+ */
+ public boolean useSSL() {
+ return currentConfig.isUseSSL();
+ }
+
+ SSLEngine createSSLEngine() throws DirectoryException {
+ return createSSLEngine(currentConfig, sslContext);
+ }
+
+ private SSLEngine createSSLEngine(LDAPConnectionHandlerCfg config, SSLContext sslContext)
+ throws DirectoryException {
+ try {
+ SSLEngine sslEngine = sslContext.createSSLEngine();
+ sslEngine.setUseClientMode(false);
+
+ final Set<String> protocols = config.getSSLProtocol();
+ if (!protocols.isEmpty()) {
+ sslEngine.setEnabledProtocols(protocols.toArray(new String[0]));
+ }
+
+ final Set<String> ciphers = config.getSSLCipherSuite();
+ if (!ciphers.isEmpty()) {
+ sslEngine.setEnabledCipherSuites(ciphers.toArray(new String[0]));
+ }
+
+ switch (config.getSSLClientAuthPolicy()) {
+ case DISABLED:
+ sslEngine.setNeedClientAuth(false);
+ sslEngine.setWantClientAuth(false);
+ break;
+ case REQUIRED:
+ sslEngine.setWantClientAuth(true);
+ sslEngine.setNeedClientAuth(true);
+ break;
+ case OPTIONAL:
+ default:
+ sslEngine.setNeedClientAuth(false);
+ sslEngine.setWantClientAuth(true);
+ break;
+ }
+
+ return sslEngine;
+ } catch (Exception e) {
+ logger.traceException(e);
+ ResultCode resCode = DirectoryServer.getServerErrorResultCode();
+ LocalizableMessage message = ERR_CONNHANDLER_SSL_CANNOT_INITIALIZE.get(getExceptionMessage(e));
+ throw new DirectoryException(resCode, message, e);
}
}
- return clientConnection;
- }
-
- /**
- * Appends a string representation of this connection handler to the provided
- * buffer.
- *
- * @param buffer
- * The buffer to which the information should be appended.
- */
- @Override
- public void toString(StringBuilder buffer)
- {
- buffer.append(handlerName);
- }
-
- /**
- * Indicates whether this connection handler should use SSL to communicate
- * with clients.
- *
- * @return {@code true} if this connection handler should use SSL to
- * communicate with clients, or {@code false} if not.
- */
- public boolean useSSL()
- {
- return currentConfig.isUseSSL();
- }
-
- SSLEngine createSSLEngine() throws DirectoryException {
- return createSSLEngine(currentConfig, sslContext);
- }
-
- private SSLEngine createSSLEngine(LDAPConnectionHandlerCfg config, SSLContext sslContext) throws DirectoryException
- {
- try
- {
- SSLEngine sslEngine = sslContext.createSSLEngine();
- sslEngine.setUseClientMode(false);
-
- final Set<String> protocols = config.getSSLProtocol();
- if (!protocols.isEmpty())
- {
- sslEngine.setEnabledProtocols(protocols.toArray(new String[0]));
- }
-
- final Set<String> ciphers = config.getSSLCipherSuite();
- if (!ciphers.isEmpty())
- {
- sslEngine.setEnabledCipherSuites(ciphers.toArray(new String[0]));
- }
-
- switch (config.getSSLClientAuthPolicy())
- {
- case DISABLED:
- sslEngine.setNeedClientAuth(false);
- sslEngine.setWantClientAuth(false);
- break;
- case REQUIRED:
- sslEngine.setWantClientAuth(true);
- sslEngine.setNeedClientAuth(true);
- break;
- case OPTIONAL:
- default:
- sslEngine.setNeedClientAuth(false);
- sslEngine.setWantClientAuth(true);
- break;
- }
-
- return sslEngine;
- }
- catch (Exception e)
- {
- logger.traceException(e);
- ResultCode resCode = DirectoryServer.getServerErrorResultCode();
- LocalizableMessage message = ERR_CONNHANDLER_SSL_CANNOT_INITIALIZE
- .get(getExceptionMessage(e));
- throw new DirectoryException(resCode, message, e);
- }
- }
-
- private void disableAndWarnIfUseSSL(LDAPConnectionHandlerCfg config)
- {
- if (config.isUseSSL())
- {
- logger.warn(INFO_DISABLE_CONNECTION, friendlyName);
- enabled = false;
- }
- }
-
- private SSLContext createSSLContext(LDAPConnectionHandlerCfg config)
- throws DirectoryException
- {
- try
- {
- DN keyMgrDN = config.getKeyManagerProviderDN();
- KeyManagerProvider<?> keyManagerProvider = DirectoryServer
- .getKeyManagerProvider(keyMgrDN);
- if (keyManagerProvider == null)
- {
- logger.error(ERR_NULL_KEY_PROVIDER_MANAGER, keyMgrDN, friendlyName);
- disableAndWarnIfUseSSL(config);
- keyManagerProvider = new NullKeyManagerProvider();
- // The SSL connection is unusable without a key manager provider
- }
- else if (! keyManagerProvider.containsAtLeastOneKey())
- {
- logger.error(ERR_INVALID_KEYSTORE, friendlyName);
- disableAndWarnIfUseSSL(config);
- }
-
- final SortedSet<String> aliases = new TreeSet<>(config.getSSLCertNickname());
- final KeyManager[] keyManagers;
- if (aliases.isEmpty())
- {
- keyManagers = keyManagerProvider.getKeyManagers();
- }
- else
- {
- final Iterator<String> it = aliases.iterator();
- while (it.hasNext())
- {
- if (!keyManagerProvider.containsKeyWithAlias(it.next()))
- {
- logger.error(ERR_KEYSTORE_DOES_NOT_CONTAIN_ALIAS, aliases, friendlyName);
- it.remove();
- }
+ private void disableAndWarnIfUseSSL(LDAPConnectionHandlerCfg config) {
+ if (config.isUseSSL()) {
+ logger.warn(INFO_DISABLE_CONNECTION, friendlyName);
+ enabled = false;
}
+ }
- if (aliases.isEmpty())
- {
- disableAndWarnIfUseSSL(config);
+ private SSLContext createSSLContext(LDAPConnectionHandlerCfg config) throws DirectoryException {
+ try {
+ DN keyMgrDN = config.getKeyManagerProviderDN();
+ KeyManagerProvider<?> keyManagerProvider = DirectoryServer.getKeyManagerProvider(keyMgrDN);
+ if (keyManagerProvider == null) {
+ logger.error(ERR_NULL_KEY_PROVIDER_MANAGER, keyMgrDN, friendlyName);
+ disableAndWarnIfUseSSL(config);
+ keyManagerProvider = new NullKeyManagerProvider();
+ // The SSL connection is unusable without a key manager provider
+ } else if (!keyManagerProvider.containsAtLeastOneKey()) {
+ logger.error(ERR_INVALID_KEYSTORE, friendlyName);
+ disableAndWarnIfUseSSL(config);
+ }
+
+ final SortedSet<String> aliases = new TreeSet<>(config.getSSLCertNickname());
+ final KeyManager[] keyManagers;
+ if (aliases.isEmpty()) {
+ keyManagers = keyManagerProvider.getKeyManagers();
+ } else {
+ final Iterator<String> it = aliases.iterator();
+ while (it.hasNext()) {
+ if (!keyManagerProvider.containsKeyWithAlias(it.next())) {
+ logger.error(ERR_KEYSTORE_DOES_NOT_CONTAIN_ALIAS, aliases, friendlyName);
+ it.remove();
+ }
+ }
+
+ if (aliases.isEmpty()) {
+ disableAndWarnIfUseSSL(config);
+ }
+ keyManagers = SelectableCertificateKeyManager.wrap(keyManagerProvider.getKeyManagers(), aliases,
+ friendlyName);
+ }
+
+ DN trustMgrDN = config.getTrustManagerProviderDN();
+ TrustManagerProvider<?> trustManagerProvider = DirectoryServer.getTrustManagerProvider(trustMgrDN);
+ if (trustManagerProvider == null) {
+ trustManagerProvider = new NullTrustManagerProvider();
+ }
+
+ SSLContext sslContext = SSLContext.getInstance(SSL_CONTEXT_INSTANCE_NAME);
+ sslContext.init(keyManagers, trustManagerProvider.getTrustManagers(), null);
+ return sslContext;
+ } catch (Exception e) {
+ logger.traceException(e);
+ ResultCode resCode = DirectoryServer.getServerErrorResultCode();
+ LocalizableMessage message = ERR_CONNHANDLER_SSL_CANNOT_INITIALIZE.get(getExceptionMessage(e));
+ throw new DirectoryException(resCode, message, e);
}
- keyManagers = SelectableCertificateKeyManager.wrap(keyManagerProvider.getKeyManagers(), aliases, friendlyName);
- }
-
- DN trustMgrDN = config.getTrustManagerProviderDN();
- TrustManagerProvider<?> trustManagerProvider = DirectoryServer
- .getTrustManagerProvider(trustMgrDN);
- if (trustManagerProvider == null)
- {
- trustManagerProvider = new NullTrustManagerProvider();
- }
-
- SSLContext sslContext = SSLContext.getInstance(SSL_CONTEXT_INSTANCE_NAME);
- sslContext.init(keyManagers, trustManagerProvider.getTrustManagers(),
- null);
- return sslContext;
}
- catch (Exception e)
- {
- logger.traceException(e);
- ResultCode resCode = DirectoryServer.getServerErrorResultCode();
- LocalizableMessage message = ERR_CONNHANDLER_SSL_CANNOT_INITIALIZE
- .get(getExceptionMessage(e));
- throw new DirectoryException(resCode, message, e);
- }
- }
- /**
- * Enqueue a connection finalizer which will be invoked after a short delay.
- *
- * @param r
- * The connection finalizer runnable.
- */
- void registerConnectionFinalizer(Runnable r)
- {
- synchronized (connectionFinalizerLock)
- {
- if (connectionFinalizer != null)
- {
- connectionFinalizerPendingJobQueue.add(r);
- }
- else
- {
- // Already finalized - invoked immediately.
- r.run();
- }
+ /**
+ * Enqueue a connection finalizer which will be invoked after a short delay.
+ *
+ * @param r
+ * The connection finalizer runnable.
+ */
+ void registerConnectionFinalizer(Runnable r) {
+ synchronized (connectionFinalizerLock) {
+ if (connectionFinalizer != null) {
+ connectionFinalizerPendingJobQueue.add(r);
+ } else {
+ // Already finalized - invoked immediately.
+ r.run();
+ }
+ }
}
- }
}
--
Gitblit v1.10.0