You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by al...@apache.org on 2017/09/27 01:48:49 UTC

nifi git commit: NIFI-2529: Added support for SSLContextService protocols in HandleHttpRequest Forced HandleHTTPRequest to use RestrictedSSLContextService and removed extraneous SSL algorithm checks Throw RuntimeException if the chosen SSL protocol isn't

Repository: nifi
Updated Branches:
  refs/heads/master 2c1f5b49e -> b7b6d9082


NIFI-2529: Added support for SSLContextService protocols in HandleHttpRequest
Forced HandleHTTPRequest to use RestrictedSSLContextService and removed extraneous SSL algorithm checks
Throw RuntimeException if the chosen SSL protocol isn't supported by HandleHttpRequest

This closes #1985.

Signed-off-by: Andy LoPresto <al...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/b7b6d908
Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/b7b6d908
Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/b7b6d908

Branch: refs/heads/master
Commit: b7b6d9082c4b5aba5c380f3b48088207d8424909
Parents: 2c1f5b4
Author: m-hogue <ho...@gmail.com>
Authored: Thu Jul 6 10:55:10 2017 -0400
Committer: Andy LoPresto <al...@apache.org>
Committed: Tue Sep 26 18:48:19 2017 -0700

----------------------------------------------------------------------
 .../processors/standard/HandleHttpRequest.java  |   8 +-
 .../standard/TestHandleHttpRequest.java         | 104 +++++++++++++++++++
 2 files changed, 110 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/b7b6d908/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/HandleHttpRequest.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/HandleHttpRequest.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/HandleHttpRequest.java
index f532ca2..a1493f1 100644
--- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/HandleHttpRequest.java
+++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/HandleHttpRequest.java
@@ -91,10 +91,11 @@ import com.sun.jersey.api.client.ClientResponse.Status;
     @WritesAttribute(attribute = "http.method", description = "The HTTP Method that was used for the request, such as GET or POST"),
     @WritesAttribute(attribute = HTTPUtils.HTTP_LOCAL_NAME, description = "IP address/hostname of the server"),
     @WritesAttribute(attribute = HTTPUtils.HTTP_PORT, description = "Listening port of the server"),
-    @WritesAttribute(attribute = "http.query.string", description = "The query string portion of hte Request URL"),
+    @WritesAttribute(attribute = "http.query.string", description = "The query string portion of the Request URL"),
     @WritesAttribute(attribute = HTTPUtils.HTTP_REMOTE_HOST, description = "The hostname of the requestor"),
     @WritesAttribute(attribute = "http.remote.addr", description = "The hostname:port combination of the requestor"),
     @WritesAttribute(attribute = "http.remote.user", description = "The username of the requestor"),
+    @WritesAttribute(attribute = "http.protocol", description = "The protocol used to communicate"),
     @WritesAttribute(attribute = HTTPUtils.HTTP_REQUEST_URI, description = "The full Request URL"),
     @WritesAttribute(attribute = "http.auth.type", description = "The type of HTTP Authorization used"),
     @WritesAttribute(attribute = "http.principal.name", description = "The name of the authenticated user making the request"),
