diff --git a/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/NiFiSystemKeyStoreProvider.java b/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/NiFiSystemKeyStoreProvider.java new file mode 100644 index 0000000000..2a80103c80 --- /dev/null +++ b/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/NiFiSystemKeyStoreProvider.java @@ -0,0 +1,143 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.tests.system; + +import org.apache.nifi.security.util.CertificateUtils; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; + +/** + * System Key Store Provider generates a Key Pair and Certificate for KeyStore and TrustStore files + */ +public class NiFiSystemKeyStoreProvider { + private static final String HOSTNAME = "localhost"; + + private static final String[] DNS_NAMES = new String[]{HOSTNAME}; + + private static final String DISTINGUISHED_NAME = String.format("CN=%s", HOSTNAME); + + private static final String PASSWORD = NiFiSystemKeyStoreProvider.class.getSimpleName(); + + private static final int VALID_DURATION_DAYS = 1; + + private static final String KEY_ALGORITHM = "RSA"; + + private static final int KEY_SIZE = 4096; + + private static final String SIGNING_ALGORITHM = "SHA256withRSA"; + + private static final String KEYSTORE_FILE = "keystore.p12"; + + private static final String TRUSTSTORE_FILE = "truststore.p12"; + + private static final String KEYSTORE_TYPE = "PKCS12"; + + private static Path persistentKeyStorePath; + + private static Path persistentTrustStorePath; + + /** + * Configure KeyStores in provided directory and reuse existing files after initial generation + * + * @param keyStoreDirectory Directory where KeyStore and TrustStore should be stored + */ + public synchronized static void configureKeyStores(final File keyStoreDirectory) { + if (persistentKeyStorePath == null) { + createKeyStores(); + } + + if (persistentKeyStorePath == null) { + throw new IllegalStateException("KeyStore not provisioned"); + } + if (persistentTrustStorePath == null) { + throw new IllegalStateException("TrustStore not provisioned"); + } + + try { + Files.copy(persistentKeyStorePath, Paths.get(keyStoreDirectory.getAbsolutePath(), KEYSTORE_FILE)); + Files.copy(persistentTrustStorePath, Paths.get(keyStoreDirectory.getAbsolutePath(), TRUSTSTORE_FILE)); + } catch (final IOException e) { + throw new UncheckedIOException("KeyStore configuration failed", e); + } + } + + private static void createKeyStores() { + try { + final KeyPair keyPair = getKeyPair(); + final X509Certificate certificate = CertificateUtils.generateSelfSignedX509Certificate( + keyPair, + DISTINGUISHED_NAME, + SIGNING_ALGORITHM, + VALID_DURATION_DAYS, + DNS_NAMES + ); + + persistentTrustStorePath = writeTrustStore(certificate); + persistentTrustStorePath.toFile().deleteOnExit(); + + persistentKeyStorePath = writeKeyStore(certificate, keyPair.getPrivate()); + persistentKeyStorePath.toFile().deleteOnExit(); + } catch (final Exception e) { + throw new RuntimeException("KeyStore Creation Failed", e); + } + } + + private static Path writeKeyStore(final X509Certificate certificate, final PrivateKey privateKey) throws Exception { + final KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE); + keyStore.load(null); + + final X509Certificate[] certificates = new X509Certificate[]{certificate}; + keyStore.setKeyEntry(HOSTNAME, privateKey, PASSWORD.toCharArray(), certificates); + + final Path keyStorePath = Files.createTempFile(KEYSTORE_FILE, KEYSTORE_TYPE); + try (final OutputStream outputStream = new FileOutputStream(keyStorePath.toFile())) { + keyStore.store(outputStream, PASSWORD.toCharArray()); + } + return keyStorePath; + } + + private static Path writeTrustStore(final X509Certificate certificate) throws Exception { + final KeyStore trustStore = KeyStore.getInstance(KEYSTORE_TYPE); + trustStore.load(null); + trustStore.setCertificateEntry(HOSTNAME, certificate); + + final Path trustStorePath = Files.createTempFile(TRUSTSTORE_FILE, KEYSTORE_TYPE); + try (final OutputStream outputStream = new FileOutputStream(trustStorePath.toFile())) { + trustStore.store(outputStream, PASSWORD.toCharArray()); + } + return trustStorePath; + } + + private static KeyPair getKeyPair() throws NoSuchAlgorithmException { + final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM); + keyPairGenerator.initialize(KEY_SIZE); + return keyPairGenerator.generateKeyPair(); + } +} diff --git a/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/SpawnedStandaloneNiFiInstanceFactory.java b/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/SpawnedStandaloneNiFiInstanceFactory.java index f14e4d325a..6bb1ee4a6a 100644 --- a/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/SpawnedStandaloneNiFiInstanceFactory.java +++ b/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/SpawnedStandaloneNiFiInstanceFactory.java @@ -33,7 +33,6 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.nio.file.Files; -import java.nio.file.Paths; import java.util.Collections; import java.util.Map; import java.util.Properties; @@ -127,14 +126,7 @@ public class SpawnedStandaloneNiFiInstanceFactory implements NiFiInstanceFactory if (!destinationCertsDir.exists()) { assertTrue(destinationCertsDir.mkdirs()); } - - // Copy keystore - final File destinationKeystore = new File(destinationCertsDir, "keystore.jks"); - Files.copy(Paths.get("src/test/resources/keystore.jks"), destinationKeystore.toPath()); - - // Copy truststore - final File destinationTruststore = new File(destinationCertsDir, "truststore.jks"); - Files.copy(Paths.get("src/test/resources/truststore.jks"), destinationTruststore.toPath()); + NiFiSystemKeyStoreProvider.configureKeyStores(destinationCertsDir); final File flowXmlGz = instanceConfiguration.getFlowXmlGz(); if (flowXmlGz != null) { @@ -203,9 +195,8 @@ public class SpawnedStandaloneNiFiInstanceFactory implements NiFiInstanceFactory try { Thread.sleep(1000L); } catch (InterruptedException ex) { + logger.debug("NiFi Startup sleep interrupted", ex); } - - continue; } } } diff --git a/nifi-system-tests/nifi-system-test-suite/src/test/resources/conf/clustered/node1/nifi.properties b/nifi-system-tests/nifi-system-test-suite/src/test/resources/conf/clustered/node1/nifi.properties index 7066fba407..071f863a0f 100644 --- a/nifi-system-tests/nifi-system-test-suite/src/test/resources/conf/clustered/node1/nifi.properties +++ b/nifi-system-tests/nifi-system-test-suite/src/test/resources/conf/clustered/node1/nifi.properties @@ -146,13 +146,13 @@ nifi.sensitive.props.key.protected= nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL nifi.sensitive.props.additional.keys= -nifi.security.keystore=certs/keystore.jks -nifi.security.keystoreType=JKS -nifi.security.keystorePasswd=passwordpassword -nifi.security.keyPasswd= -nifi.security.truststore=certs/truststore.jks -nifi.security.truststoreType=JKS -nifi.security.truststorePasswd=passwordpassword +nifi.security.keystore=certs/keystore.p12 +nifi.security.keystoreType=PKCS12 +nifi.security.keystorePasswd=NiFiSystemKeyStoreProvider +nifi.security.keyPasswd=NiFiSystemKeyStoreProvider +nifi.security.truststore=certs/truststore.p12 +nifi.security.truststoreType=PKCS12 +nifi.security.truststorePasswd=NiFiSystemKeyStoreProvider nifi.security.user.authorizer=managed-authorizer nifi.security.user.login.identity.provider= nifi.security.ocsp.responder.url= diff --git a/nifi-system-tests/nifi-system-test-suite/src/test/resources/conf/clustered/node2/nifi.properties b/nifi-system-tests/nifi-system-test-suite/src/test/resources/conf/clustered/node2/nifi.properties index 2d6f7510ea..4420403e9c 100644 --- a/nifi-system-tests/nifi-system-test-suite/src/test/resources/conf/clustered/node2/nifi.properties +++ b/nifi-system-tests/nifi-system-test-suite/src/test/resources/conf/clustered/node2/nifi.properties @@ -146,13 +146,13 @@ nifi.sensitive.props.key.protected= nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL nifi.sensitive.props.additional.keys= -nifi.security.keystore=certs/keystore.jks -nifi.security.keystoreType=JKS -nifi.security.keystorePasswd=passwordpassword -nifi.security.keyPasswd= -nifi.security.truststore=certs/truststore.jks -nifi.security.truststoreType=JKS -nifi.security.truststorePasswd=passwordpassword +nifi.security.keystore=certs/keystore.p12 +nifi.security.keystoreType=PKCS12 +nifi.security.keystorePasswd=NiFiSystemKeyStoreProvider +nifi.security.keyPasswd=NiFiSystemKeyStoreProvider +nifi.security.truststore=certs/truststore.p12 +nifi.security.truststoreType=PKCS12 +nifi.security.truststorePasswd=NiFiSystemKeyStoreProvider nifi.security.user.authorizer=managed-authorizer nifi.security.user.login.identity.provider= nifi.security.ocsp.responder.url= diff --git a/nifi-system-tests/nifi-system-test-suite/src/test/resources/conf/default/nifi.properties b/nifi-system-tests/nifi-system-test-suite/src/test/resources/conf/default/nifi.properties index e9c00352eb..27ad177583 100644 --- a/nifi-system-tests/nifi-system-test-suite/src/test/resources/conf/default/nifi.properties +++ b/nifi-system-tests/nifi-system-test-suite/src/test/resources/conf/default/nifi.properties @@ -147,13 +147,13 @@ nifi.sensitive.props.key.protected= nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL nifi.sensitive.props.additional.keys= -nifi.security.keystore=certs/keystore.jks -nifi.security.keystoreType=JKS -nifi.security.keystorePasswd=passwordpassword -nifi.security.keyPasswd= -nifi.security.truststore=certs/truststore.jks -nifi.security.truststoreType=JKS -nifi.security.truststorePasswd=passwordpassword +nifi.security.keystore=certs/keystore.p12 +nifi.security.keystoreType=PKCS12 +nifi.security.keystorePasswd=NiFiSystemKeyStoreProvider +nifi.security.keyPasswd=NiFiSystemKeyStoreProvider +nifi.security.truststore=certs/truststore.p12 +nifi.security.truststoreType=PKCS12 +nifi.security.truststorePasswd=NiFiSystemKeyStoreProvider nifi.security.user.authorizer=managed-authorizer nifi.security.user.login.identity.provider= nifi.security.ocsp.responder.url= diff --git a/nifi-system-tests/nifi-system-test-suite/src/test/resources/keystore.jks b/nifi-system-tests/nifi-system-test-suite/src/test/resources/keystore.jks deleted file mode 100644 index 34a197f365..0000000000 Binary files a/nifi-system-tests/nifi-system-test-suite/src/test/resources/keystore.jks and /dev/null differ diff --git a/nifi-system-tests/nifi-system-test-suite/src/test/resources/truststore.jks b/nifi-system-tests/nifi-system-test-suite/src/test/resources/truststore.jks deleted file mode 100644 index 4bc1b2050b..0000000000 Binary files a/nifi-system-tests/nifi-system-test-suite/src/test/resources/truststore.jks and /dev/null differ