11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * CDDL HEADER START
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * The contents of this file are subject to the terms of the
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * Common Development and Distribution License, Version 1.0 only
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * (the "License"). You may not use this file except in compliance
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * with the License.
8cf870d281dc8c242f083d14dfef05f24aa5fceeJnRouvignac * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
8cf870d281dc8c242f083d14dfef05f24aa5fceeJnRouvignac * or http://forgerock.org/license/CDDLv1.0.html.
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * See the License for the specific language governing permissions
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * and limitations under the License.
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * When distributing Covered Code, include this CDDL HEADER in each
8cf870d281dc8c242f083d14dfef05f24aa5fceeJnRouvignac * file and include the License file at legal-notices/CDDLv1_0.txt.
8cf870d281dc8c242f083d14dfef05f24aa5fceeJnRouvignac * If applicable, add the following below this CDDL HEADER, with the
8cf870d281dc8c242f083d14dfef05f24aa5fceeJnRouvignac * fields enclosed by brackets "[]" replaced with your own identifying
8cf870d281dc8c242f083d14dfef05f24aa5fceeJnRouvignac * information:
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * Portions Copyright [yyyy] [name of copyright owner]
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * CDDL HEADER END
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * Copyright 2013 ForgeRock AS
4a7f0ad21d4c6a48235ffd7f7f4610315212d0e6JnRouvignacimport org.codehaus.jackson.map.JsonMappingException;
f1a8b8986de97939dbfcbdfc23ee9e66d5faadb2JnRouvignacimport org.forgerock.json.resource.CollectionResourceProvider;
f1a8b8986de97939dbfcbdfc23ee9e66d5faadb2JnRouvignacimport org.forgerock.json.resource.ConnectionFactory;
f1a8b8986de97939dbfcbdfc23ee9e66d5faadb2JnRouvignacimport org.forgerock.json.resource.servlet.HttpServlet;
f1a8b8986de97939dbfcbdfc23ee9e66d5faadb2JnRouvignacimport org.forgerock.opendj.rest2ldap.AuthorizationPolicy;
f1a8b8986de97939dbfcbdfc23ee9e66d5faadb2JnRouvignacimport org.forgerock.opendj.rest2ldap.servlet.Rest2LDAPContextFactory;
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignacimport org.glassfish.grizzly.http.server.HttpServer;
c87c8fef4847562b343af5b65855fe0f5587c72eJnRouvignacimport org.glassfish.grizzly.http.server.HttpServerMonitoringConfig;
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignacimport org.glassfish.grizzly.http.server.NetworkListener;
c7fef36838657b602d29098075e95b4b26e0e9d0JnRouvignacimport org.glassfish.grizzly.http.server.ServerConfiguration;
c87c8fef4847562b343af5b65855fe0f5587c72eJnRouvignacimport org.glassfish.grizzly.monitoring.MonitoringConfig;
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignacimport org.glassfish.grizzly.nio.transport.TCPNIOTransport;
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignacimport org.glassfish.grizzly.servlet.WebappContext;
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignacimport org.glassfish.grizzly.ssl.SSLEngineConfigurator;
f1a8b8986de97939dbfcbdfc23ee9e66d5faadb2JnRouvignacimport org.glassfish.grizzly.strategies.SameThreadIOStrategy;
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignacimport org.opends.server.admin.server.ConfigurationChangeListener;
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignacimport org.opends.server.admin.std.server.ConnectionHandlerCfg;
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignacimport org.opends.server.admin.std.server.HTTPConnectionHandlerCfg;
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignacimport org.opends.server.extensions.NullKeyManagerProvider;
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignacimport org.opends.server.extensions.NullTrustManagerProvider;
a26e1a1d15f3dd480d0a0813ef13ac73fe6c7dceJnRouvignacimport org.opends.server.loggers.HTTPAccessLogger;
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignacimport org.opends.server.loggers.debug.DebugTracer;
c87c8fef4847562b343af5b65855fe0f5587c72eJnRouvignacimport org.opends.server.monitors.ClientConnectionMonitorProvider;
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignacimport org.opends.server.util.SelectableCertificateKeyManager;
1ed0da1f17cd5bc56955e29bc2536cf56c53a9bcJnRouvignacimport static org.opends.messages.ConfigMessages.*;
1ed0da1f17cd5bc56955e29bc2536cf56c53a9bcJnRouvignacimport static org.opends.messages.ProtocolMessages.*;
1ed0da1f17cd5bc56955e29bc2536cf56c53a9bcJnRouvignacimport static org.opends.server.loggers.ErrorLogger.*;
1ed0da1f17cd5bc56955e29bc2536cf56c53a9bcJnRouvignacimport static org.opends.server.loggers.debug.DebugLogger.*;
1ed0da1f17cd5bc56955e29bc2536cf56c53a9bcJnRouvignacimport static org.opends.server.util.ServerConstants.*;
1ed0da1f17cd5bc56955e29bc2536cf56c53a9bcJnRouvignacimport static org.opends.server.util.StaticUtils.*;
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * This class defines a connection handler that will be used for communicating
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * with clients over HTTP. The connection handler is responsible for
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * starting/stopping the embedded web server.
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignacpublic class HTTPConnectionHandler extends
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac ConnectionHandler<HTTPConnectionHandlerCfg> implements
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac ConfigurationChangeListener<HTTPConnectionHandlerCfg>,
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** The tracer object for the debug logger. */
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac private static final DebugTracer TRACER = getTracer();
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** Default friendly name for this connection handler. */
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac private static final String DEFAULT_FRIENDLY_NAME = "HTTP Connection Handler";
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** SSL instance name used in context creation. */
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac private static final String SSL_CONTEXT_INSTANCE_NAME = "TLS";
f1a8b8986de97939dbfcbdfc23ee9e66d5faadb2JnRouvignac private static final ObjectMapper JSON_MAPPER = new ObjectMapper().configure(
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** The initialization configuration. */
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** The current configuration. */
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * Indicates whether the Directory Server is in the process of shutting down.
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac private volatile boolean shutdownRequested;
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac /** Indicates whether this connection handler is enabled. */
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac private boolean enabled;
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** The set of listeners for this connection handler. */
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac private List<HostPort> listeners = new LinkedList<HostPort>();
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** The HTTP server embedded in OpenDJ. */
c87c8fef4847562b343af5b65855fe0f5587c72eJnRouvignac /** The HTTP probe that collects stats. */
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * Holds the current client connections. Using {@link ConcurrentHashMap} to
0231adf34e4b43f90bb6ccae759ade8e0de51ea2JnRouvignac * ensure no concurrent reads/writes can happen and adds/removes are fast. We
0231adf34e4b43f90bb6ccae759ade8e0de51ea2JnRouvignac * only use the keys, so it does not matter what value is put there.
0231adf34e4b43f90bb6ccae759ade8e0de51ea2JnRouvignac private Map<ClientConnection, ClientConnection> clientConnections =
0231adf34e4b43f90bb6ccae759ade8e0de51ea2JnRouvignac new ConcurrentHashMap<ClientConnection, ClientConnection>();
c87c8fef4847562b343af5b65855fe0f5587c72eJnRouvignac /** The set of statistics collected for this connection handler. */
c87c8fef4847562b343af5b65855fe0f5587c72eJnRouvignac * The client connection monitor provider associated with this connection
c87c8fef4847562b343af5b65855fe0f5587c72eJnRouvignac private ClientConnectionMonitorProvider connMonitor;
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** The unique name assigned to this connection handler. */
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** The protocol used by this connection handler. */
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * The condition variable that will be used by the start method to wait for
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * the socket port to be opened and ready to process requests before
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * returning.
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac /** The friendly name of this connection handler. */
c9e40c4ae6863d2ba547b452801067171491c082matthew * The SSL engine configurator is used for obtaining default SSL parameters.
4b818465d78607099770cce29266d0dd1c61846aJnRouvignac private SSLEngineConfigurator sslEngineConfigurator;
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * Default constructor. It is invoked by reflection to create this
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * {@link ConnectionHandler}.
f27d9a3dda3291133be6a78210fb636bbfd07aa4JnRouvignac * Returns whether unauthenticated HTTP requests are allowed. The server
f27d9a3dda3291133be6a78210fb636bbfd07aa4JnRouvignac * checks whether unauthenticated requests are allowed server-wide first then
f27d9a3dda3291133be6a78210fb636bbfd07aa4JnRouvignac * for the HTTP Connection Handler second.
f27d9a3dda3291133be6a78210fb636bbfd07aa4JnRouvignac * @return true if unauthenticated requests are allowed, false otherwise.
f27d9a3dda3291133be6a78210fb636bbfd07aa4JnRouvignac // the global setting overrides the more specific setting here.
f27d9a3dda3291133be6a78210fb636bbfd07aa4JnRouvignac return !DirectoryServer.rejectUnauthenticatedRequests()
f27d9a3dda3291133be6a78210fb636bbfd07aa4JnRouvignac && !this.currentConfig.isAuthenticationRequired();
43b51b383215ce9df9001940d3930d32ea1a784fJnRouvignac * Registers a client connection to track it.
43b51b383215ce9df9001940d3930d32ea1a784fJnRouvignac * @param clientConnection
43b51b383215ce9df9001940d3930d32ea1a784fJnRouvignac * the client connection to register
43b51b383215ce9df9001940d3930d32ea1a784fJnRouvignac void addClientConnection(ClientConnection clientConnection)
43b51b383215ce9df9001940d3930d32ea1a784fJnRouvignac clientConnections.put(clientConnection, clientConnection);
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** {@inheritDoc} */
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac public ConfigChangeResult applyConfigurationChange(
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac // Create variables to include in the response.
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac boolean adminActionRequired = false;
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac List<Message> messages = new ArrayList<Message>();
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac messages.add(ERR_CONNHANDLER_CONFIG_CHANGES_REQUIRE_RESTART.get("HTTP"));
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac // Reconfigure SSL if needed.
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac return new ConfigChangeResult(e.getResultCode(), adminActionRequired,
c87c8fef4847562b343af5b65855fe0f5587c72eJnRouvignac if (config.isEnabled() && this.currentConfig.isEnabled() && isListening())
c87c8fef4847562b343af5b65855fe0f5587c72eJnRouvignac { // server was running and will still be running
c87c8fef4847562b343af5b65855fe0f5587c72eJnRouvignac // if the "enabled" was flipped, leave it to the stop / start server to
c87c8fef4847562b343af5b65855fe0f5587c72eJnRouvignac // handle it
c87c8fef4847562b343af5b65855fe0f5587c72eJnRouvignac if (!this.currentConfig.isKeepStats() && config.isKeepStats())
c87c8fef4847562b343af5b65855fe0f5587c72eJnRouvignac { // it must now keep stats while it was not previously
c87c8fef4847562b343af5b65855fe0f5587c72eJnRouvignac else if (this.currentConfig.isKeepStats() && !config.isKeepStats()
c87c8fef4847562b343af5b65855fe0f5587c72eJnRouvignac { // it must NOT keep stats anymore
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac getHttpConfig(this.httpServer).removeProbes(this.httpProbe);
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired,
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac private boolean anyChangeRequiresRestart(HTTPConnectionHandlerCfg newCfg)
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac return !equals(newCfg.getListenPort(), initConfig.getListenPort())
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac || !equals(newCfg.getListenAddress(), initConfig.getListenAddress())
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac || !equals(newCfg.getMaxRequestSize(), currentConfig
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac || !equals(newCfg.isAllowTCPReuseAddress(), currentConfig
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac || !equals(newCfg.isUseTCPKeepAlive(), currentConfig
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac || !equals(newCfg.isUseTCPNoDelay(), currentConfig.isUseTCPNoDelay())
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac || !equals(newCfg.getMaxBlockedWriteTimeLimit(), currentConfig
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac || !equals(newCfg.getBufferSize(), currentConfig.getBufferSize())
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac || !equals(newCfg.getAcceptBacklog(), currentConfig.getAcceptBacklog())
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac || !equals(newCfg.isUseSSL(), currentConfig.isUseSSL())
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac || !equals(newCfg.getKeyManagerProviderDN(), currentConfig
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac || !equals(newCfg.getSSLCertNickname(), currentConfig
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac || !equals(newCfg.getTrustManagerProviderDN(), currentConfig
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac || !equals(newCfg.getSSLProtocol(), currentConfig.getSSLProtocol())
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac || !equals(newCfg.getSSLCipherSuite(), currentConfig
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac || !equals(newCfg.getSSLClientAuthPolicy(), currentConfig
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac private void configureSSL(HTTPConnectionHandlerCfg config)
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac protocol = config.isUseSSL() ? "HTTPS" : "HTTP";
4b818465d78607099770cce29266d0dd1c61846aJnRouvignac sslEngineConfigurator = createSSLEngineConfigurator(config);
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** {@inheritDoc} */
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac public void finalizeConnectionHandler(Message finalizeReason)
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac // Unregister this as a change listener.
194d53ecdae39d8241c06b2b60ef828f5f137bc4matthew DirectoryServer.deregisterMonitorProvider(connMonitor);
194d53ecdae39d8241c06b2b60ef828f5f137bc4matthew DirectoryServer.deregisterMonitorProvider(statTracker);
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** {@inheritDoc} */
cbb1c6adc466ca43dd1b9ae738d6e242c6b80ae7JnRouvignac Map<String, String> alerts = new LinkedHashMap<String, String>();
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac alerts.put(ALERT_TYPE_HTTP_CONNECTION_HANDLER_CONSECUTIVE_FAILURES,
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac ALERT_DESCRIPTION_HTTP_CONNECTION_HANDLER_CONSECUTIVE_FAILURES);
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** {@inheritDoc} */
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** {@inheritDoc} */
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac public Collection<ClientConnection> getClientConnections()
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** {@inheritDoc} */
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** {@inheritDoc} */
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * Returns the current config of this connection handler.
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * @return the current config of this connection handler
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** {@inheritDoc} */
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac public Collection<String> getEnabledSSLCipherSuites()
4b818465d78607099770cce29266d0dd1c61846aJnRouvignac final SSLEngineConfigurator configurator = sslEngineConfigurator;
4b818465d78607099770cce29266d0dd1c61846aJnRouvignac return Arrays.asList(configurator.getEnabledCipherSuites());
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** {@inheritDoc} */
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac public Collection<String> getEnabledSSLProtocols()
4b818465d78607099770cce29266d0dd1c61846aJnRouvignac final SSLEngineConfigurator configurator = sslEngineConfigurator;
4b818465d78607099770cce29266d0dd1c61846aJnRouvignac return Arrays.asList(configurator.getEnabledProtocols());
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** {@inheritDoc} */
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * Returns the listen port for this connection handler.
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * @return the listen port for this connection handler.
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** {@inheritDoc} */
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * Returns the SSL engine configured for this connection handler if SSL is
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * enabled, null otherwise.
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * @return the SSL engine if SSL is enabled, null otherwise
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** {@inheritDoc} */
c87c8fef4847562b343af5b65855fe0f5587c72eJnRouvignac * Retrieves the set of statistics maintained by this connection handler.
c87c8fef4847562b343af5b65855fe0f5587c72eJnRouvignac * @return The set of statistics maintained by this connection handler.
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** {@inheritDoc} */
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac public void initializeConnectionHandler(HTTPConnectionHandlerCfg config)
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac friendlyName = config.dn().getRDN().getAttributeValue(0).toString();
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac listeners.add(new HostPort(a.getHostAddress(), listenPort));
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac // Configure SSL if needed.
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac throw new InitializationException(e.getMessageObject());
c87c8fef4847562b343af5b65855fe0f5587c72eJnRouvignac // Create and register monitors.
c87c8fef4847562b343af5b65855fe0f5587c72eJnRouvignac statTracker = new HTTPStatistics(handlerName + " Statistics");
c87c8fef4847562b343af5b65855fe0f5587c72eJnRouvignac DirectoryServer.registerMonitorProvider(statTracker);
c87c8fef4847562b343af5b65855fe0f5587c72eJnRouvignac connMonitor = new ClientConnectionMonitorProvider(this);
c87c8fef4847562b343af5b65855fe0f5587c72eJnRouvignac DirectoryServer.registerMonitorProvider(connMonitor);
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac // Register this as a change listener.
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac private String getHandlerName(HTTPConnectionHandlerCfg config)
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** {@inheritDoc} */
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac public boolean isConfigurationAcceptable(ConnectionHandlerCfg configuration,
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac HTTPConnectionHandlerCfg config = (HTTPConnectionHandlerCfg) configuration;
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac if ((currentConfig == null) || (!this.enabled && config.isEnabled()))
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac // Attempt to bind to the listen port on all configured addresses to
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac // verify whether the connection handler will be able to start.
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac checkAnyListenAddressInUse(config.getListenAddress(), config
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac .getListenPort(), config.isAllowTCPReuseAddress(), config.dn());
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac return false;
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac // Check that the SSL configuration is valid.
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac return false;
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac return true;
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * Checks whether any listen address is in use for the given port. The check
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * is performed by binding to each address and port.
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * @param listenAddresses
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * the listen {@link InetAddress} to test
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * @param listenPort
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * the listen port to test
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * @param allowReuseAddress
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * whether addresses can be reused
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * @param configEntryDN
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * the configuration entry DN
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * @return an error message if at least one of the address is already in use,
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac * null otherwise.
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac Collection<InetAddress> listenAddresses, int listenPort,
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac if (isAddressInUse(a, listenPort, allowReuseAddress))
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac throw new IOException(ERR_CONNHANDLER_ADDRESS_INUSE.get().toString());
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac return ERR_CONNHANDLER_CANNOT_BIND.get("HTTP", String
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac .valueOf(configEntryDN), a.getHostAddress(), listenPort,
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** {@inheritDoc} */
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac HTTPConnectionHandlerCfg configuration, List<Message> unacceptableReasons)
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac return isConfigurationAcceptable(configuration, unacceptableReasons);
c87c8fef4847562b343af5b65855fe0f5587c72eJnRouvignac * Indicates whether this connection handler should maintain usage statistics.
c87c8fef4847562b343af5b65855fe0f5587c72eJnRouvignac * @return <CODE>true</CODE> if this connection handler should maintain usage
c87c8fef4847562b343af5b65855fe0f5587c72eJnRouvignac * statistics, or <CODE>false</CODE> if not.
c87c8fef4847562b343af5b65855fe0f5587c72eJnRouvignac public boolean keepStats()
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** {@inheritDoc} */
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac public void processServerShutdown(Message reason)
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac private boolean isListening()
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** {@inheritDoc} */
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac public void start()
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac // The Directory Server start process should only return
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac // when the connection handlers port are fully opened
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac // and working. The start method therefore needs to wait for
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac // the created thread to
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac synchronized (waitListen)
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac // If something interrupted the start its probably better
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac // to return ASAP.
43b51b383215ce9df9001940d3930d32ea1a784fJnRouvignac * Unregisters a client connection to stop tracking it.
43b51b383215ce9df9001940d3930d32ea1a784fJnRouvignac * @param clientConnection
43b51b383215ce9df9001940d3930d32ea1a784fJnRouvignac * the client connection to unregister
43b51b383215ce9df9001940d3930d32ea1a784fJnRouvignac void removeClientConnection(ClientConnection clientConnection)
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** {@inheritDoc} */
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac public void run()
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac boolean lastIterationFailed = false;
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac // If this connection handler is not enabled, then just sleep
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac // for a bit and check again.
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac // If already listening, then sleep for a bit and check again.
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac // At this point, the connection Handler either started
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac // correctly or failed to start but the start process
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac // should be notified and resume its work in any cases.
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac synchronized (waitListen)
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac // If we have gotten here, then we are about to start listening
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac // for the first time since startup or since we were previously
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac // disabled. Start the embedded HTTP server
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac // clean up the messed up HTTP server
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac // error + alert about the horked config
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac logError(ERR_CONNHANDLER_CANNOT_ACCEPT_CONNECTION.get(friendlyName,
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac String.valueOf(currentConfig.dn()), getExceptionMessage(e)));
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac // The last time through the accept loop we also
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac // encountered a failure. Rather than enter a potential
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac // infinite loop of failures, disable this acceptor and
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac // log an error.
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac ERR_CONNHANDLER_CONSECUTIVE_ACCEPT_FAILURES.get(friendlyName,
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac ALERT_TYPE_HTTP_CONNECTION_HANDLER_CONSECUTIVE_FAILURES, message);
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac this.enabled = false;
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac // Initiate shutdown
f1a8b8986de97939dbfcbdfc23ee9e66d5faadb2JnRouvignac // silence Grizzly's own logging
f1a8b8986de97939dbfcbdfc23ee9e66d5faadb2JnRouvignac Logger.getLogger("org.glassfish.grizzly").setLevel(Level.OFF);
a26e1a1d15f3dd480d0a0813ef13ac73fe6c7dceJnRouvignac if (HTTPAccessLogger.getHTTPAccessLogPublishers().isEmpty())
a26e1a1d15f3dd480d0a0813ef13ac73fe6c7dceJnRouvignac logError(WARN_CONFIG_LOGGER_NO_ACTIVE_HTTP_ACCESS_LOGGERS.get());
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac // register servlet as default servlet and also able to serve REST requests
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac createAndRegisterServlet("OpenDJ Rest2LDAP servlet", "", "/*");
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac logError(NOTE_CONNHANDLER_STARTED_LISTENING.get(handlerName));
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac final int requestSize = (int) currentConfig.getMaxRequestSize();
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac final ServerConfiguration serverConfig = server.getServerConfiguration();
c7fef36838657b602d29098075e95b4b26e0e9d0JnRouvignac serverConfig.setMaxBufferedPostSize(requestSize);
0d79a83a6c8d3af62f592c6e6f4a5b4d01719787matthew serverConfig.setDefaultQueryEncoding(Charsets.UTF8_CHARSET);
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac // configure the network listener
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac new NetworkListener("Rest2LDAP", NetworkListener.DEFAULT_NETWORK_HOST,
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac // configure the network transport
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac final TCPNIOTransport transport = listener.getTransport();
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac transport.setReuseAddress(currentConfig.isAllowTCPReuseAddress());
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac transport.setKeepAlive(currentConfig.isUseTCPKeepAlive());
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac transport.setTcpNoDelay(currentConfig.isUseTCPNoDelay());
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac transport.setWriteTimeout(currentConfig.getMaxBlockedWriteTimeLimit(),
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac final int bufferSize = (int) currentConfig.getBufferSize();
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac transport.setIOStrategy(SameThreadIOStrategy.getInstance());
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac getNumRequestHandlers(currentConfig.getNumRequestHandlers(),
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac transport.setSelectorRunnersCount(numRequestHandlers);
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac transport.setServerConnectionBackLog(currentConfig.getAcceptBacklog());
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac // configure SSL
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac listener.setSSLEngineConfig(sslEngineConfigurator);
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac private void setHttpStatsProbe(HttpServer server)
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac this.httpProbe = new HTTPStatsProbe(this.statTracker);
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac getHttpConfig(server).addProbes(this.httpProbe);
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac private MonitoringConfig<HttpProbe> getHttpConfig(HttpServer server)
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac final HttpServerMonitoringConfig monitoringCfg =
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac server.getServerConfiguration().getMonitoringConfig();
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac private void createAndRegisterServlet(final String servletName,
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac // parse and use JSON config
70e52b34d009d7ce7699b27dfee2ef539ebf1e64JnRouvignac File jsonConfigFile = getFileForPath(this.currentConfig.getConfigFile());
70e52b34d009d7ce7699b27dfee2ef539ebf1e64JnRouvignac parseJsonConfiguration(jsonConfigFile).recordKeyAccesses();
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac final HTTPAuthenticationConfig authenticationConfig =
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac final ConnectionFactory connFactory = getConnectionFactory(configuration);
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac new CollectClientConnectionsFilter(this, authenticationConfig);
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac final HttpServlet servlet = new HttpServlet(connFactory,
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac // Used for hooking our HTTPClientConnection in Rest2LDAP
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac Rest2LDAPContextFactory.getHttpServletContextFactory());
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac // Create and deploy the Web app context
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac final WebappContext ctx = new WebappContext(servletName);
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac ctx.addFilter("collectClientConnections", filter).addMappingForUrlPatterns(
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac EnumSet.of(DispatcherType.REQUEST), true, urlPatterns);
1ac8954c65ecc45727536c6c1699483ef858ff64JnRouvignac ctx.addServlet(servletName, servlet).addMapping(urlPatterns);
4a7f0ad21d4c6a48235ffd7f7f4610315212d0e6JnRouvignac private HTTPAuthenticationConfig getAuthenticationConfig(
4a7f0ad21d4c6a48235ffd7f7f4610315212d0e6JnRouvignac final HTTPAuthenticationConfig result = new HTTPAuthenticationConfig();
4a7f0ad21d4c6a48235ffd7f7f4610315212d0e6JnRouvignac final JsonValue val = configuration.get("authenticationFilter");
4a7f0ad21d4c6a48235ffd7f7f4610315212d0e6JnRouvignac result.setBasicAuthenticationSupported(asBool(val,
4a7f0ad21d4c6a48235ffd7f7f4610315212d0e6JnRouvignac "supportHTTPBasicAuthentication"));
4a7f0ad21d4c6a48235ffd7f7f4610315212d0e6JnRouvignac result.setCustomHeadersAuthenticationSupported(asBool(val,
4a7f0ad21d4c6a48235ffd7f7f4610315212d0e6JnRouvignac "supportAltAuthentication"));
4a7f0ad21d4c6a48235ffd7f7f4610315212d0e6JnRouvignac result.setCustomHeaderUsername(val.get("altAuthenticationUsernameHeader")
4a7f0ad21d4c6a48235ffd7f7f4610315212d0e6JnRouvignac result.setCustomHeaderPassword(val.get("altAuthenticationPasswordHeader")
4a7f0ad21d4c6a48235ffd7f7f4610315212d0e6JnRouvignac final String searchBaseDN = asString(val, "searchBaseDN");
4a7f0ad21d4c6a48235ffd7f7f4610315212d0e6JnRouvignac result.setSearchBaseDN(org.forgerock.opendj.ldap.DN.valueOf(searchBaseDN));
4a7f0ad21d4c6a48235ffd7f7f4610315212d0e6JnRouvignac result.setSearchScope(SearchScope.valueOf(asString(val, "searchScope")));
4a7f0ad21d4c6a48235ffd7f7f4610315212d0e6JnRouvignac result.setSearchFilterTemplate(asString(val, "searchFilterTemplate"));
4a7f0ad21d4c6a48235ffd7f7f4610315212d0e6JnRouvignac private String asString(JsonValue value, String key)
4a7f0ad21d4c6a48235ffd7f7f4610315212d0e6JnRouvignac private boolean asBool(JsonValue value, String key)
4a7f0ad21d4c6a48235ffd7f7f4610315212d0e6JnRouvignac return value.get(key).defaultTo(false).asBoolean();
4a7f0ad21d4c6a48235ffd7f7f4610315212d0e6JnRouvignac private ConnectionFactory getConnectionFactory(final JsonValue configuration)
f1a8b8986de97939dbfcbdfc23ee9e66d5faadb2JnRouvignac configuration.get("servlet").get("mappings").required();
f1a8b8986de97939dbfcbdfc23ee9e66d5faadb2JnRouvignac final JsonValue mapping = mappings.get(mappingUrl);
f1a8b8986de97939dbfcbdfc23ee9e66d5faadb2JnRouvignac Rest2LDAP.builder().authorizationPolicy(AuthorizationPolicy.REUSE)
f1a8b8986de97939dbfcbdfc23ee9e66d5faadb2JnRouvignac return Resources.newInternalConnectionFactory(router);
4a7f0ad21d4c6a48235ffd7f7f4610315212d0e6JnRouvignac private JsonValue parseJsonConfiguration(File configFile) throws IOException,
4a7f0ad21d4c6a48235ffd7f7f4610315212d0e6JnRouvignac JsonParseException, JsonMappingException, ServletException
4a7f0ad21d4c6a48235ffd7f7f4610315212d0e6JnRouvignac // Parse the config file.
4a7f0ad21d4c6a48235ffd7f7f4610315212d0e6JnRouvignac final Object content = JSON_MAPPER.readValue(configFile, Object.class);
4a7f0ad21d4c6a48235ffd7f7f4610315212d0e6JnRouvignac throw new ServletException("Servlet configuration file '" + configFile
4a7f0ad21d4c6a48235ffd7f7f4610315212d0e6JnRouvignac + "' does not contain a valid JSON configuration");
cc86899f30c9197d2867036037e4f1c4638d3e2aJnRouvignac logError(NOTE_CONNHANDLER_STOPPED_LISTENING.get(handlerName));
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac /** {@inheritDoc} */
4b818465d78607099770cce29266d0dd1c61846aJnRouvignac private SSLEngineConfigurator createSSLEngineConfigurator(
4b818465d78607099770cce29266d0dd1c61846aJnRouvignac HTTPConnectionHandlerCfg config) throws DirectoryException
4b818465d78607099770cce29266d0dd1c61846aJnRouvignac SSLContext sslContext = createSSLContext(config);
4b818465d78607099770cce29266d0dd1c61846aJnRouvignac // configure with defaults from the JVM
4b818465d78607099770cce29266d0dd1c61846aJnRouvignac final SSLEngine defaults = sslContext.createSSLEngine();
4b818465d78607099770cce29266d0dd1c61846aJnRouvignac configurator.setEnabledProtocols(defaults.getEnabledProtocols());
4b818465d78607099770cce29266d0dd1c61846aJnRouvignac configurator.setEnabledCipherSuites(defaults.getEnabledCipherSuites());
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac final Set<String> protocols = config.getSSLProtocol();
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac String[] array = protocols.toArray(new String[protocols.size()]);
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac final Set<String> ciphers = config.getSSLCipherSuite();
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac String[] array = ciphers.toArray(new String[ciphers.size()]);
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac ResultCode resCode = DirectoryServer.getServerErrorResultCode();
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac ERR_CONNHANDLER_SSL_CANNOT_INITIALIZE.get(getExceptionMessage(e));
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac throw new DirectoryException(resCode, message, e);
11dea2cb49f8dfbd12424d677ab779a25d453b2aJnRouvignac private SSLContext createSSLContext(HTTPConnectionHandlerCfg config)
4b818465d78607099770cce29266d0dd1c61846aJnRouvignac DirectoryServer.getKeyManagerProvider(keyMgrDN);
4b818465d78607099770cce29266d0dd1c61846aJnRouvignac keyManagerProvider = new NullKeyManagerProvider();
4b818465d78607099770cce29266d0dd1c61846aJnRouvignac keyManagers = keyManagerProvider.getKeyManagers();
4b818465d78607099770cce29266d0dd1c61846aJnRouvignac SelectableCertificateKeyManager.wrap(keyManagerProvider
4b818465d78607099770cce29266d0dd1c61846aJnRouvignac DN trustMgrDN = config.getTrustManagerProviderDN();
4b818465d78607099770cce29266d0dd1c61846aJnRouvignac DirectoryServer.getTrustManagerProvider(trustMgrDN);
4b818465d78607099770cce29266d0dd1c61846aJnRouvignac trustManagerProvider = new NullTrustManagerProvider();
4b818465d78607099770cce29266d0dd1c61846aJnRouvignac SSLContext sslContext = SSLContext.getInstance(SSL_CONTEXT_INSTANCE_NAME);