mirror of https://github.com/apache/nifi.git
NIFI-12021 Refactored Groovy TLS Toolkit Tests to Java
This closes #7674 Signed-off-by: David Handermann <exceptionfactory@apache.org>
This commit is contained in:
parent
47f4c8ce2e
commit
796ae2f5d1
|
@ -90,11 +90,6 @@
|
|||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
<artifactId>groovy-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
|
|
|
@ -1,214 +0,0 @@
|
|||
/*
|
||||
* 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.toolkit.tls.standalone
|
||||
|
||||
import org.apache.nifi.security.cert.builder.StandardCertificateBuilder
|
||||
import org.apache.nifi.toolkit.tls.configuration.StandaloneConfig
|
||||
import org.bouncycastle.openssl.jcajce.JcaMiscPEMGenerator
|
||||
import org.bouncycastle.util.io.pem.PemWriter
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
|
||||
import javax.security.auth.x500.X500Principal
|
||||
import java.nio.file.Files
|
||||
import java.security.KeyPair
|
||||
import java.security.KeyPairGenerator
|
||||
import java.security.SignatureException
|
||||
import java.security.cert.X509Certificate
|
||||
import java.time.Duration
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows
|
||||
|
||||
class TlsToolkitStandaloneGroovyTest {
|
||||
private final String TEST_SRC_DIR = "src/test/resources/"
|
||||
private final String DEFAULT_KEY_PAIR_ALGORITHM = "RSA"
|
||||
|
||||
@Test
|
||||
void testShouldVerifyCertificateSignatureWhenSelfSigned(@TempDir File tempDir) {
|
||||
// Arrange
|
||||
|
||||
// Create a temp directory for this test and populate it with the nifi-cert.pem and nifi-key.key files
|
||||
File baseDir = createBaseDirAndPopulateWithCAFiles(tempDir)
|
||||
|
||||
// Make a standalone config which doesn't trigger any keystore generation and just has a self-signed cert and key
|
||||
StandaloneConfig standaloneConfig = new StandaloneConfig()
|
||||
standaloneConfig.setBaseDir(baseDir)
|
||||
standaloneConfig.setInstanceDefinitions([])
|
||||
standaloneConfig.setClientDns([])
|
||||
standaloneConfig.initDefaults()
|
||||
|
||||
TlsToolkitStandalone standalone = new TlsToolkitStandalone()
|
||||
|
||||
// Act
|
||||
standalone.createNifiKeystoresAndTrustStores(standaloneConfig)
|
||||
|
||||
// Assert
|
||||
|
||||
// The test will fail with an exception if the certificate is not signed by a known certificate
|
||||
}
|
||||
|
||||
/**
|
||||
* The certificate under examination is self-signed, but there is another signing cert which will be iterated over first, fail, and then the self-signed signature will be validated.
|
||||
*/
|
||||
@Test
|
||||
void testShouldVerifyCertificateSignatureWithMultipleSigningCerts(@TempDir File tempDir) {
|
||||
// Create a temp directory for this test and populate it with the nifi-cert.pem and nifi-key.key files
|
||||
File baseDir = createBaseDirAndPopulateWithCAFiles(tempDir)
|
||||
|
||||
// Create a different cert and persist it to the base dir
|
||||
X509Certificate otherCert = generateX509Certificate()
|
||||
File otherCertFile = writeCertificateToPEMFile(otherCert, "${baseDir.path}/other.pem")
|
||||
|
||||
// Make a standalone config which doesn't trigger any keystore generation and just has a self-signed cert and key
|
||||
StandaloneConfig standaloneConfig = new StandaloneConfig()
|
||||
standaloneConfig.setBaseDir(baseDir)
|
||||
standaloneConfig.setInstanceDefinitions([])
|
||||
standaloneConfig.setClientDns([])
|
||||
standaloneConfig.initDefaults()
|
||||
|
||||
// Inject the additional CA cert path
|
||||
standaloneConfig.setAdditionalCACertificate(otherCertFile.path)
|
||||
|
||||
TlsToolkitStandalone standalone = new TlsToolkitStandalone()
|
||||
|
||||
// Act
|
||||
standalone.createNifiKeystoresAndTrustStores(standaloneConfig)
|
||||
}
|
||||
|
||||
/**
|
||||
* The certificate under examination is signed with the external signing cert.
|
||||
*/
|
||||
@Test
|
||||
void testShouldVerifyCertificateSignatureWithAdditionalSigningCert(@TempDir File baseDir) {
|
||||
// Create a root CA, create an intermediate CA, use the root to sign the intermediate and then provide the root
|
||||
KeyPair rootKeyPair = generateKeyPair()
|
||||
X509Certificate rootCert = generateX509Certificate("CN=Root CA", rootKeyPair)
|
||||
|
||||
File rootCertFile = writeCertificateToPEMFile(rootCert, "${baseDir.path}/root.pem")
|
||||
|
||||
KeyPair intermediateKeyPair = generateKeyPair()
|
||||
X509Certificate intermediateCert = new StandardCertificateBuilder(rootKeyPair, rootCert.getIssuerX500Principal(), Duration.ofDays(1))
|
||||
.setSubject(new X500Principal("CN=Intermediate CA"))
|
||||
.setSubjectPublicKey(intermediateKeyPair.getPublic())
|
||||
.build()
|
||||
|
||||
File intermediateCertFile = writeCertificateToPEMFile(intermediateCert, "${baseDir.path}/nifi-cert.pem")
|
||||
|
||||
// Write the private key of the intermediate cert to nifi-key.key
|
||||
File intermediateKeyFile = writePrivateKeyToFile(intermediateKeyPair, "${baseDir}/nifi-key.key")
|
||||
|
||||
// Make a standalone config which doesn't trigger any keystore generation and just has a signed cert and key
|
||||
StandaloneConfig standaloneConfig = new StandaloneConfig()
|
||||
standaloneConfig.setBaseDir(baseDir)
|
||||
standaloneConfig.setInstanceDefinitions([])
|
||||
standaloneConfig.setClientDns([])
|
||||
standaloneConfig.initDefaults()
|
||||
|
||||
// Inject the additional CA cert path
|
||||
standaloneConfig.setAdditionalCACertificate(rootCertFile.path)
|
||||
|
||||
TlsToolkitStandalone standalone = new TlsToolkitStandalone()
|
||||
|
||||
// Act
|
||||
standalone.createNifiKeystoresAndTrustStores(standaloneConfig)
|
||||
}
|
||||
|
||||
@Test
|
||||
void testShouldNotVerifyCertificateSignatureWithWrongSigningCert(@TempDir File baseDir) {
|
||||
// Create a root CA, create an intermediate CA, use the root to sign the intermediate and then do not provide the root
|
||||
KeyPair rootKeyPair = generateKeyPair()
|
||||
X509Certificate rootCert = generateX509Certificate("CN=Root CA", rootKeyPair)
|
||||
|
||||
KeyPair intermediateKeyPair = generateKeyPair()
|
||||
X509Certificate intermediateCert = new StandardCertificateBuilder(rootKeyPair, rootCert.getIssuerX500Principal(), Duration.ofDays(1))
|
||||
.setSubject(new X500Principal("CN=Intermediate CA"))
|
||||
.setSubjectPublicKey(intermediateKeyPair.getPublic())
|
||||
.build()
|
||||
|
||||
File intermediateCertFile = writeCertificateToPEMFile(intermediateCert, "${baseDir.path}/nifi-cert.pem")
|
||||
|
||||
// Write the private key of the intermediate cert to nifi-key.key
|
||||
File intermediateKeyFile = writePrivateKeyToFile(intermediateKeyPair, "${baseDir.path}/nifi-key.key")
|
||||
|
||||
// Make a standalone config which doesn't trigger any keystore generation and just has a signed cert and key
|
||||
StandaloneConfig standaloneConfig = new StandaloneConfig()
|
||||
standaloneConfig.setBaseDir(baseDir)
|
||||
standaloneConfig.setInstanceDefinitions([])
|
||||
standaloneConfig.setClientDns([])
|
||||
standaloneConfig.initDefaults()
|
||||
|
||||
TlsToolkitStandalone standalone = new TlsToolkitStandalone()
|
||||
|
||||
assertThrows(SignatureException.class, () -> standalone.createNifiKeystoresAndTrustStores(standaloneConfig))
|
||||
}
|
||||
|
||||
private static File writePrivateKeyToFile(KeyPair intermediateKeyPair, String destination) {
|
||||
File intermediateKeyFile = new File(destination)
|
||||
PemWriter pemWriter = new PemWriter(new FileWriter(intermediateKeyFile))
|
||||
pemWriter.writeObject(new JcaMiscPEMGenerator(intermediateKeyPair))
|
||||
pemWriter.close()
|
||||
intermediateKeyFile
|
||||
}
|
||||
|
||||
private File createBaseDirAndPopulateWithCAFiles(File baseDir) {
|
||||
populateBaseDirWithCAFiles(baseDir)
|
||||
}
|
||||
|
||||
private File populateBaseDirWithCAFiles(File baseDir) {
|
||||
File certificateFile = new File(TEST_SRC_DIR, "rootCert.crt")
|
||||
File keyFile = new File(TEST_SRC_DIR, "rootCert.key")
|
||||
File destinationCertFile = new File(baseDir.path, "nifi-cert.pem")
|
||||
Files.copy(certificateFile.toPath(), destinationCertFile.toPath())
|
||||
File destinationKeyFile = new File(baseDir.path, "nifi-key.key")
|
||||
Files.copy(keyFile.toPath(), destinationKeyFile.toPath())
|
||||
|
||||
baseDir
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link X509Certificate} with the provided DN and default algorithms. The validity period is only 1 day.
|
||||
*
|
||||
* @param dn the DN (defaults to {@code CN=Test Certificate})
|
||||
* @return the X509Certificate
|
||||
*/
|
||||
private X509Certificate generateX509Certificate(String dn = "CN=Test Certificate", KeyPair keyPair = generateKeyPair()) {
|
||||
new StandardCertificateBuilder(keyPair, new X500Principal(dn), Duration.ofDays(1)).build()
|
||||
}
|
||||
|
||||
private KeyPair generateKeyPair() {
|
||||
KeyPairGenerator instance = KeyPairGenerator.getInstance(DEFAULT_KEY_PAIR_ALGORITHM)
|
||||
instance.initialize(2048)
|
||||
instance.generateKeyPair()
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the provided {@link X509Certificate} to the specified file in PEM format.
|
||||
*
|
||||
* @param certificate the certificate
|
||||
* @param destination the path to write the certificate in PEM format
|
||||
* @return the file
|
||||
*/
|
||||
private static File writeCertificateToPEMFile(X509Certificate certificate, String destination) {
|
||||
File certificateFile = new File(destination)
|
||||
PemWriter pemWriter = new PemWriter(new FileWriter(certificateFile))
|
||||
pemWriter.writeObject(new JcaMiscPEMGenerator(certificate))
|
||||
pemWriter.close()
|
||||
|
||||
certificateFile
|
||||
}
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
/*
|
||||
* 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.toolkit.tls.util
|
||||
|
||||
import org.bouncycastle.crypto.params.RSAKeyParameters
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPublicKey
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||
import org.junit.jupiter.api.BeforeAll
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
import javax.security.auth.x500.X500Principal
|
||||
import java.security.KeyPair
|
||||
import java.security.PrivateKey
|
||||
import java.security.Security
|
||||
import java.security.cert.X509Certificate
|
||||
|
||||
class TlsHelperGroovyTest {
|
||||
|
||||
@BeforeAll
|
||||
static void setProvider() {
|
||||
System.setProperty("org.bouncycastle.rsa.allow_unsafe_mod","true")
|
||||
Security.addProvider(new BouncyCastleProvider())
|
||||
BCRSAPublicKey badPublicKey = new BCRSAPublicKey(new RSAKeyParameters(false, new BigInteger("3", 10), new BigInteger("1", 10)))
|
||||
}
|
||||
|
||||
@Test
|
||||
void testShouldVerifyCertificateSignatureWhenSelfSigned() {
|
||||
File certificateFile = new File("src/test/resources/rootCert.crt")
|
||||
FileReader certReader = new FileReader(certificateFile)
|
||||
X509Certificate certificate = TlsHelper.parseCertificate(certReader)
|
||||
|
||||
boolean isCertificateSigned = TlsHelper.verifyCertificateSignature(certificate, [certificate])
|
||||
assert isCertificateSigned
|
||||
}
|
||||
|
||||
@Test
|
||||
void testShouldVerifyCertificateSignatureWithMultipleSigningCerts() {
|
||||
File certificateFile = new File("src/test/resources/rootCert.crt")
|
||||
FileReader certReader = new FileReader(certificateFile)
|
||||
X509Certificate certificate = TlsHelper.parseCertificate(certReader)
|
||||
|
||||
X509Certificate mockCertificate = [
|
||||
getSubjectX500Principal: { -> new X500Principal("CN=Mock Certificate") },
|
||||
getPublicKey : { -> badPublicKey }
|
||||
] as X509Certificate
|
||||
|
||||
boolean isCertificateSigned = TlsHelper.verifyCertificateSignature(certificate, [mockCertificate, certificate])
|
||||
assert isCertificateSigned
|
||||
}
|
||||
|
||||
@Test
|
||||
void testShouldNotVerifyCertificateSignatureWithNoSigningCerts() {
|
||||
File certificateFile = new File("src/test/resources/rootCert.crt")
|
||||
FileReader certReader = new FileReader(certificateFile)
|
||||
X509Certificate certificate = TlsHelper.parseCertificate(certReader)
|
||||
|
||||
boolean isCertificateSigned = TlsHelper.verifyCertificateSignature(certificate, [])
|
||||
assert !isCertificateSigned
|
||||
}
|
||||
|
||||
@Test
|
||||
void testShouldNotVerifyCertificateSignatureWithWrongSigningCert() {
|
||||
File certificateFile = new File("src/test/resources/rootCert.crt")
|
||||
FileReader certReader = new FileReader(certificateFile)
|
||||
X509Certificate certificate = TlsHelper.parseCertificate(certReader)
|
||||
|
||||
X509Certificate mockCertificate = [
|
||||
getSubjectX500Principal: { -> new X500Principal("CN=Mock Certificate") },
|
||||
getPublicKey : { -> badPublicKey }
|
||||
] as X509Certificate
|
||||
|
||||
boolean isCertificateSigned = TlsHelper.verifyCertificateSignature(certificate, [mockCertificate])
|
||||
assert !isCertificateSigned
|
||||
}
|
||||
|
||||
@Test
|
||||
void testParseKeyPairFromReaderShouldHandlePKCS8PrivateKey() {
|
||||
File keyFile = new File("src/test/resources/rootCert-pkcs8.key")
|
||||
FileReader keyReader = new FileReader(keyFile)
|
||||
|
||||
final KeyPair expectedKeyPair = TlsHelper.parseKeyPairFromReader(new FileReader(new File ("src/test/resources/rootCert.key")))
|
||||
final PrivateKey EXPECTED_PRIVATE_KEY = expectedKeyPair.getPrivate()
|
||||
|
||||
KeyPair keyPair = TlsHelper.parseKeyPairFromReader(keyReader)
|
||||
assert keyPair.private == EXPECTED_PRIVATE_KEY
|
||||
}
|
||||
}
|
|
@ -17,77 +17,79 @@
|
|||
|
||||
package org.apache.nifi.toolkit.tls.standalone;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.nifi.security.util.KeystoreType;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.nifi.security.cert.builder.StandardCertificateBuilder;
|
||||
import org.apache.nifi.security.util.KeyStoreUtils;
|
||||
import org.apache.nifi.security.util.KeystoreType;
|
||||
import org.apache.nifi.toolkit.tls.SystemExitCapturer;
|
||||
import org.apache.nifi.toolkit.tls.commandLine.BaseTlsToolkitCommandLine;
|
||||
import org.apache.nifi.toolkit.tls.commandLine.ExitCode;
|
||||
import org.apache.nifi.toolkit.tls.configuration.TlsConfig;
|
||||
import org.apache.nifi.toolkit.tls.configuration.InstanceIdentifier;
|
||||
import org.apache.nifi.toolkit.tls.configuration.StandaloneConfig;
|
||||
import org.apache.nifi.toolkit.tls.configuration.TlsConfig;
|
||||
import org.apache.nifi.toolkit.tls.service.TlsCertificateAuthorityTest;
|
||||
import org.apache.nifi.toolkit.tls.util.TlsHelper;
|
||||
import org.apache.nifi.toolkit.tls.util.TlsHelperTest;
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
import org.bouncycastle.asn1.x509.GeneralName;
|
||||
import org.bouncycastle.openssl.jcajce.JcaMiscPEMGenerator;
|
||||
import org.bouncycastle.util.io.pem.PemWriter;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.KeyStore;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.SignatureException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class TlsToolkitStandaloneTest {
|
||||
public static final String NIFI_FAKE_PROPERTY = "nifi.fake.property";
|
||||
public static final String FAKE_VALUE = "fake value";
|
||||
public static final String TEST_NIFI_PROPERTIES = "src/test/resources/localhost/nifi.properties";
|
||||
public static final Logger logger = LoggerFactory.getLogger(TlsToolkitStandaloneTest.class);
|
||||
private SystemExitCapturer systemExitCapturer;
|
||||
|
||||
@TempDir
|
||||
private File tempDir;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() throws IOException {
|
||||
tempDir = File.createTempFile("tls-test", UUID.randomUUID().toString());
|
||||
if (!tempDir.delete()) {
|
||||
throw new IOException("Couldn't delete " + tempDir);
|
||||
}
|
||||
|
||||
if (!tempDir.mkdirs()) {
|
||||
throw new IOException("Couldn't make directory " + tempDir);
|
||||
}
|
||||
systemExitCapturer = new SystemExitCapturer();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void teardown() throws IOException {
|
||||
public void teardown() {
|
||||
systemExitCapturer.close();
|
||||
FileUtils.deleteDirectory(tempDir);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -104,7 +106,7 @@ public class TlsToolkitStandaloneTest {
|
|||
@Test
|
||||
public void testDirOutput() throws Exception {
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", TlsConfig.DEFAULT_HOSTNAME);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey();
|
||||
|
||||
Properties nifiProperties = checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
|
||||
assertNull(nifiProperties.get("nifi.fake.property"));
|
||||
|
@ -114,7 +116,7 @@ public class TlsToolkitStandaloneTest {
|
|||
@Test
|
||||
public void testDifferentArg() throws Exception {
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-g", "-n", TlsConfig.DEFAULT_HOSTNAME);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey();
|
||||
|
||||
Properties nifiProperties = checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
|
||||
assertNull(nifiProperties.get("nifi.fake.property"));
|
||||
|
@ -124,7 +126,7 @@ public class TlsToolkitStandaloneTest {
|
|||
@Test
|
||||
public void testFileArg() throws Exception {
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-f", TEST_NIFI_PROPERTIES, "-n", TlsConfig.DEFAULT_HOSTNAME);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey();
|
||||
|
||||
Properties nifiProperties = checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
|
||||
assertEquals(FAKE_VALUE, nifiProperties.get(NIFI_FAKE_PROPERTY));
|
||||
|
@ -137,7 +139,7 @@ public class TlsToolkitStandaloneTest {
|
|||
String nifi3 = "nifi3";
|
||||
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nifi1 + "," + nifi2);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey();
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nifi3);
|
||||
|
||||
checkHostDirAndReturnNifiProperties(nifi1, x509Certificate);
|
||||
|
@ -152,7 +154,7 @@ public class TlsToolkitStandaloneTest {
|
|||
String nifi = "nifi";
|
||||
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nifi);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey();
|
||||
checkHostDirAndReturnNifiProperties(nifi, x509Certificate);
|
||||
runAndAssertExitCode(ExitCode.ERROR_GENERATING_CONFIG, "-o", tempDir.getAbsolutePath(), "-n", nifi);
|
||||
}
|
||||
|
@ -161,7 +163,7 @@ public class TlsToolkitStandaloneTest {
|
|||
public void testKeyPasswordArg() throws Exception {
|
||||
String testKey = "testKey";
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-K", testKey, "-n", TlsConfig.DEFAULT_HOSTNAME);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey();
|
||||
|
||||
Properties nifiProperties = checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
|
||||
assertEquals(testKey, nifiProperties.getProperty(NiFiProperties.SECURITY_KEY_PASSWD));
|
||||
|
@ -171,7 +173,7 @@ public class TlsToolkitStandaloneTest {
|
|||
public void testKeyStorePasswordArg() throws Exception {
|
||||
String testKeyStore = "testKeyStore";
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-S", testKeyStore, "-n", TlsConfig.DEFAULT_HOSTNAME);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey();
|
||||
|
||||
Properties nifiProperties = checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
|
||||
assertEquals(testKeyStore, nifiProperties.getProperty(NiFiProperties.SECURITY_KEYSTORE_PASSWD));
|
||||
|
@ -181,7 +183,7 @@ public class TlsToolkitStandaloneTest {
|
|||
public void testTrustStorePasswordArg() throws Exception {
|
||||
String testTrustStore = "testTrustStore";
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-P", testTrustStore, "-n", TlsConfig.DEFAULT_HOSTNAME);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey();
|
||||
|
||||
Properties nifiProperties = checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
|
||||
assertEquals(testTrustStore, nifiProperties.getProperty(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD));
|
||||
|
@ -193,7 +195,7 @@ public class TlsToolkitStandaloneTest {
|
|||
String nifiDnSuffix = ", OU=nifi";
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", TlsConfig.DEFAULT_HOSTNAME,
|
||||
"--" + TlsToolkitStandaloneCommandLine.NIFI_DN_PREFIX_ARG, nifiDnPrefix, "--" + TlsToolkitStandaloneCommandLine.NIFI_DN_SUFFIX_ARG, nifiDnSuffix);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey();
|
||||
checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, nifiDnPrefix, nifiDnSuffix, x509Certificate);
|
||||
}
|
||||
|
||||
|
@ -202,7 +204,7 @@ public class TlsToolkitStandaloneTest {
|
|||
final String certificateAuthorityHostname = "certificate-authority";
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", TlsConfig.DEFAULT_HOSTNAME, "-T", KeystoreType.PKCS12.toString().toLowerCase(),
|
||||
"-K", "change", "-S", "change", "-P", "change", "-c", certificateAuthorityHostname);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey();
|
||||
checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
|
||||
}
|
||||
|
||||
|
@ -211,7 +213,7 @@ public class TlsToolkitStandaloneTest {
|
|||
String clientDn = "OU=NIFI,CN=testuser";
|
||||
String clientDn2 = "OU=NIFI,CN=testuser2";
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-C", clientDn, "-C", clientDn2, "-B", "pass1", "-P", "pass2");
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey();
|
||||
|
||||
checkClientCert(clientDn, x509Certificate);
|
||||
checkClientCert(clientDn2, x509Certificate);
|
||||
|
@ -224,7 +226,7 @@ public class TlsToolkitStandaloneTest {
|
|||
public void testClientDnsArgNoOverwrite() throws Exception {
|
||||
String clientDn = "OU=NIFI,CN=testuser";
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-C", clientDn, "-B", "passwor");
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey();
|
||||
|
||||
checkClientCert(clientDn, x509Certificate);
|
||||
|
||||
|
@ -236,7 +238,7 @@ public class TlsToolkitStandaloneTest {
|
|||
String hostname = "static.nifi.apache.org";
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", hostname);
|
||||
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey();
|
||||
Certificate[] certificateChain = loadCertificateChain(hostname, x509Certificate);
|
||||
X509Certificate clientCert = (X509Certificate) certificateChain[0];
|
||||
Collection<List<?>> clientSaNames = clientCert.getSubjectAlternativeNames();
|
||||
|
@ -255,7 +257,7 @@ public class TlsToolkitStandaloneTest {
|
|||
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", hostname, "--subjectAlternativeName", san);
|
||||
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey();
|
||||
Certificate[] certificateChain = loadCertificateChain(hostname, x509Certificate);
|
||||
X509Certificate clientCert = (X509Certificate) certificateChain[0];
|
||||
Collection<List<?>> clientSaNames = clientCert.getSubjectAlternativeNames();
|
||||
|
@ -273,7 +275,7 @@ public class TlsToolkitStandaloneTest {
|
|||
String san = "alternative.nifi.apache.org";
|
||||
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nodeNames, "--subjectAlternativeName", san);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey();
|
||||
Stream<InstanceIdentifier> hostIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{nodeNames}));
|
||||
|
||||
for (InstanceIdentifier hostInstance : (Iterable<InstanceIdentifier>) hostIds::iterator) {
|
||||
|
@ -295,7 +297,7 @@ public class TlsToolkitStandaloneTest {
|
|||
String saNames = "alternative[1-2].nifi.apache.org";
|
||||
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nodeNames, "--subjectAlternativeName", saNames);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey();
|
||||
|
||||
Stream<InstanceIdentifier> hostIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{nodeNames}));
|
||||
Stream<InstanceIdentifier> sansIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{saNames}));
|
||||
|
@ -331,7 +333,7 @@ public class TlsToolkitStandaloneTest {
|
|||
String saNames = "alternative[3-4].nifi.apache.org";
|
||||
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nodeNames, "--subjectAlternativeName", saNames);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey();
|
||||
|
||||
Stream<InstanceIdentifier> hostIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{nodeNames}));
|
||||
Stream<InstanceIdentifier> sansIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{saNames}));
|
||||
|
@ -367,7 +369,7 @@ public class TlsToolkitStandaloneTest {
|
|||
String saNames = "alternative[5-7].nifi.apache.org";
|
||||
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nodeNames, "--subjectAlternativeName", saNames);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey();
|
||||
|
||||
Stream<InstanceIdentifier> hostIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{nodeNames}));
|
||||
Stream<InstanceIdentifier> sansIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{saNames}));
|
||||
|
@ -400,7 +402,7 @@ public class TlsToolkitStandaloneTest {
|
|||
String saNames = "alternative[2-1].nifi.apache.org";
|
||||
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nodeNames, "--subjectAlternativeName", saNames);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey();
|
||||
|
||||
Stream<InstanceIdentifier> hostIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{nodeNames}));
|
||||
Stream<InstanceIdentifier> sansIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{saNames}));
|
||||
|
@ -438,11 +440,122 @@ public class TlsToolkitStandaloneTest {
|
|||
runAndAssertExitCode(ExitCode.ERROR_PARSING_INT_ARG, "-o", tempDir.getAbsolutePath(), "-n", nodeNames, "--subjectAlternativeName", saNames);
|
||||
}
|
||||
|
||||
private X509Certificate checkLoadCertPrivateKey(String algorithm) throws IOException, CertificateException {
|
||||
@Test
|
||||
void testShouldVerifyCertificateSignatureWhenSelfSigned() throws Exception {
|
||||
// Create a temp directory for this test and populate it with the nifi-cert.pem and nifi-key.key files
|
||||
populateTempDirWithCAFiles();
|
||||
|
||||
// Make a standalone config which doesn't trigger any keystore generation and just has a self-signed cert and key
|
||||
StandaloneConfig standaloneConfig = new StandaloneConfig();
|
||||
standaloneConfig.setBaseDir(tempDir);
|
||||
standaloneConfig.setInstanceDefinitions(new ArrayList<>());
|
||||
standaloneConfig.setClientDns(new ArrayList<>());
|
||||
standaloneConfig.initDefaults();
|
||||
|
||||
TlsToolkitStandalone standalone = new TlsToolkitStandalone();
|
||||
// The test will fail with an exception if the certificate is not signed by a known certificate
|
||||
assertDoesNotThrow(() -> standalone.createNifiKeystoresAndTrustStores(standaloneConfig));
|
||||
}
|
||||
|
||||
/**
|
||||
* The certificate under examination is self-signed, but there is another signing cert which will be iterated over first, fail, and then the self-signed signature will be validated.
|
||||
*/
|
||||
@Test
|
||||
void testShouldVerifyCertificateSignatureWithMultipleSigningCerts() throws Exception {
|
||||
// Populate temp directory for this test with the nifi-cert.pem and nifi-key.key files
|
||||
populateTempDirWithCAFiles();
|
||||
|
||||
// Create a different cert and persist it to the base dir
|
||||
X509Certificate otherCert = generateX509Certificate();
|
||||
File otherCertFile = writeCertificateToPEMFile(otherCert, tempDir.getPath() + "/other.pem");
|
||||
|
||||
// Make a standalone config which doesn't trigger any keystore generation and just has a self-signed cert and key
|
||||
StandaloneConfig standaloneConfig = new StandaloneConfig();
|
||||
standaloneConfig.setBaseDir(tempDir);
|
||||
standaloneConfig.setInstanceDefinitions(new ArrayList<>());
|
||||
standaloneConfig.setClientDns(new ArrayList<>());
|
||||
standaloneConfig.initDefaults();
|
||||
|
||||
// Inject the additional CA cert path
|
||||
standaloneConfig.setAdditionalCACertificate(otherCertFile.getPath());
|
||||
TlsToolkitStandalone standalone = new TlsToolkitStandalone();
|
||||
|
||||
assertDoesNotThrow(() -> standalone.createNifiKeystoresAndTrustStores(standaloneConfig));
|
||||
}
|
||||
|
||||
/**
|
||||
* The certificate under examination is signed with the external signing cert.
|
||||
*/
|
||||
@Test
|
||||
void testShouldVerifyCertificateSignatureWithAdditionalSigningCert() throws Exception {
|
||||
// Create a root CA, create an intermediate CA, use the root to sign the intermediate and then provide the root
|
||||
KeyPair rootKeyPair = generateKeyPair();
|
||||
X509Certificate rootCert = generateX509Certificate("CN=Root CA", rootKeyPair);
|
||||
|
||||
File rootCertFile = writeCertificateToPEMFile(rootCert, tempDir.getPath() + "/root.pem");
|
||||
|
||||
KeyPair intermediateKeyPair = generateKeyPair();
|
||||
X509Certificate intermediateCert = new StandardCertificateBuilder(rootKeyPair, rootCert.getIssuerX500Principal(), Duration.ofDays(1))
|
||||
.setSubject(new X500Principal("CN=Intermediate CA"))
|
||||
.setSubjectPublicKey(intermediateKeyPair.getPublic())
|
||||
.build();
|
||||
|
||||
//intermediateCertFile
|
||||
writeCertificateToPEMFile(intermediateCert, tempDir.getPath() + "/nifi-cert.pem");
|
||||
|
||||
// Write the private key of the intermediate cert to nifi-key.key
|
||||
//intermediateKeyFile
|
||||
writePrivateKeyToFile(intermediateKeyPair, tempDir.getPath() + "/nifi-key.key");
|
||||
|
||||
// Make a standalone config which doesn't trigger any keystore generation and just has a signed cert and key
|
||||
StandaloneConfig standaloneConfig = new StandaloneConfig();
|
||||
standaloneConfig.setBaseDir(tempDir);
|
||||
standaloneConfig.setInstanceDefinitions(new ArrayList<>());
|
||||
standaloneConfig.setClientDns(new ArrayList<>());
|
||||
standaloneConfig.initDefaults();
|
||||
|
||||
// Inject the additional CA cert path
|
||||
standaloneConfig.setAdditionalCACertificate(rootCertFile.getPath());
|
||||
TlsToolkitStandalone standalone = new TlsToolkitStandalone();
|
||||
|
||||
assertDoesNotThrow(() -> standalone.createNifiKeystoresAndTrustStores(standaloneConfig));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testShouldNotVerifyCertificateSignatureWithWrongSigningCert() throws Exception {
|
||||
// Create a root CA, create an intermediate CA, use the root to sign the intermediate and then do not provide the root
|
||||
KeyPair rootKeyPair = generateKeyPair();
|
||||
X509Certificate rootCert = generateX509Certificate("CN=Root CA", rootKeyPair);
|
||||
|
||||
KeyPair intermediateKeyPair = generateKeyPair();
|
||||
X509Certificate intermediateCert = new StandardCertificateBuilder(rootKeyPair, rootCert.getIssuerX500Principal(), Duration.ofDays(1))
|
||||
.setSubject(new X500Principal("CN=Intermediate CA"))
|
||||
.setSubjectPublicKey(intermediateKeyPair.getPublic())
|
||||
.build();
|
||||
|
||||
//intermediateCertFile
|
||||
writeCertificateToPEMFile(intermediateCert, tempDir.getPath() + "/nifi-cert.pem");
|
||||
|
||||
// Write the private key of the intermediate cert to nifi-key.key
|
||||
//intermediateKeyFile
|
||||
writePrivateKeyToFile(intermediateKeyPair, tempDir.getPath() + "/nifi-key.key");
|
||||
|
||||
// Make a standalone config which doesn't trigger any keystore generation and just has a signed cert and key
|
||||
StandaloneConfig standaloneConfig = new StandaloneConfig();
|
||||
standaloneConfig.setBaseDir(tempDir);
|
||||
standaloneConfig.setInstanceDefinitions(new ArrayList<>());
|
||||
standaloneConfig.setClientDns(new ArrayList<>());
|
||||
standaloneConfig.initDefaults();
|
||||
TlsToolkitStandalone standalone = new TlsToolkitStandalone();
|
||||
|
||||
assertThrows(SignatureException.class, () -> standalone.createNifiKeystoresAndTrustStores(standaloneConfig));
|
||||
}
|
||||
|
||||
private X509Certificate checkLoadCertPrivateKey() throws IOException, CertificateException {
|
||||
KeyPair keyPair = TlsHelperTest.loadKeyPair(new File(tempDir, TlsToolkitStandalone.NIFI_KEY + ".key"));
|
||||
|
||||
assertEquals(algorithm, keyPair.getPrivate().getAlgorithm());
|
||||
assertEquals(algorithm, keyPair.getPublic().getAlgorithm());
|
||||
assertEquals(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM, keyPair.getPrivate().getAlgorithm());
|
||||
assertEquals(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM, keyPair.getPublic().getAlgorithm());
|
||||
|
||||
X509Certificate x509Certificate = TlsHelperTest.loadCertificate(new File(tempDir, TlsToolkitStandalone.NIFI_CERT + ".pem"));
|
||||
assertEquals(keyPair.getPublic(), x509Certificate.getPublicKey());
|
||||
|
@ -485,7 +598,7 @@ public class TlsToolkitStandaloneTest {
|
|||
}
|
||||
|
||||
char[] keyPassword = nifiProperties.getProperty(NiFiProperties.SECURITY_KEY_PASSWD).toCharArray();
|
||||
if (keyPassword == null || keyPassword.length == 0) {
|
||||
if(ArrayUtils.isEmpty(keyPassword)) {
|
||||
keyPassword = keyStorePassword;
|
||||
}
|
||||
|
||||
|
@ -529,7 +642,6 @@ public class TlsToolkitStandaloneTest {
|
|||
certificateChain[0].verify(rootCert.getPublicKey());
|
||||
PublicKey publicKey = certificateChain[0].getPublicKey();
|
||||
TlsCertificateAuthorityTest.assertPrivateAndPublicKeyMatch(privateKey, publicKey);
|
||||
|
||||
}
|
||||
|
||||
private Certificate[] loadCertificateChain(String hostname, X509Certificate rootCert) throws Exception {
|
||||
|
@ -550,4 +662,65 @@ public class TlsToolkitStandaloneTest {
|
|||
private void runAndAssertExitCode(ExitCode exitCode, String... args) {
|
||||
systemExitCapturer.runAndAssertExitCode(() -> TlsToolkitStandaloneCommandLine.main(args), exitCode);
|
||||
}
|
||||
|
||||
private void populateTempDirWithCAFiles() throws Exception {
|
||||
final String testSrcDir = "src/test/resources/";
|
||||
File certificateFile = new File(testSrcDir, "rootCert.crt");
|
||||
File keyFile = new File(testSrcDir, "rootCert.key");
|
||||
File destinationCertFile = new File(tempDir, "nifi-cert.pem");
|
||||
Files.copy(certificateFile.toPath(), destinationCertFile.toPath());
|
||||
File destinationKeyFile = new File(tempDir, "nifi-key.key");
|
||||
Files.copy(keyFile.toPath(), destinationKeyFile.toPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link X509Certificate} with the provided DN and default algorithms. The validity period is only 1 day.
|
||||
* DN (defaults to {@code CN=Test Certificate})
|
||||
* @return the X509Certificate
|
||||
*/
|
||||
private static X509Certificate generateX509Certificate() throws Exception {
|
||||
return generateX509Certificate("CN=Test Certificate", generateKeyPair());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link X509Certificate} with the provided DN and default algorithms. The validity period is only 1 day.
|
||||
*
|
||||
* @param dn the DN (defaults to {@code CN=Test Certificate})
|
||||
* @return the X509Certificate
|
||||
*/
|
||||
private static X509Certificate generateX509Certificate(String dn, KeyPair keyPair) {
|
||||
return new StandardCertificateBuilder(keyPair, new X500Principal(dn), Duration.ofDays(1)).build();
|
||||
}
|
||||
|
||||
private static KeyPair generateKeyPair() throws Exception {
|
||||
final String defaultKeyPairAlgorithm = "RSA";
|
||||
KeyPairGenerator instance = KeyPairGenerator.getInstance(defaultKeyPairAlgorithm);
|
||||
instance.initialize(2048);
|
||||
|
||||
return instance.generateKeyPair();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the provided {@link X509Certificate} to the specified file in PEM format.
|
||||
*
|
||||
* @param certificate the certificate
|
||||
* @param destination the path to write the certificate in PEM format
|
||||
* @return the file
|
||||
*/
|
||||
private static File writeCertificateToPEMFile(X509Certificate certificate, String destination) throws Exception {
|
||||
return writePem(certificate, destination);
|
||||
}
|
||||
|
||||
private static File writePem(Object object, String destination) throws Exception{
|
||||
File destinationFile = new File(destination);
|
||||
try(PemWriter pemWriter = new PemWriter(new FileWriter(destinationFile))) {
|
||||
pemWriter.writeObject(new JcaMiscPEMGenerator(object));
|
||||
}
|
||||
|
||||
return destinationFile;
|
||||
}
|
||||
|
||||
private static void writePrivateKeyToFile(KeyPair intermediateKeyPair, String destination) throws Exception {
|
||||
writePem(intermediateKeyPair, destination);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,14 +34,13 @@ import org.bouncycastle.openssl.PEMParser;
|
|||
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
|
||||
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest;
|
||||
import org.bouncycastle.util.IPAddress;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
import java.io.BufferedReader;
|
||||
|
@ -58,6 +57,7 @@ import java.security.KeyPairGenerator;
|
|||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.Security;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
|
@ -67,6 +67,7 @@ import java.security.cert.X509Certificate;
|
|||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
@ -75,31 +76,19 @@ import java.util.stream.Collectors;
|
|||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class TlsHelperTest {
|
||||
public static final Logger logger = LoggerFactory.getLogger(TlsHelperTest.class);
|
||||
|
||||
private static final String PASSWORD = "changeit";
|
||||
private static X509Certificate rootCert;
|
||||
private int days;
|
||||
|
||||
private int keySize;
|
||||
|
||||
private String keyPairAlgorithm;
|
||||
|
||||
private String signingAlgorithm;
|
||||
|
||||
private KeyPairGenerator keyPairGenerator;
|
||||
|
||||
private final String password = "changeit";
|
||||
|
||||
@Mock(lenient = true)
|
||||
OutputStreamFactory outputStreamFactory;
|
||||
|
||||
private File file;
|
||||
|
||||
public static KeyPair loadKeyPair(final Reader reader) throws IOException {
|
||||
try (PEMParser pemParser = new PEMParser(reader)) {
|
||||
Object object = pemParser.readObject();
|
||||
|
@ -128,19 +117,16 @@ public class TlsHelperTest {
|
|||
}
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
static void setUpBeforeAll() throws Exception {
|
||||
rootCert = TlsHelper.parseCertificate(new FileReader("src/test/resources/rootCert.crt"));
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void setup() throws Exception {
|
||||
days = 360;
|
||||
keySize = 2048;
|
||||
keyPairAlgorithm = "RSA";
|
||||
signingAlgorithm = "SHA256withRSA";
|
||||
keyPairGenerator = KeyPairGenerator.getInstance(keyPairAlgorithm);
|
||||
keyPairGenerator.initialize(keySize);
|
||||
|
||||
file = File.createTempFile("keystore", "file");
|
||||
file.deleteOnExit();
|
||||
ByteArrayOutputStream tmpFileOutputStream = new ByteArrayOutputStream();
|
||||
when(outputStreamFactory.create(file)).thenReturn(tmpFileOutputStream);
|
||||
}
|
||||
|
||||
private Date inFuture(int days) {
|
||||
|
@ -149,13 +135,8 @@ public class TlsHelperTest {
|
|||
|
||||
@Test
|
||||
public void testTokenLengthInCalculateHmac() throws GeneralSecurityException {
|
||||
List<String> badTokens = new ArrayList<>();
|
||||
List<String> goodTokens = new ArrayList<>();
|
||||
badTokens.add(null);
|
||||
badTokens.add("");
|
||||
badTokens.add("123");
|
||||
goodTokens.add("0123456789abcdefghijklm");
|
||||
goodTokens.add("0123456789abcdef");
|
||||
List<String> badTokens = Arrays.asList(null, "", "123");
|
||||
List<String> goodTokens = Arrays.asList("0123456789abcdefghijklm", "0123456789abcdef");
|
||||
|
||||
String dn = "CN=testDN,O=testOrg";
|
||||
X509Certificate x509Certificate = new StandardCertificateBuilder(TlsHelper.generateKeyPair(keyPairAlgorithm, keySize), new X500Principal(dn), Duration.ofDays(days)).build();
|
||||
|
@ -193,14 +174,15 @@ public class TlsHelperTest {
|
|||
assertTrue(notBefore.before(inFuture(1)));
|
||||
|
||||
assertEquals(dn, x509Certificate.getIssuerX500Principal().getName());
|
||||
assertEquals(signingAlgorithm, x509Certificate.getSigAlgName());
|
||||
assertEquals("SHA256withRSA", x509Certificate.getSigAlgName());
|
||||
assertEquals(keyPairAlgorithm, x509Certificate.getPublicKey().getAlgorithm());
|
||||
|
||||
x509Certificate.checkValidity();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteKeyStoreSuccess() throws IOException, GeneralSecurityException {
|
||||
public void testWriteKeyStoreSuccess(@Mock OutputStreamFactory outputStreamFactory, @TempDir File file) throws IOException, GeneralSecurityException {
|
||||
when(outputStreamFactory.create(file)).thenReturn(new ByteArrayOutputStream());
|
||||
String testPassword = "testPassword";
|
||||
final KeyStore keyStore = setupKeystore();
|
||||
assertEquals(testPassword, TlsHelper.writeKeyStore(keyStore, outputStreamFactory, file, testPassword, false));
|
||||
|
@ -209,32 +191,29 @@ public class TlsHelperTest {
|
|||
@Test
|
||||
public void testShouldIncludeSANFromCSR() throws Exception {
|
||||
// Arrange
|
||||
final List<String> SAN_ENTRIES = Arrays.asList("127.0.0.1", "nifi.nifi.apache.org");
|
||||
final int SAN_COUNT = SAN_ENTRIES.size();
|
||||
final String DN = "CN=localhost";
|
||||
final List<String> sanEntries = Arrays.asList("127.0.0.1", "nifi.nifi.apache.org");
|
||||
final int sanCount = sanEntries.size();
|
||||
final String dn = "CN=localhost";
|
||||
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(keyPairAlgorithm);
|
||||
keyPairGenerator.initialize(keySize);
|
||||
KeyPair keyPair = keyPairGenerator.generateKeyPair();
|
||||
logger.info("Generating CSR with DN: " + DN);
|
||||
|
||||
// Act
|
||||
JcaPKCS10CertificationRequest csrWithSan = TlsHelper.generateCertificationRequest(DN, SAN_ENTRIES, keyPair, TlsConfig.DEFAULT_SIGNING_ALGORITHM);
|
||||
logger.info("Created CSR with SAN: " + SAN_ENTRIES);
|
||||
String testCsrPem = TlsHelper.pemEncodeJcaObject(csrWithSan);
|
||||
logger.info("Encoded CSR as PEM: " + testCsrPem);
|
||||
JcaPKCS10CertificationRequest csrWithSan = TlsHelper.generateCertificationRequest(dn, sanEntries, keyPair, TlsConfig.DEFAULT_SIGNING_ALGORITHM);
|
||||
|
||||
// Assert
|
||||
String subjectName = csrWithSan.getSubject().toString();
|
||||
logger.info("CSR Subject Name: " + subjectName);
|
||||
assert subjectName.equals(DN);
|
||||
assertEquals(dn, subjectName);
|
||||
|
||||
List<String> extractedSans = extractSanFromCsr(csrWithSan);
|
||||
assert extractedSans.size() == SAN_COUNT + 1;
|
||||
List<String> formattedSans = SAN_ENTRIES.stream()
|
||||
assertEquals(sanCount + 1, extractedSans.size());
|
||||
List<String> formattedSans = sanEntries.stream()
|
||||
.map(s -> (IPAddress.isValid(s) ? "IP Address: " + new GeneralName(GeneralName.iPAddress, s).getName() : "DNS: " + s))
|
||||
.collect(Collectors.toList());
|
||||
assert extractedSans.containsAll(formattedSans);
|
||||
assertTrue(extractedSans.containsAll(formattedSans));
|
||||
|
||||
// We check that the SANs also contain the CN
|
||||
assert extractedSans.contains("DNS: localhost");
|
||||
assertTrue(extractedSans.contains("DNS: localhost"));
|
||||
}
|
||||
|
||||
private List<String> extractSanFromCsr(JcaPKCS10CertificationRequest csr) {
|
||||
|
@ -246,7 +225,6 @@ public class TlsHelperTest {
|
|||
GeneralNames gns = GeneralNames.fromExtensions(extensions, Extension.subjectAlternativeName);
|
||||
GeneralName[] names = gns.getNames();
|
||||
for (GeneralName name : names) {
|
||||
logger.info("Type: " + name.getTagNo() + " | Name: " + name.getName());
|
||||
String title = "";
|
||||
if (name.getTagNo() == GeneralName.dNSName) {
|
||||
title = "DNS";
|
||||
|
@ -325,7 +303,7 @@ public class TlsHelperTest {
|
|||
private KeyStore setupKeystore() throws CertificateException, NoSuchAlgorithmException, IOException, KeyStoreException {
|
||||
KeyStore ks = KeyStore.getInstance("JKS");
|
||||
try (InputStream readStream = getClass().getClassLoader().getResourceAsStream("keystore.jks")) {
|
||||
ks.load(readStream, password.toCharArray());
|
||||
ks.load(readStream, PASSWORD.toCharArray());
|
||||
}
|
||||
return ks;
|
||||
}
|
||||
|
@ -338,7 +316,7 @@ public class TlsHelperTest {
|
|||
HashMap<String, Certificate> certs = TlsHelper.extractCerts(keyStore);
|
||||
TlsHelper.outputCertsAsPem(certs, folder,".crt");
|
||||
|
||||
assertEquals(folder.listFiles().length, 2);
|
||||
assertEquals(2, folder.listFiles().length);
|
||||
|
||||
for (File file : folder.listFiles()) {
|
||||
X509Certificate certFromFile = loadCertificate(file);
|
||||
|
@ -354,7 +332,7 @@ public class TlsHelperTest {
|
|||
@Test
|
||||
public void testOutputToFileOneKeyAsPem(@TempDir final File folder) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException {
|
||||
KeyStore keyStore = setupKeystore();
|
||||
HashMap<String, Key> keys = TlsHelper.extractKeys(keyStore, password.toCharArray());
|
||||
HashMap<String, Key> keys = TlsHelper.extractKeys(keyStore, PASSWORD.toCharArray());
|
||||
TlsHelper.outputKeysAsPem(keys, folder, ".key");
|
||||
|
||||
for (File file : folder.listFiles()) {
|
||||
|
@ -379,8 +357,39 @@ public class TlsHelperTest {
|
|||
@Test
|
||||
public void testExtractKeys() throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException {
|
||||
KeyStore keyStore = setupKeystore();
|
||||
HashMap<String, Key> keys = TlsHelper.extractKeys(keyStore, password.toCharArray());
|
||||
HashMap<String, Key> keys = TlsHelper.extractKeys(keyStore, PASSWORD.toCharArray());
|
||||
assertEquals(1, keys.size());
|
||||
keys.forEach((String alias, Key key) -> assertEquals("PKCS#8", key.getFormat()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldVerifyCertificateSignatureWhenSelfSigned() {
|
||||
assertTrue(TlsHelper.verifyCertificateSignature(rootCert, Collections.singletonList(rootCert)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldVerifyCertificateSignatureWithMultipleSigningCerts(@Mock X509Certificate mockCertificate) {
|
||||
when(mockCertificate.getSubjectX500Principal()).thenReturn(new X500Principal("CN=Mock Certificate"));
|
||||
assertTrue(TlsHelper.verifyCertificateSignature(rootCert, Arrays.asList(mockCertificate, rootCert)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldNotVerifyCertificateSignatureWithNoSigningCerts() {
|
||||
assertFalse(TlsHelper.verifyCertificateSignature(rootCert, new ArrayList<>()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldNotVerifyCertificateSignatureWithWrongSigningCert(@Mock X509Certificate mockCertificate) {
|
||||
when(mockCertificate.getSubjectX500Principal()).thenReturn(new X500Principal("CN=Mock Certificate"));
|
||||
assertFalse(TlsHelper.verifyCertificateSignature(rootCert, Collections.singletonList(mockCertificate)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseKeyPairFromReaderShouldHandlePKCS8PrivateKey() throws Exception {
|
||||
final KeyPair expectedKeyPair = TlsHelper.parseKeyPairFromReader(new FileReader("src/test/resources/rootCert.key"));
|
||||
final PrivateKey expectedPrivateKey = expectedKeyPair.getPrivate();
|
||||
final KeyPair keyPair = TlsHelper.parseKeyPairFromReader(new FileReader("src/test/resources/rootCert-pkcs8.key"));
|
||||
|
||||
assertEquals(expectedPrivateKey, keyPair.getPrivate());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue