From 2a3801e64d3422a8887f5b9c5ea6dfbe91faadbb Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Sat, 2 Aug 2014 15:36:14 +0000 Subject: QPID-5955 : [Java Broker] Allow HTTP Management to run TCP and SSL on the same port git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1615322 13f79535-47bb-0310-9956-ffa450edef68 --- .../server/management/plugin/HttpManagement.java | 6 +- .../connector/TcpAndSslSelectChannelConnector.java | 356 +++++++++++++++++++++ 2 files changed, 361 insertions(+), 1 deletion(-) create mode 100644 qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/connector/TcpAndSslSelectChannelConnector.java diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java index ece4ccca4f..613218f2fc 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java @@ -41,6 +41,7 @@ import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.SessionManager; import org.eclipse.jetty.server.nio.SelectChannelConnector; +import org.eclipse.jetty.server.ssl.SslSelectChannelConnector; import org.eclipse.jetty.server.ssl.SslSocketConnector; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.ServletContextHandler; @@ -49,6 +50,7 @@ import org.eclipse.jetty.util.ssl.SslContextFactory; import org.apache.qpid.server.configuration.IllegalConfigurationException; import org.apache.qpid.server.logging.messages.ManagementConsoleMessages; +import org.apache.qpid.server.management.plugin.connector.TcpAndSslSelectChannelConnector; import org.apache.qpid.server.management.plugin.filter.ForbiddingAuthorisationFilter; import org.apache.qpid.server.management.plugin.filter.RedirectingAuthorisationFilter; import org.apache.qpid.server.management.plugin.servlet.DefinedFileServlet; @@ -380,7 +382,9 @@ public class HttpManagement extends AbstractPluginAdapter implem { throw new ServerScopedRuntimeException("Cannot configure port " + port.getName() + " for transport " + Transport.SSL, e); } - connector = new SslSocketConnector(factory); + connector = port.getTransports().contains(Transport.TCP) + ? new TcpAndSslSelectChannelConnector(factory) + : new SslSelectChannelConnector(factory); return connector; } diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/connector/TcpAndSslSelectChannelConnector.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/connector/TcpAndSslSelectChannelConnector.java new file mode 100644 index 0000000000..7bdeb7fee8 --- /dev/null +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/connector/TcpAndSslSelectChannelConnector.java @@ -0,0 +1,356 @@ +package org.apache.qpid.server.management.plugin.connector; + +import java.io.IOException; +import java.nio.channels.SelectionKey; +import java.nio.channels.SocketChannel; + +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLSession; + +import org.eclipse.jetty.http.HttpSchemes; +import org.eclipse.jetty.io.AsyncEndPoint; +import org.eclipse.jetty.io.Buffer; +import org.eclipse.jetty.io.Connection; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.io.nio.AsyncConnection; +import org.eclipse.jetty.io.nio.IndirectNIOBuffer; +import org.eclipse.jetty.io.nio.SelectChannelEndPoint; +import org.eclipse.jetty.io.nio.SelectorManager; +import org.eclipse.jetty.io.nio.SslConnection; +import org.eclipse.jetty.server.AsyncHttpConnection; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.nio.SelectChannelConnector; +import org.eclipse.jetty.server.ssl.SslCertificates; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.ssl.SslContextFactory; + +public class TcpAndSslSelectChannelConnector extends SelectChannelConnector +{ + + private static final Logger LOG = Log.getLogger(TcpAndSslSelectChannelConnector.class); + + private final SslContextFactory _sslContextFactory; + + public TcpAndSslSelectChannelConnector(SslContextFactory factory) + { + _sslContextFactory = factory; + addBean(_sslContextFactory); + setUseDirectBuffers(false); + setSoLingerTime(30000); + } + + + @Override + public void customize(EndPoint endpoint, Request request) throws IOException + { + if(endpoint instanceof SslConnection.SslEndPoint) + { + request.setScheme(HttpSchemes.HTTPS); + } + + super.customize(endpoint,request); + + if(endpoint instanceof SslConnection.SslEndPoint) + { + SslConnection.SslEndPoint sslEndpoint = (SslConnection.SslEndPoint) endpoint; + SSLEngine sslEngine = sslEndpoint.getSslEngine(); + SSLSession sslSession = sslEngine.getSession(); + + SslCertificates.customize(sslSession, endpoint, request); + } + } + + /* ------------------------------------------------------------------------------- */ + @Override + protected AsyncConnection newConnection(SocketChannel channel, AsyncEndPoint endpoint) + { + return new ProtocolIdentifyingConnection((ProtocolIdentifyingEndpoint) endpoint); + } + + @Override + protected SelectChannelEndPoint newEndPoint(final SocketChannel channel, + final SelectorManager.SelectSet selectSet, + final SelectionKey key) throws IOException + { + + SelectChannelEndPoint endp = new ProtocolIdentifyingEndpoint(channel,selectSet,key, getMaxIdleTime()); + endp.setConnection(selectSet.getManager().newConnection(channel,endp, key.attachment())); + return endp; + } + + /* ------------------------------------------------------------ */ + /** + * @param channel A channel which if passed is used as to extract remote + * host and port for the purposes of SSL session caching + * @return A SSLEngine for a new or cached SSL Session + * @throws IOException if the SSLEngine cannot be created + */ + protected SSLEngine createSSLEngine(SocketChannel channel) throws IOException + { + SSLEngine engine; + if (channel != null) + { + String peerHost = channel.socket().getInetAddress().getHostAddress(); + int peerPort = channel.socket().getPort(); + engine = _sslContextFactory.newSslEngine(peerHost, peerPort); + } + else + { + engine = _sslContextFactory.newSslEngine(); + } + + engine.setUseClientMode(false); + return engine; + } + + @Override + protected void doStart() throws Exception + { + _sslContextFactory.checkKeyStore(); + _sslContextFactory.start(); + + SSLEngine sslEngine = _sslContextFactory.newSslEngine(); + + sslEngine.setUseClientMode(false); + + SSLSession sslSession = sslEngine.getSession(); + + if (getRequestHeaderSize()