@@ -106,7 +107,7 @@ import com.sun.jersey.api.client.ClientResponse.Status;
             + "attribute, prefixed with \"http.headers.\" For example, if the request contains an HTTP Header named \"x-my-header\", then the value "
             + "will be added to an attribute named \"http.headers.x-my-header\"")})
 @SeeAlso(value = {HandleHttpResponse.class},
-        classNames = {"org.apache.nifi.http.StandardHttpContextMap", "org.apache.nifi.ssl.StandardSSLContextService"})
+        classNames = {"org.apache.nifi.http.StandardHttpContextMap", "org.apache.nifi.ssl.RestrictedStandardSSLContextService"})
 public class HandleHttpRequest extends AbstractProcessor {
 
     private static final Pattern URL_QUERY_PARAM_DELIMITER = Pattern.compile("&");
@@ -448,6 +449,8 @@ public class HandleHttpRequest extends AbstractProcessor {
         sslFactory.setNeedClientAuth(needClientAuth);
         sslFactory.setWantClientAuth(wantClientAuth);
 
+        sslFactory.setProtocol(sslService.getSslAlgorithm());
+
         if (sslService.isKeyStoreConfigured()) {
             sslFactory.setKeyStorePath(sslService.getKeyStoreFile());
             sslFactory.setKeyStorePassword(sslService.getKeyStorePassword());
@@ -528,6 +531,7 @@ public class HandleHttpRequest extends AbstractProcessor {
             putAttribute(attributes, HTTPUtils.HTTP_REMOTE_HOST, request.getRemoteHost());
             putAttribute(attributes, "http.remote.addr", request.getRemoteAddr());
             putAttribute(attributes, "http.remote.user", request.getRemoteUser());
+            putAttribute(attributes, "http.protocol", request.getProtocol());
             putAttribute(attributes, HTTPUtils.HTTP_REQUEST_URI, request.getRequestURI());
             putAttribute(attributes, "http.request.url", request.getRequestURL().toString());
             putAttribute(attributes, "http.auth.type", request.getAuthType());

http://git-wip-us.apache.org/repos/asf/nifi/blob/b7b6d908/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestHandleHttpRequest.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestHandleHttpRequest.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestHandleHttpRequest.java
index c6bb337..0315ba2 100644
--- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestHandleHttpRequest.java
+++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestHandleHttpRequest.java
@@ -22,9 +22,13 @@ import java.io.IOException;
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
 import javax.servlet.AsyncContext;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -32,6 +36,9 @@ import javax.servlet.http.HttpServletResponse;
 import org.apache.nifi.controller.AbstractControllerService;
 import org.apache.nifi.http.HttpContextMap;
 import org.apache.nifi.reporting.InitializationException;
+import org.apache.nifi.ssl.SSLContextService;
+import org.apache.nifi.ssl.StandardRestrictedSSLContextService;
+import org.apache.nifi.ssl.StandardSSLContextService;
 import org.apache.nifi.stream.io.NullOutputStream;
 import org.apache.nifi.stream.io.StreamUtils;
 import org.apache.nifi.util.MockFlowFile;
@@ -42,6 +49,36 @@ import org.junit.Test;
 
 public class TestHandleHttpRequest {
 
+    private static Map<String, String> getTruststoreProperties() {
+        final Map<String, String> props = new HashMap<>();
+        props.put(StandardSSLContextService.TRUSTSTORE.getName(), "src/test/resources/localhost-ts.jks");
+        props.put(StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), "localtest");
+        props.put(StandardSSLContextService.TRUSTSTORE_TYPE.getName(), "JKS");
+        return props;
+    }
+
+    private static Map<String, String> getKeystoreProperties() {
+        final Map<String, String> properties = new HashMap<>();
+        properties.put(StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/localhost-ks.jks");
+        properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "localtest");
+        properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), "JKS");
+        return properties;
+    }
+
+    private static SSLContext useSSLContextService(final TestRunner controller, final Map<String, String> sslProperties) {
+        final SSLContextService service = new StandardRestrictedSSLContextService();
+        try {
+            controller.addControllerService("ssl-service", service, sslProperties);
+            controller.enableControllerService(service);
+        } catch (InitializationException ex) {
+            ex.printStackTrace();
+            Assert.fail("Could not create SSL Context Service");
+        }
+
+        controller.setProperty(HandleHttpRequest.SSL_CONTEXT, "ssl-service");
+        return service.createSSLContext(SSLContextService.ClientAuth.WANT);
+    }
+
     @Test(timeout=10000)
     public void testRequestAddedToService() throws InitializationException, MalformedURLException, IOException, InterruptedException {
         final TestRunner runner = TestRunners.newTestRunner(HandleHttpRequest.class);
@@ -165,6 +202,73 @@ public class TestHandleHttpRequest {
         }
     }
 
+    @Test
+    public void testSecure() throws InitializationException {
+        final TestRunner runner = TestRunners.newTestRunner(HandleHttpRequest.class);
+        runner.setProperty(HandleHttpRequest.PORT, "0");
+
+        final MockHttpContextMap contextMap = new MockHttpContextMap();
+        runner.addControllerService("http-context-map", contextMap);
+        runner.enableControllerService(contextMap);
+        runner.setProperty(HandleHttpRequest.HTTP_CONTEXT_MAP, "http-context-map");
+
+        final Map<String, String> sslProperties = getKeystoreProperties();
+        sslProperties.putAll(getTruststoreProperties());
+        sslProperties.put(StandardSSLContextService.SSL_ALGORITHM.getName(), "TLSv1.2");
+        final SSLContext sslContext = useSSLContextService(runner, sslProperties);
+
+        // trigger processor to stop but not shutdown.
+        runner.run(1, false);
+        try {
+            final Thread httpThread = new Thread(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        final int port = ((HandleHttpRequest) runner.getProcessor()).getPort();
+                        final HttpsURLConnection connection = (HttpsURLConnection) new URL("https://localhost:"
+                                + port + "/my/path?query=true&value1=value1&value2=&value3&value4=apple=orange").openConnection();
+
+                        connection.setSSLSocketFactory(sslContext.getSocketFactory());
+                        connection.setDoOutput(false);
+                        connection.setRequestMethod("GET");
+                        connection.setRequestProperty("header1", "value1");
+                        connection.setRequestProperty("header2", "");
+                        connection.setRequestProperty("header3", "apple=orange");
+                        connection.setConnectTimeout(3000);
+                        connection.setReadTimeout(3000);
+
+                        StreamUtils.copy(connection.getInputStream(), new NullOutputStream());
+                    } catch (final Throwable t) {
+                        t.printStackTrace();
+                        Assert.fail(t.toString());
+                    }
+                }
+            });
+            httpThread.start();
+
+            while ( runner.getFlowFilesForRelationship(HandleHttpRequest.REL_SUCCESS).isEmpty() ) {
+                // process the request.
+                runner.run(1, false, false);
+            }
+
+            runner.assertAllFlowFilesTransferred(HandleHttpRequest.REL_SUCCESS, 1);
+            assertEquals(1, contextMap.size());
+
+            final MockFlowFile mff = runner.getFlowFilesForRelationship(HandleHttpRequest.REL_SUCCESS).get(0);
+            mff.assertAttributeEquals("http.query.param.query", "true");
+            mff.assertAttributeEquals("http.query.param.value1", "value1");
+            mff.assertAttributeEquals("http.query.param.value2", "");
+            mff.assertAttributeEquals("http.query.param.value3", "");
+            mff.assertAttributeEquals("http.query.param.value4", "apple=orange");
+            mff.assertAttributeEquals("http.headers.header1", "value1");
+            mff.assertAttributeEquals("http.headers.header3", "apple=orange");
+            mff.assertAttributeEquals("http.protocol", "HTTP/1.1");
+        } finally {
+            // shut down the server
+            runner.run(1, true);
+        }
+    }
+
     private static class MockHttpContextMap extends AbstractControllerService implements HttpContextMap {
 
         private boolean registerSuccessfully = true;