NIFI-8171 This closes #4779. Upgraded Bouncy Castle libraries to 1.68 and centralized dependency version

NIFI-8171 Increased response and idle timeouts for HTTP unit tests
NIFI-8171 Increased TestServer idle timeout to 45 seconds for HTTP unit tests
NIFI-8171 Adjusted timeout and sleep on TestPutTCPCommon.testPruneSenders
NIFI-8171 Increased TestServer idle timeout to 60 seconds and removed 500ms Thread.sleep() in TestInvokeHttpSSL
NIFI-8171 Optimized OkHttpClientUtils to avoid reading trust store twice during initialization
NIFI-8171 Added static variable for server startup sleep
NIFI-8171 Increased TestInvokeHTTP Connect Timeout and TestListenHTTP Response Timeout to 30 seconds
NIFI-8171 Refactored unit tests for InvokeHTTP and ListenHTTP to optimize SSLContext creation
NIFI-8171 Updated TestListenHTTP for static creation of SSLContext
NIFI-8171 Added started check for ListenHTTP Server in TestListenHTTP
NIFI-8171 Refactored TestPutTCP classes to optimize SSLContext creation
NIFI-8171 Increased TestListenHTTP timeout for server start to 120 seconds and added exception when not connected
NIFI-8171 Increased Connect and Read Timeouts for InvokeHTTP SSL unit tests

Signed-off-by: Joe Witt <joewitt@apache.org>
This commit is contained in:
exceptionfactory 2021-01-25 07:42:06 -06:00 committed by Joe Witt
parent 2cdb0fb6a3
commit abb6ed3128
No known key found for this signature in database
GPG Key ID: 9093BF854F811A1A
21 changed files with 455 additions and 372 deletions

View File

@ -45,7 +45,6 @@
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.66</version>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>

View File

@ -60,12 +60,10 @@
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.66</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.66</version>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>

View File

