From a49037c45192b749c045cbd27798f146192fa8d5 Mon Sep 17 00:00:00 2001 From: rfeng Date: Sat, 9 Aug 2008 06:11:54 +0000 Subject: Enable the https support for embedded tomcat and jetty with unit tests git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@684186 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/tuscany/sca/http/jetty/JettyServer.java | 66 +++++++++++++------ .../sca/http/jetty/JettyServerTestCase.java | 71 ++++++++++++++++----- .../host-jetty/src/test/resources/tuscany.keyStore | Bin 0 -> 1265 bytes .../tuscany/sca/http/tomcat/TomcatServer.java | 66 ++++++++++++++----- .../sca/http/tomcat/TomcatServerTestCase.java | 44 ++++++++++++- .../src/test/resources/tuscany.keyStore | Bin 0 -> 1265 bytes 6 files changed, 192 insertions(+), 55 deletions(-) create mode 100644 java/sca/modules/host-jetty/src/test/resources/tuscany.keyStore create mode 100644 java/sca/modules/host-tomcat/src/test/resources/tuscany.keyStore (limited to 'java/sca/modules') diff --git a/java/sca/modules/host-jetty/src/main/java/org/apache/tuscany/sca/http/jetty/JettyServer.java b/java/sca/modules/host-jetty/src/main/java/org/apache/tuscany/sca/http/jetty/JettyServer.java index 0e5cdf2183..dfb34f11a5 100644 --- a/java/sca/modules/host-jetty/src/main/java/org/apache/tuscany/sca/http/jetty/JettyServer.java +++ b/java/sca/modules/host-jetty/src/main/java/org/apache/tuscany/sca/http/jetty/JettyServer.java @@ -23,6 +23,9 @@ import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.net.UnknownHostException; +import java.security.AccessController; +import java.security.KeyStore; +import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -62,9 +65,15 @@ public class JettyServer implements ServletHost { private static final Logger logger = Logger.getLogger(JettyServer.class.getName()); private final Object joinLock = new Object(); - private String keystore; - private String certPassword; - private String keyPassword; + private String trustStore; + private String truststorePassword; + private String keyStore; + private String keyStorePassword; + + private String keyStoreType; + private String trustStoreType; + + private boolean sendServerVersion; private WorkScheduler workScheduler; private int defaultPort = 8080; @@ -101,6 +110,18 @@ public class JettyServer implements ServletHost { public JettyServer(WorkScheduler workScheduler) { this.workScheduler = workScheduler; + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + trustStore = System.getProperty("javax.net.ssl.trustStore"); + truststorePassword = System.getProperty("javax.net.ssl.trustStorePassword"); + keyStore = System.getProperty("javax.net.ssl.keyStore"); + keyStorePassword = System.getProperty("javax.net.ssl.keyStorePassword"); + + keyStoreType = System.getProperty("javax.net.ssl.keyStoreType", KeyStore.getDefaultType()); + trustStoreType = System.getProperty("javax.net.ssl.trustStoreType", KeyStore.getDefaultType()); + return null; + } + }); } public void setDefaultPort(int port) { @@ -115,18 +136,6 @@ public class JettyServer implements ServletHost { this.sendServerVersion = sendServerVersion; } - public void setKeystore(String keystore) { - this.keystore = keystore; - } - - public void setCertPassword(String certPassword) { - this.certPassword = certPassword; - } - - public void setKeyPassword(String keyPassword) { - this.keyPassword = keyPassword; - } - /** * Stop all the started servers. */ @@ -145,6 +154,23 @@ public class JettyServer implements ServletHost { throw new ServletMappingException(e); } } + + private void configureSSL(SslSocketConnector connector) { + connector.setProtocol("TLS"); + connector.setKeystore(keyStore); + connector.setKeyPassword(keyStorePassword); + connector.setKeystoreType(keyStoreType); + + connector.setTruststore(trustStore); + connector.setTrustPassword(truststorePassword); + connector.setTruststoreType(trustStoreType); + + connector.setPassword(keyStorePassword); + if (trustStore != null) { + connector.setNeedClientAuth(true); + } + + } public void addServletMapping(String suri, Servlet servlet) throws ServletMappingException { URI uri = URI.create(suri); @@ -168,14 +194,12 @@ public class JettyServer implements ServletHost { Server server = new Server(); server.setThreadPool(new WorkSchedulerThreadPool()); if ("https".equals(scheme)) { - Connector httpConnector = new SelectChannelConnector(); - httpConnector.setPort(portNumber); +// Connector httpConnector = new SelectChannelConnector(); +// httpConnector.setPort(portNumber); SslSocketConnector sslConnector = new SslSocketConnector(); sslConnector.setPort(portNumber); - sslConnector.setKeystore(keystore); - sslConnector.setPassword(certPassword); - sslConnector.setKeyPassword(keyPassword); - server.setConnectors(new Connector[] {httpConnector, sslConnector}); + configureSSL(sslConnector); + server.setConnectors(new Connector[] {sslConnector}); } else { SelectChannelConnector selectConnector = new SelectChannelConnector(); selectConnector.setPort(portNumber); diff --git a/java/sca/modules/host-jetty/src/test/java/org/apache/tuscany/sca/http/jetty/JettyServerTestCase.java b/java/sca/modules/host-jetty/src/test/java/org/apache/tuscany/sca/http/jetty/JettyServerTestCase.java index 4b8e4ae4f1..020dd4af0e 100644 --- a/java/sca/modules/host-jetty/src/test/java/org/apache/tuscany/sca/http/jetty/JettyServerTestCase.java +++ b/java/sca/modules/host-jetty/src/test/java/org/apache/tuscany/sca/http/jetty/JettyServerTestCase.java @@ -20,11 +20,16 @@ package org.apache.tuscany.sca.http.jetty; import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.ConnectException; import java.net.Socket; +import java.net.URL; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSession; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -93,6 +98,37 @@ public class JettyServerTestCase extends TestCase { assertTrue(servlet.invoked); } + public void testRegisterServletMappingSSL() throws Exception { + System.setProperty("javax.net.ssl.keyStore", "target/test-classes/tuscany.keyStore"); + System.setProperty("javax.net.ssl.keyStorePassword", "apache"); + System.setProperty("jetty.ssl.password", "apache"); + JettyServer service = new JettyServer(workScheduler); + TestServlet servlet = new TestServlet(); + try { + service.addServletMapping("https://127.0.0.1:" + HTTP_PORT + "/foo", servlet); + } finally { + System.clearProperty("javax.net.ssl.keyStore"); + System.clearProperty("javax.net.ssl.keyStorePassword"); + System.clearProperty("jetty.ssl.password"); + } + System.setProperty("javax.net.ssl.trustStore", "target/test-classes/tuscany.keyStore"); + System.setProperty("javax.net.ssl.trustStorePassword", "apache"); + URL url = new URL("https://127.0.0.1:8085/foo"); + HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); + conn.setHostnameVerifier(new HostnameVerifier() { + public boolean verify(String hostname, SSLSession session) { + return true; + }} + ); + + conn.connect(); + read(conn.getInputStream()); + + service.stop(); + assertTrue(servlet.invoked); + + } + /** * Verifies that Servlets can be registered with multiple ports */ @@ -116,7 +152,7 @@ public class JettyServerTestCase extends TestCase { os.flush(); read(client); } - + service.stop(); assertTrue(servlet.invoked); assertTrue(servlet2.invoked); @@ -172,50 +208,55 @@ public class JettyServerTestCase extends TestCase { assertNotNull(ex); service.stop(); } - + public void testResourceServlet() throws Exception { JettyServer service = new JettyServer(workScheduler); - + String documentRoot = getClass().getClassLoader().getResource("content/test.html").toString(); documentRoot = documentRoot.substring(0, documentRoot.lastIndexOf('/')); DefaultResourceServlet resourceServlet = new DefaultResourceServlet(documentRoot); TestResourceServlet servlet = new TestResourceServlet(resourceServlet); service.addServletMapping("http://127.0.0.1:" + HTTP_PORT + "/webcontent/*", servlet); - + Socket client = new Socket("127.0.0.1", HTTP_PORT); OutputStream os = client.getOutputStream(); os.write(REQUEST2.getBytes()); os.flush(); - + String document = read(client); assertTrue(document.indexOf("

hello") != -1); - + service.stop(); } public void testDefaultServlet() throws Exception { JettyServer service = new JettyServer(workScheduler); - + String documentRoot = getClass().getClassLoader().getResource("content/test.html").toString(); documentRoot = documentRoot.substring(0, documentRoot.lastIndexOf('/')); DefaultResourceServlet resourceServlet = new DefaultResourceServlet(documentRoot); service.addServletMapping("http://127.0.0.1:" + HTTP_PORT + "/webcontent/*", resourceServlet); - + Socket client = new Socket("127.0.0.1", HTTP_PORT); OutputStream os = client.getOutputStream(); os.write(REQUEST2.getBytes()); os.flush(); - + String document = read(client); assertTrue(document.indexOf("

hello") != -1); - + service.stop(); } private static String read(Socket socket) throws IOException { + InputStream is = socket.getInputStream(); + return read(is); + } + + private static String read(InputStream is) throws IOException { BufferedReader reader = null; try { - reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); + reader = new BufferedReader(new InputStreamReader(is)); StringBuffer sb = new StringBuffer(); String str; while ((str = reader.readLine()) != null) { @@ -251,11 +292,11 @@ public class JettyServerTestCase extends TestCase { private class TestResourceServlet extends HttpServlet { private static final long serialVersionUID = 1L; private HttpServlet delegate; - + public TestResourceServlet(HttpServlet delegate) { this.delegate = delegate; } - + @Override public void init() throws ServletException { super.init(); @@ -267,12 +308,12 @@ public class JettyServerTestCase extends TestCase { super.init(); delegate.init(config); } - + @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { delegate.service(req, resp); } - + @Override public void destroy() { super.destroy(); diff --git a/java/sca/modules/host-jetty/src/test/resources/tuscany.keyStore b/java/sca/modules/host-jetty/src/test/resources/tuscany.keyStore new file mode 100644 index 0000000000..7ea23f7ff4 Binary files /dev/null and b/java/sca/modules/host-jetty/src/test/resources/tuscany.keyStore differ diff --git a/java/sca/modules/host-tomcat/src/main/java/org/apache/tuscany/sca/http/tomcat/TomcatServer.java b/java/sca/modules/host-tomcat/src/main/java/org/apache/tuscany/sca/http/tomcat/TomcatServer.java index 9b28729231..5ea1701c05 100644 --- a/java/sca/modules/host-tomcat/src/main/java/org/apache/tuscany/sca/http/tomcat/TomcatServer.java +++ b/java/sca/modules/host-tomcat/src/main/java/org/apache/tuscany/sca/http/tomcat/TomcatServer.java @@ -25,6 +25,7 @@ import java.net.URI; import java.net.URL; import java.net.UnknownHostException; import java.security.AccessController; +import java.security.KeyStore; import java.security.PrivilegedAction; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; @@ -217,7 +218,7 @@ public class TomcatServer implements ServletHost { if (scheme == null) { scheme = "http"; } - final int portNumber = (uri.getPort() == -1 ? defaultPortNumber : uri.getPort() ); + final int portNumber = (uri.getPort() == -1 ? defaultPortNumber : uri.getPort()); // Get the port object associated with the given port number Port port = ports.get(portNumber); @@ -226,13 +227,12 @@ public class TomcatServer implements ServletHost { // Create an engine // Allow privileged access to read properties. Requires PropertiesPermission read in // security policy. - final StandardEngine engine = - AccessController.doPrivileged(new PrivilegedAction() { + final StandardEngine engine = AccessController.doPrivileged(new PrivilegedAction() { public StandardEngine run() { return new StandardEngine(); } }); - + engine.setBaseDir(""); engine.setDefaultHost("localhost"); engine.setName("engine/" + portNumber); @@ -265,7 +265,7 @@ public class TomcatServer implements ServletHost { // Allow privileged access to read properties. Requires PropertiesPermission read in // security policy. try { - AccessController.doPrivileged(new PrivilegedExceptionAction() { + AccessController.doPrivileged(new PrivilegedExceptionAction() { public Object run() throws LifecycleException { engine.start(); return null; @@ -274,20 +274,52 @@ public class TomcatServer implements ServletHost { } catch (PrivilegedActionException e) { // throw (LifecycleException)e.getException(); throw new ServletMappingException(e); - } + } Connector connector; // Allow privileged access to read properties. Requires PropertiesPermission read in // security policy. try { + final String protocol = scheme; connector = AccessController.doPrivileged(new PrivilegedExceptionAction() { public CustomConnector run() throws Exception { - CustomConnector customConnector = new CustomConnector(); - customConnector.setPort(portNumber); - customConnector.setContainer(engine); - customConnector.initialize(); - customConnector.start(); - return customConnector; - } + CustomConnector customConnector = new CustomConnector(); + customConnector.setPort(portNumber); + customConnector.setContainer(engine); + + if ("https".equalsIgnoreCase(protocol)) { + configureSSL(customConnector); + ((Http11Protocol) customConnector.getProtocolHandler()).setSSLEnabled(true); + } + customConnector.initialize(); + customConnector.start(); + return customConnector; + } + + private void configureSSL(CustomConnector customConnector) { + String trustStore = System.getProperty("javax.net.ssl.trustStore"); + String trustStorePass = System.getProperty("javax.net.ssl.trustStorePassword"); + String keyStore = System.getProperty("javax.net.ssl.keyStore"); + String keyStorePass = System.getProperty("javax.net.ssl.keyStorePassword"); + + customConnector.setProperty("protocol", "TLS"); + + customConnector.setProperty("keystore", keyStore); + customConnector.setProperty("keypass", keyStorePass); + String keyStoreType = + System.getProperty("javax.net.ssl.keyStoreType", KeyStore.getDefaultType()); + String trustStoreType = + System.getProperty("javax.net.ssl.trustStoreType", KeyStore.getDefaultType()); + customConnector.setProperty("keytype", keyStoreType); + customConnector.setProperty("trusttype", trustStoreType); + customConnector.setProperty("truststore", trustStore); + customConnector.setProperty("trustpass", trustStorePass); + + customConnector.setProperty("clientauth", "false"); + customConnector.setProtocol("HTTP/1.1"); + customConnector.setScheme(protocol); + customConnector.setProperty("backlog", "10"); + customConnector.setSecure(true); + } }); } catch (Exception e) { throw new ServletMappingException(e); @@ -512,12 +544,12 @@ public class TomcatServer implements ServletHost { } catch (Exception ex) { // Hack to handle destruction of Servlets without Servlet context } - + logger.info("Removed Servlet mapping: " + suri); - + // Stop the port if there's no servlets on it anymore String[] contextNames = port.getConnector().getMapper().getContextNames(); - if (contextNames == null || contextNames.length ==0) { + if (contextNames == null || contextNames.length == 0) { try { port.getConnector().stop(); port.getEngine().stop(); @@ -526,7 +558,7 @@ public class TomcatServer implements ServletHost { throw new IllegalStateException(e); } } - + return servletWrapper.getServlet(); } else { logger.warning("Trying to Remove servlet mapping: " + mapping + " where mapping is not registered"); diff --git a/java/sca/modules/host-tomcat/src/test/java/org/apache/tuscany/sca/http/tomcat/TomcatServerTestCase.java b/java/sca/modules/host-tomcat/src/test/java/org/apache/tuscany/sca/http/tomcat/TomcatServerTestCase.java index 7ca5325ccb..afbec52cd9 100644 --- a/java/sca/modules/host-tomcat/src/test/java/org/apache/tuscany/sca/http/tomcat/TomcatServerTestCase.java +++ b/java/sca/modules/host-tomcat/src/test/java/org/apache/tuscany/sca/http/tomcat/TomcatServerTestCase.java @@ -20,10 +20,15 @@ package org.apache.tuscany.sca.http.tomcat; import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.Socket; +import java.net.URL; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSession; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -91,7 +96,38 @@ public class TomcatServerTestCase extends TestCase { service.stop(); assertTrue(servlet.invoked); } + + /** + * Verifies requests are properly routed according to the Servlet mapping + */ + public void testRegisterServletMappingSSL() throws Exception { + System.setProperty("javax.net.ssl.keyStore", "target/test-classes/tuscany.keyStore"); + System.setProperty("javax.net.ssl.keyStorePassword", "apache"); + TomcatServer service = new TomcatServer(workScheduler); + TestServlet servlet = new TestServlet(); + try { + service.addServletMapping("https://127.0.0.1:" + HTTP_PORT + "/foo", servlet); + } finally { + System.clearProperty("javax.net.ssl.keyStore"); + System.clearProperty("javax.net.ssl.keyStorePassword"); + } + System.setProperty("javax.net.ssl.trustStore", "target/test-classes/tuscany.keyStore"); + System.setProperty("javax.net.ssl.trustStorePassword", "apache"); + URL url = new URL("https://127.0.0.1:8085/foo"); + HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); + conn.setHostnameVerifier(new HostnameVerifier() { + public boolean verify(String hostname, SSLSession session) { + return true; + }} + ); + conn.connect(); + read(conn.getInputStream()); + + service.stop(); + assertTrue(servlet.invoked); + + } /** * Verifies that Servlets can be registered with multiple ports */ @@ -244,9 +280,14 @@ public class TomcatServerTestCase extends TestCase { } private static String read(Socket socket) throws IOException { + InputStream is = socket.getInputStream(); + return read(is); + } + + private static String read(InputStream is) throws IOException { BufferedReader reader = null; try { - reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); + reader = new BufferedReader(new InputStreamReader(is)); StringBuffer sb = new StringBuffer(); String str; while ((str = reader.readLine()) != null) { @@ -259,7 +300,6 @@ public class TomcatServerTestCase extends TestCase { } } } - private class TestServlet extends HttpServlet { private static final long serialVersionUID = 1L; boolean invoked; diff --git a/java/sca/modules/host-tomcat/src/test/resources/tuscany.keyStore b/java/sca/modules/host-tomcat/src/test/resources/tuscany.keyStore new file mode 100644 index 0000000000..7ea23f7ff4 Binary files /dev/null and b/java/sca/modules/host-tomcat/src/test/resources/tuscany.keyStore differ -- cgit v1.2.3