diff --git a/nifi-assembly/NOTICE b/nifi-assembly/NOTICE index b6b305d766..fc94815e66 100644 --- a/nifi-assembly/NOTICE +++ b/nifi-assembly/NOTICE @@ -591,7 +591,7 @@ The following binary components are provided under the Apache Software License v (ASLv2) Jetty The following NOTICE information applies: Jetty Web Container - Copyright 1995-2017 Mort Bay Consulting Pty Ltd. + Copyright 1995-2019 Mort Bay Consulting Pty Ltd. (ASLv2) Apache Tomcat The following NOTICE information applies: diff --git a/nifi-nar-bundles/nifi-flume-bundle/nifi-flume-nar/src/main/resources/META-INF/NOTICE b/nifi-nar-bundles/nifi-flume-bundle/nifi-flume-nar/src/main/resources/META-INF/NOTICE index 621ea61e20..1c2149832c 100644 --- a/nifi-nar-bundles/nifi-flume-bundle/nifi-flume-nar/src/main/resources/META-INF/NOTICE +++ b/nifi-nar-bundles/nifi-flume-bundle/nifi-flume-nar/src/main/resources/META-INF/NOTICE @@ -173,7 +173,7 @@ The following binary components are provided under the Apache Software License v (ASLv2) Jetty The following NOTICE information applies: Jetty Web Container - Copyright 1995-2017 Mort Bay Consulting Pty Ltd. + Copyright 1995-2019 Mort Bay Consulting Pty Ltd. (ASLv2) Apache Velocity The following NOTICE information applies: diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/JettyServer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/JettyServer.java index 0862dacfd6..4b6359bf21 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/JettyServer.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/JettyServer.java @@ -868,6 +868,11 @@ public class JettyServer implements NiFiServer, ExtensionUiLoader { } protected static void configureSslContextFactory(SslContextFactory contextFactory, NiFiProperties props) { + // Need to set SslContextFactory's endpointIdentificationAlgorithm to null; this is a server, + // not a client. Server does not need to perform hostname verification on the client. + // Previous to Jetty 9.4.15.v20190215, this defaulted to null, and now defaults to "HTTPS". + contextFactory.setEndpointIdentificationAlgorithm(null); + // require client auth when not supporting login, Kerberos service, or anonymous access if (props.isClientAuthRequiredForRestApi()) { contextFactory.setNeedClientAuth(true); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestServer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestServer.java index 832c7df454..1a8a997ce1 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestServer.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestServer.java @@ -78,6 +78,11 @@ public class NiFiTestServer { private void createSecureConnector() { org.eclipse.jetty.util.ssl.SslContextFactory contextFactory = new org.eclipse.jetty.util.ssl.SslContextFactory(); + // Need to set SslContextFactory's endpointIdentificationAlgorithm to null; this is a server, + // not a client. Server does not need to perform hostname verification on the client. + // Previous to Jetty 9.4.15.v20190215, this defaulted to null, and now defaults to "HTTPS". + contextFactory.setEndpointIdentificationAlgorithm(null); + // require client auth when not supporting login or anonymous access if (StringUtils.isBlank(properties.getProperty(NiFiProperties.SECURITY_USER_LOGIN_IDENTITY_PROVIDER))) { contextFactory.setNeedClientAuth(true); diff --git a/nifi-nar-bundles/nifi-hive-bundle/nifi-hive-nar/src/main/resources/META-INF/NOTICE b/nifi-nar-bundles/nifi-hive-bundle/nifi-hive-nar/src/main/resources/META-INF/NOTICE index ae22e3f79d..cec48b3254 100644 --- a/nifi-nar-bundles/nifi-hive-bundle/nifi-hive-nar/src/main/resources/META-INF/NOTICE +++ b/nifi-nar-bundles/nifi-hive-bundle/nifi-hive-nar/src/main/resources/META-INF/NOTICE @@ -231,7 +231,7 @@ The following binary components are provided under the Apache Software License v (ASLv2) Jetty The following NOTICE information applies: Jetty Web Container - Copyright 1995-2017 Mort Bay Consulting Pty Ltd. + Copyright 1995-2019 Mort Bay Consulting Pty Ltd. (ASLv2) Apache log4j The following NOTICE information applies: diff --git a/nifi-nar-bundles/nifi-hive-bundle/nifi-hive3-nar/src/main/resources/META-INF/NOTICE b/nifi-nar-bundles/nifi-hive-bundle/nifi-hive3-nar/src/main/resources/META-INF/NOTICE index 04fa0a0ebf..0b4ed2bb5d 100644 --- a/nifi-nar-bundles/nifi-hive-bundle/nifi-hive3-nar/src/main/resources/META-INF/NOTICE +++ b/nifi-nar-bundles/nifi-hive-bundle/nifi-hive3-nar/src/main/resources/META-INF/NOTICE @@ -237,7 +237,7 @@ The following binary components are provided under the Apache Software License v (ASLv2) Jetty The following NOTICE information applies: Jetty Web Container - Copyright 1995-2017 Mort Bay Consulting Pty Ltd. + Copyright 1995-2019 Mort Bay Consulting Pty Ltd. (ASLv2) Apache log4j The following NOTICE information applies: diff --git a/nifi-nar-bundles/nifi-hive-bundle/nifi-hive_1_1-nar/src/main/resources/META-INF/NOTICE b/nifi-nar-bundles/nifi-hive-bundle/nifi-hive_1_1-nar/src/main/resources/META-INF/NOTICE index 9b7cc566ef..4862760790 100644 --- a/nifi-nar-bundles/nifi-hive-bundle/nifi-hive_1_1-nar/src/main/resources/META-INF/NOTICE +++ b/nifi-nar-bundles/nifi-hive-bundle/nifi-hive_1_1-nar/src/main/resources/META-INF/NOTICE @@ -171,7 +171,7 @@ The following binary components are provided under the Apache Software License v (ASLv2) Jetty The following NOTICE information applies: Jetty Web Container - Copyright 1995-2017 Mort Bay Consulting Pty Ltd. + Copyright 1995-2019 Mort Bay Consulting Pty Ltd. (ASLv2) Apache log4j The following NOTICE information applies: diff --git a/nifi-nar-bundles/nifi-jetty-bundle/src/main/resources/META-INF/NOTICE b/nifi-nar-bundles/nifi-jetty-bundle/src/main/resources/META-INF/NOTICE index b060dcf768..0f111c6dc8 100644 --- a/nifi-nar-bundles/nifi-jetty-bundle/src/main/resources/META-INF/NOTICE +++ b/nifi-nar-bundles/nifi-jetty-bundle/src/main/resources/META-INF/NOTICE @@ -13,7 +13,7 @@ The following binary components are provided under the Apache Software License v (ASLv2) Jetty The following NOTICE information applies: Jetty Web Container - Copyright 1995-2017 Mort Bay Consulting Pty Ltd. + Copyright 1995-2019 Mort Bay Consulting Pty Ltd. ************************ Common Development and Distribution License 1.1 diff --git a/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-nar/src/main/resources/META-INF/NOTICE b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-nar/src/main/resources/META-INF/NOTICE index 2cac6601a9..2108cfa62a 100644 --- a/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-nar/src/main/resources/META-INF/NOTICE +++ b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-nar/src/main/resources/META-INF/NOTICE @@ -275,7 +275,7 @@ Apache Software License v2 (ASLv2) Jetty The following NOTICE information applies: Jetty Web Container - Copyright 1995-2017 Mort Bay Consulting Pty Ltd. + Copyright 1995-2019 Mort Bay Consulting Pty Ltd. (ASLv2) Apache Kafka The following NOTICE information applies: 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 fdd4d3d559..897a431e21 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 @@ -506,6 +506,11 @@ public class HandleHttpRequest extends AbstractProcessor { sslFactory.setProtocol(sslService.getSslAlgorithm()); + // Need to set SslContextFactory's endpointIdentificationAlgorithm to null; this is a server, + // not a client. Server does not need to perform hostname verification on the client. + // Previous to Jetty 9.4.15.v20190215, this defaulted to null. + sslFactory.setEndpointIdentificationAlgorithm(null); + if (sslService.isKeyStoreConfigured()) { sslFactory.setKeyStorePath(sslService.getKeyStoreFile()); sslFactory.setKeyStorePassword(sslService.getKeyStorePassword()); diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListenHTTP.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListenHTTP.java index 5ea9f3afee..e799648450 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListenHTTP.java +++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListenHTTP.java @@ -246,6 +246,11 @@ public class ListenHTTP extends AbstractSessionFactoryProcessor { final SslContextFactory contextFactory = new SslContextFactory(); contextFactory.setNeedClientAuth(needClientAuth); + // Need to set SslContextFactory's endpointIdentificationAlgorithm to null; this is a server, + // not a client. Server does not need to perform hostname verification on the client. + // Previous to Jetty 9.4.15.v20190215, this defaulted to null, and now defaults to "HTTPS". + contextFactory.setEndpointIdentificationAlgorithm(null); + if (needClientAuth) { contextFactory.setTrustStorePath(sslContextService.getTrustStoreFile()); contextFactory.setTrustStoreType(sslContextService.getTrustStoreType()); diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/ITestHandleHttpRequest.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/ITestHandleHttpRequest.java index 1645e55c41..f65c0b958e 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/ITestHandleHttpRequest.java +++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/ITestHandleHttpRequest.java @@ -30,6 +30,7 @@ import org.apache.nifi.controller.AbstractControllerService; import org.apache.nifi.http.HttpContextMap; import org.apache.nifi.processors.standard.util.HTTPUtils; import org.apache.nifi.reporting.InitializationException; +import org.apache.nifi.security.util.SslContextFactory; import org.apache.nifi.ssl.SSLContextService; import org.apache.nifi.ssl.StandardRestrictedSSLContextService; import org.apache.nifi.ssl.StandardSSLContextService; @@ -72,7 +73,7 @@ public class ITestHandleHttpRequest { return props; } - private static Map getKeystoreProperties() { + private static Map getServerKeystoreProperties() { final Map properties = new HashMap<>(); properties.put(StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/keystore.jks"); properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "passwordpassword"); @@ -80,7 +81,15 @@ public class ITestHandleHttpRequest { return properties; } - private static SSLContext useSSLContextService(final TestRunner controller, final Map sslProperties) { + private static Map getClientKeystoreProperties() { + final Map properties = new HashMap<>(); + properties.put(StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/client-keystore.p12"); + properties.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "passwordpassword"); + properties.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), "PKCS12"); + return properties; + } + + private static SSLContext useSSLContextService(final TestRunner controller, final Map sslProperties, SSLContextService.ClientAuth clientAuth) { final SSLContextService service = new StandardRestrictedSSLContextService(); try { controller.addControllerService("ssl-service", service, sslProperties); @@ -91,7 +100,7 @@ public class ITestHandleHttpRequest { } controller.setProperty(HandleHttpRequest.SSL_CONTEXT, "ssl-service"); - return service.createSSLContext(SSLContextService.ClientAuth.WANT); + return service.createSSLContext(clientAuth); } @Test(timeout=30000) @@ -427,6 +436,15 @@ public class ITestHandleHttpRequest { @Test public void testSecure() throws InitializationException { + secureTest(false); + } + + @Test + public void testSecureTwoWaySsl() throws InitializationException { + secureTest(true); + } + + private void secureTest(boolean twoWaySsl) throws InitializationException { final TestRunner runner = TestRunners.newTestRunner(HandleHttpRequest.class); runner.setProperty(HandleHttpRequest.PORT, "0"); @@ -435,10 +453,10 @@ public class ITestHandleHttpRequest { runner.enableControllerService(contextMap); runner.setProperty(HandleHttpRequest.HTTP_CONTEXT_MAP, "http-context-map"); - final Map sslProperties = getKeystoreProperties(); + final Map sslProperties = getServerKeystoreProperties(); sslProperties.putAll(getTruststoreProperties()); sslProperties.put(StandardSSLContextService.SSL_ALGORITHM.getName(), "TLSv1.2"); - final SSLContext sslContext = useSSLContextService(runner, sslProperties); + useSSLContextService(runner, sslProperties, twoWaySsl ? SSLContextService.ClientAuth.WANT : SSLContextService.ClientAuth.NONE); // trigger processor to stop but not shutdown. runner.run(1, false); @@ -451,7 +469,27 @@ public class ITestHandleHttpRequest { 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()); + if (twoWaySsl) { + // use a client certificate, do not reuse the server's keystore + SSLContext clientSslContext = SslContextFactory.createSslContext( + getClientKeystoreProperties().get(StandardSSLContextService.KEYSTORE.getName()), + getClientKeystoreProperties().get(StandardSSLContextService.KEYSTORE_PASSWORD.getName()).toCharArray(), + "JKS", + getTruststoreProperties().get(StandardSSLContextService.TRUSTSTORE.getName()), + getTruststoreProperties().get(StandardSSLContextService.TRUSTSTORE_PASSWORD.getName()).toCharArray(), + "JKS", + null, + "TLSv1.2"); + connection.setSSLSocketFactory(clientSslContext.getSocketFactory()); + } else { + // with one-way SSL, the client still needs a truststore + SSLContext clientSslContext = SslContextFactory.createTrustSslContext( + getTruststoreProperties().get(StandardSSLContextService.TRUSTSTORE.getName()), + getTruststoreProperties().get(StandardSSLContextService.TRUSTSTORE_PASSWORD.getName()).toCharArray(), + "JKS", + "TLSv1.2"); + connection.setSSLSocketFactory(clientSslContext.getSocketFactory()); + } connection.setDoOutput(false); connection.setRequestMethod("GET"); connection.setRequestProperty("header1", "value1"); diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestInvokeHttpSSL.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestInvokeHttpSSL.java index 5ed3a16c14..5ef25762f4 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestInvokeHttpSSL.java +++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestInvokeHttpSSL.java @@ -49,7 +49,7 @@ public class TestInvokeHttpSSL extends TestInvokeHttpCommon { // create the SSL properties, which basically store keystore / trustore information // this is used by the StandardSSLContextService and the Jetty Server serverSslProperties = createServerSslProperties(false); - sslProperties = createSslProperties(false); + sslProperties = createClientSslProperties(false); // create a Jetty server on a random port server = createServer(); @@ -103,24 +103,24 @@ public class TestInvokeHttpSSL extends TestInvokeHttpCommon { map.put(TestServer.NEED_CLIENT_AUTH, Boolean.toString(false)); } // keystore is always required for the server SSL properties - map.putAll(getKeystoreProperties()); + map.putAll(getServerKeystoreProperties()); return map; } - static Map createSslProperties(boolean clientAuth) { + static Map createClientSslProperties(boolean clientAuth) { final Map map = new HashMap<>(); // if requesting client auth then we must provide a keystore if (clientAuth) { - map.putAll(getKeystoreProperties()); + map.putAll(getClientKeystoreProperties()); } // truststore is always required for the client SSL properties map.putAll(getTruststoreProperties()); return map; } - private static Map getKeystoreProperties() { + private static Map getServerKeystoreProperties() { final Map map = new HashMap<>(); map.put(StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/keystore.jks"); map.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "passwordpassword"); @@ -128,6 +128,14 @@ public class TestInvokeHttpSSL extends TestInvokeHttpCommon { return map; } + private static Map getClientKeystoreProperties() { + final Map map = new HashMap<>(); + map.put(StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/client-keystore.p12"); + map.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "passwordpassword"); + map.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), "PKCS12"); + return map; + } + private static Map getTruststoreProperties() { final Map map = new HashMap<>(); map.put(StandardSSLContextService.TRUSTSTORE.getName(), "src/test/resources/truststore.jks"); diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestInvokeHttpTwoWaySSL.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestInvokeHttpTwoWaySSL.java index cfd96e0500..3ca4cd35d7 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestInvokeHttpTwoWaySSL.java +++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestInvokeHttpTwoWaySSL.java @@ -36,7 +36,7 @@ public class TestInvokeHttpTwoWaySSL extends TestInvokeHttpSSL { // create the SSL properties, which basically store keystore / trustore information // this is used by the StandardSSLContextService and the Jetty Server serverSslProperties = createServerSslProperties(true); - sslProperties = createSslProperties(true); + sslProperties = createClientSslProperties(true); // create a Jetty server on a random port server = createServer(); diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestListenHTTP.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestListenHTTP.java index f8e9015238..b45a0c046a 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestListenHTTP.java +++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestListenHTTP.java @@ -20,6 +20,7 @@ import org.apache.nifi.processor.ProcessContext; import org.apache.nifi.processor.ProcessSessionFactory; import org.apache.nifi.remote.io.socket.NetworkUtils; import org.apache.nifi.reporting.InitializationException; +import org.apache.nifi.security.util.SslContextFactory; import org.apache.nifi.ssl.StandardRestrictedSSLContextService; import org.apache.nifi.ssl.SSLContextService; import org.apache.nifi.ssl.StandardSSLContextService; @@ -98,7 +99,7 @@ public class TestListenHTTP { runner.setProperty(ListenHTTP.PORT, Integer.toString(availablePort)); runner.setProperty(ListenHTTP.BASE_PATH, HTTP_BASE_PATH); - testPOSTRequestsReceived(HttpServletResponse.SC_OK); + testPOSTRequestsReceived(HttpServletResponse.SC_OK, false, false); } @Test @@ -107,7 +108,7 @@ public class TestListenHTTP { runner.setProperty(ListenHTTP.BASE_PATH, HTTP_BASE_PATH); runner.setProperty(ListenHTTP.RETURN_CODE, Integer.toString(HttpServletResponse.SC_NO_CONTENT)); - testPOSTRequestsReceived(HttpServletResponse.SC_NO_CONTENT); + testPOSTRequestsReceived(HttpServletResponse.SC_NO_CONTENT, false, false); } @Test @@ -116,7 +117,7 @@ public class TestListenHTTP { runner.setProperty(ListenHTTP.BASE_PATH, HTTP_SERVER_BASEPATH_EL); runner.assertValid(); - testPOSTRequestsReceived(HttpServletResponse.SC_OK); + testPOSTRequestsReceived(HttpServletResponse.SC_OK, false, false); } @Test @@ -126,12 +127,12 @@ public class TestListenHTTP { runner.setProperty(ListenHTTP.RETURN_CODE, Integer.toString(HttpServletResponse.SC_NO_CONTENT)); runner.assertValid(); - testPOSTRequestsReceived(HttpServletResponse.SC_NO_CONTENT); + testPOSTRequestsReceived(HttpServletResponse.SC_NO_CONTENT, false, false); } @Test public void testSecurePOSTRequestsReceivedWithoutEL() throws Exception { - SSLContextService sslContextService = configureProcessorSslContextService(); + SSLContextService sslContextService = configureProcessorSslContextService(false); runner.setProperty(sslContextService, StandardRestrictedSSLContextService.RESTRICTED_SSL_ALGORITHM, "TLSv1.2"); runner.enableControllerService(sslContextService); @@ -139,12 +140,12 @@ public class TestListenHTTP { runner.setProperty(ListenHTTP.BASE_PATH, HTTP_BASE_PATH); runner.assertValid(); - testPOSTRequestsReceived(HttpServletResponse.SC_OK); + testPOSTRequestsReceived(HttpServletResponse.SC_OK, true, false); } @Test public void testSecurePOSTRequestsReturnCodeReceivedWithoutEL() throws Exception { - SSLContextService sslContextService = configureProcessorSslContextService(); + SSLContextService sslContextService = configureProcessorSslContextService(false); runner.setProperty(sslContextService, StandardRestrictedSSLContextService.RESTRICTED_SSL_ALGORITHM, "TLSv1.2"); runner.enableControllerService(sslContextService); @@ -153,12 +154,12 @@ public class TestListenHTTP { runner.setProperty(ListenHTTP.RETURN_CODE, Integer.toString(HttpServletResponse.SC_NO_CONTENT)); runner.assertValid(); - testPOSTRequestsReceived(HttpServletResponse.SC_NO_CONTENT); + testPOSTRequestsReceived(HttpServletResponse.SC_NO_CONTENT, true, false); } @Test public void testSecurePOSTRequestsReceivedWithEL() throws Exception { - SSLContextService sslContextService = configureProcessorSslContextService(); + SSLContextService sslContextService = configureProcessorSslContextService(false); runner.setProperty(sslContextService, StandardRestrictedSSLContextService.RESTRICTED_SSL_ALGORITHM, "TLSv1.2"); runner.enableControllerService(sslContextService); @@ -166,12 +167,12 @@ public class TestListenHTTP { runner.setProperty(ListenHTTP.BASE_PATH, HTTP_SERVER_BASEPATH_EL); runner.assertValid(); - testPOSTRequestsReceived(HttpServletResponse.SC_OK); + testPOSTRequestsReceived(HttpServletResponse.SC_OK, true, false); } @Test public void testSecurePOSTRequestsReturnCodeReceivedWithEL() throws Exception { - SSLContextService sslContextService = configureProcessorSslContextService(); + SSLContextService sslContextService = configureProcessorSslContextService(false); runner.setProperty(sslContextService, StandardRestrictedSSLContextService.RESTRICTED_SSL_ALGORITHM, "TLSv1.2"); runner.enableControllerService(sslContextService); @@ -180,7 +181,61 @@ public class TestListenHTTP { runner.setProperty(ListenHTTP.RETURN_CODE, Integer.toString(HttpServletResponse.SC_NO_CONTENT)); runner.assertValid(); - testPOSTRequestsReceived(HttpServletResponse.SC_NO_CONTENT); + testPOSTRequestsReceived(HttpServletResponse.SC_NO_CONTENT, true, false); + } + + @Test + public void testSecureTwoWaySslPOSTRequestsReceivedWithoutEL() throws Exception { + SSLContextService sslContextService = configureProcessorSslContextService(true); + runner.setProperty(sslContextService, StandardRestrictedSSLContextService.RESTRICTED_SSL_ALGORITHM, "TLSv1.2"); + runner.enableControllerService(sslContextService); + + runner.setProperty(ListenHTTP.PORT, Integer.toString(availablePort)); + runner.setProperty(ListenHTTP.BASE_PATH, HTTP_BASE_PATH); + runner.assertValid(); + + testPOSTRequestsReceived(HttpServletResponse.SC_OK, true, true); + } + + @Test + public void testSecureTwoWaySslPOSTRequestsReturnCodeReceivedWithoutEL() throws Exception { + SSLContextService sslContextService = configureProcessorSslContextService(true); + runner.setProperty(sslContextService, StandardRestrictedSSLContextService.RESTRICTED_SSL_ALGORITHM, "TLSv1.2"); + runner.enableControllerService(sslContextService); + + runner.setProperty(ListenHTTP.PORT, Integer.toString(availablePort)); + runner.setProperty(ListenHTTP.BASE_PATH, HTTP_BASE_PATH); + runner.setProperty(ListenHTTP.RETURN_CODE, Integer.toString(HttpServletResponse.SC_NO_CONTENT)); + runner.assertValid(); + + testPOSTRequestsReceived(HttpServletResponse.SC_NO_CONTENT, true, true); + } + + @Test + public void testSecureTwoWaySslPOSTRequestsReceivedWithEL() throws Exception { + SSLContextService sslContextService = configureProcessorSslContextService(true); + runner.setProperty(sslContextService, StandardRestrictedSSLContextService.RESTRICTED_SSL_ALGORITHM, "TLSv1.2"); + runner.enableControllerService(sslContextService); + + runner.setProperty(ListenHTTP.PORT, HTTP_SERVER_PORT_EL); + runner.setProperty(ListenHTTP.BASE_PATH, HTTP_SERVER_BASEPATH_EL); + runner.assertValid(); + + testPOSTRequestsReceived(HttpServletResponse.SC_OK, true, true); + } + + @Test + public void testSecureTwoWaySslPOSTRequestsReturnCodeReceivedWithEL() throws Exception { + SSLContextService sslContextService = configureProcessorSslContextService(true); + runner.setProperty(sslContextService, StandardRestrictedSSLContextService.RESTRICTED_SSL_ALGORITHM, "TLSv1.2"); + runner.enableControllerService(sslContextService); + + runner.setProperty(ListenHTTP.PORT, Integer.toString(availablePort)); + runner.setProperty(ListenHTTP.BASE_PATH, HTTP_BASE_PATH); + runner.setProperty(ListenHTTP.RETURN_CODE, Integer.toString(HttpServletResponse.SC_NO_CONTENT)); + runner.assertValid(); + + testPOSTRequestsReceived(HttpServletResponse.SC_NO_CONTENT, true, true); } @Test @@ -194,19 +249,35 @@ public class TestListenHTTP { runner.assertNotValid(); } - private int executePOST(String message) throws Exception { - final SSLContextService sslContextService = runner.getControllerService(SSL_CONTEXT_SERVICE_IDENTIFIER, SSLContextService.class); - final boolean secure = (sslContextService != null); + private int executePOST(String message, boolean secure, boolean twoWaySsl) throws Exception { String endpointUrl = buildUrl(secure); final URL url = new URL(endpointUrl); HttpURLConnection connection; if (secure) { final HttpsURLConnection sslCon = (HttpsURLConnection) url.openConnection(); - final SSLContext sslContext = sslContextService.createSSLContext(SSLContextService.ClientAuth.WANT); - sslCon.setSSLSocketFactory(sslContext.getSocketFactory()); + if (twoWaySsl) { + // use a client certificate, do not reuse the server's keystore + SSLContext clientSslContext = SslContextFactory.createSslContext( + "src/test/resources/client-keystore.p12", + "passwordpassword".toCharArray(), + "PKCS12", + "src/test/resources/truststore.jks", + "passwordpassword".toCharArray(), + "JKS", + null, + "TLSv1.2"); + sslCon.setSSLSocketFactory(clientSslContext.getSocketFactory()); + } else { + // with one-way SSL, the client still needs a truststore + SSLContext clientSslContext = SslContextFactory.createTrustSslContext( + "src/test/resources/truststore.jks", + "passwordpassword".toCharArray(), + "JKS", + "TLSv1.2"); + sslCon.setSSLSocketFactory(clientSslContext.getSocketFactory()); + } connection = sslCon; - } else { connection = (HttpURLConnection) url.openConnection(); } @@ -227,14 +298,14 @@ public class TestListenHTTP { return String.format("%s://localhost:%s/%s", secure ? "https" : "http" , availablePort, HTTP_BASE_PATH); } - private void testPOSTRequestsReceived(int returnCode) throws Exception { + private void testPOSTRequestsReceived(int returnCode, boolean secure, boolean twoWaySsl) throws Exception { final List messages = new ArrayList<>(); messages.add("payload 1"); messages.add(""); messages.add(null); messages.add("payload 2"); - startWebServerAndSendMessages(messages, returnCode); + startWebServerAndSendMessages(messages, returnCode, secure, twoWaySsl); List mockFlowFiles = runner.getFlowFilesForRelationship(RELATIONSHIP_SUCCESS); @@ -265,13 +336,13 @@ public class TestListenHTTP { runner.assertTransferCount(ListenHTTP.RELATIONSHIP_SUCCESS, numberOfExpectedFlowFiles); } - private void startWebServerAndSendMessages(final List messages, int returnCode) + private void startWebServerAndSendMessages(final List messages, int returnCode, boolean secure, boolean twoWaySsl) throws Exception { Runnable sendMessagestoWebServer = () -> { try { for (final String message : messages) { - if (executePOST(message) != returnCode) { + if (executePOST(message, secure, twoWaySsl) != returnCode) { fail("HTTP POST failed."); } } @@ -284,12 +355,14 @@ public class TestListenHTTP { startWebServerAndSendRequests(sendMessagestoWebServer, messages.size(), returnCode); } - private SSLContextService configureProcessorSslContextService() throws InitializationException { + private SSLContextService configureProcessorSslContextService(boolean twoWaySsl) throws InitializationException { final SSLContextService sslContextService = new StandardRestrictedSSLContextService(); runner.addControllerService(SSL_CONTEXT_SERVICE_IDENTIFIER, sslContextService); - runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE, "src/test/resources/truststore.jks"); - runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE_PASSWORD, "passwordpassword"); - runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE_TYPE, "JKS"); + if (twoWaySsl) { + runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE, "src/test/resources/truststore.jks"); + runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE_PASSWORD, "passwordpassword"); + runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE_TYPE, "JKS"); + } runner.setProperty(sslContextService, StandardSSLContextService.KEYSTORE, "src/test/resources/keystore.jks"); runner.setProperty(sslContextService, StandardSSLContextService.KEYSTORE_PASSWORD, "passwordpassword"); runner.setProperty(sslContextService, StandardSSLContextService.KEYSTORE_TYPE, "JKS"); diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/client-keystore.p12 b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/client-keystore.p12 new file mode 100644 index 0000000000..5cc6ed22e9 Binary files /dev/null and b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/client-keystore.p12 differ diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/keystore.jks b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/keystore.jks index 5f3cbe3a78..34a197f365 100644 Binary files a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/keystore.jks and b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/keystore.jks differ diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/truststore.jks b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/truststore.jks index d26ec92e44..4bc1b2050b 100644 Binary files a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/truststore.jks and b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/truststore.jks differ diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-web-test-utils/src/main/java/org/apache/nifi/web/util/TestServer.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-web-test-utils/src/main/java/org/apache/nifi/web/util/TestServer.java index 5fc74a5cfe..23e128bcd2 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-web-test-utils/src/main/java/org/apache/nifi/web/util/TestServer.java +++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-web-test-utils/src/main/java/org/apache/nifi/web/util/TestServer.java @@ -97,6 +97,11 @@ public class TestServer { ssl.setNeedClientAuth(Boolean.parseBoolean(clientAuth)); } + // Need to set SslContextFactory's endpointIdentificationAlgorithm to null; this is a server, + // not a client. Server does not need to perform hostname verification on the client. + // Previous to Jetty 9.4.15.v20190215, this defaulted to null, and now defaults to "HTTPS". + ssl.setEndpointIdentificationAlgorithm(null); + // build the connector final ServerConnector https = new ServerConnector(jetty, ssl); diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-hbase_2-client-service-bundle/nifi-hbase_2-client-service-nar/src/main/resources/META-INF/NOTICE b/nifi-nar-bundles/nifi-standard-services/nifi-hbase_2-client-service-bundle/nifi-hbase_2-client-service-nar/src/main/resources/META-INF/NOTICE index a44bf40d18..dd7ee7708f 100644 --- a/nifi-nar-bundles/nifi-standard-services/nifi-hbase_2-client-service-bundle/nifi-hbase_2-client-service-nar/src/main/resources/META-INF/NOTICE +++ b/nifi-nar-bundles/nifi-standard-services/nifi-hbase_2-client-service-bundle/nifi-hbase_2-client-service-nar/src/main/resources/META-INF/NOTICE @@ -312,5 +312,5 @@ Apache Software License v2 (ASLv2) Jetty The following NOTICE information applies: Jetty Web Container - Copyright 1995-2017 Mort Bay Consulting Pty Ltd. + Copyright 1995-2019 Mort Bay Consulting Pty Ltd. diff --git a/nifi-nar-bundles/nifi-websocket-bundle/nifi-websocket-services-jetty-nar/src/main/resources/META-INF/NOTICE b/nifi-nar-bundles/nifi-websocket-bundle/nifi-websocket-services-jetty-nar/src/main/resources/META-INF/NOTICE index 89b319d72d..47977ee04d 100644 --- a/nifi-nar-bundles/nifi-websocket-bundle/nifi-websocket-services-jetty-nar/src/main/resources/META-INF/NOTICE +++ b/nifi-nar-bundles/nifi-websocket-bundle/nifi-websocket-services-jetty-nar/src/main/resources/META-INF/NOTICE @@ -26,7 +26,7 @@ The following binary components are provided under the Apache Software License v (ASLv2) Jetty The following NOTICE information applies: Jetty Web Container - Copyright 1995-2017 Mort Bay Consulting Pty Ltd. + Copyright 1995-2019 Mort Bay Consulting Pty Ltd. (ASLv2) Jackson JSON processor The following NOTICE information applies: diff --git a/nifi-nar-bundles/nifi-websocket-bundle/nifi-websocket-services-jetty/src/main/java/org/apache/nifi/websocket/jetty/AbstractJettyWebSocketService.java b/nifi-nar-bundles/nifi-websocket-bundle/nifi-websocket-services-jetty/src/main/java/org/apache/nifi/websocket/jetty/AbstractJettyWebSocketService.java index 39d67d5df0..546a853759 100644 --- a/nifi-nar-bundles/nifi-websocket-bundle/nifi-websocket-services-jetty/src/main/java/org/apache/nifi/websocket/jetty/AbstractJettyWebSocketService.java +++ b/nifi-nar-bundles/nifi-websocket-bundle/nifi-websocket-services-jetty/src/main/java/org/apache/nifi/websocket/jetty/AbstractJettyWebSocketService.java @@ -66,12 +66,18 @@ public abstract class AbstractJettyWebSocketService extends AbstractWebSocketSer } - protected SslContextFactory createSslFactory(final SSLContextService sslService, final boolean needClientAuth, final boolean wantClientAuth) { + protected SslContextFactory createSslFactory(final SSLContextService sslService, final boolean needClientAuth, final boolean wantClientAuth, final String endpointIdentificationAlgorithm) { final SslContextFactory sslFactory = new SslContextFactory(); sslFactory.setNeedClientAuth(needClientAuth); sslFactory.setWantClientAuth(wantClientAuth); + // Need to set SslContextFactory's endpointIdentificationAlgorithm. + // For clients, hostname verification should be enabled. + // For servers, hostname verification should be disabled. + // Previous to Jetty 9.4.15.v20190215, this defaulted to null, and now defaults to "HTTPS". + sslFactory.setEndpointIdentificationAlgorithm(endpointIdentificationAlgorithm); + if (sslService.isKeyStoreConfigured()) { sslFactory.setKeyStorePath(sslService.getKeyStoreFile()); sslFactory.setKeyStorePassword(sslService.getKeyStorePassword()); diff --git a/nifi-nar-bundles/nifi-websocket-bundle/nifi-websocket-services-jetty/src/main/java/org/apache/nifi/websocket/jetty/JettyWebSocketClient.java b/nifi-nar-bundles/nifi-websocket-bundle/nifi-websocket-services-jetty/src/main/java/org/apache/nifi/websocket/jetty/JettyWebSocketClient.java index f866743b42..e412006322 100644 --- a/nifi-nar-bundles/nifi-websocket-bundle/nifi-websocket-services-jetty/src/main/java/org/apache/nifi/websocket/jetty/JettyWebSocketClient.java +++ b/nifi-nar-bundles/nifi-websocket-bundle/nifi-websocket-services-jetty/src/main/java/org/apache/nifi/websocket/jetty/JettyWebSocketClient.java @@ -171,7 +171,7 @@ public class JettyWebSocketClient extends AbstractJettyWebSocketService implemen final SSLContextService sslService = context.getProperty(SSL_CONTEXT).asControllerService(SSLContextService.class); SslContextFactory sslContextFactory = null; if (sslService != null) { - sslContextFactory = createSslFactory(sslService, false, false); + sslContextFactory = createSslFactory(sslService, false, false, null); } client = new WebSocketClient(sslContextFactory); diff --git a/nifi-nar-bundles/nifi-websocket-bundle/nifi-websocket-services-jetty/src/main/java/org/apache/nifi/websocket/jetty/JettyWebSocketServer.java b/nifi-nar-bundles/nifi-websocket-bundle/nifi-websocket-services-jetty/src/main/java/org/apache/nifi/websocket/jetty/JettyWebSocketServer.java index eac43bbcd9..f5a49c5af2 100644 --- a/nifi-nar-bundles/nifi-websocket-bundle/nifi-websocket-services-jetty/src/main/java/org/apache/nifi/websocket/jetty/JettyWebSocketServer.java +++ b/nifi-nar-bundles/nifi-websocket-bundle/nifi-websocket-services-jetty/src/main/java/org/apache/nifi/websocket/jetty/JettyWebSocketServer.java @@ -356,7 +356,7 @@ public class JettyWebSocketServer extends AbstractJettyWebSocketService implemen want = false; } - final SslContextFactory sslFactory = (sslService == null) ? null : createSslFactory(sslService, need, want); + final SslContextFactory sslFactory = (sslService == null) ? null : createSslFactory(sslService, need, want, null); return sslFactory; } diff --git a/nifi-nar-bundles/nifi-websocket-bundle/nifi-websocket-services-jetty/src/test/java/org/apache/nifi/websocket/example/WebSocketServerExample.java b/nifi-nar-bundles/nifi-websocket-bundle/nifi-websocket-services-jetty/src/test/java/org/apache/nifi/websocket/example/WebSocketServerExample.java index e7a3ab6943..dad8520a39 100644 --- a/nifi-nar-bundles/nifi-websocket-bundle/nifi-websocket-services-jetty/src/test/java/org/apache/nifi/websocket/example/WebSocketServerExample.java +++ b/nifi-nar-bundles/nifi-websocket-bundle/nifi-websocket-services-jetty/src/test/java/org/apache/nifi/websocket/example/WebSocketServerExample.java @@ -157,6 +157,11 @@ public class WebSocketServerExample { sslContextFactory.setKeyStorePassword("passwordpassword"); sslContextFactory.setKeyStoreType("JKS"); + // Need to set SslContextFactory's endpointIdentificationAlgorithm to null; this is a server, + // not a client. Server does not need to perform hostname verification on the client. + // Previous to Jetty 9.4.15.v20190215, this defaulted to null, and now defaults to "HTTPS". + sslContextFactory.setEndpointIdentificationAlgorithm(null); + final HttpConfiguration https = new HttpConfiguration(); https.addCustomizer(new SecureRequestCustomizer()); sslConnector = new ServerConnector(server, diff --git a/nifi-toolkit/nifi-toolkit-assembly/NOTICE b/nifi-toolkit/nifi-toolkit-assembly/NOTICE index a1775a198b..1007829af2 100644 --- a/nifi-toolkit/nifi-toolkit-assembly/NOTICE +++ b/nifi-toolkit/nifi-toolkit-assembly/NOTICE @@ -94,7 +94,7 @@ The following binary components are provided under the Apache Software License v (ASLv2) Jetty The following NOTICE information applies: Jetty Web Container - Copyright 1995-2017 Mort Bay Consulting Pty Ltd. + Copyright 1995-2019 Mort Bay Consulting Pty Ltd. (ASLv2) Groovy (org.codehaus.groovy:groovy-all:jar:2.4.5 - http://www.groovy-lang.org) The following NOTICE information applies: diff --git a/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/service/server/TlsCertificateAuthorityService.java b/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/service/server/TlsCertificateAuthorityService.java index 18c4f65356..68c5c013a8 100644 --- a/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/service/server/TlsCertificateAuthorityService.java +++ b/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/service/server/TlsCertificateAuthorityService.java @@ -67,6 +67,11 @@ public class TlsCertificateAuthorityService { sslContextFactory.setKeyStore(keyStore); sslContextFactory.setKeyManagerPassword(keyPassword); + // Need to set SslContextFactory's endpointIdentificationAlgorithm to null; this is a server, + // not a client. Server does not need to perform hostname verification on the client. + // Previous to Jetty 9.4.15.v20190215, this defaulted to null, and now defaults to "HTTPS". + sslContextFactory.setEndpointIdentificationAlgorithm(null); + HttpConfiguration httpsConfig = new HttpConfiguration(); httpsConfig.addCustomizer(new SecureRequestCustomizer()); diff --git a/pom.xml b/pom.xml index 728a9dd32c..05e5973a38 100644 --- a/pom.xml +++ b/pom.xml @@ -94,7 +94,7 @@ 2014 1.7.26 1.0.0 - 9.4.11.v20180605 + 9.4.15.v20190215 2.9.8 0.3.0