generic jetty https server support 09/58509/10
authorJorge Hernandez <jh1730@att.com>
Wed, 1 Aug 2018 21:18:25 +0000 (16:18 -0500)
committerJorge Hernandez <jh1730@att.com>
Fri, 3 Aug 2018 19:14:05 +0000 (14:14 -0500)
jetty https support in constructor, or by using
".https" when creating an http server service.

Change-Id: I94e8e3e4b93eb6b194657028c740b6781316c7da
Issue-ID: POLICY-940
Signed-off-by: Jorge Hernandez <jh1730@att.com>
.gitignore
policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/HttpServletServerFactory.java
policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/internal/JettyJerseyServer.java
policy-endpoints/src/main/java/org/onap/policy/common/endpoints/http/server/internal/JettyServletServer.java
policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/HttpClientTest.java
policy-endpoints/src/test/java/org/onap/policy/common/endpoints/http/server/test/HttpServerTest.java
policy-endpoints/src/test/resources/keystore-test [new file with mode: 0644]

index ae515bd..13d4a1e 100644 (file)
@@ -8,6 +8,9 @@
 target
 bin
 .metadata/
+.idea/
+**/*.iml
+*/logs/
 integrity-audit/sql/generatedCreateIA.ddl
 integrity-audit/sql/generatedDropIA.ddl
 integrity-audit/sql/iaTest.mv.db