@ -17,7 +17,9 @@
package org.apache.nifi.security.util;
import java.security.UnrecoverableKeyException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import okhttp3.OkHttpClient;
import org.apache.nifi.processor.exception.ProcessException;
@ -41,12 +43,19 @@ public class OkHttpClientUtils {
*/
public static boolean applyTlsToOkHttpClientBuilder(TlsConfiguration tlsConfiguration, OkHttpClient.Builder okHttpClient) {
try {
final SSLSocketFactory sslSocketFactory = SslContextFactory.createSSLSocketFactory(tlsConfiguration);
final X509TrustManager x509TrustManager = SslContextFactory.getX509TrustManager(tlsConfiguration);
if (sslSocketFactory != null && x509TrustManager != null) {
okHttpClient.sslSocketFactory(sslSocketFactory, x509TrustManager);
return true;
final X509TrustManager trustManager = SslContextFactory.getX509TrustManager(tlsConfiguration);
if (trustManager == null) {
return false;
}
final SSLContext sslContext = SslContextFactory.createSslContext(tlsConfiguration, new TrustManager[]{trustManager});
if (sslContext == null) {
return false;
}
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
okHttpClient.sslSocketFactory(sslSocketFactory, trustManager);
return true;
} catch (TlsException e) {
if (e.getCause() instanceof UnrecoverableKeyException) {
logger.error("Key password may be incorrect or not set. Check your keystore passwords." + e.getMessage());

View File

@ -135,7 +135,6 @@
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.66</version>
<scope>provided</scope>
</dependency>
</dependencies>

View File

@ -320,16 +320,6 @@
<artifactId>h2</artifactId>
<version>1.4.199</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.66</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.66</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>

View File

@ -61,11 +61,6 @@
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.66</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>

View File

@ -31,12 +31,7 @@ import java.net.Proxy.Type;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@ -55,7 +50,11 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
import okhttp3.Cache;
import okhttp3.ConnectionPool;
import okhttp3.Credentials;
@ -100,8 +99,9 @@ import org.apache.nifi.processors.standard.util.ProxyAuthenticator;
import org.apache.nifi.processors.standard.util.SoftLimitBoundedByteArrayOutputStream;
import org.apache.nifi.proxy.ProxyConfiguration;
import org.apache.nifi.proxy.ProxySpec;
import org.apache.nifi.security.util.OkHttpClientUtils;
import org.apache.nifi.security.util.SslContextFactory;
import org.apache.nifi.security.util.TlsConfiguration;
import org.apache.nifi.security.util.TlsException;
import org.apache.nifi.ssl.SSLContextService;
import org.apache.nifi.stream.io.StreamUtils;
import org.joda.time.format.DateTimeFormat;
@ -704,7 +704,7 @@ public class InvokeHTTP extends AbstractProcessor {
}
@OnScheduled
public void setUpClient(final ProcessContext context) throws IOException, UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
public void setUpClient(final ProcessContext context) throws TlsException {
okHttpClientAtomicReference.set(null);
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient().newBuilder();
@ -761,8 +761,11 @@ public class InvokeHTTP extends AbstractProcessor {
// Apply the TLS configuration if present
final SSLContextService sslService = context.getProperty(PROP_SSL_CONTEXT_SERVICE).asControllerService(SSLContextService.class);
if (sslService != null) {
final SSLContext sslContext = sslService.createContext();
final SSLSocketFactory socketFactory = sslContext.getSocketFactory();
final TlsConfiguration tlsConfiguration = sslService.createTlsConfiguration();
OkHttpClientUtils.applyTlsToOkHttpClientBuilder(tlsConfiguration, okHttpClientBuilder);
final X509TrustManager trustManager = SslContextFactory.getX509TrustManager(tlsConfiguration);
okHttpClientBuilder.sslSocketFactory(socketFactory, trustManager);
}
setAuthenticator(okHttpClientBuilder, context);

View File

@ -31,18 +31,13 @@ import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.SystemUtils;
import org.apache.nifi.processors.standard.util.TestInvokeHttpCommon;
import org.apache.nifi.ssl.StandardSSLContextService;
import org.apache.nifi.util.MockFlowFile;
import org.apache.nifi.util.TestRunners;
import org.apache.nifi.web.util.TestServer;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
@ -54,40 +49,12 @@ public class TestInvokeHTTP extends TestInvokeHttpCommon {
@BeforeClass
public static void beforeClass() throws Exception {
Assume.assumeTrue("Test only runs on *nix", !SystemUtils.IS_OS_WINDOWS);
// useful for verbose logging output
// don't commit this with this property enabled, or any 'mvn test' will be really verbose
// System.setProperty("org.slf4j.simpleLogger.log.nifi.processors.standard", "debug");
// create a Jetty server on a random port
server = createServer();
server.startServer();
// this is the base url with the random port
url = server.getUrl();
}
@AfterClass
public static void afterClass() throws Exception {
if(server != null) {
server.shutdownServer();
}
configureServer(null, null);
}
@Before
public void before() {
public void before() throws Exception {
runner = TestRunners.newTestRunner(InvokeHTTP.class);
server.clearHandlers();
}
@After
public void after() {
runner.shutdown();
}
private static TestServer createServer() {
return new TestServer();
}
@Test

View File

@ -17,20 +17,20 @@
package org.apache.nifi.processors.standard;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.SystemUtils;
import org.apache.nifi.processors.standard.util.TestInvokeHttpCommon;
import org.apache.nifi.ssl.StandardSSLContextService;
import org.apache.nifi.security.util.ClientAuth;
import org.apache.nifi.security.util.KeystoreType;
import org.apache.nifi.security.util.SslContextFactory;
import org.apache.nifi.security.util.StandardTlsConfiguration;
import org.apache.nifi.security.util.TlsConfiguration;
import org.apache.nifi.ssl.SSLContextService;
import org.apache.nifi.util.TestRunners;
import org.apache.nifi.web.util.TestServer;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assume;
import org.junit.Before;
import org.junit.BeforeClass;
import org.mockito.Mockito;
import javax.net.ssl.SSLContext;
/**
* Executes the same tests as TestInvokeHttp but with one-way SSL enabled. The Jetty server created for these tests
@ -38,115 +38,59 @@ import org.junit.BeforeClass;
*/
public class TestInvokeHttpSSL extends TestInvokeHttpCommon {
protected static Map<String, String> sslProperties;
protected static Map<String, String> serverSslProperties;
protected static final String TRUSTSTORE_PATH = "src/test/resources/truststore.no-password.jks";
protected static final String TRUSTSTORE_PASSWORD = "";
protected static final KeystoreType TRUSTSTORE_TYPE = KeystoreType.JKS;
private static final String KEYSTORE_PATH = "src/test/resources/keystore.jks";
private static final String KEYSTORE_PASSWORD = "passwordpassword";
private static final KeystoreType KEYSTORE_TYPE = KeystoreType.JKS;
private static final String HTTP_CONNECT_TIMEOUT = "30 s";
private static final String HTTP_READ_TIMEOUT = "30 s";
protected static final TlsConfiguration SERVER_CONFIGURATION = new StandardTlsConfiguration(
KEYSTORE_PATH,
KEYSTORE_PASSWORD,
KEYSTORE_TYPE,
TRUSTSTORE_PATH,
TRUSTSTORE_PASSWORD,
TRUSTSTORE_TYPE
);
protected static SSLContext clientSslContext;
private static final TlsConfiguration CLIENT_CONFIGURATION = new StandardTlsConfiguration(
null,
null,
null,
TRUSTSTORE_PATH,
TRUSTSTORE_PASSWORD,
TRUSTSTORE_TYPE
);
@BeforeClass
public static void beforeClass() throws Exception {
Assume.assumeTrue("Test only runs on *nix", !SystemUtils.IS_OS_WINDOWS);
// useful for verbose logging output
// don't commit this with this property enabled, or any 'mvn test' will be really verbose
// System.setProperty("org.slf4j.simpleLogger.log.nifi.processors.standard", "debug");
// create the SSL properties, which basically store keystore / truststore information
// this is used by the StandardSSLContextService and the Jetty Server
serverSslProperties = createServerSslProperties(false);
sslProperties = createClientSslProperties(false);
// create a Jetty server on a random port
server = createServer();
server.startServer();
// Allow time for the server to start
Thread.sleep(500);
// this is the base url with the random port
url = server.getSecureUrl();
}
@AfterClass
public static void afterClass() throws Exception {
if(server != null) {
server.shutdownServer();
}
final SSLContext serverContext = SslContextFactory.createSslContext(SERVER_CONFIGURATION);
configureServer(serverContext, ClientAuth.NONE);
clientSslContext = SslContextFactory.createSslContext(CLIENT_CONFIGURATION);
}
@Before
public void before() throws Exception {
final SSLContextService sslContextService = Mockito.mock(SSLContextService.class);
final String serviceIdentifier = SSLContextService.class.getName();
Mockito.when(sslContextService.getIdentifier()).thenReturn(serviceIdentifier);
Mockito.when(sslContextService.createContext()).thenReturn(clientSslContext);
Mockito.when(sslContextService.createTlsConfiguration()).thenReturn(CLIENT_CONFIGURATION);
runner = TestRunners.newTestRunner(InvokeHTTP.class);
final StandardSSLContextService sslService = new StandardSSLContextService();
runner.addControllerService("ssl-context", sslService, sslProperties);
runner.enableControllerService(sslService);
runner.setProperty(InvokeHTTP.PROP_SSL_CONTEXT_SERVICE, "ssl-context");
runner.addControllerService(serviceIdentifier, sslContextService);
runner.enableControllerService(sslContextService);
// Allow time for the controller service to fully initialize
Thread.sleep(500);
// Provide more time to setup and run
runner.setProperty(InvokeHTTP.PROP_READ_TIMEOUT, "30 secs");
runner.setProperty(InvokeHTTP.PROP_CONNECT_TIMEOUT, "30 secs");
server.clearHandlers();
}
@After
public void after() {
runner.shutdown();
}
static TestServer createServer() throws IOException {
return new TestServer(serverSslProperties);
}
static Map<String, String> createServerSslProperties(boolean clientAuth) {
final Map<String, String> map = new HashMap<>();
// if requesting client auth then we must also provide a truststore
if (clientAuth) {
map.put(TestServer.NEED_CLIENT_AUTH, Boolean.toString(true));
map.putAll(getTruststoreProperties());
} else {
map.put(TestServer.NEED_CLIENT_AUTH, Boolean.toString(false));
}
// keystore is always required for the server SSL properties
map.putAll(getServerKeystoreProperties());
return map;
}
static Map<String, String> createClientSslProperties(boolean clientAuth) {
final Map<String, String> map = new HashMap<>();
// if requesting client auth then we must provide a keystore
if (clientAuth) {
map.putAll(getClientKeystoreProperties());
}
// truststore is always required for the client SSL properties
map.putAll(getTruststoreProperties());
return map;
}
private static Map<String, String> getServerKeystoreProperties() {
final Map<String, String> map = new HashMap<>();
map.put(StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/keystore.jks");
map.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "passwordpassword");
map.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), "JKS");
return map;
}
private static Map<String, String> getClientKeystoreProperties() {
final Map<String, String> 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<String, String> getTruststoreProperties() {
final Map<String, String> map = new HashMap<>();
map.put(StandardSSLContextService.TRUSTSTORE.getName(), "src/test/resources/truststore.no-password.jks");
// Commented this line to test passwordless truststores for NIFI-6770
// map.put(StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), "passwordpassword");
map.put(StandardSSLContextService.TRUSTSTORE_TYPE.getName(), "JKS");
return map;
runner.setProperty(InvokeHTTP.PROP_SSL_CONTEXT_SERVICE, serviceIdentifier);
runner.setProperty(InvokeHTTP.PROP_CONNECT_TIMEOUT, HTTP_CONNECT_TIMEOUT);
runner.setProperty(InvokeHTTP.PROP_READ_TIMEOUT, HTTP_READ_TIMEOUT);
}
}

View File

@ -17,10 +17,15 @@
package org.apache.nifi.processors.standard;
import org.apache.commons.lang3.SystemUtils;
import org.junit.Assume;
import org.apache.nifi.security.util.ClientAuth;
import org.apache.nifi.security.util.KeystoreType;
import org.apache.nifi.security.util.SslContextFactory;
import org.apache.nifi.security.util.StandardTlsConfiguration;
import org.apache.nifi.security.util.TlsConfiguration;
import org.junit.BeforeClass;
import javax.net.ssl.SSLContext;
/**
* This is probably overkill but in keeping with the same pattern as the TestInvokeHttp and TestInvokeHttpSSL class,
* we will execute the same tests using two-way SSL. The Jetty server created for these tests will require client
@ -28,27 +33,23 @@ import org.junit.BeforeClass;
*/
public class TestInvokeHttpTwoWaySSL extends TestInvokeHttpSSL {
private static final String CLIENT_KEYSTORE_PATH = "src/test/resources/client-keystore.p12";
private static final String CLIENT_KEYSTORE_PASSWORD = "passwordpassword";
private static final KeystoreType CLIENT_KEYSTORE_TYPE = KeystoreType.PKCS12;
private static final TlsConfiguration CLIENT_CONFIGURATION = new StandardTlsConfiguration(
CLIENT_KEYSTORE_PATH,
CLIENT_KEYSTORE_PASSWORD,
CLIENT_KEYSTORE_TYPE,
TRUSTSTORE_PATH,
TRUSTSTORE_PASSWORD,
TRUSTSTORE_TYPE
);
@BeforeClass
public static void beforeClass() throws Exception {
Assume.assumeTrue("Test only runs on *nix", !SystemUtils.IS_OS_WINDOWS);
// useful for verbose logging output
// don't commit this with this property enabled, or any 'mvn test' will be really verbose
// System.setProperty("org.slf4j.simpleLogger.log.nifi.processors.standard", "debug");
// create the SSL properties, which basically store keystore / trustore information
// this is used by the StandardSSLContextService and the Jetty Server
serverSslProperties = createServerSslProperties(true);
sslProperties = createClientSslProperties(true);
// create a Jetty server on a random port
server = createServer();
server.startServer();
// Allow time for the server to start
Thread.sleep(500);
// this is the base url with the random port
url = server.getSecureUrl();
final SSLContext serverContext = SslContextFactory.createSslContext(SERVER_CONFIGURATION);
configureServer(serverContext, ClientAuth.REQUIRED);
clientSslContext = SslContextFactory.createSslContext(CLIENT_CONFIGURATION);
}
}

View File

@ -29,6 +29,8 @@ import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
@ -41,6 +43,7 @@ import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.servlet.http.HttpServletResponse;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
@ -48,7 +51,7 @@ import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.apache.commons.lang3.SystemUtils;
import org.apache.nifi.processor.ProcessContext;
import org.apache.nifi.processor.ProcessSessionFactory;
import org.apache.nifi.remote.io.socket.NetworkUtils;
@ -58,8 +61,8 @@ import org.apache.nifi.security.util.SslContextFactory;
import org.apache.nifi.security.util.StandardTlsConfiguration;
import org.apache.nifi.security.util.TlsConfiguration;
import org.apache.nifi.security.util.TlsException;
import org.apache.nifi.ssl.RestrictedSSLContextService;
import org.apache.nifi.ssl.SSLContextService;
import org.apache.nifi.ssl.StandardRestrictedSSLContextService;
import org.apache.nifi.ssl.StandardSSLContextService;
import org.apache.nifi.util.MockFlowFile;
import org.apache.nifi.util.TestRunner;
@ -70,6 +73,7 @@ import org.junit.Assume;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Mockito;
public class TestListenHTTP {
@ -86,18 +90,57 @@ public class TestListenHTTP {
private static final String KEYSTORE = "src/test/resources/keystore.jks";
private static final String KEYSTORE_PASSWORD = "passwordpassword";
private static final KeystoreType KEYSTORE_TYPE = KeystoreType.JKS;
private static final String TRUSTSTORE = "src/test/resources/truststore.jks";
private static final String TRUSTSTORE_PASSWORD = "passwordpassword";
private static final String TRUSTSTORE_TYPE = KeystoreType.JKS.getType();
private static final KeystoreType TRUSTSTORE_TYPE = KeystoreType.JKS;
private static final String CLIENT_KEYSTORE = "src/test/resources/client-keystore.p12";
private static final String CLIENT_KEYSTORE_TYPE = KeystoreType.PKCS12.getType();
private static final KeystoreType CLIENT_KEYSTORE_TYPE = KeystoreType.PKCS12;
private static final String TLS_1_3 = "TLSv1.3";
private static final String TLS_1_2 = "TLSv1.2";
private static final String LOCALHOST = "localhost";
private static TlsConfiguration clientTlsConfiguration;
private static TlsConfiguration trustOnlyTlsConfiguration;
private static final long SEND_REQUEST_SLEEP = 150;
private static final long RESPONSE_TIMEOUT = 1200000;
private static final int SOCKET_CONNECT_TIMEOUT = 100;
private static final long SERVER_START_TIMEOUT = 1200000;
private static final TlsConfiguration SERVER_CONFIGURATION = new StandardTlsConfiguration(
KEYSTORE,
KEYSTORE_PASSWORD,
KEYSTORE_PASSWORD,
KEYSTORE_TYPE,
TRUSTSTORE,
TRUSTSTORE_PASSWORD,
TRUSTSTORE_TYPE,
TLS_1_2
);
private static final TlsConfiguration SERVER_TLS_1_3_CONFIGURATION = new StandardTlsConfiguration(
KEYSTORE,
KEYSTORE_PASSWORD,
KEYSTORE_PASSWORD,
KEYSTORE_TYPE,
TRUSTSTORE,
TRUSTSTORE_PASSWORD,
TRUSTSTORE_TYPE,
TLS_1_3
);
private static final TlsConfiguration SERVER_NO_TRUSTSTORE_CONFIGURATION = new StandardTlsConfiguration(
KEYSTORE,
KEYSTORE_PASSWORD,
KEYSTORE_PASSWORD,
KEYSTORE_TYPE,
null,
null,
null,
TLS_1_2
);
private static SSLContext serverKeyStoreSslContext;
private static SSLContext serverKeyStoreNoTrustStoreSslContext;
private static SSLContext keyStoreSslContext;
private static SSLContext trustStoreSslContext;
private ListenHTTP proc;
private TestRunner runner;
@ -105,8 +148,27 @@ public class TestListenHTTP {
private int availablePort;
@BeforeClass
public static void setUpSuite() {
Assume.assumeTrue("Test only runs on *nix", !SystemUtils.IS_OS_WINDOWS);
public static void setUpSuite() throws TlsException {
serverKeyStoreSslContext = SslContextFactory.createSslContext(SERVER_CONFIGURATION);
final TrustManager[] defaultTrustManagers = SslContextFactory.getTrustManagers(SERVER_NO_TRUSTSTORE_CONFIGURATION);
serverKeyStoreNoTrustStoreSslContext = SslContextFactory.createSslContext(SERVER_NO_TRUSTSTORE_CONFIGURATION, defaultTrustManagers);
keyStoreSslContext = SslContextFactory.createSslContext(new StandardTlsConfiguration(
CLIENT_KEYSTORE,
KEYSTORE_PASSWORD,
CLIENT_KEYSTORE_TYPE,
TRUSTSTORE,
TRUSTSTORE_PASSWORD,
TRUSTSTORE_TYPE)
);
trustStoreSslContext = SslContextFactory.createSslContext(new StandardTlsConfiguration(
null,
null,
null,
TRUSTSTORE,
TRUSTSTORE_PASSWORD,
TRUSTSTORE_TYPE)
);
}
@Before
@ -116,11 +178,6 @@ public class TestListenHTTP {
availablePort = NetworkUtils.availablePort();
runner.setVariable(PORT_VARIABLE, Integer.toString(availablePort));
runner.setVariable(BASEPATH_VARIABLE, HTTP_BASE_PATH);
clientTlsConfiguration = new StandardTlsConfiguration(CLIENT_KEYSTORE, KEYSTORE_PASSWORD, null, CLIENT_KEYSTORE_TYPE,
TRUSTSTORE, TRUSTSTORE_PASSWORD, TRUSTSTORE_TYPE, TlsConfiguration.getHighestCurrentSupportedTlsProtocolVersion());
trustOnlyTlsConfiguration = new StandardTlsConfiguration(null, null, null, null,
TRUSTSTORE, TRUSTSTORE_PASSWORD, TRUSTSTORE_TYPE, TlsConfiguration.getHighestCurrentSupportedTlsProtocolVersion());
}
@After
@ -167,9 +224,7 @@ public class TestListenHTTP {
@Test
public void testSecurePOSTRequestsReceivedWithoutEL() throws Exception {
SSLContextService sslContextService = configureProcessorSslContextService(false);
runner.setProperty(sslContextService, StandardRestrictedSSLContextService.RESTRICTED_SSL_ALGORITHM, TlsConfiguration.getHighestCurrentSupportedTlsProtocolVersion());
runner.enableControllerService(sslContextService);
configureProcessorSslContextService(ListenHTTP.ClientAuthentication.AUTO, SERVER_NO_TRUSTSTORE_CONFIGURATION);
runner.setProperty(ListenHTTP.PORT, Integer.toString(availablePort));
runner.setProperty(ListenHTTP.BASE_PATH, HTTP_BASE_PATH);
@ -180,9 +235,7 @@ public class TestListenHTTP {
@Test
public void testSecurePOSTRequestsReturnCodeReceivedWithoutEL() throws Exception {
SSLContextService sslContextService = configureProcessorSslContextService(false);
runner.setProperty(sslContextService, StandardRestrictedSSLContextService.RESTRICTED_SSL_ALGORITHM, TlsConfiguration.getHighestCurrentSupportedTlsProtocolVersion());
runner.enableControllerService(sslContextService);
configureProcessorSslContextService(ListenHTTP.ClientAuthentication.AUTO, SERVER_NO_TRUSTSTORE_CONFIGURATION);
runner.setProperty(ListenHTTP.PORT, Integer.toString(availablePort));
runner.setProperty(ListenHTTP.BASE_PATH, HTTP_BASE_PATH);
@ -194,9 +247,7 @@ public class TestListenHTTP {
@Test
public void testSecurePOSTRequestsReceivedWithEL() throws Exception {
SSLContextService sslContextService = configureProcessorSslContextService(false);
runner.setProperty(sslContextService, StandardRestrictedSSLContextService.RESTRICTED_SSL_ALGORITHM, TlsConfiguration.getHighestCurrentSupportedTlsProtocolVersion());
runner.enableControllerService(sslContextService);
configureProcessorSslContextService(ListenHTTP.ClientAuthentication.AUTO, SERVER_NO_TRUSTSTORE_CONFIGURATION);
runner.setProperty(ListenHTTP.PORT, HTTP_SERVER_PORT_EL);
runner.setProperty(ListenHTTP.BASE_PATH, HTTP_SERVER_BASEPATH_EL);
@ -207,9 +258,7 @@ public class TestListenHTTP {
@Test
public void testSecurePOSTRequestsReturnCodeReceivedWithEL() throws Exception {
SSLContextService sslContextService = configureProcessorSslContextService(false);
runner.setProperty(sslContextService, StandardRestrictedSSLContextService.RESTRICTED_SSL_ALGORITHM, TlsConfiguration.getHighestCurrentSupportedTlsProtocolVersion());
runner.enableControllerService(sslContextService);
configureProcessorSslContextService(ListenHTTP.ClientAuthentication.AUTO, SERVER_NO_TRUSTSTORE_CONFIGURATION);
runner.setProperty(ListenHTTP.PORT, Integer.toString(availablePort));
runner.setProperty(ListenHTTP.BASE_PATH, HTTP_BASE_PATH);
@ -221,9 +270,7 @@ public class TestListenHTTP {
@Test
public void testSecureTwoWaySslPOSTRequestsReceivedWithoutEL() throws Exception {
SSLContextService sslContextService = configureProcessorSslContextService(true);
runner.setProperty(sslContextService, StandardRestrictedSSLContextService.RESTRICTED_SSL_ALGORITHM, TlsConfiguration.getHighestCurrentSupportedTlsProtocolVersion());
runner.enableControllerService(sslContextService);
configureProcessorSslContextService(ListenHTTP.ClientAuthentication.REQUIRED, SERVER_CONFIGURATION);
runner.setProperty(ListenHTTP.PORT, Integer.toString(availablePort));
runner.setProperty(ListenHTTP.BASE_PATH, HTTP_BASE_PATH);
@ -234,9 +281,7 @@ public class TestListenHTTP {
@Test
public void testSecureTwoWaySslPOSTRequestsReturnCodeReceivedWithoutEL() throws Exception {
SSLContextService sslContextService = configureProcessorSslContextService(true);
runner.setProperty(sslContextService, StandardRestrictedSSLContextService.RESTRICTED_SSL_ALGORITHM, TlsConfiguration.getHighestCurrentSupportedTlsProtocolVersion());
runner.enableControllerService(sslContextService);
configureProcessorSslContextService(ListenHTTP.ClientAuthentication.REQUIRED, SERVER_CONFIGURATION);
runner.setProperty(ListenHTTP.PORT, Integer.toString(availablePort));
runner.setProperty(ListenHTTP.BASE_PATH, HTTP_BASE_PATH);
@ -248,9 +293,7 @@ public class TestListenHTTP {
@Test
public void testSecureTwoWaySslPOSTRequestsReceivedWithEL() throws Exception {
SSLContextService sslContextService = configureProcessorSslContextService(true);
runner.setProperty(sslContextService, StandardRestrictedSSLContextService.RESTRICTED_SSL_ALGORITHM, TlsConfiguration.getHighestCurrentSupportedTlsProtocolVersion());
runner.enableControllerService(sslContextService);
configureProcessorSslContextService(ListenHTTP.ClientAuthentication.REQUIRED, SERVER_CONFIGURATION);
runner.setProperty(ListenHTTP.PORT, HTTP_SERVER_PORT_EL);
runner.setProperty(ListenHTTP.BASE_PATH, HTTP_SERVER_BASEPATH_EL);
@ -261,9 +304,7 @@ public class TestListenHTTP {
@Test
public void testSecureTwoWaySslPOSTRequestsReturnCodeReceivedWithEL() throws Exception {
SSLContextService sslContextService = configureProcessorSslContextService(true);
runner.setProperty(sslContextService, StandardRestrictedSSLContextService.RESTRICTED_SSL_ALGORITHM, TlsConfiguration.getHighestCurrentSupportedTlsProtocolVersion());
runner.enableControllerService(sslContextService);
configureProcessorSslContextService(ListenHTTP.ClientAuthentication.REQUIRED, SERVER_CONFIGURATION);
runner.setProperty(ListenHTTP.PORT, Integer.toString(availablePort));
runner.setProperty(ListenHTTP.BASE_PATH, HTTP_BASE_PATH);
@ -276,7 +317,6 @@ public class TestListenHTTP {
@Test
public void testSecureInvalidSSLConfiguration() throws Exception {
SSLContextService sslContextService = configureInvalidProcessorSslContextService();
runner.setProperty(sslContextService, StandardSSLContextService.SSL_ALGORITHM, TlsConfiguration.getHighestCurrentSupportedTlsProtocolVersion());
runner.enableControllerService(sslContextService);
runner.setProperty(ListenHTTP.PORT, HTTP_SERVER_PORT_EL);
@ -286,11 +326,12 @@ public class TestListenHTTP {
@Test
public void testSecureServerSupportsCurrentTlsProtocolVersion() throws Exception {
startSecureServer(false);
configureProcessorSslContextService(ListenHTTP.ClientAuthentication.AUTO, SERVER_NO_TRUSTSTORE_CONFIGURATION);
startSecureServer();
final SSLSocketFactory sslSocketFactory = SslContextFactory.createSSLSocketFactory(trustOnlyTlsConfiguration);
final SSLSocketFactory sslSocketFactory = trustStoreSslContext.getSocketFactory();
final SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(LOCALHOST, availablePort);
final String currentProtocol = TlsConfiguration.getHighestCurrentSupportedTlsProtocolVersion();
final String currentProtocol = SERVER_NO_TRUSTSTORE_CONFIGURATION.getProtocol();
sslSocket.setEnabledProtocols(new String[]{currentProtocol});
sslSocket.startHandshake();
@ -300,19 +341,21 @@ public class TestListenHTTP {
@Test
public void testSecureServerTrustStoreConfiguredClientAuthenticationRequired() throws Exception {
startSecureServer(true);
final HttpsURLConnection connection = getSecureConnection(trustOnlyTlsConfiguration);
configureProcessorSslContextService(ListenHTTP.ClientAuthentication.REQUIRED, SERVER_CONFIGURATION);
startSecureServer();
final HttpsURLConnection connection = getSecureConnection(trustStoreSslContext);
assertThrows(SSLException.class, connection::getResponseCode);
final HttpsURLConnection clientCertificateConnection = getSecureConnection(clientTlsConfiguration);
final HttpsURLConnection clientCertificateConnection = getSecureConnection(keyStoreSslContext);
final int responseCode = clientCertificateConnection.getResponseCode();
assertEquals(HttpServletResponse.SC_METHOD_NOT_ALLOWED, responseCode);
}
@Test
public void testSecureServerTrustStoreNotConfiguredClientAuthenticationNotRequired() throws Exception {
startSecureServer(false);
final HttpsURLConnection connection = getSecureConnection(trustOnlyTlsConfiguration);
configureProcessorSslContextService(ListenHTTP.ClientAuthentication.AUTO, SERVER_NO_TRUSTSTORE_CONFIGURATION);
startSecureServer();
final HttpsURLConnection connection = getSecureConnection(trustStoreSslContext);
final int responseCode = connection.getResponseCode();
assertEquals(HttpServletResponse.SC_METHOD_NOT_ALLOWED, responseCode);
}
@ -323,9 +366,7 @@ public class TestListenHTTP {
final String protocolMessage = String.format("TLS Protocol required [%s] found [%s]", TLS_1_3, currentProtocol);
Assume.assumeTrue(protocolMessage, TLS_1_3.equals(currentProtocol));
final SSLContextService sslContextService = configureProcessorSslContextService(false);
runner.setProperty(sslContextService, StandardSSLContextService.SSL_ALGORITHM, TLS_1_3);
runner.enableControllerService(sslContextService);
configureProcessorSslContextService(ListenHTTP.ClientAuthentication.AUTO, SERVER_TLS_1_3_CONFIGURATION);
runner.setProperty(ListenHTTP.PORT, Integer.toString(availablePort));
runner.setProperty(ListenHTTP.BASE_PATH, HTTP_BASE_PATH);
@ -333,18 +374,14 @@ public class TestListenHTTP {
runner.assertValid();
startWebServer();
final SSLSocketFactory sslSocketFactory = SslContextFactory.createSSLSocketFactory(trustOnlyTlsConfiguration);
final SSLSocketFactory sslSocketFactory = trustStoreSslContext.getSocketFactory();
final SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(LOCALHOST, availablePort);
sslSocket.setEnabledProtocols(new String[]{TLS_1_2});
assertThrows(SSLHandshakeException.class, sslSocket::startHandshake);
}
private void startSecureServer(final boolean setServerTrustStoreProperties) throws InitializationException {
final SSLContextService sslContextService = configureProcessorSslContextService(ListenHTTP.ClientAuthentication.AUTO, setServerTrustStoreProperties);
runner.setProperty(sslContextService, StandardSSLContextService.SSL_ALGORITHM, TlsConfiguration.TLS_PROTOCOL);
runner.enableControllerService(sslContextService);
private void startSecureServer() {
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));
@ -352,11 +389,10 @@ public class TestListenHTTP {
startWebServer();
}
private HttpsURLConnection getSecureConnection(final TlsConfiguration tlsConfiguration) throws Exception {
private HttpsURLConnection getSecureConnection(final SSLContext sslContext) throws Exception {
final URL url = new URL(buildUrl(true));
final HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
final SSLSocketFactory sslSocketFactory = SslContextFactory.createSSLSocketFactory(tlsConfiguration);
connection.setSSLSocketFactory(sslSocketFactory);
connection.setSSLSocketFactory(sslContext.getSocketFactory());
return connection;
}
@ -383,18 +419,16 @@ public class TestListenHTTP {
return connection.getResponseCode();
}
private static HttpsURLConnection buildSecureConnection(boolean twoWaySsl, URL url) throws IOException, TlsException {
final HttpsURLConnection sslCon = (HttpsURLConnection) url.openConnection();
SSLContext clientSslContext;
private static HttpsURLConnection buildSecureConnection(boolean twoWaySsl, URL url) throws IOException {
final HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
if (twoWaySsl) {
// Use a client certificate, do not reuse the server's keystore
clientSslContext = SslContextFactory.createSslContext(clientTlsConfiguration);
connection.setSSLSocketFactory(keyStoreSslContext.getSocketFactory());
} else {
// With one-way SSL, the client still needs a truststore
clientSslContext = SslContextFactory.createSslContext(trustOnlyTlsConfiguration);
connection.setSSLSocketFactory(trustStoreSslContext.getSocketFactory());
}
sslCon.setSSLSocketFactory(clientSslContext.getSocketFactory());
return sslCon;
return connection;
}
private String buildUrl(final boolean secure) {
@ -423,21 +457,45 @@ public class TestListenHTTP {
final ProcessSessionFactory processSessionFactory = runner.getProcessSessionFactory();
final ProcessContext context = runner.getProcessContext();
proc.onTrigger(context, processSessionFactory);
final int port = context.getProperty(ListenHTTP.PORT).evaluateAttributeExpressions().asInteger();
final InetSocketAddress socketAddress = new InetSocketAddress(LOCALHOST, port);
final Socket socket = new Socket();
boolean connected = false;
long elapsed = 0;
while (!connected && elapsed < SERVER_START_TIMEOUT) {
final long started = System.currentTimeMillis();
try {
socket.connect(socketAddress, SOCKET_CONNECT_TIMEOUT);
connected = true;
runner.getLogger().debug("Server Socket Connected after {} ms", new Object[]{elapsed});
socket.close();
} catch (final Exception e) {
runner.getLogger().debug("Server Socket Connect Failed: [{}] {}", new Object[]{e.getClass(), e.getMessage()});
}
final long connectElapsed = System.currentTimeMillis() - started;
elapsed += connectElapsed;
}
if (!connected) {
final String message = String.format("HTTP Server Port [%d] not listening after %d ms", port, SERVER_START_TIMEOUT);
throw new IllegalStateException(message);
}
}
private void startWebServerAndSendRequests(Runnable sendRequestToWebserver, int numberOfExpectedFlowFiles) throws Exception {
startWebServer();
new Thread(sendRequestToWebserver).start();
long responseTimeout = 10000;
final ProcessSessionFactory processSessionFactory = runner.getProcessSessionFactory();
final ProcessContext context = runner.getProcessContext();
int numTransferred = 0;
long startTime = System.currentTimeMillis();
while (numTransferred < numberOfExpectedFlowFiles && (System.currentTimeMillis() - startTime < responseTimeout)) {
while (numTransferred < numberOfExpectedFlowFiles && (System.currentTimeMillis() - startTime < RESPONSE_TIMEOUT)) {
proc.onTrigger(context, processSessionFactory);
numTransferred = runner.getFlowFilesForRelationship(RELATIONSHIP_SUCCESS).size();
Thread.sleep(100);
Thread.sleep(SEND_REQUEST_SLEEP);
}
runner.assertTransferCount(ListenHTTP.RELATIONSHIP_SUCCESS, numberOfExpectedFlowFiles);
@ -462,33 +520,23 @@ public class TestListenHTTP {
startWebServerAndSendRequests(sendMessagesToWebServer, messages.size());
}
private SSLContextService configureProcessorSslContextService(boolean setTrustStoreProperties) throws InitializationException {
ListenHTTP.ClientAuthentication clientAuthentication = ListenHTTP.ClientAuthentication.AUTO;
if (setTrustStoreProperties) {
clientAuthentication = ListenHTTP.ClientAuthentication.REQUIRED;
}
return configureProcessorSslContextService(clientAuthentication, setTrustStoreProperties);
}
private void configureProcessorSslContextService(final ListenHTTP.ClientAuthentication clientAuthentication,
final TlsConfiguration tlsConfiguration) throws InitializationException {
final RestrictedSSLContextService sslContextService = Mockito.mock(RestrictedSSLContextService.class);
Mockito.when(sslContextService.getIdentifier()).thenReturn(SSL_CONTEXT_SERVICE_IDENTIFIER);
Mockito.when(sslContextService.createTlsConfiguration()).thenReturn(tlsConfiguration);
private SSLContextService configureProcessorSslContextService(final ListenHTTP.ClientAuthentication clientAuthentication,
final boolean setTrustStoreProperties) throws InitializationException {
final SSLContextService sslContextService = new StandardRestrictedSSLContextService();
if (ListenHTTP.ClientAuthentication.REQUIRED.equals(clientAuthentication)) {
Mockito.when(sslContextService.createContext()).thenReturn(serverKeyStoreSslContext);
} else {
Mockito.when(sslContextService.createContext()).thenReturn(serverKeyStoreNoTrustStoreSslContext);
}
runner.addControllerService(SSL_CONTEXT_SERVICE_IDENTIFIER, sslContextService);
if (setTrustStoreProperties) {
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE, TRUSTSTORE);
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE_PASSWORD, TRUSTSTORE_PASSWORD);
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE_TYPE, KeystoreType.JKS.getType());
}
runner.setProperty(ListenHTTP.CLIENT_AUTHENTICATION, clientAuthentication.name());
runner.setProperty(sslContextService, StandardSSLContextService.KEYSTORE, KEYSTORE);
runner.setProperty(sslContextService, StandardSSLContextService.KEYSTORE_PASSWORD, TRUSTSTORE_PASSWORD);
runner.setProperty(sslContextService, StandardSSLContextService.KEYSTORE_TYPE, KeystoreType.JKS.getType());
runner.setProperty(ListenHTTP.SSL_CONTEXT_SERVICE, SSL_CONTEXT_SERVICE_IDENTIFIER);
return sslContextService;
runner.enableControllerService(sslContextService);
}
private SSLContextService configureInvalidProcessorSslContextService() throws InitializationException {

View File

@ -22,7 +22,6 @@ public class TestPutTCP extends TestPutTCPCommon {
public TestPutTCP() {
super();
ssl = false;
}
@Override
@ -41,6 +40,4 @@ public class TestPutTCP extends TestPutTCPCommon {
runner.assertNotValid();
}
}
}

View File

@ -16,23 +16,42 @@
*/
package org.apache.nifi.processors.standard;
import java.util.HashMap;
import java.util.Map;
import org.apache.nifi.processors.standard.util.TestPutTCPCommon;
import org.apache.nifi.reporting.InitializationException;
import org.apache.nifi.ssl.StandardSSLContextService;
import org.apache.nifi.security.util.KeystoreType;
import org.apache.nifi.security.util.SslContextFactory;
import org.apache.nifi.security.util.StandardTlsConfiguration;
import org.apache.nifi.security.util.TlsConfiguration;
import org.apache.nifi.security.util.TlsException;
import org.apache.nifi.ssl.SSLContextService;
import org.junit.BeforeClass;
import org.mockito.Mockito;
import javax.net.ssl.SSLContext;
public class TestPutTcpSSL extends TestPutTCPCommon {
private static Map<String, String> sslProperties;
private static final String TLS_PROTOCOL = "TLSv1.2";
// TODO: The NiFi SSL classes don't yet support TLSv1.3, so set the CS version explicitly
private static final String TLS_PROTOCOL_VERSION = "TLSv1.2";
private static SSLContext sslContext;
@BeforeClass
public static void configureServices() throws TlsException {
final TlsConfiguration configuration = new StandardTlsConfiguration(
"src/test/resources/keystore.jks",
"passwordpassword",
"passwordpassword",
KeystoreType.JKS,
"src/test/resources/truststore.jks",
"passwordpassword",
KeystoreType.JKS,
TLS_PROTOCOL
);
sslContext = SslContextFactory.createSslContext(configuration);
}
public TestPutTcpSSL() {
super();
ssl = true;
sslProperties = createSslProperties();
serverSocketFactory = sslContext.getServerSocketFactory();
}
@Override
@ -40,10 +59,14 @@ public class TestPutTcpSSL extends TestPutTCPCommon {
runner.setProperty(PutTCP.HOSTNAME, host);
runner.setProperty(PutTCP.PORT, Integer.toString(port));
final StandardSSLContextService sslService = new StandardSSLContextService();
runner.addControllerService("ssl-context", sslService, sslProperties);
runner.enableControllerService(sslService);
runner.setProperty(PutTCP.SSL_CONTEXT_SERVICE, "ssl-context");
final SSLContextService sslContextService = Mockito.mock(SSLContextService.class);
final String serviceIdentifier = SSLContextService.class.getName();
Mockito.when(sslContextService.getIdentifier()).thenReturn(serviceIdentifier);
Mockito.when(sslContextService.createContext()).thenReturn(sslContext);
runner.addControllerService(serviceIdentifier, sslContextService);
runner.enableControllerService(sslContextService);
runner.setProperty(PutTCP.SSL_CONTEXT_SERVICE, serviceIdentifier);
if (outgoingMessageDelimiter != null) {
runner.setProperty(PutTCP.OUTGOING_MESSAGE_DELIMITER, outgoingMessageDelimiter);
@ -56,16 +79,4 @@ public class TestPutTcpSSL extends TestPutTCPCommon {
runner.assertNotValid();
}
}
private static Map<String, String> createSslProperties() {
final Map<String, String> map = new HashMap<>();
map.put(StandardSSLContextService.KEYSTORE.getName(), "src/test/resources/keystore.jks");
map.put(StandardSSLContextService.KEYSTORE_PASSWORD.getName(), "passwordpassword");
map.put(StandardSSLContextService.KEYSTORE_TYPE.getName(), "JKS");
map.put(StandardSSLContextService.TRUSTSTORE.getName(), "src/test/resources/truststore.jks");
map.put(StandardSSLContextService.TRUSTSTORE_PASSWORD.getName(), "passwordpassword");
map.put(StandardSSLContextService.TRUSTSTORE_TYPE.getName(), "JKS");
map.put(StandardSSLContextService.SSL_ALGORITHM.getName(), TLS_PROTOCOL_VERSION);
return map;
}
}

View File

@ -25,10 +25,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import javax.net.ServerSocketFactory;
import javax.net.ssl.SSLContext;
import org.apache.nifi.security.util.SslContextFactory;
import org.apache.nifi.security.util.StandardTlsConfiguration;
import org.apache.nifi.security.util.TlsConfiguration;
public class TCPTestServer implements Runnable {
@ -51,17 +47,12 @@ public class TCPTestServer implements Runnable {
this.messageDelimiter = messageDelimiter;
}
public synchronized void startServer(boolean ssl) throws Exception {
public synchronized void startServer(final ServerSocketFactory serverSocketFactory) throws Exception {
if (!isServerRunning()) {
if(ssl){
TlsConfiguration tlsConfiguration = new StandardTlsConfiguration("src/test/resources/keystore.jks","passwordpassword", null, "JKS", "src/test/resources/truststore.jks",
"passwordpassword", "JKS", TlsConfiguration.getHighestCurrentSupportedTlsProtocolVersion());
final SSLContext sslCtx = SslContextFactory.createSslContext(tlsConfiguration);
ServerSocketFactory sslSocketFactory = sslCtx.getServerSocketFactory();
serverSocket = sslSocketFactory.createServerSocket(0, 0, ipAddress);
} else {
if (serverSocketFactory == null) {
serverSocket = new ServerSocket(0, 0, ipAddress);
} else {
serverSocket = serverSocketFactory.createServerSocket(0, 0, ipAddress);
}
Thread t = new Thread(this);
t.setName(this.getClass().getSimpleName());

View File

@ -33,6 +33,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.net.ssl.SSLContext;
import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@ -45,10 +46,12 @@ import org.apache.nifi.flowfile.attributes.CoreAttributes;
import org.apache.nifi.processors.standard.InvokeHTTP;
import org.apache.nifi.provenance.ProvenanceEventRecord;
import org.apache.nifi.provenance.ProvenanceEventType;
import org.apache.nifi.remote.io.socket.NetworkUtils;
import org.apache.nifi.security.util.ClientAuth;
import org.apache.nifi.util.MockFlowFile;
import org.apache.nifi.util.StringUtils;
import org.apache.nifi.util.TestRunner;
import org.apache.nifi.web.util.TestServer;
import org.apache.nifi.web.util.JettyServerUtils;
import org.eclipse.jetty.http.MultiPartFormInputStream;
import org.eclipse.jetty.security.ConstraintSecurityHandler;
import org.eclipse.jetty.security.DefaultIdentityService;
@ -58,20 +61,63 @@ import org.eclipse.jetty.security.authentication.DigestAuthenticator;
import org.eclipse.jetty.server.Authentication;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.util.MultiPartInputStreamParser;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Test;
public abstract class TestInvokeHttpCommon {
public static TestServer server;
public static String url;
protected static Server server;
public TestRunner runner;
protected static String url;
public void addHandler(Handler handler) {
server.addHandler(handler);
private static final long READ_TIMEOUT_SLEEP = 1000;
protected TestRunner runner;
protected static void configureServer(final SSLContext sslContext, final ClientAuth clientAuth) throws Exception {
final int port = NetworkUtils.availablePort();
final String protocol = sslContext == null ? "http" : "https";
setUrl(protocol, port);
final Server configuredServer = JettyServerUtils.createServer(port, sslContext, clientAuth);
final ServerConnector connector = new ServerConnector(configuredServer);
connector.setPort(port);
JettyServerUtils.startServer(configuredServer);
setServer(configuredServer);
}
private static void setUrl(final String scheme, final int port) {
url = String.format("%s://localhost:%d", scheme, port);
}
private static void setServer(final Server configuredServer) {
server = configuredServer;
}
protected static void addHandler(final Handler handler) {
JettyServerUtils.addHandler(server, handler);
}
@AfterClass
public static void afterClass() throws Exception {
if (server != null) {
server.stop();
server.destroy();
}
}
@After
public void after() {
JettyServerUtils.clearHandlers(server);
runner.shutdown();
}
@Test
@ -84,6 +130,9 @@ public abstract class TestInvokeHttpCommon {
createFlowFiles(runner);
runner.run();
runner.assertTransferCount(InvokeHTTP.REL_SUCCESS_REQ, 1);
runner.assertTransferCount(InvokeHTTP.REL_RESPONSE, 1);
// extract the date string sent to the server
// and store it as a java.util.Date
final SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
@ -100,7 +149,6 @@ public abstract class TestInvokeHttpCommon {
if (diff > threshold) {
fail("Difference (" + diff + ") was greater than threshold (" + threshold + ")");
}
System.out.println("diff: " + diff);
}
@Test
@ -773,7 +821,6 @@ public abstract class TestInvokeHttpCommon {
createFlowFiles(runner);
//assertTrue(server.jetty.isRunning());
runner.run();
runner.assertTransferCount(InvokeHTTP.REL_SUCCESS_REQ, 0);
runner.assertTransferCount(InvokeHTTP.REL_RESPONSE, 0);
@ -1489,7 +1536,7 @@ public abstract class TestInvokeHttpCommon {
addHandler(new ReadTimeoutHandler());
runner.setProperty(InvokeHTTP.PROP_URL, url + "/status/200");
runner.setProperty(InvokeHTTP.PROP_READ_TIMEOUT, "5 secs");
runner.setProperty(InvokeHTTP.PROP_READ_TIMEOUT, String.format("%d ms", READ_TIMEOUT_SLEEP / 2));
createFlowFiles(runner);
@ -2020,7 +2067,7 @@ public abstract class TestInvokeHttpCommon {
if ("Get".equalsIgnoreCase(request.getMethod())) {
try {
Thread.sleep(10000);
Thread.sleep(READ_TIMEOUT_SLEEP);
} catch (InterruptedException e) {
return;
}

View File

@ -30,6 +30,7 @@ import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import javax.net.ServerSocketFactory;
import java.net.InetAddress;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
@ -59,7 +60,7 @@ public abstract class TestPutTCPCommon {
private final static char CONTENT_CHAR = 'x';
private final static int DATA_WAIT_PERIOD = 1000;
private final static int DEFAULT_TEST_TIMEOUT_PERIOD = 10000;
private final static int LONG_TEST_TIMEOUT_PERIOD = 100000;
private final static int LONG_TEST_TIMEOUT_PERIOD = 180000;
private final static String OUTGOING_MESSAGE_DELIMITER = "\n";
private final static String OUTGOING_MESSAGE_DELIMITER_MULTI_CHAR = "{delimiter}\r\n";
@ -67,7 +68,7 @@ public abstract class TestPutTCPCommon {
private int tcp_server_port;
private ArrayBlockingQueue<List<Byte>> recvQueue;
public boolean ssl;
public ServerSocketFactory serverSocketFactory;
public TestRunner runner;
// Test Data
@ -88,7 +89,7 @@ public abstract class TestPutTCPCommon {
private synchronized TCPTestServer createTestServer(final String address, final ArrayBlockingQueue<List<Byte>> recvQueue, final String delimiter) throws Exception {
TCPTestServer server = new TCPTestServer(InetAddress.getByName(address), recvQueue, delimiter);
server.startServer(ssl);
server.startServer(serverSocketFactory);
tcp_server_port = server.getPort();
return server;
}
@ -136,8 +137,8 @@ public abstract class TestPutTCPCommon {
checkReceivedAllData(recvQueue, VALID_FILES);
checkInputQueueIsEmpty();
checkTotalNumConnections(server, 1);
runner.setProperty(PutTCP.IDLE_EXPIRATION, "1 second");
Thread.sleep(2000);
runner.setProperty(PutTCP.IDLE_EXPIRATION, "100 ms");
Thread.sleep(200);
runner.run(1, false, false);
runner.clearTransferState();
sendTestData(VALID_FILES);

View File

@ -0,0 +1,88 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.nifi.web.util;
import org.apache.nifi.security.util.ClientAuth;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import javax.net.ssl.SSLContext;
public class JettyServerUtils {
private static final long IDLE_TIMEOUT = 60000;
private static final long SERVER_START_SLEEP = 100L;
public static Server createServer(final int port, final SSLContext sslContext, final ClientAuth clientAuth) {
final Server server = new Server();
final ServerConnector connector;
if (sslContext == null) {
connector = new ServerConnector(server);
} else {
final SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setSslContext(sslContext);
if (ClientAuth.REQUIRED.equals(clientAuth)) {
sslContextFactory.setNeedClientAuth(true);
}
connector = new ServerConnector(server, sslContextFactory);
}
connector.setPort(port);
connector.setIdleTimeout(IDLE_TIMEOUT);
server.addConnector(connector);
final HandlerCollection handlerCollection = new HandlerCollection(true);
server.setHandler(handlerCollection);
return server;
}
public static void startServer(final Server server) throws Exception {
server.start();
while (!server.isStarted()) {
Thread.sleep(SERVER_START_SLEEP);
}
}
public static void addHandler(final Server server, final Handler handler) {
final Handler serverHandler = server.getHandler();
if (serverHandler instanceof HandlerCollection) {
final HandlerCollection handlerCollection = (HandlerCollection) serverHandler;
handlerCollection.addHandler(handler);
}
}
public static void clearHandlers(final Server server) {
final Handler serverHandler = server.getHandler();
if (serverHandler instanceof HandlerCollection) {
final HandlerCollection handlerCollection = (HandlerCollection) serverHandler;
final Handler[] handlers = handlerCollection.getHandlers();
if (handlers != null) {
for (final Handler handler : handlerCollection.getHandlers()) {
handlerCollection.removeHandler(handler);
}
}
}
}
}

View File

@ -31,6 +31,8 @@ public class TestServer {
public static final String NEED_CLIENT_AUTH = "clientAuth";
private static final long IDLE_TIMEOUT = 60000;
private Server jetty;
private boolean secure = false;
@ -71,12 +73,12 @@ public class TestServer {
final ServerConnector http = new ServerConnector(jetty);
http.setPort(0);
// Severely taxed environments may have significant delays when executing.
http.setIdleTimeout(30000L);
http.setIdleTimeout(IDLE_TIMEOUT);
jetty.addConnector(http);
}
private void createSecureConnector(final Map<String, String> sslProperties) {
SslContextFactory ssl = new SslContextFactory.Server();
SslContextFactory.Server ssl = new SslContextFactory.Server();
if (sslProperties.get(StandardSSLContextService.KEYSTORE.getName()) != null) {
ssl.setKeyStorePath(sslProperties.get(StandardSSLContextService.KEYSTORE.getName()));
@ -103,7 +105,7 @@ public class TestServer {
// set host and port
https.setPort(0);
// Severely taxed environments may have significant delays when executing.
https.setIdleTimeout(30000L);
https.setIdleTimeout(IDLE_TIMEOUT);
// add the connector
jetty.addConnector(https);
@ -113,17 +115,11 @@ public class TestServer {
}
public void clearHandlers() {
HandlerCollection hc = (HandlerCollection) jetty.getHandler();
Handler[] ha = hc.getHandlers();
if (ha != null) {
for (Handler h : ha) {
hc.removeHandler(h);
}
}
JettyServerUtils.clearHandlers(jetty);
}
public void addHandler(Handler handler) {
((HandlerCollection) jetty.getHandler()).addHandler(handler);
public void addHandler(final Handler handler) {
JettyServerUtils.addHandler(jetty, handler);
}
public void startServer() throws Exception {

View File

@ -181,21 +181,6 @@
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.66</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpg-jdk15on</artifactId>
<version>1.66</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.66</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>

View File

@ -51,12 +51,10 @@
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.66</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.66</version>
</dependency>
<dependency>
<groupId>commons-cli</groupId>

16
pom.xml
View File

@ -88,6 +88,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<inceptionYear>2014</inceptionYear>
<org.bouncycastle.version>1.68</org.bouncycastle.version>
<org.slf4j.version>1.7.30</org.slf4j.version>
<ranger.version>2.1.0</ranger.version>
<jetty.version>9.4.35.v20201120</jetty.version>
@ -261,6 +262,21 @@
<artifactId>slf4j-log4j12</artifactId>
<version>${org.slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>${org.bouncycastle.version}</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>${org.bouncycastle.version}</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpg-jdk15on</artifactId>
<version>${org.bouncycastle.version}</version>
</dependency>
<!-- These junit/mockito/groovy/spock/hamcrest dependencies are here to encourage consistent unit test library usage -->
<dependency>