You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by ex...@apache.org on 2021/02/03 14:54:27 UTC
[nifi] branch main updated: NIFI-1355 Implemented new methods in
KeyStoreUtils to programmatically-generate certificates, Keystores,
and Truststores and return it wrapped in a TLS configuration. Updated
TestInvokeHTTP, TestInvokeHttpSSL, TestInvokeHttpTwoWaySSL,
and TestListenHTTP to use new Keystore functionality.
This is an automated email from the ASF dual-hosted git repository.
exceptionfactory pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/main by this push:
new 6e1f737 NIFI-1355 Implemented new methods in KeyStoreUtils to programmatically-generate certificates, Keystores, and Truststores and return it wrapped in a TLS configuration. Updated TestInvokeHTTP, TestInvokeHttpSSL, TestInvokeHttpTwoWaySSL, and TestListenHTTP to use new Keystore functionality.
6e1f737 is described below
commit 6e1f737c53523843b7a3222d0c6dbc2d84e4aa09
Author: mtien <mt...@gmail.com>
AuthorDate: Tue Dec 15 18:08:26 2020 -0800
NIFI-1355 Implemented new methods in KeyStoreUtils to programmatically-generate certificates, Keystores, and Truststores and return it wrapped in a TLS configuration.
Updated TestInvokeHTTP, TestInvokeHttpSSL, TestInvokeHttpTwoWaySSL, and TestListenHTTP to use new Keystore functionality.
NIFI-1355 Refactored and removed unnecessary unit tests in KeyStoreUtilsGroovyTest.
NIFI-1355 Added a password requirement when creating a new truststore.
Handled exception when loading a passwordless truststore type of Bouncy Castle PKCS12.
This closes #4801
Signed-off-by: David Handermann <ex...@apache.org>
---
.../apache/nifi/security/util/KeyStoreUtils.java | 213 ++++++++++++++++++++-
.../security/util/KeyStoreUtilsGroovyTest.groovy | 98 +++++++++-
.../nifi/security/util/KeyStoreUtilsTest.java | 5 +-
.../nifi/processors/standard/TestInvokeHTTP.java | 71 ++++---
.../processors/standard/TestInvokeHttpSSL.java | 91 +++++----
.../standard/TestInvokeHttpTwoWaySSL.java | 64 +++++--
.../nifi/processors/standard/TestListenHTTP.java | 185 +++++++++++-------
.../standard/util/TestInvokeHttpCommon.java | 13 +-
8 files changed, 563 insertions(+), 177 deletions(-)
diff --git a/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/util/KeyStoreUtils.java b/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/util/KeyStoreUtils.java
index 704d2ef..1bab318 100644
--- a/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/util/KeyStoreUtils.java
+++ b/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/util/KeyStoreUtils.java
@@ -19,23 +19,35 @@ package org.apache.nifi.security.util;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.UncheckedIOException;
import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.GeneralSecurityException;
import java.security.Key;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
import java.security.Security;
import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
+import java.util.Objects;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.TrustManagerFactory;
+import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
@@ -46,8 +58,24 @@ public class KeyStoreUtils {
private static final Logger logger = LoggerFactory.getLogger(KeyStoreUtils.class);
public static final String SUN_PROVIDER_NAME = "SUN";
+ private static final String JKS_EXT = ".jks";
+ private static final String PKCS12_EXT = ".p12";
+ private static final String BCFKS_EXT = ".bcfks";
+ private static final String KEY_ALIAS = "nifi-key";
+ private static final String CERT_ALIAS = "nifi-cert";
+ private static final String CERT_DN = "CN=localhost";
+ private static final String KEY_ALGORITHM = "RSA";
+ private static final String SIGNING_ALGORITHM = "SHA256withRSA";
+ private static final int CERT_DURATION_DAYS = 365;
+ private static final int PASSWORD_LENGTH = 16;
+ private static final String TEST_KEYSTORE_PREFIX = "test-keystore-";
+ private static final String TEST_TRUSTSTORE_PREFIX = "test-truststore-";
+
+ private static final String KEYSTORE_ERROR_MSG = "There was an error creating a Keystore.";
+ private static final String TRUSTSTORE_ERROR_MSG = "There was an error creating a Truststore.";
private static final Map<String, String> KEY_STORE_TYPE_PROVIDERS = new HashMap<>();
+ private static final Map<KeystoreType, String> KEY_STORE_EXTENSIONS = new HashMap<>();
static {
Security.addProvider(new BouncyCastleProvider());
@@ -57,6 +85,12 @@ public class KeyStoreUtils {
KEY_STORE_TYPE_PROVIDERS.put(KeystoreType.JKS.getType(), SUN_PROVIDER_NAME);
}
+ static {
+ KEY_STORE_EXTENSIONS.put(KeystoreType.JKS, JKS_EXT);
+ KEY_STORE_EXTENSIONS.put(KeystoreType.PKCS12, PKCS12_EXT);
+ KEY_STORE_EXTENSIONS.put(KeystoreType.BCFKS, BCFKS_EXT);
+ }
+
/**
* Returns the provider that will be used for the given keyStoreType
*
@@ -112,6 +146,63 @@ public class KeyStoreUtils {
}
/**
+ * Creates a temporary default Keystore and Truststore and returns it wrapped in a TLS configuration.
+ *
+ * @return a {@link org.apache.nifi.security.util.TlsConfiguration}
+ */
+ public static TlsConfiguration createTlsConfigAndNewKeystoreTruststore() throws IOException, GeneralSecurityException {
+ return createTlsConfigAndNewKeystoreTruststore(new StandardTlsConfiguration());
+ }
+
+ /**
+ * Creates a temporary Keystore and Truststore and returns it wrapped in a new TLS configuration with the given values.
+ *
+ * @param tlsConfiguration a {@link org.apache.nifi.security.util.TlsConfiguration}
+ * @return a {@link org.apache.nifi.security.util.TlsConfiguration}
+ */
+ public static TlsConfiguration createTlsConfigAndNewKeystoreTruststore(final TlsConfiguration tlsConfiguration) throws IOException, GeneralSecurityException {
+ final Path keyStorePath;
+ final String keystorePassword = StringUtils.isNotBlank(tlsConfiguration.getKeystorePassword()) ? tlsConfiguration.getKeystorePassword() : generatePassword();
+ final KeystoreType keystoreType = tlsConfiguration.getKeystoreType() != null ? tlsConfiguration.getKeystoreType() : KeystoreType.PKCS12;
+ final String keyPassword = StringUtils.isNotBlank(tlsConfiguration.getKeyPassword()) ? tlsConfiguration.getKeyPassword() : keystorePassword;
+ final Path trustStorePath;
+ final String truststorePassword = StringUtils.isNotBlank(tlsConfiguration.getTruststorePassword()) ? tlsConfiguration.getTruststorePassword() : generatePassword();
+ final KeystoreType truststoreType = tlsConfiguration.getTruststoreType() != null ? tlsConfiguration.getTruststoreType() : KeystoreType.PKCS12;
+
+ // Create temporary Keystore file
+ try {
+ keyStorePath = generateTempKeystorePath(keystoreType);
+ } catch (IOException e) {
+ logger.error(KEYSTORE_ERROR_MSG, e);
+ throw new UncheckedIOException(KEYSTORE_ERROR_MSG, e);
+ }
+
+ // Create temporary Truststore file
+ try {
+ trustStorePath = generateTempTruststorePath(truststoreType);
+ } catch (IOException e) {
+ logger.error(TRUSTSTORE_ERROR_MSG, e);
+ throw new UncheckedIOException(TRUSTSTORE_ERROR_MSG, e);
+ }
+
+ // Create X509 Certificate
+ final X509Certificate clientCert = createKeyStoreAndGetX509Certificate(KEY_ALIAS, keystorePassword, keyPassword, keyStorePath.toString(), keystoreType);
+
+ // Create Truststore
+ createTrustStore(clientCert, CERT_ALIAS, truststorePassword, trustStorePath.toString(), truststoreType);
+
+ return new StandardTlsConfiguration(
+ keyStorePath.toString(),
+ keystorePassword,
+ keyPassword,
+ keystoreType,
+ trustStorePath.toString(),
+ truststorePassword,
+ truststoreType,
+ TlsPlatform.getLatestProtocol());
+ }
+
+ /**
* Returns the {@link KeyManagerFactory} from the provided {@link KeyStore} object, initialized with the key or keystore password.
*
* @param keyStore the loaded keystore
@@ -136,7 +227,7 @@ public class KeyStoreUtils {
}
/**
- * Returns the intialized {@link KeyManagerFactory}.
+ * Returns the initialized {@link KeyManagerFactory}.
*
* @param tlsConfiguration the TLS configuration
* @return the initialized key manager factory
@@ -167,7 +258,6 @@ public class KeyStoreUtils {
return getKeyManagerFactoryFromKeyStore(keyStore, keystorePasswordChars, keyPasswordChars);
}
-
/**
* Returns a loaded {@link KeyStore} (acting as a truststore) given the provided configuration values.
*
@@ -210,7 +300,7 @@ public class KeyStoreUtils {
}
/**
- * Returns the intialized {@link TrustManagerFactory}.
+ * Returns the initialized {@link TrustManagerFactory}.
*
* @param tlsConfiguration the TLS configuration
* @return the initialized trust manager factory
@@ -230,6 +320,11 @@ public class KeyStoreUtils {
* @throws TlsException if there is a problem initializing or reading from the truststore
*/
public static TrustManagerFactory loadTrustManagerFactory(String truststorePath, String truststorePassword, String truststoreType) throws TlsException {
+ // Bouncy Castle PKCS12 type requires a password
+ if (truststoreType.equalsIgnoreCase(KeystoreType.PKCS12.getType()) && StringUtils.isBlank(truststorePassword)) {
+ throw new IllegalArgumentException("A PKCS12 Truststore Type requires a password");
+ }
+
// Legacy truststore passwords can be empty
final char[] truststorePasswordChars = StringUtils.isNotBlank(truststorePassword) ? truststorePassword.toCharArray() : null;
KeyStore trustStore = loadTrustStore(truststorePath, truststorePasswordChars, truststoreType);
@@ -352,4 +447,116 @@ public class KeyStoreUtils {
.append("useClientMode", sslServerSocket.getUseClientMode())
.toString();
}
+
+ /**
+ * Loads the Keystore and returns a X509 Certificate with the given values.
+ *
+ * @param alias the certificate alias
+ * @param keyStorePassword the keystore password
+ * @param keyPassword the key password
+ * @param keyStorePath the keystore path
+ * @param keyStoreType the keystore type
+ * @return a {@link X509Certificate}
+ */
+ private static X509Certificate createKeyStoreAndGetX509Certificate(
+ final String alias, final String keyStorePassword, final String keyPassword, final String keyStorePath,
+ final KeystoreType keyStoreType) throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException {
+
+ try (final FileOutputStream outputStream = new FileOutputStream(keyStorePath)) {
+ final KeyPair keyPair = KeyPairGenerator.getInstance(KEY_ALGORITHM).generateKeyPair();
+
+ final X509Certificate selfSignedCert = CertificateUtils.generateSelfSignedX509Certificate(
+ keyPair, CERT_DN, SIGNING_ALGORITHM, CERT_DURATION_DAYS
+ );
+
+ final KeyStore keyStore = loadEmptyKeyStore(keyStoreType);
+ keyStore.setKeyEntry(alias, keyPair.getPrivate(), keyPassword.toCharArray(), new Certificate[]{selfSignedCert});
+ keyStore.store(outputStream, keyStorePassword.toCharArray());
+
+ return selfSignedCert;
+ }
+ }
+
+ /**
+ * Loads the Truststore with the given values.
+ *
+ * @param cert the certificate
+ * @param alias the certificate alias
+ * @param password the truststore password
+ * @param path the truststore path
+ * @param truststoreType the truststore type
+ */
+ private static void createTrustStore(final X509Certificate cert,
+ final String alias, final String password, final String path, final KeystoreType truststoreType)
+ throws KeyStoreException, NoSuchAlgorithmException, CertificateException {
+
+ try (final FileOutputStream outputStream = new FileOutputStream(path)) {
+ final KeyStore trustStore = loadEmptyKeyStore(truststoreType);
+ trustStore.setCertificateEntry(alias, cert);
+ trustStore.store(outputStream, password.toCharArray());
+ } catch (IOException e) {
+ throw new UncheckedIOException(TRUSTSTORE_ERROR_MSG, e);
+ }
+ }
+
+ /**
+ * Generates a temporary keystore file and returns the path.
+ *
+ * @param keystoreType the Keystore type
+ * @return a Path
+ */
+ private static Path generateTempKeystorePath(KeystoreType keystoreType) throws IOException {
+ return Files.createTempFile(TEST_KEYSTORE_PREFIX, getKeystoreExtension(keystoreType));
+ }
+
+ /**
+ * Generates a temporary truststore file and returns the path.
+ *
+ * @param truststoreType the Truststore type
+ * @return a Path
+ */
+ private static Path generateTempTruststorePath(KeystoreType truststoreType) throws IOException {
+ return Files.createTempFile(TEST_TRUSTSTORE_PREFIX, getKeystoreExtension(truststoreType));
+ }
+
+ /**
+ * Loads and returns an empty Keystore backed by the appropriate provider.
+ *
+ * @param keyStoreType the keystore type
+ * @return an empty keystore
+ * @throws KeyStoreException if a keystore of the given type cannot be instantiated
+ */
+ private static KeyStore loadEmptyKeyStore(KeystoreType keyStoreType) throws KeyStoreException, CertificateException, NoSuchAlgorithmException {
+ final KeyStore keyStore;
+ try {
+ keyStore = KeyStore.getInstance(
+ Objects.requireNonNull(keyStoreType).getType());
+ keyStore.load(null, null);
+ return keyStore;
+ } catch (IOException e) {
+ logger.error("Encountered an error loading keystore: {}", e.getLocalizedMessage());
+ throw new UncheckedIOException("Error loading keystore", e);
+ }
+ }
+
+ /**
+ * Returns the Keystore extension given the Keystore type.
+ *
+ * @param keystoreType the keystore type
+ * @return the keystore extension
+ */
+ private static String getKeystoreExtension(KeystoreType keystoreType) {
+ return KEY_STORE_EXTENSIONS.get(keystoreType);
+ }
+
+ /**
+ * Generates a random Hex-encoded password.
+ *
+ * @return a password as a Hex-encoded String
+ */
+ private static String generatePassword() {
+ final byte[] password = new byte[PASSWORD_LENGTH];
+ new SecureRandom().nextBytes(password);
+ return Hex.encodeHexString(password);
+ }
}
diff --git a/nifi-commons/nifi-security-utils/src/test/groovy/org/apache/nifi/security/util/KeyStoreUtilsGroovyTest.groovy b/nifi-commons/nifi-security-utils/src/test/groovy/org/apache/nifi/security/util/KeyStoreUtilsGroovyTest.groovy
index 7a76348..b3c85f5 100644
--- a/nifi-commons/nifi-security-utils/src/test/groovy/org/apache/nifi/security/util/KeyStoreUtilsGroovyTest.groovy
+++ b/nifi-commons/nifi-security-utils/src/test/groovy/org/apache/nifi/security/util/KeyStoreUtilsGroovyTest.groovy
@@ -16,7 +16,9 @@
*/
package org.apache.nifi.security.util
+import org.apache.nifi.util.StringUtils
import org.junit.After
+import org.junit.AfterClass
import org.junit.Before
import org.junit.BeforeClass
import org.junit.Ignore
@@ -29,6 +31,8 @@ import org.slf4j.LoggerFactory
import javax.net.ssl.HttpsURLConnection
import javax.net.ssl.SSLSocket
import javax.net.ssl.SSLSocketFactory
+import java.nio.file.Files
+import java.nio.file.Paths
import java.security.KeyStore
import java.security.cert.Certificate
@@ -36,16 +40,29 @@ import java.security.cert.Certificate
class KeyStoreUtilsGroovyTest extends GroovyTestCase {
private static final Logger logger = LoggerFactory.getLogger(KeyStoreUtilsGroovyTest.class)
- private static final File KEYSTORE_FILE = new File("src/test/resources/keystore.jks")
- private static final String KEYSTORE_PASSWORD = "passwordpassword"
- private static final String KEY_PASSWORD = "keypassword"
- private static final KeystoreType KEYSTORE_TYPE = KeystoreType.JKS
+ private static final String TEST_KEYSTORE_PASSWORD = "keystorepassword"
+ private static final String TEST_KEY_PASSWORD = "keypassword"
+ private static final String TEST_TRUSTSTORE_PASSWORD = "truststorepassword"
+ private static final KeystoreType DEFAULT_STORE_TYPE = KeystoreType.JKS
+ private static final KeystoreType PKCS12_STORE_TYPE = KeystoreType.PKCS12
+
+ private static TlsConfiguration tlsConfigParam
+ private static TlsConfiguration tlsConfiguration
@BeforeClass
static void setUpOnce() {
logger.metaClass.methodMissing = { String name, args ->
logger.info("[${name?.toUpperCase()}] ${(args as List).join(" ")}")
}
+
+ tlsConfigParam = new StandardTlsConfiguration(null, TEST_KEYSTORE_PASSWORD, TEST_KEY_PASSWORD, DEFAULT_STORE_TYPE, null, TEST_TRUSTSTORE_PASSWORD, null)
+
+ tlsConfiguration = KeyStoreUtils.createTlsConfigAndNewKeystoreTruststore(tlsConfigParam)
+ }
+
+ @AfterClass
+ static void afterClass() throws Exception {
+ deleteKeystoreTruststore(tlsConfiguration);
}
@Before
@@ -61,9 +78,10 @@ class KeyStoreUtilsGroovyTest extends GroovyTestCase {
@Test
void testShouldVerifyKeystoreIsValid() {
// Arrange
+ final URL ksUrl = getKeystorePathAsUrl(tlsConfiguration.getKeystorePath())
// Act
- boolean keystoreIsValid = KeyStoreUtils.isStoreValid(KEYSTORE_FILE.toURI().toURL(), KEYSTORE_TYPE, KEYSTORE_PASSWORD.toCharArray())
+ boolean keystoreIsValid = KeyStoreUtils.isStoreValid(ksUrl, DEFAULT_STORE_TYPE, TEST_KEYSTORE_PASSWORD.toCharArray())
// Assert
assert keystoreIsValid
@@ -72,9 +90,10 @@ class KeyStoreUtilsGroovyTest extends GroovyTestCase {
@Test
void testShouldVerifyKeystoreIsNotValid() {
// Arrange
+ final URL ksUrl = getKeystorePathAsUrl(tlsConfiguration.getKeystorePath())
// Act
- boolean keystoreIsValid = KeyStoreUtils.isStoreValid(KEYSTORE_FILE.toURI().toURL(), KEYSTORE_TYPE, KEYSTORE_PASSWORD.reverse().toCharArray())
+ boolean keystoreIsValid = KeyStoreUtils.isStoreValid(ksUrl, DEFAULT_STORE_TYPE, TEST_KEYSTORE_PASSWORD.reverse().toCharArray())
// Assert
assert !keystoreIsValid
@@ -83,9 +102,10 @@ class KeyStoreUtilsGroovyTest extends GroovyTestCase {
@Test
void testShouldVerifyKeyPasswordIsValid() {
// Arrange
+ final URL ksUrl = getKeystorePathAsUrl(tlsConfiguration.getKeystorePath())
// Act
- boolean keyPasswordIsValid = KeyStoreUtils.isKeyPasswordCorrect(KEYSTORE_FILE.toURI().toURL(), KEYSTORE_TYPE, KEYSTORE_PASSWORD.toCharArray(), KEYSTORE_PASSWORD.toCharArray())
+ boolean keyPasswordIsValid = KeyStoreUtils.isKeyPasswordCorrect(ksUrl, DEFAULT_STORE_TYPE, TEST_KEYSTORE_PASSWORD.toCharArray(), TEST_KEY_PASSWORD.toCharArray())
// Assert
assert keyPasswordIsValid
@@ -94,9 +114,10 @@ class KeyStoreUtilsGroovyTest extends GroovyTestCase {
@Test
void testShouldVerifyKeyPasswordIsNotValid() {
// Arrange
+ final URL ksUrl = getKeystorePathAsUrl(tlsConfiguration.getKeystorePath())
// Act
- boolean keyPasswordIsValid = KeyStoreUtils.isKeyPasswordCorrect(KEYSTORE_FILE.toURI().toURL(), KEYSTORE_TYPE, KEYSTORE_PASSWORD.toCharArray(), KEYSTORE_PASSWORD.reverse().toCharArray())
+ boolean keyPasswordIsValid = KeyStoreUtils.isKeyPasswordCorrect(ksUrl, tlsConfiguration.getKeystoreType(), TEST_KEYSTORE_PASSWORD.toCharArray(), TEST_KEY_PASSWORD.reverse().toCharArray())
// Assert
assert !keyPasswordIsValid
@@ -141,4 +162,65 @@ class KeyStoreUtilsGroovyTest extends GroovyTestCase {
FileOutputStream fos = new FileOutputStream("/Users/alopresto/Workspace/nifi/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/truststore.no-password.jks")
truststore.store(fos, "".chars)
}
+
+ @Test
+ void testShouldValidateTlsConfigAndNewKeystoreTruststoreWithParams() {
+ // Assert
+ assert tlsConfiguration.getKeystorePath()
+ assert tlsConfiguration.getTruststorePath()
+ assert tlsConfiguration.getKeystoreType() == DEFAULT_STORE_TYPE
+ assert tlsConfiguration.getTruststoreType() == PKCS12_STORE_TYPE
+ assert tlsConfiguration.getKeystorePassword() == TEST_KEYSTORE_PASSWORD
+ }
+
+ @Test
+ void testShouldValidateTlsConfigAndNewKeystoreTruststoreWithoutParams() {
+ // Act
+ TlsConfiguration testTlsConfig = KeyStoreUtils.createTlsConfigAndNewKeystoreTruststore()
+ deleteKeystoreTruststore(testTlsConfig)
+
+ // Assert
+ assert testTlsConfig.getKeystorePath()
+ assert testTlsConfig.getKeyPassword() == testTlsConfig.getKeystorePassword()
+ assert testTlsConfig.getTruststorePassword()
+ assert testTlsConfig.getKeystoreType() == PKCS12_STORE_TYPE
+ assert testTlsConfig.getTruststoreType() == PKCS12_STORE_TYPE
+ }
+
+ @Test
+ void testShouldValidateTlsConfigWithoutKeyPasswordParam() {
+ // Arrange
+ TlsConfiguration testTlsConfigParam = new StandardTlsConfiguration(null, TEST_KEYSTORE_PASSWORD, null, DEFAULT_STORE_TYPE, null, TEST_TRUSTSTORE_PASSWORD, DEFAULT_STORE_TYPE)
+
+ // Act
+ final TlsConfiguration testTlsConfig = KeyStoreUtils.createTlsConfigAndNewKeystoreTruststore(testTlsConfigParam)
+ deleteKeystoreTruststore(testTlsConfig)
+
+ // Assert
+ assert testTlsConfig.getKeyPassword() == testTlsConfig.getKeystorePassword()
+ }
+
+ private static URL getKeystorePathAsUrl(String path) {
+ return new File(path).toURI().toURL()
+ }
+
+ private static void deleteKeystoreTruststore(TlsConfiguration tlsConfig) {
+ if (tlsConfig != null) {
+ try {
+ if (StringUtils.isNotBlank(tlsConfig.getKeystorePath())) {
+ Files.deleteIfExists(Paths.get(tlsConfig.getKeystorePath()))
+ }
+ } catch (IOException e) {
+ throw new IOException("There was an error deleting a keystore: ${e.getMessage()}, ${e}");
+ }
+
+ try {
+ if (StringUtils.isNotBlank(tlsConfig.getTruststorePath())) {
+ Files.deleteIfExists(Paths.get(tlsConfig.getTruststorePath()))
+ }
+ } catch (IOException e) {
+ throw new IOException("There was an error deleting a truststore: ${e.getMessage()}, ${e}");
+ }
+ }
+ }
}
diff --git a/nifi-commons/nifi-security-utils/src/test/java/org/apache/nifi/security/util/KeyStoreUtilsTest.java b/nifi-commons/nifi-security-utils/src/test/java/org/apache/nifi/security/util/KeyStoreUtilsTest.java
index 2a8d1fe..bbf8e8e 100644
--- a/nifi-commons/nifi-security-utils/src/test/java/org/apache/nifi/security/util/KeyStoreUtilsTest.java
+++ b/nifi-commons/nifi-security-utils/src/test/java/org/apache/nifi/security/util/KeyStoreUtilsTest.java
@@ -17,9 +17,6 @@
package org.apache.nifi.security.util;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -31,6 +28,8 @@ import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
+import org.junit.BeforeClass;
+import org.junit.Test;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestInvokeHTTP.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestInvokeHTTP.java
index ee3a62c..0a46bbe 100644
--- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestInvokeHTTP.java
+++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestInvokeHTTP.java
@@ -16,30 +16,27 @@
*/
package org.apache.nifi.processors.standard;
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.net.URL;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.processors.standard.util.TestInvokeHttpCommon;
-import org.apache.nifi.security.util.KeystoreType;
+import org.apache.nifi.security.util.KeyStoreUtils;
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.MockFlowFile;
import org.apache.nifi.util.TestRunners;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -48,30 +45,45 @@ import org.mockito.Mockito;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
public class TestInvokeHTTP extends TestInvokeHttpCommon {
private static final Logger logger = LoggerFactory.getLogger(TestInvokeHTTP.class);
- private static final String TRUSTSTORE_PATH = "src/test/resources/truststore.jks";
- private static final String TRUSTSTORE_PASSWORD = "passwordpassword";
- private 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 TlsConfiguration TLS_CONFIGURATION = new StandardTlsConfiguration(
- KEYSTORE_PATH,
- KEYSTORE_PASSWORD,
- KEYSTORE_TYPE,
- TRUSTSTORE_PATH,
- TRUSTSTORE_PASSWORD,
- TRUSTSTORE_TYPE
- );
+ private static TlsConfiguration tlsConfiguration;
@BeforeClass
public static void beforeClass() throws Exception {
+ // generate new keystore and truststore
+ tlsConfiguration = KeyStoreUtils.createTlsConfigAndNewKeystoreTruststore();
configureServer(null, null);
}
+ @AfterClass
+ public static void afterClass() throws Exception {
+ if (tlsConfiguration != null) {
+ try {
+ if (StringUtils.isNotBlank(tlsConfiguration.getKeystorePath())) {
+ Files.deleteIfExists(Paths.get(tlsConfiguration.getKeystorePath()));
+ }
+ } catch (IOException e) {
+ throw new IOException("There was an error deleting a keystore: " + e.getMessage(), e);
+ }
+
+ try {
+ if (StringUtils.isNotBlank(tlsConfiguration.getTruststorePath())) {
+ Files.deleteIfExists(Paths.get(tlsConfiguration.getTruststorePath()));
+ }
+ } catch (IOException e) {
+ throw new IOException("There was an error deleting a truststore: " + e.getMessage(), e);
+ }
+ }
+ }
+
@Before
public void before() throws Exception {
runner = TestRunners.newTestRunner(InvokeHTTP.class);
@@ -82,9 +94,9 @@ public class TestInvokeHTTP extends TestInvokeHttpCommon {
final String serviceIdentifier = SSLContextService.class.getName();
final SSLContextService sslContextService = Mockito.mock(SSLContextService.class);
Mockito.when(sslContextService.getIdentifier()).thenReturn(serviceIdentifier);
- final SSLContext sslContext = SslContextFactory.createSslContext(TLS_CONFIGURATION);
+ final SSLContext sslContext = SslContextFactory.createSslContext(tlsConfiguration);
Mockito.when(sslContextService.createContext()).thenReturn(sslContext);
- Mockito.when(sslContextService.createTlsConfiguration()).thenReturn(TLS_CONFIGURATION);
+ Mockito.when(sslContextService.createTlsConfiguration()).thenReturn(tlsConfiguration);
runner = TestRunners.newTestRunner(InvokeHTTP.class);
@@ -140,20 +152,20 @@ public class TestInvokeHTTP extends TestInvokeHttpCommon {
runner.setProperty(InvokeHTTP.PROP_URL, "http://nifi.apache.org/"); // just a dummy URL no connection goes out
runner.setProperty(InvokeHTTP.PROP_PROXY_HOST, "${proxy.host}");
- try{
+ try {
runner.run();
Assert.fail();
- } catch (AssertionError e){
+ } catch (AssertionError e) {
// Expect assertion error when proxy port isn't set but host is.
}
runner.setProperty(InvokeHTTP.PROP_PROXY_PORT, "${proxy.port}");
runner.setProperty(InvokeHTTP.PROP_PROXY_USER, "${proxy.username}");
- try{
+ try {
runner.run();
Assert.fail();
- } catch (AssertionError e){
+ } catch (AssertionError e) {
// Expect assertion error when proxy password isn't set but host is.
}
runner.setProperty(InvokeHTTP.PROP_PROXY_PASSWORD, "${proxy.password}");
@@ -433,5 +445,4 @@ public class TestInvokeHTTP extends TestInvokeHttpCommon {
}
}
}
-
}
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 87c10be..67c6e77 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
@@ -17,63 +17,76 @@
package org.apache.nifi.processors.standard;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import javax.net.ssl.SSLContext;
+import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.processors.standard.util.TestInvokeHttpCommon;
import org.apache.nifi.security.util.ClientAuth;
-import org.apache.nifi.security.util.KeystoreType;
+import org.apache.nifi.security.util.KeyStoreUtils;
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.junit.AfterClass;
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
* will not require client certificates and the client will not use keystore properties in the SSLContextService.
*/
public class TestInvokeHttpSSL extends TestInvokeHttpCommon {
- 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
- );
+ protected static TlsConfiguration serverConfiguration;
+
+ private static SSLContext truststoreSslContext;
+ private static TlsConfiguration truststoreConfiguration;
@BeforeClass
public static void beforeClass() throws Exception {
- final SSLContext serverContext = SslContextFactory.createSslContext(SERVER_CONFIGURATION);
+ // generate new keystore and truststore
+ serverConfiguration = KeyStoreUtils.createTlsConfigAndNewKeystoreTruststore();
+
+ truststoreConfiguration = new StandardTlsConfiguration(
+ null,
+ null,
+ null,
+ serverConfiguration.getTruststorePath(),
+ serverConfiguration.getTruststorePassword(),
+ serverConfiguration.getTruststoreType()
+ );
+
+ final SSLContext serverContext = SslContextFactory.createSslContext(serverConfiguration);
configureServer(serverContext, ClientAuth.NONE);
- clientSslContext = SslContextFactory.createSslContext(CLIENT_CONFIGURATION);
+ truststoreSslContext = SslContextFactory.createSslContext(truststoreConfiguration);
+ }
+
+ @AfterClass
+ public static void afterClass() throws Exception {
+ if (serverConfiguration != null) {
+ try {
+ if (StringUtils.isNotBlank(serverConfiguration.getKeystorePath())) {
+ Files.deleteIfExists(Paths.get(serverConfiguration.getKeystorePath()));
+ }
+ } catch (IOException e) {
+ throw new IOException("There was an error deleting a keystore: " + e.getMessage(), e);
+ }
+
+ try {
+ if (StringUtils.isNotBlank(serverConfiguration.getTruststorePath())) {
+ Files.deleteIfExists(Paths.get(serverConfiguration.getTruststorePath()));
+ }
+ } catch (IOException e) {
+ throw new IOException("There was an error deleting a truststore: " + e.getMessage(), e);
+ }
+ }
}
@Before
@@ -82,8 +95,8 @@ public class TestInvokeHttpSSL extends TestInvokeHttpCommon {
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);
+ Mockito.when(sslContextService.createContext()).thenReturn(getClientSslContext());
+ Mockito.when(sslContextService.createTlsConfiguration()).thenReturn(getClientConfiguration());
runner = TestRunners.newTestRunner(InvokeHTTP.class);
runner.addControllerService(serviceIdentifier, sslContextService);
@@ -93,4 +106,12 @@ public class TestInvokeHttpSSL extends TestInvokeHttpCommon {
runner.setProperty(InvokeHTTP.PROP_CONNECT_TIMEOUT, HTTP_CONNECT_TIMEOUT);
runner.setProperty(InvokeHTTP.PROP_READ_TIMEOUT, HTTP_READ_TIMEOUT);
}
+
+ protected SSLContext getClientSslContext() {
+ return truststoreSslContext;
+ }
+
+ protected TlsConfiguration getClientConfiguration() {
+ return truststoreConfiguration;
+ }
}
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 6c3d71d..a068437 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
@@ -17,15 +17,18 @@
package org.apache.nifi.processors.standard;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import javax.net.ssl.SSLContext;
+import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.security.util.ClientAuth;
-import org.apache.nifi.security.util.KeystoreType;
+import org.apache.nifi.security.util.KeyStoreUtils;
import org.apache.nifi.security.util.SslContextFactory;
-import org.apache.nifi.security.util.StandardTlsConfiguration;
import org.apache.nifi.security.util.TlsConfiguration;
+import org.junit.AfterClass;
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
@@ -33,23 +36,48 @@ import javax.net.ssl.SSLContext;
*/
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
- );
+ private static TlsConfiguration serverConfig;
+ private static SSLContext clientSslContext;
@BeforeClass
public static void beforeClass() throws Exception {
- final SSLContext serverContext = SslContextFactory.createSslContext(SERVER_CONFIGURATION);
+ // generate new keystore and truststore
+ serverConfig = KeyStoreUtils.createTlsConfigAndNewKeystoreTruststore();
+
+ final SSLContext serverContext = SslContextFactory.createSslContext(serverConfig);
configureServer(serverContext, ClientAuth.REQUIRED);
- clientSslContext = SslContextFactory.createSslContext(CLIENT_CONFIGURATION);
+ clientSslContext = SslContextFactory.createSslContext(serverConfig);
}
+
+ @AfterClass
+ public static void afterClass() throws Exception {
+ if (serverConfig != null) {
+ try {
+ if (StringUtils.isNotBlank(serverConfig.getKeystorePath())) {
+ Files.deleteIfExists(Paths.get(serverConfig.getKeystorePath()));
+ }
+ } catch (IOException e) {
+ throw new IOException("There was an error deleting a keystore: " + e.getMessage(), e);
+ }
+
+ try {
+ if (StringUtils.isNotBlank(serverConfig.getTruststorePath())) {
+ Files.deleteIfExists(Paths.get(serverConfig.getTruststorePath()));
+ }
+ } catch (IOException e) {
+ throw new IOException("There was an error deleting a truststore: " + e.getMessage(), e);
+ }
+ }
+ }
+
+ @Override
+ protected SSLContext getClientSslContext() {
+ return clientSslContext;
+ }
+
+ @Override
+ protected TlsConfiguration getClientConfiguration() {
+ return serverConfig;
+ }
+
}
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 7fc620a..09caa5c 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
@@ -16,23 +16,23 @@
*/
package org.apache.nifi.processors.standard;
-import static org.apache.nifi.processors.standard.ListenHTTP.RELATIONSHIP_SUCCESS;
-import static org.junit.Assert.assertThrows;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
import com.google.common.base.Charsets;
import com.google.common.base.Optional;
import com.google.common.collect.Iterables;
-import com.google.common.io.Files;
import java.io.DataOutputStream;
import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.GeneralSecurityException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
@@ -51,22 +51,24 @@ import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
-
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
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.KeyStoreUtils;
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.RestrictedSSLContextService;
import org.apache.nifi.ssl.SSLContextService;
import org.apache.nifi.util.MockFlowFile;
import org.apache.nifi.util.TestRunner;
import org.apache.nifi.util.TestRunners;
import org.junit.After;
+import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before;
@@ -74,6 +76,11 @@ import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Mockito;
+import static org.apache.nifi.processors.standard.ListenHTTP.RELATIONSHIP_SUCCESS;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.fail;
+
public class TestListenHTTP {
private static final String SSL_CONTEXT_SERVICE_IDENTIFIER = "ssl-context";
@@ -105,39 +112,12 @@ public class TestListenHTTP {
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 TlsConfiguration tlsConfiguration;
+ private static TlsConfiguration serverConfiguration;
+ private static TlsConfiguration serverTls_1_3_Configuration;
+ private static TlsConfiguration serverNoTruststoreConfiguration;
private static SSLContext serverKeyStoreSslContext;
private static SSLContext serverKeyStoreNoTrustStoreSslContext;
-
private static SSLContext keyStoreSslContext;
private static SSLContext trustStoreSslContext;
@@ -147,29 +127,84 @@ public class TestListenHTTP {
private int availablePort;
@BeforeClass
- 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);
+ public static void setUpSuite() throws GeneralSecurityException, IOException {
+ // generate new keystore and truststore
+ tlsConfiguration = KeyStoreUtils.createTlsConfigAndNewKeystoreTruststore();
+
+ serverConfiguration = new StandardTlsConfiguration(
+ tlsConfiguration.getKeystorePath(),
+ tlsConfiguration.getKeystorePassword(),
+ tlsConfiguration.getKeyPassword(),
+ tlsConfiguration.getKeystoreType(),
+ tlsConfiguration.getTruststorePath(),
+ tlsConfiguration.getTruststorePassword(),
+ tlsConfiguration.getTruststoreType(),
+ TLS_1_2
+ );
+ serverTls_1_3_Configuration = new StandardTlsConfiguration(
+ tlsConfiguration.getKeystorePath(),
+ tlsConfiguration.getKeystorePassword(),
+ tlsConfiguration.getKeyPassword(),
+ tlsConfiguration.getKeystoreType(),
+ tlsConfiguration.getTruststorePath(),
+ tlsConfiguration.getTruststorePassword(),
+ tlsConfiguration.getTruststoreType(),
+ TLS_1_3
+ );
+ serverNoTruststoreConfiguration = new StandardTlsConfiguration(
+ tlsConfiguration.getKeystorePath(),
+ tlsConfiguration.getKeystorePassword(),
+ tlsConfiguration.getKeyPassword(),
+ tlsConfiguration.getKeystoreType(),
+ null,
+ null,
+ null,
+ TLS_1_2
+ );
+
+ serverKeyStoreSslContext = SslContextFactory.createSslContext(serverConfiguration);
+ final TrustManager[] defaultTrustManagers = SslContextFactory.getTrustManagers(serverNoTruststoreConfiguration);
+ serverKeyStoreNoTrustStoreSslContext = SslContextFactory.createSslContext(serverNoTruststoreConfiguration, defaultTrustManagers);
keyStoreSslContext = SslContextFactory.createSslContext(new StandardTlsConfiguration(
- CLIENT_KEYSTORE,
- KEYSTORE_PASSWORD,
- CLIENT_KEYSTORE_TYPE,
- TRUSTSTORE,
- TRUSTSTORE_PASSWORD,
- TRUSTSTORE_TYPE)
+ tlsConfiguration.getKeystorePath(),
+ tlsConfiguration.getKeystorePassword(),
+ tlsConfiguration.getKeystoreType(),
+ tlsConfiguration.getTruststorePath(),
+ tlsConfiguration.getTruststorePassword(),
+ tlsConfiguration.getTruststoreType())
);
trustStoreSslContext = SslContextFactory.createSslContext(new StandardTlsConfiguration(
null,
null,
null,
- TRUSTSTORE,
- TRUSTSTORE_PASSWORD,
- TRUSTSTORE_TYPE)
+ tlsConfiguration.getTruststorePath(),
+ tlsConfiguration.getTruststorePassword(),
+ tlsConfiguration.getTruststoreType())
);
}
+ @AfterClass
+ public static void afterClass() throws Exception {
+ if (tlsConfiguration != null) {
+ try {
+ if (StringUtils.isNotBlank(tlsConfiguration.getKeystorePath())) {
+ Files.deleteIfExists(Paths.get(tlsConfiguration.getKeystorePath()));
+ }
+ } catch (IOException e) {
+ throw new IOException("There was an error deleting a keystore: " + e.getMessage(), e);
+ }
+
+ try {
+ if (StringUtils.isNotBlank(tlsConfiguration.getTruststorePath())) {
+ Files.deleteIfExists(Paths.get(tlsConfiguration.getTruststorePath()));
+ }
+ } catch (IOException e) {
+ throw new IOException("There was an error deleting a truststore: " + e.getMessage(), e);
+ }
+ }
+ }
+
@Before
public void setup() throws IOException {
proc = new ListenHTTP();
@@ -223,7 +258,7 @@ public class TestListenHTTP {
@Test
public void testSecurePOSTRequestsReceivedWithoutEL() throws Exception {
- configureProcessorSslContextService(ListenHTTP.ClientAuthentication.AUTO, SERVER_NO_TRUSTSTORE_CONFIGURATION);
+ configureProcessorSslContextService(ListenHTTP.ClientAuthentication.AUTO, serverNoTruststoreConfiguration);
runner.setProperty(ListenHTTP.PORT, Integer.toString(availablePort));
runner.setProperty(ListenHTTP.BASE_PATH, HTTP_BASE_PATH);
@@ -234,7 +269,7 @@ public class TestListenHTTP {
@Test
public void testSecurePOSTRequestsReturnCodeReceivedWithoutEL() throws Exception {
- configureProcessorSslContextService(ListenHTTP.ClientAuthentication.AUTO, SERVER_NO_TRUSTSTORE_CONFIGURATION);
+ configureProcessorSslContextService(ListenHTTP.ClientAuthentication.AUTO, serverNoTruststoreConfiguration);
runner.setProperty(ListenHTTP.PORT, Integer.toString(availablePort));
runner.setProperty(ListenHTTP.BASE_PATH, HTTP_BASE_PATH);
@@ -246,7 +281,7 @@ public class TestListenHTTP {
@Test
public void testSecurePOSTRequestsReceivedWithEL() throws Exception {
- configureProcessorSslContextService(ListenHTTP.ClientAuthentication.AUTO, SERVER_NO_TRUSTSTORE_CONFIGURATION);
+ configureProcessorSslContextService(ListenHTTP.ClientAuthentication.AUTO, serverNoTruststoreConfiguration);
runner.setProperty(ListenHTTP.PORT, HTTP_SERVER_PORT_EL);
runner.setProperty(ListenHTTP.BASE_PATH, HTTP_SERVER_BASEPATH_EL);
@@ -257,7 +292,7 @@ public class TestListenHTTP {
@Test
public void testSecurePOSTRequestsReturnCodeReceivedWithEL() throws Exception {
- configureProcessorSslContextService(ListenHTTP.ClientAuthentication.AUTO, SERVER_NO_TRUSTSTORE_CONFIGURATION);
+ configureProcessorSslContextService(ListenHTTP.ClientAuthentication.AUTO, serverNoTruststoreConfiguration);
runner.setProperty(ListenHTTP.PORT, Integer.toString(availablePort));
runner.setProperty(ListenHTTP.BASE_PATH, HTTP_BASE_PATH);
@@ -269,7 +304,7 @@ public class TestListenHTTP {
@Test
public void testSecureTwoWaySslPOSTRequestsReceivedWithoutEL() throws Exception {
- configureProcessorSslContextService(ListenHTTP.ClientAuthentication.REQUIRED, SERVER_CONFIGURATION);
+ configureProcessorSslContextService(ListenHTTP.ClientAuthentication.REQUIRED, serverConfiguration);
runner.setProperty(ListenHTTP.PORT, Integer.toString(availablePort));
runner.setProperty(ListenHTTP.BASE_PATH, HTTP_BASE_PATH);
@@ -280,7 +315,7 @@ public class TestListenHTTP {
@Test
public void testSecureTwoWaySslPOSTRequestsReturnCodeReceivedWithoutEL() throws Exception {
- configureProcessorSslContextService(ListenHTTP.ClientAuthentication.REQUIRED, SERVER_CONFIGURATION);
+ configureProcessorSslContextService(ListenHTTP.ClientAuthentication.REQUIRED, serverConfiguration);
runner.setProperty(ListenHTTP.PORT, Integer.toString(availablePort));
runner.setProperty(ListenHTTP.BASE_PATH, HTTP_BASE_PATH);
@@ -292,7 +327,7 @@ public class TestListenHTTP {
@Test
public void testSecureTwoWaySslPOSTRequestsReceivedWithEL() throws Exception {
- configureProcessorSslContextService(ListenHTTP.ClientAuthentication.REQUIRED, SERVER_CONFIGURATION);
+ configureProcessorSslContextService(ListenHTTP.ClientAuthentication.REQUIRED, serverConfiguration);
runner.setProperty(ListenHTTP.PORT, HTTP_SERVER_PORT_EL);
runner.setProperty(ListenHTTP.BASE_PATH, HTTP_SERVER_BASEPATH_EL);
@@ -303,7 +338,7 @@ public class TestListenHTTP {
@Test
public void testSecureTwoWaySslPOSTRequestsReturnCodeReceivedWithEL() throws Exception {
- configureProcessorSslContextService(ListenHTTP.ClientAuthentication.REQUIRED, SERVER_CONFIGURATION);
+ configureProcessorSslContextService(ListenHTTP.ClientAuthentication.REQUIRED, serverConfiguration);
runner.setProperty(ListenHTTP.PORT, Integer.toString(availablePort));
runner.setProperty(ListenHTTP.BASE_PATH, HTTP_BASE_PATH);
@@ -315,12 +350,12 @@ public class TestListenHTTP {
@Test
public void testSecureServerSupportsCurrentTlsProtocolVersion() throws Exception {
- configureProcessorSslContextService(ListenHTTP.ClientAuthentication.AUTO, SERVER_NO_TRUSTSTORE_CONFIGURATION);
+ configureProcessorSslContextService(ListenHTTP.ClientAuthentication.AUTO, serverNoTruststoreConfiguration);
startSecureServer();
final SSLSocketFactory sslSocketFactory = trustStoreSslContext.getSocketFactory();
final SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(LOCALHOST, availablePort);
- final String currentProtocol = SERVER_NO_TRUSTSTORE_CONFIGURATION.getProtocol();
+ final String currentProtocol = serverNoTruststoreConfiguration.getProtocol();
sslSocket.setEnabledProtocols(new String[]{currentProtocol});
sslSocket.startHandshake();
@@ -330,7 +365,7 @@ public class TestListenHTTP {
@Test
public void testSecureServerTrustStoreConfiguredClientAuthenticationRequired() throws Exception {
- configureProcessorSslContextService(ListenHTTP.ClientAuthentication.REQUIRED, SERVER_CONFIGURATION);
+ configureProcessorSslContextService(ListenHTTP.ClientAuthentication.REQUIRED, serverConfiguration);
startSecureServer();
final HttpsURLConnection connection = getSecureConnection(trustStoreSslContext);
assertThrows(SSLException.class, connection::getResponseCode);
@@ -342,7 +377,7 @@ public class TestListenHTTP {
@Test
public void testSecureServerTrustStoreNotConfiguredClientAuthenticationNotRequired() throws Exception {
- configureProcessorSslContextService(ListenHTTP.ClientAuthentication.AUTO, SERVER_NO_TRUSTSTORE_CONFIGURATION);
+ configureProcessorSslContextService(ListenHTTP.ClientAuthentication.AUTO, serverNoTruststoreConfiguration);
startSecureServer();
final HttpsURLConnection connection = getSecureConnection(trustStoreSslContext);
final int responseCode = connection.getResponseCode();
@@ -355,7 +390,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));
- configureProcessorSslContextService(ListenHTTP.ClientAuthentication.AUTO, SERVER_TLS_1_3_CONFIGURATION);
+ configureProcessorSslContextService(ListenHTTP.ClientAuthentication.AUTO, serverTls_1_3_Configuration);
runner.setProperty(ListenHTTP.PORT, Integer.toString(availablePort));
runner.setProperty(ListenHTTP.BASE_PATH, HTTP_BASE_PATH);
@@ -541,11 +576,14 @@ public class TestListenHTTP {
Runnable sendRequestToWebserver = () -> {
try {
+ File file1 = createTextFile("my-file-text-", ".txt", "Hello", "World");
+ File file2 = createTextFile("my-file-text-", ".txt", "{ \"name\":\"John\", \"age\":30 }");
+
MultipartBody multipartBody = new MultipartBody.Builder().setType(MultipartBody.FORM)
.addFormDataPart("p1", "v1")
.addFormDataPart("p2", "v2")
- .addFormDataPart("file1", "my-file-text.txt", RequestBody.create(MediaType.parse("text/plain"), createTextFile("my-file-text.txt", "Hello", "World")))
- .addFormDataPart("file2", "my-file-data.json", RequestBody.create(MediaType.parse("application/json"), createTextFile("my-file-text.txt", "{ \"name\":\"John\", \"age\":30 }")))
+ .addFormDataPart("file1", "my-file-text.txt", RequestBody.create(MediaType.parse("text/plain"), file1))
+ .addFormDataPart("file2", "my-file-data.json", RequestBody.create(MediaType.parse("application/json"), file2))
.addFormDataPart("file3", "my-file-binary.bin", RequestBody.create(MediaType.parse("application/octet-stream"), generateRandomBinaryData(100)))
.build();
@@ -562,6 +600,8 @@ public class TestListenHTTP {
.build();
try (Response response = client.newCall(request).execute()) {
+ Files.deleteIfExists(Paths.get(String.valueOf(file1)));
+ Files.deleteIfExists(Paths.get(String.valueOf(file2)));
Assert.assertTrue(String.format("Unexpected code: %s, body: %s", response.code(), response.body().string()), response.isSuccessful());
}
} catch (final Throwable t) {
@@ -625,13 +665,12 @@ public class TestListenHTTP {
return bytes;
}
- private File createTextFile(String fileName, String... lines) throws IOException {
- File file = new File("target/" + fileName);
- file.deleteOnExit();
- for (String string : lines) {
- Files.append(string, file, Charsets.UTF_8);
+ private File createTextFile(String prefix, String extension, String...lines) throws IOException {
+ Path file = Files.createTempFile(prefix, extension);
+ try (FileOutputStream fos = new FileOutputStream(file.toFile())) {
+ IOUtils.writeLines(Arrays.asList(lines), System.lineSeparator(), fos, Charsets.UTF_8);
}
- return file;
+ return file.toFile();
}
protected MockFlowFile findFlowFile(List<MockFlowFile> flowFilesForRelationship, String attributeName, String attributeValue) {
diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/util/TestInvokeHttpCommon.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/util/TestInvokeHttpCommon.java
index b787e25..c20e9ca 100644
--- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/util/TestInvokeHttpCommon.java
+++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/util/TestInvokeHttpCommon.java
@@ -17,12 +17,6 @@
package org.apache.nifi.processors.standard.util;
-import static org.apache.commons.codec.binary.Base64.encodeBase64;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
@@ -39,7 +33,6 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
-
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.expression.ExpressionLanguageScope;
import org.apache.nifi.flowfile.attributes.CoreAttributes;
@@ -70,6 +63,12 @@ import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Test;
+import static org.apache.commons.codec.binary.Base64.encodeBase64;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
public abstract class TestInvokeHttpCommon {
protected static Server server;