index f09893b..c7d2b1b 100644 (file)
@@ -37,9 +37,10 @@ import org.slf4j.LoggerFactory;
 public interface HttpServletServerFactory {
 
     /**
-     * builds an http server with support for servlets
+     * builds an http or https server with support for servlets
      * 
      * @param name name
+     * @param https use secured http over tls connection
      * @param host binding host
      * @param port port
      * @param contextPath server base path
@@ -48,9 +49,24 @@ public interface HttpServletServerFactory {
      * @return http server
      * @throws IllegalArgumentException when invalid parameters are provided
      */
-    public HttpServletServer build(String name, String host, int port, String contextPath, boolean swagger,
+    HttpServletServer build(String name, boolean https, String host, int port, String contextPath, boolean swagger,
             boolean managed);
 
+    /**
+     * builds an http server with support for servlets
+     *
+     * @param name name
+     * @param host binding host
+     * @param port port
+     * @param contextPath server base path
+     * @param swagger enable swagger documentation
+     * @param managed is it managed by infrastructure
+     * @return http server
+     * @throws IllegalArgumentException when invalid parameters are provided
+     */
+    HttpServletServer build(String name, String host, int port, String contextPath, boolean swagger,
+        boolean managed);
+
     /**
      * list of http servers per properties
      * 
@@ -58,7 +74,7 @@ public interface HttpServletServerFactory {
      * @return list of http servers
      * @throws IllegalArgumentException when invalid parameters are provided
      */
-    public List<HttpServletServer> build(Properties properties);
+    List<HttpServletServer> build(Properties properties);
 
     /**
      * gets a server based on the port
@@ -66,26 +82,26 @@ public interface HttpServletServerFactory {
      * @param port port
      * @return http server
      */
-    public HttpServletServer get(int port);
+    HttpServletServer get(int port);
 
     /**
      * provides an inventory of servers
      * 
      * @return inventory of servers
      */
-    public List<HttpServletServer> inventory();
+    List<HttpServletServer> inventory();
 
     /**
      * destroys server bound to a port
      * 
      * @param port
      */
-    public void destroy(int port);
+    void destroy(int port);
 
     /**
      * destroys the factory and therefore all servers
      */
-    public void destroy();
+    void destroy();
 }
 
 
@@ -107,14 +123,14 @@ class IndexedHttpServletServerFactory implements HttpServletServerFactory {
     protected HashMap<Integer, HttpServletServer> servers = new HashMap<>();
 
     @Override
-    public synchronized HttpServletServer build(String name, String host, int port, String contextPath, boolean swagger,
+    public synchronized HttpServletServer build(String name, boolean https, String host, int port, String contextPath, boolean swagger,
             boolean managed) {
 
         if (servers.containsKey(port)) {
             return servers.get(port);
         }
 
-        JettyJerseyServer server = new JettyJerseyServer(name, host, port, contextPath, swagger);
+        JettyJerseyServer server = new JettyJerseyServer(name, https, host, port, contextPath, swagger);
         if (managed) {
             servers.put(port, server);
         }
@@ -122,6 +138,13 @@ class IndexedHttpServletServerFactory implements HttpServletServerFactory {
         return server;
     }
 
+    @Override
+    public synchronized HttpServletServer build(String name, String host, int port, String contextPath,
+                                                boolean swagger, boolean managed) {
+        return build(name, false, host, port, contextPath, swagger, managed);
+    }
+
+
     @Override
     public synchronized List<HttpServletServer> build(Properties properties) {
 
@@ -192,7 +215,14 @@ class IndexedHttpServletServerFactory implements HttpServletServerFactory {
                 swagger = Boolean.parseBoolean(swaggerString);
             }
 
-            HttpServletServer service = build(serviceName, hostName, servicePort, contextUriPath, swagger, managed);
+            String httpsString = properties.getProperty(PolicyEndPointProperties.PROPERTY_HTTP_SERVER_SERVICES + "."
+                + serviceName + PolicyEndPointProperties.PROPERTY_HTTP_HTTPS_SUFFIX);
+            boolean https = false;
+            if (httpsString != null && !httpsString.isEmpty()) {
+                https = Boolean.parseBoolean(httpsString);
+            }
+
+            HttpServletServer service = build(serviceName, https, hostName, servicePort, contextUriPath, swagger, managed);
             if (userName != null && !userName.isEmpty() && password != null && !password.isEmpty()) {
                 service.setBasicAuthentication(userName, password, authUriPath);
             }
index cd28692..9932d09 100644 (file)
@@ -104,6 +104,7 @@ public class JettyJerseyServer extends JettyServletServer {
      * Constructor
      * 
      * @param name name
+     * @param https enable https?
      * @param host host server host
      * @param port port server port
      * @param swagger support swagger?
@@ -111,19 +112,19 @@ public class JettyJerseyServer extends JettyServletServer {
      * 
      * @throws IllegalArgumentException in invalid arguments are provided
      */
-    public JettyJerseyServer(String name, String host, int port, String contextPath, boolean swagger) {
+    public JettyJerseyServer(String name, boolean https, String host, int port, String contextPath, boolean swagger) {
 
-        super(name, host, port, contextPath);
+        super(name, https, host, port, contextPath);
         if (swagger) {
             this.swaggerId = "swagger-" + this.port;
-            attachSwaggerServlet();
+            attachSwaggerServlet(https);
         }
     }
 
     /**
      * attaches a swagger initialization servlet
      */
-    protected void attachSwaggerServlet() {
+    protected void attachSwaggerServlet(boolean https) {
 
         ServletHolder swaggerServlet = context.addServlet(JerseyJaxrsConfig.class, "/");
 
@@ -133,7 +134,7 @@ public class JettyJerseyServer extends JettyServletServer {
         }
 
         swaggerServlet.setInitParameter(SWAGGER_API_BASEPATH,
-                "http://" + hostname + ":" + this.connector.getPort() + "/");
+                ((https) ? "https://" : "http://") + hostname + ":" + this.connector.getPort() + "/");
         swaggerServlet.setInitParameter(SWAGGER_CONTEXT_ID, swaggerId);
         swaggerServlet.setInitParameter(SWAGGER_SCANNER_ID, swaggerId);
         swaggerServlet.setInitParameter(SWAGGER_PRETTY_PRINT, "true");
index 97166ec..a4cc9b5 100644 (file)
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * ONAP
  * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -26,12 +26,16 @@ import org.eclipse.jetty.security.ConstraintMapping;
 import org.eclipse.jetty.security.ConstraintSecurityHandler;
 import org.eclipse.jetty.security.HashLoginService;
 import org.eclipse.jetty.security.authentication.BasicAuthenticator;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.SecureRequestCustomizer;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.ServerConnector;
 import org.eclipse.jetty.server.Slf4jRequestLog;
 import org.eclipse.jetty.servlet.ServletContextHandler;
 import org.eclipse.jetty.util.security.Constraint;
 import org.eclipse.jetty.util.security.Credential;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.onap.policy.common.endpoints.http.server.HttpServletServer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -41,6 +45,14 @@ import org.slf4j.LoggerFactory;
  */
 public abstract class JettyServletServer implements HttpServletServer, Runnable {
 
+    /**
+     * Keystore/Truststore system property names
+     */
+    public static final String SYSTEM_KEYSTORE_PROPERTY_NAME = "javax.net.ssl.keyStore";
+    public static final String SYSTEM_KEYSTORE_PASSWORD_PROPERTY_NAME = "javax.net.ssl.keyStorePassword";
+    public static final String SYSTEM_TRUSTSTORE_PROPERTY_NAME = "javax.net.ssl.trustStore";
+    public static final String SYSTEM_TRUSTSTORE_PASSWORD_PROPERTY_NAME = "javax.net.ssl.trustStorePassword";
+
     /**
      * Logger
      */
@@ -111,7 +123,7 @@ public abstract class JettyServletServer implements HttpServletServer, Runnable
      * 
      * @throws IllegalArgumentException if invalid parameters are passed in
      */
-    public JettyServletServer(String name, String host, int port, String contextPath) {
+    public JettyServletServer(String name, boolean https, String host, int port, String contextPath) {
         String srvName = name;
         String srvHost = host;
         String ctxtPath = contextPath;
@@ -120,7 +132,7 @@ public abstract class JettyServletServer implements HttpServletServer, Runnable
             srvName = "http-" + port;
         }
 
-        if (port <= 0 && port >= 65535) {
+        if (port <= 0 || port >= 65535) {
             throw new IllegalArgumentException("Invalid Port provided: " + port);
         }
 
@@ -145,7 +157,11 @@ public abstract class JettyServletServer implements HttpServletServer, Runnable
         this.jettyServer = new Server();
         this.jettyServer.setRequestLog(new Slf4jRequestLog());
 
-        this.connector = new ServerConnector(this.jettyServer);
+        if (https)
+            this.connector = httpsConnector();
+        else
+            this.connector = httpConnector();
+
         this.connector.setName(srvName);
         this.connector.setReuseAddress(true);
         this.connector.setPort(port);
@@ -155,6 +171,41 @@ public abstract class JettyServletServer implements HttpServletServer, Runnable
         this.jettyServer.setHandler(context);
     }
 
+    public JettyServletServer(String name, String host, int port, String contextPath) {
+        this(name, false, host, port, contextPath);
+    }
+
+    public ServerConnector httpsConnector() {
+        SslContextFactory sslContextFactory = new SslContextFactory();
+
+        String keyStore = System.getProperty(SYSTEM_KEYSTORE_PROPERTY_NAME);
+        if (keyStore != null) {
+            sslContextFactory.setKeyStorePath(keyStore);
+
+            String ksPassword = System.getProperty(SYSTEM_KEYSTORE_PASSWORD_PROPERTY_NAME);
+            if (ksPassword != null)
+                sslContextFactory.setKeyStorePassword(ksPassword);
+        }
+
+        String trustStore = System.getProperty(SYSTEM_TRUSTSTORE_PROPERTY_NAME);
+        if (trustStore != null) {
+            sslContextFactory.setTrustStorePath(trustStore);
+
+            String tsPassword = System.getProperty(SYSTEM_TRUSTSTORE_PASSWORD_PROPERTY_NAME);
+            if (tsPassword != null)
+                sslContextFactory.setTrustStorePassword(tsPassword);
+        }
+
+        HttpConfiguration https = new HttpConfiguration();
+        https.addCustomizer(new SecureRequestCustomizer());
+
+        return new ServerConnector(jettyServer, sslContextFactory, new HttpConnectionFactory(https));
+    }
+
+    public ServerConnector httpConnector() {
+        return new ServerConnector(this.jettyServer);
+    }
+
     @Override
     public void setBasicAuthentication(String user, String password, String servletPath) {
         String srvltPath = servletPath;
index 08399e9..6ec9bc2 100644 (file)
@@ -1,8 +1,8 @@
 /*-
  * ============LICENSE_START=======================================================
- * policy-endpoints
+ * ONAP
  * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@ package org.onap.policy.common.endpoints.http.server.test;
 import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Properties;
 
@@ -33,20 +34,22 @@ import org.junit.BeforeClass;
 import org.junit.Test;
 import org.onap.policy.common.endpoints.http.client.HttpClient;
 import org.onap.policy.common.endpoints.http.server.HttpServletServer;
+import org.onap.policy.common.endpoints.http.server.internal.JettyJerseyServer;
 import org.onap.policy.common.endpoints.properties.PolicyEndPointProperties;
 import org.onap.policy.common.utils.network.NetworkUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class HttpClientTest {
+    private static final Logger logger = LoggerFactory.getLogger(HttpClientTest.class);
 
-    private static Logger logger = LoggerFactory.getLogger(HttpClientTest.class);
+    private static final HashMap<String, String> savedValuesMap = new HashMap<>();
 
     @BeforeClass
     public static void setUp() throws InterruptedException, IOException {
         logger.info("-- setup() --");
 
-        /* echo server */
+        /* echo server - http + no auth */
 
         final HttpServletServer echoServerNoAuth =
                 HttpServletServer.factory.build("echo", "localhost", 6666, "/", false, true);
@@ -57,10 +60,38 @@ public class HttpClientTest {
             throw new IllegalStateException("cannot connect to port " + echoServerNoAuth.getPort());
         }
 
-        /* no auth echo server */
+        String keyStoreSystemProperty = System.getProperty(JettyJerseyServer.SYSTEM_KEYSTORE_PROPERTY_NAME);
+        if (keyStoreSystemProperty != null) {
+            savedValuesMap.put(JettyJerseyServer.SYSTEM_KEYSTORE_PROPERTY_NAME, keyStoreSystemProperty);
+        }
+
+        String keyStorePasswordSystemProperty = System.getProperty(JettyJerseyServer.SYSTEM_KEYSTORE_PASSWORD_PROPERTY_NAME);
+        if (keyStorePasswordSystemProperty != null) {
+            savedValuesMap.put(JettyJerseyServer.SYSTEM_KEYSTORE_PASSWORD_PROPERTY_NAME, keyStorePasswordSystemProperty);
+        }
+
+        String trustStoreSystemProperty = System.getProperty(JettyJerseyServer.SYSTEM_TRUSTSTORE_PROPERTY_NAME);
+        if (trustStoreSystemProperty != null) {
+            savedValuesMap
+                .put(JettyJerseyServer.SYSTEM_TRUSTSTORE_PROPERTY_NAME, trustStoreSystemProperty);
+        }
+
+        String trustStorePasswordSystemProperty = System.getProperty(JettyJerseyServer.SYSTEM_TRUSTSTORE_PASSWORD_PROPERTY_NAME);
+        if (trustStorePasswordSystemProperty != null) {
+            savedValuesMap
+                .put(JettyJerseyServer.SYSTEM_TRUSTSTORE_PASSWORD_PROPERTY_NAME, trustStorePasswordSystemProperty);
+        }
+
+        System.setProperty(JettyJerseyServer.SYSTEM_KEYSTORE_PROPERTY_NAME, "src/test/resources/keystore-test");
+        System.setProperty(JettyJerseyServer.SYSTEM_KEYSTORE_PASSWORD_PROPERTY_NAME, "kstest");
+
+        System.setProperty(JettyJerseyServer.SYSTEM_TRUSTSTORE_PROPERTY_NAME, "src/test/resources/keystore-test");
+        System.setProperty(JettyJerseyServer.SYSTEM_TRUSTSTORE_PASSWORD_PROPERTY_NAME, "kstest");
+
+        /* echo server - https + basic auth */
 
         final HttpServletServer echoServerAuth =
-                HttpServletServer.factory.build("echo", "localhost", 6667, "/", false, true);
+                HttpServletServer.factory.build("echo", true, "localhost", 6667, "/", false, true);
         echoServerAuth.setBasicAuthentication("x", "y", null);
         echoServerAuth.addServletPackage("/*", HttpClientTest.class.getPackage().getName());
         echoServerAuth.waitedStart(5000);
@@ -76,6 +107,36 @@ public class HttpClientTest {
 
         HttpServletServer.factory.destroy();
         HttpClient.factory.destroy();
+
+        if (savedValuesMap.containsKey(JettyJerseyServer.SYSTEM_KEYSTORE_PROPERTY_NAME)) {
+            System.setProperty(JettyJerseyServer.SYSTEM_KEYSTORE_PROPERTY_NAME, savedValuesMap.get(JettyJerseyServer.SYSTEM_KEYSTORE_PROPERTY_NAME));
+            savedValuesMap.remove(JettyJerseyServer.SYSTEM_KEYSTORE_PROPERTY_NAME);
+        } else {
+            System.clearProperty(JettyJerseyServer.SYSTEM_KEYSTORE_PROPERTY_NAME);
+        }
+
+        if (savedValuesMap.containsKey(JettyJerseyServer.SYSTEM_KEYSTORE_PASSWORD_PROPERTY_NAME)) {
+            System.setProperty(JettyJerseyServer.SYSTEM_KEYSTORE_PASSWORD_PROPERTY_NAME, savedValuesMap.get(JettyJerseyServer.SYSTEM_KEYSTORE_PASSWORD_PROPERTY_NAME));
+            savedValuesMap.remove(JettyJerseyServer.SYSTEM_KEYSTORE_PASSWORD_PROPERTY_NAME);
+        } else {
+            System.clearProperty(JettyJerseyServer.SYSTEM_KEYSTORE_PASSWORD_PROPERTY_NAME);
+        }
+
+        if (savedValuesMap.containsKey(JettyJerseyServer.SYSTEM_TRUSTSTORE_PROPERTY_NAME)) {
+            System.setProperty(JettyJerseyServer.SYSTEM_TRUSTSTORE_PROPERTY_NAME, savedValuesMap.get(JettyJerseyServer.SYSTEM_TRUSTSTORE_PROPERTY_NAME));
+            savedValuesMap.remove(JettyJerseyServer.SYSTEM_TRUSTSTORE_PROPERTY_NAME);
+        } else {
+            System.clearProperty(JettyJerseyServer.SYSTEM_TRUSTSTORE_PROPERTY_NAME);
+        }
+
+        if (savedValuesMap.containsKey(JettyJerseyServer.SYSTEM_TRUSTSTORE_PASSWORD_PROPERTY_NAME)) {
+            System.setProperty(JettyJerseyServer.SYSTEM_TRUSTSTORE_PASSWORD_PROPERTY_NAME, savedValuesMap.get(JettyJerseyServer.SYSTEM_TRUSTSTORE_PASSWORD_PROPERTY_NAME));
+            savedValuesMap.remove(JettyJerseyServer.SYSTEM_TRUSTSTORE_PASSWORD_PROPERTY_NAME);
+        } else {
+            System.clearProperty(JettyJerseyServer.SYSTEM_TRUSTSTORE_PASSWORD_PROPERTY_NAME);
+        }
+
+
     }
 
     @Test
@@ -95,7 +156,7 @@ public class HttpClientTest {
     public void testHttpAuthClient() throws Exception {
         logger.info("-- testHttpAuthClient() --");
 
-        final HttpClient client = HttpClient.factory.build("testHttpAuthClient", false, false, "localhost", 6667,
+        final HttpClient client = HttpClient.factory.build("testHttpAuthClient", true, true,"localhost", 6667,
                 "junit/echo", "x", "y", true);
         final Response response = client.get("hello");
         final String body = HttpClient.getBody(response, String.class);
@@ -108,7 +169,7 @@ public class HttpClientTest {
     public void testHttpAuthClient401() throws Exception {
         logger.info("-- testHttpAuthClient401() --");
 
-        final HttpClient client = HttpClient.factory.build("testHttpAuthClient401", false, false, "localhost", 6667,
+        final HttpClient client = HttpClient.factory.build("testHttpAuthClient401", true, true, "localhost", 6667,
                 "junit/echo", null, null, true);
         final Response response = client.get("hello");
         assertTrue(response.getStatus() == 401);
index b6f0c0e..0db6cfe 100644 (file)
@@ -1,8 +1,8 @@
 /*-
  * ============LICENSE_START=======================================================
- * policy-endpoints
+ * ONAP
  * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -77,7 +77,7 @@ public class HttpServerTest {
     public void testMultipleServers() throws Exception {
         logger.info("-- testMultipleServers() --");
 
-        HttpServletServer server1 = HttpServletServer.factory.build("echo-1", "localhost", 5688, "/", true, true);
+        HttpServletServer server1 = HttpServletServer.factory.build("echo-1", false,"localhost", 5688, "/", true, true);
         server1.addServletPackage("/*", this.getClass().getPackage().getName());
         server1.waitedStart(5000);
 
diff --git a/policy-endpoints/src/test/resources/keystore-test b/policy-endpoints/src/test/resources/keystore-test
new file mode 100644 (file)
index 0000000..5820e0f
Binary files /dev/null and b/policy-endpoints/src/test/resources/keystore-test differ