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>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>jcl-over-slf4j</artifactId>
|
<artifactId>jcl-over-slf4j</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.codehaus.groovy</groupId>
|
|
||||||
<artifactId>groovy-test</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<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;
|
package org.apache.nifi.toolkit.tls.standalone;
|
||||||
|
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
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.KeyStoreUtils;
|
||||||
|
import org.apache.nifi.security.util.KeystoreType;
|
||||||
import org.apache.nifi.toolkit.tls.SystemExitCapturer;
|
import org.apache.nifi.toolkit.tls.SystemExitCapturer;
|
||||||
import org.apache.nifi.toolkit.tls.commandLine.BaseTlsToolkitCommandLine;
|
import org.apache.nifi.toolkit.tls.commandLine.BaseTlsToolkitCommandLine;
|
||||||
import org.apache.nifi.toolkit.tls.commandLine.ExitCode;
|
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.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.service.TlsCertificateAuthorityTest;
|
||||||
import org.apache.nifi.toolkit.tls.util.TlsHelper;
|
import org.apache.nifi.toolkit.tls.util.TlsHelper;
|
||||||
import org.apache.nifi.toolkit.tls.util.TlsHelperTest;
|
import org.apache.nifi.toolkit.tls.util.TlsHelperTest;
|
||||||
import org.apache.nifi.util.NiFiProperties;
|
import org.apache.nifi.util.NiFiProperties;
|
||||||
import org.bouncycastle.asn1.x509.GeneralName;
|
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.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.slf4j.Logger;
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
|
import javax.security.auth.x500.X500Principal;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
|
import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
|
import java.security.KeyPairGenerator;
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
|
import java.security.SignatureException;
|
||||||
import java.security.cert.Certificate;
|
import java.security.cert.Certificate;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
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.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
public class TlsToolkitStandaloneTest {
|
public class TlsToolkitStandaloneTest {
|
||||||
public static final String NIFI_FAKE_PROPERTY = "nifi.fake.property";
|
public static final String NIFI_FAKE_PROPERTY = "nifi.fake.property";
|
||||||
public static final String FAKE_VALUE = "fake value";
|
public static final String FAKE_VALUE = "fake value";
|
||||||
public static final String TEST_NIFI_PROPERTIES = "src/test/resources/localhost/nifi.properties";
|
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;
|
private SystemExitCapturer systemExitCapturer;
|
||||||
|
|
||||||
|
@TempDir
|
||||||
private File tempDir;
|
private File tempDir;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setup() throws IOException {
|
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();
|
systemExitCapturer = new SystemExitCapturer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
public void teardown() throws IOException {
|
public void teardown() {
|
||||||
systemExitCapturer.close();
|
systemExitCapturer.close();
|
||||||
FileUtils.deleteDirectory(tempDir);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -104,7 +106,7 @@ public class TlsToolkitStandaloneTest {
|
||||||
@Test
|
@Test
|
||||||
public void testDirOutput() throws Exception {
|
public void testDirOutput() throws Exception {
|
||||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", TlsConfig.DEFAULT_HOSTNAME);
|
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);
|
Properties nifiProperties = checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
|
||||||
assertNull(nifiProperties.get("nifi.fake.property"));
|
assertNull(nifiProperties.get("nifi.fake.property"));
|
||||||
|
@ -114,7 +116,7 @@ public class TlsToolkitStandaloneTest {
|
||||||
@Test
|
@Test
|
||||||
public void testDifferentArg() throws Exception {
|
public void testDifferentArg() throws Exception {
|
||||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-g", "-n", TlsConfig.DEFAULT_HOSTNAME);
|
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);
|
Properties nifiProperties = checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
|
||||||
assertNull(nifiProperties.get("nifi.fake.property"));
|
assertNull(nifiProperties.get("nifi.fake.property"));
|
||||||
|
@ -124,7 +126,7 @@ public class TlsToolkitStandaloneTest {
|
||||||
@Test
|
@Test
|
||||||
public void testFileArg() throws Exception {
|
public void testFileArg() throws Exception {
|
||||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-f", TEST_NIFI_PROPERTIES, "-n", TlsConfig.DEFAULT_HOSTNAME);
|
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);
|
Properties nifiProperties = checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
|
||||||
assertEquals(FAKE_VALUE, nifiProperties.get(NIFI_FAKE_PROPERTY));
|
assertEquals(FAKE_VALUE, nifiProperties.get(NIFI_FAKE_PROPERTY));
|
||||||
|
@ -137,7 +139,7 @@ public class TlsToolkitStandaloneTest {
|
||||||
String nifi3 = "nifi3";
|
String nifi3 = "nifi3";
|
||||||
|
|
||||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nifi1 + "," + nifi2);
|
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);
|
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nifi3);
|
||||||
|
|
||||||
checkHostDirAndReturnNifiProperties(nifi1, x509Certificate);
|
checkHostDirAndReturnNifiProperties(nifi1, x509Certificate);
|
||||||
|
@ -152,7 +154,7 @@ public class TlsToolkitStandaloneTest {
|
||||||
String nifi = "nifi";
|
String nifi = "nifi";
|
||||||
|
|
||||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nifi);
|
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nifi);
|
||||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
X509Certificate x509Certificate = checkLoadCertPrivateKey();
|
||||||
checkHostDirAndReturnNifiProperties(nifi, x509Certificate);
|
checkHostDirAndReturnNifiProperties(nifi, x509Certificate);
|
||||||
runAndAssertExitCode(ExitCode.ERROR_GENERATING_CONFIG, "-o", tempDir.getAbsolutePath(), "-n", nifi);
|
runAndAssertExitCode(ExitCode.ERROR_GENERATING_CONFIG, "-o", tempDir.getAbsolutePath(), "-n", nifi);
|
||||||
}
|
}
|
||||||
|
@ -161,7 +163,7 @@ public class TlsToolkitStandaloneTest {
|
||||||
public void testKeyPasswordArg() throws Exception {
|
public void testKeyPasswordArg() throws Exception {
|
||||||
String testKey = "testKey";
|
String testKey = "testKey";
|
||||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-K", testKey, "-n", TlsConfig.DEFAULT_HOSTNAME);
|
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);
|
Properties nifiProperties = checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
|
||||||
assertEquals(testKey, nifiProperties.getProperty(NiFiProperties.SECURITY_KEY_PASSWD));
|
assertEquals(testKey, nifiProperties.getProperty(NiFiProperties.SECURITY_KEY_PASSWD));
|
||||||
|
@ -171,7 +173,7 @@ public class TlsToolkitStandaloneTest {
|
||||||
public void testKeyStorePasswordArg() throws Exception {
|
public void testKeyStorePasswordArg() throws Exception {
|
||||||
String testKeyStore = "testKeyStore";
|
String testKeyStore = "testKeyStore";
|
||||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-S", testKeyStore, "-n", TlsConfig.DEFAULT_HOSTNAME);
|
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);
|
Properties nifiProperties = checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
|
||||||
assertEquals(testKeyStore, nifiProperties.getProperty(NiFiProperties.SECURITY_KEYSTORE_PASSWD));
|
assertEquals(testKeyStore, nifiProperties.getProperty(NiFiProperties.SECURITY_KEYSTORE_PASSWD));
|
||||||
|
@ -181,7 +183,7 @@ public class TlsToolkitStandaloneTest {
|
||||||
public void testTrustStorePasswordArg() throws Exception {
|
public void testTrustStorePasswordArg() throws Exception {
|
||||||
String testTrustStore = "testTrustStore";
|
String testTrustStore = "testTrustStore";
|
||||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-P", testTrustStore, "-n", TlsConfig.DEFAULT_HOSTNAME);
|
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);
|
Properties nifiProperties = checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
|
||||||
assertEquals(testTrustStore, nifiProperties.getProperty(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD));
|
assertEquals(testTrustStore, nifiProperties.getProperty(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD));
|
||||||
|
@ -193,7 +195,7 @@ public class TlsToolkitStandaloneTest {
|
||||||
String nifiDnSuffix = ", OU=nifi";
|
String nifiDnSuffix = ", OU=nifi";
|
||||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", TlsConfig.DEFAULT_HOSTNAME,
|
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", TlsConfig.DEFAULT_HOSTNAME,
|
||||||
"--" + TlsToolkitStandaloneCommandLine.NIFI_DN_PREFIX_ARG, nifiDnPrefix, "--" + TlsToolkitStandaloneCommandLine.NIFI_DN_SUFFIX_ARG, nifiDnSuffix);
|
"--" + 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);
|
checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, nifiDnPrefix, nifiDnSuffix, x509Certificate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,7 +204,7 @@ public class TlsToolkitStandaloneTest {
|
||||||
final String certificateAuthorityHostname = "certificate-authority";
|
final String certificateAuthorityHostname = "certificate-authority";
|
||||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", TlsConfig.DEFAULT_HOSTNAME, "-T", KeystoreType.PKCS12.toString().toLowerCase(),
|
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", TlsConfig.DEFAULT_HOSTNAME, "-T", KeystoreType.PKCS12.toString().toLowerCase(),
|
||||||
"-K", "change", "-S", "change", "-P", "change", "-c", certificateAuthorityHostname);
|
"-K", "change", "-S", "change", "-P", "change", "-c", certificateAuthorityHostname);
|
||||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
X509Certificate x509Certificate = checkLoadCertPrivateKey();
|
||||||
checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
|
checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,7 +213,7 @@ public class TlsToolkitStandaloneTest {
|
||||||
String clientDn = "OU=NIFI,CN=testuser";
|
String clientDn = "OU=NIFI,CN=testuser";
|
||||||
String clientDn2 = "OU=NIFI,CN=testuser2";
|
String clientDn2 = "OU=NIFI,CN=testuser2";
|
||||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-C", clientDn, "-C", clientDn2, "-B", "pass1", "-P", "pass2");
|
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(clientDn, x509Certificate);
|
||||||
checkClientCert(clientDn2, x509Certificate);
|
checkClientCert(clientDn2, x509Certificate);
|
||||||
|
@ -224,7 +226,7 @@ public class TlsToolkitStandaloneTest {
|
||||||
public void testClientDnsArgNoOverwrite() throws Exception {
|
public void testClientDnsArgNoOverwrite() throws Exception {
|
||||||
String clientDn = "OU=NIFI,CN=testuser";
|
String clientDn = "OU=NIFI,CN=testuser";
|
||||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-C", clientDn, "-B", "passwor");
|
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-C", clientDn, "-B", "passwor");
|
||||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
X509Certificate x509Certificate = checkLoadCertPrivateKey();
|
||||||
|
|
||||||
checkClientCert(clientDn, x509Certificate);
|
checkClientCert(clientDn, x509Certificate);
|
||||||
|
|
||||||
|
@ -236,7 +238,7 @@ public class TlsToolkitStandaloneTest {
|
||||||
String hostname = "static.nifi.apache.org";
|
String hostname = "static.nifi.apache.org";
|
||||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", hostname);
|
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", hostname);
|
||||||
|
|
||||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
X509Certificate x509Certificate = checkLoadCertPrivateKey();
|
||||||
Certificate[] certificateChain = loadCertificateChain(hostname, x509Certificate);
|
Certificate[] certificateChain = loadCertificateChain(hostname, x509Certificate);
|
||||||
X509Certificate clientCert = (X509Certificate) certificateChain[0];
|
X509Certificate clientCert = (X509Certificate) certificateChain[0];
|
||||||
Collection<List<?>> clientSaNames = clientCert.getSubjectAlternativeNames();
|
Collection<List<?>> clientSaNames = clientCert.getSubjectAlternativeNames();
|
||||||
|
@ -255,7 +257,7 @@ public class TlsToolkitStandaloneTest {
|
||||||
|
|
||||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", hostname, "--subjectAlternativeName", san);
|
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);
|
Certificate[] certificateChain = loadCertificateChain(hostname, x509Certificate);
|
||||||
X509Certificate clientCert = (X509Certificate) certificateChain[0];
|
X509Certificate clientCert = (X509Certificate) certificateChain[0];
|
||||||
Collection<List<?>> clientSaNames = clientCert.getSubjectAlternativeNames();
|
Collection<List<?>> clientSaNames = clientCert.getSubjectAlternativeNames();
|
||||||
|
@ -273,7 +275,7 @@ public class TlsToolkitStandaloneTest {
|
||||||
String san = "alternative.nifi.apache.org";
|
String san = "alternative.nifi.apache.org";
|
||||||
|
|
||||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nodeNames, "--subjectAlternativeName", san);
|
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}));
|
Stream<InstanceIdentifier> hostIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{nodeNames}));
|
||||||
|
|
||||||
for (InstanceIdentifier hostInstance : (Iterable<InstanceIdentifier>) hostIds::iterator) {
|
for (InstanceIdentifier hostInstance : (Iterable<InstanceIdentifier>) hostIds::iterator) {
|
||||||
|
@ -295,7 +297,7 @@ public class TlsToolkitStandaloneTest {
|
||||||
String saNames = "alternative[1-2].nifi.apache.org";
|
String saNames = "alternative[1-2].nifi.apache.org";
|
||||||
|
|
||||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nodeNames, "--subjectAlternativeName", saNames);
|
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> hostIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{nodeNames}));
|
||||||
Stream<InstanceIdentifier> sansIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{saNames}));
|
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";
|
String saNames = "alternative[3-4].nifi.apache.org";
|
||||||
|
|
||||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nodeNames, "--subjectAlternativeName", saNames);
|
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> hostIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{nodeNames}));
|
||||||
Stream<InstanceIdentifier> sansIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{saNames}));
|
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";
|
String saNames = "alternative[5-7].nifi.apache.org";
|
||||||
|
|
||||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nodeNames, "--subjectAlternativeName", saNames);
|
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> hostIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{nodeNames}));
|
||||||
Stream<InstanceIdentifier> sansIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{saNames}));
|
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";
|
String saNames = "alternative[2-1].nifi.apache.org";
|
||||||
|
|
||||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nodeNames, "--subjectAlternativeName", saNames);
|
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> hostIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{nodeNames}));
|
||||||
Stream<InstanceIdentifier> sansIds = InstanceIdentifier.createIdentifiers(Arrays.stream(new String[]{saNames}));
|
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);
|
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"));
|
KeyPair keyPair = TlsHelperTest.loadKeyPair(new File(tempDir, TlsToolkitStandalone.NIFI_KEY + ".key"));
|
||||||
|
|
||||||
assertEquals(algorithm, keyPair.getPrivate().getAlgorithm());
|
assertEquals(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM, keyPair.getPrivate().getAlgorithm());
|
||||||
assertEquals(algorithm, keyPair.getPublic().getAlgorithm());
|
assertEquals(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM, keyPair.getPublic().getAlgorithm());
|
||||||
|
|
||||||
X509Certificate x509Certificate = TlsHelperTest.loadCertificate(new File(tempDir, TlsToolkitStandalone.NIFI_CERT + ".pem"));
|
X509Certificate x509Certificate = TlsHelperTest.loadCertificate(new File(tempDir, TlsToolkitStandalone.NIFI_CERT + ".pem"));
|
||||||
assertEquals(keyPair.getPublic(), x509Certificate.getPublicKey());
|
assertEquals(keyPair.getPublic(), x509Certificate.getPublicKey());
|
||||||
|
@ -485,7 +598,7 @@ public class TlsToolkitStandaloneTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
char[] keyPassword = nifiProperties.getProperty(NiFiProperties.SECURITY_KEY_PASSWD).toCharArray();
|
char[] keyPassword = nifiProperties.getProperty(NiFiProperties.SECURITY_KEY_PASSWD).toCharArray();
|
||||||
if (keyPassword == null || keyPassword.length == 0) {
|
if(ArrayUtils.isEmpty(keyPassword)) {
|
||||||
keyPassword = keyStorePassword;
|
keyPassword = keyStorePassword;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -529,7 +642,6 @@ public class TlsToolkitStandaloneTest {
|
||||||
certificateChain[0].verify(rootCert.getPublicKey());
|
certificateChain[0].verify(rootCert.getPublicKey());
|
||||||
PublicKey publicKey = certificateChain[0].getPublicKey();
|
PublicKey publicKey = certificateChain[0].getPublicKey();
|
||||||
TlsCertificateAuthorityTest.assertPrivateAndPublicKeyMatch(privateKey, publicKey);
|
TlsCertificateAuthorityTest.assertPrivateAndPublicKeyMatch(privateKey, publicKey);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Certificate[] loadCertificateChain(String hostname, X509Certificate rootCert) throws Exception {
|
private Certificate[] loadCertificateChain(String hostname, X509Certificate rootCert) throws Exception {
|
||||||
|
@ -550,4 +662,65 @@ public class TlsToolkitStandaloneTest {
|
||||||
private void runAndAssertExitCode(ExitCode exitCode, String... args) {
|
private void runAndAssertExitCode(ExitCode exitCode, String... args) {
|
||||||
systemExitCapturer.runAndAssertExitCode(() -> TlsToolkitStandaloneCommandLine.main(args), exitCode);
|
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.openssl.jcajce.JcaPEMKeyConverter;
|
||||||
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest;
|
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest;
|
||||||
import org.bouncycastle.util.IPAddress;
|
import org.bouncycastle.util.IPAddress;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.junit.jupiter.api.io.TempDir;
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import javax.security.auth.x500.X500Principal;
|
import javax.security.auth.x500.X500Principal;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
|
@ -58,6 +57,7 @@ import java.security.KeyPairGenerator;
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
import java.security.KeyStoreException;
|
import java.security.KeyStoreException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.PrivateKey;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
import java.security.UnrecoverableKeyException;
|
import java.security.UnrecoverableKeyException;
|
||||||
|
@ -67,6 +67,7 @@ import java.security.cert.X509Certificate;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
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.assertArrayEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
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.assertTrue;
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
public class TlsHelperTest {
|
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 days;
|
||||||
|
|
||||||
private int keySize;
|
private int keySize;
|
||||||
|
|
||||||
private String keyPairAlgorithm;
|
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 {
|
public static KeyPair loadKeyPair(final Reader reader) throws IOException {
|
||||||
try (PEMParser pemParser = new PEMParser(reader)) {
|
try (PEMParser pemParser = new PEMParser(reader)) {
|
||||||
Object object = pemParser.readObject();
|
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
|
@BeforeEach
|
||||||
public void setup() throws Exception {
|
public void setup() throws Exception {
|
||||||
days = 360;
|
days = 360;
|
||||||
keySize = 2048;
|
keySize = 2048;
|
||||||
keyPairAlgorithm = "RSA";
|
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) {
|
private Date inFuture(int days) {
|
||||||
|
@ -149,13 +135,8 @@ public class TlsHelperTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTokenLengthInCalculateHmac() throws GeneralSecurityException {
|
public void testTokenLengthInCalculateHmac() throws GeneralSecurityException {
|
||||||
List<String> badTokens = new ArrayList<>();
|
List<String> badTokens = Arrays.asList(null, "", "123");
|
||||||
List<String> goodTokens = new ArrayList<>();
|
List<String> goodTokens = Arrays.asList("0123456789abcdefghijklm", "0123456789abcdef");
|
||||||
badTokens.add(null);
|
|
||||||
badTokens.add("");
|
|
||||||
badTokens.add("123");
|
|
||||||
goodTokens.add("0123456789abcdefghijklm");
|
|
||||||
goodTokens.add("0123456789abcdef");
|
|
||||||
|
|
||||||
String dn = "CN=testDN,O=testOrg";
|
String dn = "CN=testDN,O=testOrg";
|
||||||
X509Certificate x509Certificate = new StandardCertificateBuilder(TlsHelper.generateKeyPair(keyPairAlgorithm, keySize), new X500Principal(dn), Duration.ofDays(days)).build();
|
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)));
|
assertTrue(notBefore.before(inFuture(1)));
|
||||||
|
|
||||||
assertEquals(dn, x509Certificate.getIssuerX500Principal().getName());
|
assertEquals(dn, x509Certificate.getIssuerX500Principal().getName());
|
||||||
assertEquals(signingAlgorithm, x509Certificate.getSigAlgName());
|
assertEquals("SHA256withRSA", x509Certificate.getSigAlgName());
|
||||||
assertEquals(keyPairAlgorithm, x509Certificate.getPublicKey().getAlgorithm());
|
assertEquals(keyPairAlgorithm, x509Certificate.getPublicKey().getAlgorithm());
|
||||||
|
|
||||||
x509Certificate.checkValidity();
|
x509Certificate.checkValidity();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@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";
|
String testPassword = "testPassword";
|
||||||
final KeyStore keyStore = setupKeystore();
|
final KeyStore keyStore = setupKeystore();
|
||||||
assertEquals(testPassword, TlsHelper.writeKeyStore(keyStore, outputStreamFactory, file, testPassword, false));
|
assertEquals(testPassword, TlsHelper.writeKeyStore(keyStore, outputStreamFactory, file, testPassword, false));
|
||||||
|
@ -209,32 +191,29 @@ public class TlsHelperTest {
|
||||||
@Test
|
@Test
|
||||||
public void testShouldIncludeSANFromCSR() throws Exception {
|
public void testShouldIncludeSANFromCSR() throws Exception {
|
||||||
// Arrange
|
// Arrange
|
||||||
final List<String> SAN_ENTRIES = Arrays.asList("127.0.0.1", "nifi.nifi.apache.org");
|
final List<String> sanEntries = Arrays.asList("127.0.0.1", "nifi.nifi.apache.org");
|
||||||
final int SAN_COUNT = SAN_ENTRIES.size();
|
final int sanCount = sanEntries.size();
|
||||||
final String DN = "CN=localhost";
|
final String dn = "CN=localhost";
|
||||||
|
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(keyPairAlgorithm);
|
||||||
|
keyPairGenerator.initialize(keySize);
|
||||||
KeyPair keyPair = keyPairGenerator.generateKeyPair();
|
KeyPair keyPair = keyPairGenerator.generateKeyPair();
|
||||||
logger.info("Generating CSR with DN: " + DN);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
JcaPKCS10CertificationRequest csrWithSan = TlsHelper.generateCertificationRequest(DN, SAN_ENTRIES, keyPair, TlsConfig.DEFAULT_SIGNING_ALGORITHM);
|
JcaPKCS10CertificationRequest csrWithSan = TlsHelper.generateCertificationRequest(dn, sanEntries, 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);
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
String subjectName = csrWithSan.getSubject().toString();
|
String subjectName = csrWithSan.getSubject().toString();
|
||||||
logger.info("CSR Subject Name: " + subjectName);
|
assertEquals(dn, subjectName);
|
||||||
assert subjectName.equals(DN);
|
|
||||||
|
|
||||||
List<String> extractedSans = extractSanFromCsr(csrWithSan);
|
List<String> extractedSans = extractSanFromCsr(csrWithSan);
|
||||||
assert extractedSans.size() == SAN_COUNT + 1;
|
assertEquals(sanCount + 1, extractedSans.size());
|
||||||
List<String> formattedSans = SAN_ENTRIES.stream()
|
List<String> formattedSans = sanEntries.stream()
|
||||||
.map(s -> (IPAddress.isValid(s) ? "IP Address: " + new GeneralName(GeneralName.iPAddress, s).getName() : "DNS: " + s))
|
.map(s -> (IPAddress.isValid(s) ? "IP Address: " + new GeneralName(GeneralName.iPAddress, s).getName() : "DNS: " + s))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
assert extractedSans.containsAll(formattedSans);
|
assertTrue(extractedSans.containsAll(formattedSans));
|
||||||
|
|
||||||
// We check that the SANs also contain the CN
|
// 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) {
|
private List<String> extractSanFromCsr(JcaPKCS10CertificationRequest csr) {
|
||||||
|
@ -246,7 +225,6 @@ public class TlsHelperTest {
|
||||||
GeneralNames gns = GeneralNames.fromExtensions(extensions, Extension.subjectAlternativeName);
|
GeneralNames gns = GeneralNames.fromExtensions(extensions, Extension.subjectAlternativeName);
|
||||||
GeneralName[] names = gns.getNames();
|
GeneralName[] names = gns.getNames();
|
||||||
for (GeneralName name : names) {
|
for (GeneralName name : names) {
|
||||||
logger.info("Type: " + name.getTagNo() + " | Name: " + name.getName());
|
|
||||||
String title = "";
|
String title = "";
|
||||||
if (name.getTagNo() == GeneralName.dNSName) {
|
if (name.getTagNo() == GeneralName.dNSName) {
|
||||||
title = "DNS";
|
title = "DNS";
|
||||||
|
@ -325,7 +303,7 @@ public class TlsHelperTest {
|
||||||
private KeyStore setupKeystore() throws CertificateException, NoSuchAlgorithmException, IOException, KeyStoreException {
|
private KeyStore setupKeystore() throws CertificateException, NoSuchAlgorithmException, IOException, KeyStoreException {
|
||||||
KeyStore ks = KeyStore.getInstance("JKS");
|
KeyStore ks = KeyStore.getInstance("JKS");
|
||||||
try (InputStream readStream = getClass().getClassLoader().getResourceAsStream("keystore.jks")) {
|
try (InputStream readStream = getClass().getClassLoader().getResourceAsStream("keystore.jks")) {
|
||||||
ks.load(readStream, password.toCharArray());
|
ks.load(readStream, PASSWORD.toCharArray());
|
||||||
}
|
}
|
||||||
return ks;
|
return ks;
|
||||||
}
|
}
|
||||||
|
@ -338,7 +316,7 @@ public class TlsHelperTest {
|
||||||
HashMap<String, Certificate> certs = TlsHelper.extractCerts(keyStore);
|
HashMap<String, Certificate> certs = TlsHelper.extractCerts(keyStore);
|
||||||
TlsHelper.outputCertsAsPem(certs, folder,".crt");
|
TlsHelper.outputCertsAsPem(certs, folder,".crt");
|
||||||
|
|
||||||
assertEquals(folder.listFiles().length, 2);
|
assertEquals(2, folder.listFiles().length);
|
||||||
|
|
||||||
for (File file : folder.listFiles()) {
|
for (File file : folder.listFiles()) {
|
||||||
X509Certificate certFromFile = loadCertificate(file);
|
X509Certificate certFromFile = loadCertificate(file);
|
||||||
|
@ -354,7 +332,7 @@ public class TlsHelperTest {
|
||||||
@Test
|
@Test
|
||||||
public void testOutputToFileOneKeyAsPem(@TempDir final File folder) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException {
|
public void testOutputToFileOneKeyAsPem(@TempDir final File folder) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException {
|
||||||
KeyStore keyStore = setupKeystore();
|
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");
|
TlsHelper.outputKeysAsPem(keys, folder, ".key");
|
||||||
|
|
||||||
for (File file : folder.listFiles()) {
|
for (File file : folder.listFiles()) {
|
||||||
|
@ -379,8 +357,39 @@ public class TlsHelperTest {
|
||||||
@Test
|
@Test
|
||||||
public void testExtractKeys() throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException {
|
public void testExtractKeys() throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException {
|
||||||
KeyStore keyStore = setupKeystore();
|
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());
|
assertEquals(1, keys.size());
|
||||||
keys.forEach((String alias, Key key) -> assertEquals("PKCS#8", key.getFormat()));
|
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