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 <exceptionfactory@apache.org>
This commit is contained in:
mtien 2020-12-15 18:08:26 -08:00 committed by exceptionfactory
parent 5a8b18b12d
commit 6e1f737c53
No known key found for this signature in database
GPG Key ID: 29B6A52D2AAE8DBA
8 changed files with 565 additions and 179 deletions

View File

@ -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
*
@ -111,6 +145,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.
*
@ -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);
}
}

View File

@ -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}");
}
}
}
}

View File

@ -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;

View File

@ -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 {
}
}
}
}

View File

@ -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 TlsConfiguration serverConfiguration;
protected static SSLContext clientSslContext;
private static final TlsConfiguration CLIENT_CONFIGURATION = new StandardTlsConfiguration(
null,
null,
null,
TRUSTSTORE_PATH,
TRUSTSTORE_PASSWORD,
TRUSTSTORE_TYPE
);
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;
}
}

View File

@ -17,14 +17,17 @@
package org.apache.nifi.processors.standard;
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 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.KeyStoreUtils;
import org.apache.nifi.security.util.SslContextFactory;
import org.apache.nifi.security.util.TlsConfiguration;
import org.junit.AfterClass;
import org.junit.BeforeClass;
/**
* This is probably overkill but in keeping with the same pattern as the TestInvokeHttp and TestInvokeHttpSSL class,
@ -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;
}
}

View File

@ -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) {

View File

@ -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;