aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorr.bogacki <r.bogacki@samsung.com>2019-10-10 08:48:03 +0200
committerOfir Sonsino <ofir.sonsino@intl.att.com>2019-10-15 08:10:32 +0000
commit9c48e6785455a58d69fcbb4651fbd15575fe2747 (patch)
treed53f9ad42ff99693982a016bb9b640c0fdf1ef05
parent73d85da66a89bed17b0792002f7f9a525c0f78a5 (diff)
Enabled HTTPS for sdc-workflow-designer
-Fixes for frontend and backend communication Change-Id: Ic8e27e1e8f116ccef23e032fbb02a99af56fa516 Issue-ID: SDC-2479 Signed-off-by: Robert Bogacki <r.bogacki@samsung.com> Signed-off-by: Krystian Kedron <k.kedron@partner.samsung.com>
-rw-r--r--README.md29
-rw-r--r--workflow-designer-ui/docker/Dockerfile6
-rw-r--r--workflow-designer-ui/docker/startup.sh33
-rw-r--r--workflow-designer-ui/src/main/java/org/onap/workflow/web/SSLProxyServlet.java211
-rw-r--r--workflow-designer-ui/src/main/java/org/onap/workflow/web/TransparentProxy.java96
-rw-r--r--workflow-designer-ui/src/main/webapp/WEB-INF/web.xml7
6 files changed, 249 insertions, 133 deletions
diff --git a/README.md b/README.md
index 0c090314..c37b281f 100644
--- a/README.md
+++ b/README.md
@@ -152,7 +152,7 @@ protected with a password. The following command will start a backend container
`docker run -d --name workflow-backend -e SDC_PROTOCOL=http
-e SDC_ENDPOINT=$(docker inspect sdc-BE --format={{.NetworkSettings.IPAddress}}):8080
-e CS_HOSTS=$(docker inspect workflow-cassandra --format={{.NetworkSettings.IPAddress}})
--e SDC_USER=workflow -e SDC_PASSWORD=<secret> -e JAVA_OPTIONS="-Xmx128m -Xms128m -Xss1m"
+-e SDC_USER=workflow -e SDC_PASSWORD=<secret> -e JAVA_OPTIONS="-Xmx128m -Xms128m -Xss1m" -p 8184:8443
nexus3.onap.org:10001/onap/workflow-backend:latest`
### Troubleshooting
@@ -179,19 +179,20 @@ For SSL connectivity:
- IS_HTTPS &mdash; flag to set if frontend accepts https connection from client. Default is false.
- KEYSTORE_PATH
-- KEYSTORE_PASSWORD
-- KEYSTORE_TYPE
+- KEYSTORE_PASS
- TRUSTSTORE_PATH
-- TRUSTSTORE_PASSWORD
-- TRUSTSTORE_TYPE
+- TRUSTSTORE_PASS
If not set then Using jetty default SSL keys.
### Example
`docker run -d --name workflow-frontend
--e BACKEND=http://$(docker inspect workflow-backend --format={{.NetworkSettings.IPAddress}}):8080
--e JAVA_OPTIONS="-Xmx64m -Xms64m -Xss1m" -p 9088:8080 -p 8186:8443 -e IS_HTTPS=true nexus3.onap.org:10001/onap/workflow-frontend:latest`
+-e BACKEND=http://$(docker inspect workflow-backend --format={{.NetworkSettings.IPAddress}}):8443 -e IS_HTTPS=true
+-e KEYSTORE_PATH="etc/org.onap.sdc.p12" -e KEYSTORE_PASS='!ppJ.JvWn0hGh)oVF]([Kv)^'
+-e TRUSTSTORE_PATH="etc/org.onap.sdc.trust.jks" -e TRUSTSTORE_PASS="].][xgtze]hBhz*wy]}m#lf*"
+-e JAVA_OPTIONS="-Xmx64m -Xms64m -Xss1m" -p 9088:8080 -p 8186:8443
+-e IS_HTTPS=true nexus3.onap.org:10001/onap/workflow-frontend:latest`
Notice that port 8080 of the frontend container has been
[mapped]( https://docs.docker.com/config/containers/container-networking/#published-ports) to port 9088 of the host
@@ -323,13 +324,13 @@ corresponding section of *plugins-configuration.yaml* will look like below:
```
- pluginId: WORKFLOW
- pluginDiscoveryUrl: "http://workflow.example.com:9088/ping"
- pluginSourceUrl: "http://workflow.example.com:9088"
- pluginStateUrl: "workflowDesigner"
- pluginDisplayOptions:
- tab:
- displayName: "WORKFLOW"
- displayRoles: ["DESIGNER", "TESTER"]
+ pluginDiscoveryUrl: "http://workflow.example.com:9088/ping"
+ pluginSourceUrl: "http://workflow.example.com:9088"
+ pluginStateUrl: "workflowDesigner"
+ pluginDisplayOptions:
+ tab:
+ displayName: "WORKFLOW"
+ displayRoles: ["DESIGNER", "TESTER"]
```
diff --git a/workflow-designer-ui/docker/Dockerfile b/workflow-designer-ui/docker/Dockerfile
index 2a0ef24c..58130888 100644
--- a/workflow-designer-ui/docker/Dockerfile
+++ b/workflow-designer-ui/docker/Dockerfile
@@ -1,4 +1,4 @@
-FROM jetty:9.4.9-alpine
+FROM jetty:9.4-jre8-alpine
EXPOSE 8080
EXPOSE 8443
@@ -7,10 +7,10 @@ USER root
ARG ARTIFACT
-COPY org.onap.sdc.p12 org.onap.sdc.trust.jks /etc/sdc-cert/
+COPY org.onap.sdc.p12 org.onap.sdc.trust.jks ${JETTY_BASE}/etc/
ADD ${ARTIFACT} ${JETTY_BASE}/webapps/
-RUN chown -R jetty:jetty ${JETTY_BASE}/webapps /etc/sdc-cert
+RUN chown -R jetty:jetty ${JETTY_BASE}/webapps ${JETTY_BASE}/etc/
COPY startup.sh .
RUN chmod 744 startup.sh
diff --git a/workflow-designer-ui/docker/startup.sh b/workflow-designer-ui/docker/startup.sh
index 297be0de..b2f2d516 100644
--- a/workflow-designer-ui/docker/startup.sh
+++ b/workflow-designer-ui/docker/startup.sh
@@ -1,26 +1,27 @@
#!/bin/sh
+
# adding support for https
HTTPS_ENABLED=${IS_HTTPS:-"false"}
-
-if [ "$HTTPS_ENABLED" = "true" ]; then
+CLIENT_AUTH=${IS_CLIENT_AUTH:-"false"}
+if [ "$HTTPS_ENABLED" = "true" ]
+then
echo "enable ssl"
- if [ -n "$KEYSTORE_PATH" ]; then
- keystore_pass="!ppJ.JvWn0hGh)oVF]([Kv)^"
- truststore_pass="].][xgtze]hBhz*wy]}m#lf*"
+ java -jar "${JETTY_HOME}/start.jar" --add-to-start=https,ssl \
+ jetty.sslContext.keyStorePath=$KEYSTORE_PATH \
+ jetty.sslContext.keyStorePassword=$KEYSTORE_PASS \
+ jetty.sslContext.keyManagerPassword=$KEYSTORE_PASS \
+ jetty.sslContext.trustStorePath=$TRUSTSTORE_PATH \
+ jetty.sslContext.trustStorePassword=$TRUSTSTORE_PASS
+
+ echo "setting SSL environment variable"
+
+ SSL_JAVA_OPTS=" -DkeystorePath=$JETTY_BASE/$KEYSTORE_PATH -DkeystorePassword=$KEYSTORE_PASS -DkeyManagerPassword=$KEYSTORE_PASS -DtruststorePath=$JETTY_BASE/$KEYSTORE_PATH -DtruststorePassword=$TRUSTSTORE_PASS -DsslTrustAll=$TRUST_ALL"
+
+ echo $SSL_JAVA_OPTS
- java -jar "${JETTY_HOME}/start.jar" --add-to-start=https,ssl \
- jetty.sslContext.keyStorePath=$KEYSTORE_PATH \
- jetty.sslContext.keyStorePassword=${KEYSTORE_PASS:-$keystore_pass} \
- jetty.sslContext.trustStorePath=$TRUSTSTORE_PATH \
- jetty.sslContext.trustStorePassword=${TRUSTSTORE_PASS:-$truststore_pass}
- else
- echo "Using jetty default SSL"
- java -jar "${JETTY_HOME}/start.jar" --add-to-start=https,ssl
- fi
else
echo "no ssl required"
fi
-
-java -DproxyTo=$BACKEND $JAVA_OPTIONS -jar $JETTY_HOME/start.jar
+java $JAVA_OPTIONS -DproxyTo=$BACKEND $SSL_JAVA_OPTS -jar $JETTY_HOME/start.jar
diff --git a/workflow-designer-ui/src/main/java/org/onap/workflow/web/SSLProxyServlet.java b/workflow-designer-ui/src/main/java/org/onap/workflow/web/SSLProxyServlet.java
new file mode 100644
index 00000000..775706d2
--- /dev/null
+++ b/workflow-designer-ui/src/main/java/org/onap/workflow/web/SSLProxyServlet.java
@@ -0,0 +1,211 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2017 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+
+package org.onap.workflow.web;
+
+
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpScheme;
+import org.eclipse.jetty.proxy.ProxyServlet;
+import org.eclipse.jetty.util.URIUtil;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Enumeration;
+
+
+/***
+ * Class that provides the proxy implementation for both secured and unsecured backend connections.
+ *
+ * The following nevironment value is mandatory:
+ * proxyTo - the full URL to the backend server (including protocol and context path if relevant)
+ *
+ * In case of a secured connection (proxyTo starting with https) the following may be set:
+ * sslTrustAll - set to true if all secure connection are accepted
+ * maxPoolConnections - number of connection in the pool, only when overriding the jetty default
+ *
+ * In case of SSL and nto trusting all certificates:
+ * keystorePath - path to the keystore
+ * keystoreType - type of the keystore
+ * keystorePassword - keystore password
+ *
+ * truststorePath - path to the truststore
+ * truststoreType - type of the truststore
+ * truststorePassword - truststore password
+
+ */
+
+public class SSLProxyServlet extends ProxyServlet {
+
+
+ public static final int TIMEOUT = 600000;
+ protected static final String PROXY_TO = "proxyTo";
+ protected static final String TRUST_ALL = "sslTrustAll";
+ protected static final String MAX_POOL_CONNECTIONS = "maxPoolConnections";
+ protected static final String KEYSTORE_PATH = "keystorePath";
+ protected static final String KEYSTORE_TYPE = "keystoreType";
+ protected static final String KEYSTORE_P = "keystorePassword";
+ protected static final String KEYMANAGER_P = "keyManagerPassword";
+ protected static final String KEYSTORE_CYPHER = "keystoreCypher";
+ protected static final String TRUSTSTORE_PATH = "truststorePath";
+ protected static final String TRUSTSTORE_TYPE = "truststoreType";
+ protected static final String TRUSTSTORE_P = "truststorePassword";
+ protected static final String ENDPOINT_IDENTIFICATION_ALGORITHM = "endpointIdentificationAlgorithm";
+ private static final long serialVersionUID = 1L;
+ private static URL proxyUrl = null;
+
+
+ private static void setProxyUrl(URL proxy) {
+ SSLProxyServlet.proxyUrl = proxy;
+ }
+
+ private void initProxyUrl() throws ServletException, MalformedURLException {
+
+ if (SSLProxyServlet.proxyUrl != null)
+ return;
+ String proxyUrlStr = System.getProperty(PROXY_TO);
+ if (proxyUrlStr == null) {
+ throw new ServletException("-D" + PROXY_TO + " must be specified");
+ }
+ setProxyUrl(new URL(proxyUrlStr));
+ }
+
+
+ @Override
+ public void init() throws ServletException {
+ super.init();
+ try {
+ initProxyUrl();
+ } catch (MalformedURLException e) {
+ throw new ServletException(e);
+ }
+ }
+
+
+ @Override
+ public void sendProxyRequest(HttpServletRequest request, HttpServletResponse response, Request proxyRequest) {
+
+ @SuppressWarnings("unchecked")
+ Enumeration<String> headerNames = request.getHeaderNames();
+ while (headerNames.hasMoreElements()) {
+ String headerName = headerNames.nextElement();
+ if (!proxyRequest.getHeaders().containsKey(headerName)) {
+ String headerVal = request.getHeader(headerName);
+ proxyRequest.header(headerName, headerVal);
+ }
+ }
+ proxyRequest.getHeaders().remove(HttpHeader.HOST);
+ super.sendProxyRequest(request, response, proxyRequest);
+
+ }
+
+ @Override
+ protected HttpClient newHttpClient() {
+ // ioverride parent method to be able to create a secured client as well.
+ boolean isSecureClient = (
+ proxyUrl.getProtocol() != null &&
+ proxyUrl.getProtocol().equalsIgnoreCase(HttpScheme.HTTPS.toString()));
+ if ((isSecureClient)) {
+ String trustAll = System.getProperty(TRUST_ALL);
+ SslContextFactory sslContextFactory = null;
+ if (trustAll != null && Boolean.parseBoolean(trustAll) == Boolean.TRUE) {
+ sslContextFactory = new SslContextFactory.Client(true);
+ } else {
+ sslContextFactory = new SslContextFactory.Client(false);
+ // setting up truststore
+ sslContextFactory.setTrustStorePath(System.getProperty(TRUSTSTORE_PATH));
+ sslContextFactory.setTrustStorePassword(System.getProperty(TRUSTSTORE_P));
+ sslContextFactory.setTrustStoreType(System.getProperty(TRUSTSTORE_TYPE));
+ // setting up keystore
+ sslContextFactory.setKeyStorePath(System.getProperty(KEYSTORE_PATH));
+ sslContextFactory.setKeyStorePassword(System.getProperty(KEYSTORE_P));
+ sslContextFactory.setKeyStoreType(System.getProperty(KEYSTORE_TYPE));
+ sslContextFactory.setKeyManagerPassword(System.getProperty(KEYMANAGER_P));
+
+ if (System.getProperty(ENDPOINT_IDENTIFICATION_ALGORITHM) != null &&
+ !System.getProperty(ENDPOINT_IDENTIFICATION_ALGORITHM).equals("")) {
+ sslContextFactory
+ .setEndpointIdentificationAlgorithm(System.getProperty(ENDPOINT_IDENTIFICATION_ALGORITHM));
+ }
+
+ if (System.getProperty(KEYSTORE_CYPHER) != null &&
+ !System.getProperty(KEYSTORE_CYPHER).equals("")) {
+ sslContextFactory.setIncludeCipherSuites(System.getProperty(KEYSTORE_CYPHER));
+ }
+ }
+
+ return new HttpClient(sslContextFactory);
+
+ } else {
+ return super.newHttpClient();
+ }
+
+ }
+
+ @Override
+ protected HttpClient createHttpClient() throws ServletException {
+
+ try {
+ initProxyUrl();
+ } catch (MalformedURLException e) {
+ throw new ServletException(e);
+ }
+ // calling the parent and setting the configuration for our implementation
+ HttpClient client = super.createHttpClient();
+ setTimeout(TIMEOUT);
+ client.setIdleTimeout(TIMEOUT);
+ client.setStopTimeout(TIMEOUT);
+ if (System.getProperty(MAX_POOL_CONNECTIONS) != null) {
+ client.setMaxConnectionsPerDestination(
+ Integer.valueOf(System.getProperty(MAX_POOL_CONNECTIONS)));
+ }
+ return client;
+
+ }
+
+
+
+ @Override
+ protected String rewriteTarget(HttpServletRequest request) {
+
+ String path = proxyUrl.getPath();
+ if (request.getServletPath() != null) {
+ path += request.getServletPath();
+ }
+ if (request.getPathInfo() != null) {
+ path += request.getPathInfo();
+ }
+
+ return URIUtil.newURI(
+ proxyUrl.getProtocol(),
+ proxyUrl.getHost(),
+ proxyUrl.getPort(),
+ path,
+ request.getQueryString());
+ }
+
+}
diff --git a/workflow-designer-ui/src/main/java/org/onap/workflow/web/TransparentProxy.java b/workflow-designer-ui/src/main/java/org/onap/workflow/web/TransparentProxy.java
deleted file mode 100644
index 3dc65234..00000000
--- a/workflow-designer-ui/src/main/java/org/onap/workflow/web/TransparentProxy.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright © 2016-2018 European Support Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.onap.workflow.web;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Enumeration;
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import org.eclipse.jetty.proxy.ProxyServlet;
-
-/**
- * <p>A naive implementation of transparent proxy based on
- * <a href="https://www.eclipse.org/jetty/documentation/9.4.x/proxy-servlet.html">Jetty proxy servlet</a>.
- * The only difference is that the <code>proxyTo</code> configuration parameter is taken from a JVM argument (and can
- * be therefore injected via an environment variable), instead of an <code>init-param</code> in <i>web.xml</i>.</p>
- * <p>Example: <code>java -DproxyTo=http://172.17.0.9:8080 -jar $JETTY_HOME/start.jar</code></p>
- * <p>If you get a <i>502 Bad Gateway</i> error:</p>
- * <ul>
- * <ol>
- * Make sure that Jetty 'proxy' module
- * <a href="https://www.eclipse.org/jetty/documentation/9.4.x/startup-modules.html">is not enabled</a>.
- * </ol>
- * <ol>
- * Check the value of <code>proxyTo</code>. Make sure it does not redirect to the proxy server itself.
- * </ol>
- * <ol>
- * Make sure there is no proxy (e.g. in a corporate environment) between the servlet and <code>proxyTo</code>.
- * </ol>
- * </ul>
- *
- * @author evitaliy
- * @since 16 Jul 2018
- */
-public class TransparentProxy extends ProxyServlet.Transparent {
-
- @Override
- public void init(ServletConfig config) throws ServletException {
- super.init(new ServletConfigWrapper(config));
- }
-
- private class ServletConfigWrapper implements ServletConfig {
-
- private static final String PROXY_TO = "proxyTo";
-
- private final String proxyTo;
- private final ServletConfig config;
-
- ServletConfigWrapper(ServletConfig config) throws ServletException {
-
- this.proxyTo = System.getProperty(PROXY_TO);
- if (this.proxyTo == null) {
- throw new ServletException("-D" + PROXY_TO + " must be specified");
- }
-
- this.config = config;
- }
-
- @Override
- public String getServletName() {
- return config.getServletName();
- }
-
- @Override
- public ServletContext getServletContext() {
- return config.getServletContext();
- }
-
- @Override
- public String getInitParameter(String s) {
- return PROXY_TO.equals(s) ? this.proxyTo : config.getInitParameter(s);
- }
-
- @Override
- public Enumeration<String> getInitParameterNames() {
- ArrayList<String> params = Collections.list(config.getInitParameterNames());
- params.add(PROXY_TO);
- return Collections.enumeration(params);
- }
- }
-}
diff --git a/workflow-designer-ui/src/main/webapp/WEB-INF/web.xml b/workflow-designer-ui/src/main/webapp/WEB-INF/web.xml
index a58e1274..279b405e 100644
--- a/workflow-designer-ui/src/main/webapp/WEB-INF/web.xml
+++ b/workflow-designer-ui/src/main/webapp/WEB-INF/web.xml
@@ -5,14 +5,13 @@
version="4.0">
<servlet>
- <servlet-name>Transparent Proxy</servlet-name>
- <servlet-class>org.onap.workflow.web.TransparentProxy</servlet-class>
+ <servlet-name>Backend Proxy</servlet-name>
+ <servlet-class>org.onap.workflow.web.SSLProxyServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
-
<servlet-mapping>
- <servlet-name>Transparent Proxy</servlet-name>
+ <servlet-name>Backend Proxy</servlet-name>
<url-pattern>/wf/*</url-pattern>
<url-pattern>/v1.0/activity-spec/*</url-pattern>
</servlet-mapping>