NIFI-2526 - DN order, multiple standalone runs, client certificates - Logic for sorting DN, reversing X500Names before using them to generate certificate - Logging reordered dn - Accounting for limited crypto pkcs12, allowing password specification for client certificates - Updating tests to work with or without jce unlimited - Loading keystore for test in try-with
This closes #824. Signed-off-by: Bryan Bende <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/nifi/repo Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/fa5da543 Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/fa5da543 Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/fa5da543 Branch: refs/heads/master Commit: fa5da543e6334aec363f5fb0c470a7e0b682042d Parents: fd0dd51 Author: Bryan Rosander <[email protected]> Authored: Tue Aug 9 11:11:21 2016 -0400 Committer: Bryan Bende <[email protected]> Committed: Mon Aug 15 10:21:34 2016 -0400 ---------------------------------------------------------------------- .../nifi/security/util/CertificateUtils.java | 99 ++++++++++- .../security/util/CertificateUtilsTest.groovy | 26 ++- .../nifi/toolkit/tls/commandLine/ExitCode.java | 1 - .../tls/configuration/StandaloneConfig.java | 125 ++++++++++++++ .../toolkit/tls/configuration/TlsConfig.java | 3 +- .../toolkit/tls/manager/BaseTlsManager.java | 14 +- .../manager/TlsCertificateAuthorityManager.java | 2 +- .../toolkit/tls/manager/TlsClientManager.java | 13 +- .../TlsCertificateSigningRequestPerformer.java | 8 +- .../TlsCertificateAuthorityServiceHandler.java | 6 +- .../tls/standalone/TlsToolkitStandalone.java | 168 +++++++++++++++---- .../TlsToolkitStandaloneCommandLine.java | 118 +++++++------ .../apache/nifi/toolkit/tls/util/TlsHelper.java | 99 ++++++++++- .../service/TlsCertificateAuthorityTest.java | 4 +- ...sCertificateAuthorityServiceHandlerTest.java | 2 +- .../TlsToolkitStandaloneCommandLineTest.java | 107 ++++++++---- .../standalone/TlsToolkitStandaloneTest.java | 98 +++++++++-- .../nifi/toolkit/tls/util/TlsHelperTest.java | 151 +++++++++++++++-- .../src/test/resources/log4j.properties | 22 +++ 19 files changed, 882 insertions(+), 184 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/nifi/blob/fa5da543/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/util/CertificateUtils.java ---------------------------------------------------------------------- diff --git a/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/util/CertificateUtils.java b/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/util/CertificateUtils.java index 2049718..760e82e 100644 --- a/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/util/CertificateUtils.java +++ b/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/util/CertificateUtils.java @@ -17,7 +17,11 @@ package org.apache.nifi.security.util; import org.apache.commons.lang3.StringUtils; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.x500.AttributeTypeAndValue; +import org.bouncycastle.asn1.x500.RDN; import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x500.style.BCStyle; import org.bouncycastle.asn1.x509.BasicConstraints; import org.bouncycastle.asn1.x509.ExtendedKeyUsage; import org.bouncycastle.asn1.x509.Extension; @@ -57,16 +61,37 @@ import java.security.cert.CertificateFactory; import java.security.cert.CertificateParsingException; import java.security.cert.X509Certificate; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.TimeUnit; public final class CertificateUtils { - private static final Logger logger = LoggerFactory.getLogger(CertificateUtils.class); private static final String PEER_NOT_AUTHENTICATED_MSG = "peer not authenticated"; + private static final Map<ASN1ObjectIdentifier, Integer> dnOrderMap = createDnOrderMap(); + + private static Map<ASN1ObjectIdentifier, Integer> createDnOrderMap() { + Map<ASN1ObjectIdentifier, Integer> orderMap = new HashMap<>(); + int count = 0; + orderMap.put(BCStyle.CN, count++); + orderMap.put(BCStyle.L, count++); + orderMap.put(BCStyle.ST, count++); + orderMap.put(BCStyle.O, count++); + orderMap.put(BCStyle.OU, count++); + orderMap.put(BCStyle.C, count++); + orderMap.put(BCStyle.STREET, count++); + orderMap.put(BCStyle.DC, count++); + orderMap.put(BCStyle.UID, count++); + return Collections.unmodifiableMap(orderMap); + } + public enum ClientAuth { NONE(0, "none"), WANT(1, "want"), @@ -350,6 +375,70 @@ public final class CertificateUtils { } /** + * Reorders DN to the order the elements appear in the RFC 2253 table + * + * https://www.ietf.org/rfc/rfc2253.txt + * + * String X.500 AttributeType + * ------------------------------ + * CN commonName + * L localityName + * ST stateOrProvinceName + * O organizationName + * OU organizationalUnitName + * C countryName + * STREET streetAddress + * DC domainComponent + * UID userid + * + * @param dn a possibly unordered DN + * @return the ordered dn + */ + public static String reorderDn(String dn) { + RDN[] rdNs = new X500Name(dn).getRDNs(); + Arrays.sort(rdNs, new Comparator<RDN>() { + @Override + public int compare(RDN o1, RDN o2) { + AttributeTypeAndValue o1First = o1.getFirst(); + AttributeTypeAndValue o2First = o2.getFirst(); + + ASN1ObjectIdentifier o1Type = o1First.getType(); + ASN1ObjectIdentifier o2Type = o2First.getType(); + + Integer o1Rank = dnOrderMap.get(o1Type); + Integer o2Rank = dnOrderMap.get(o2Type); + if (o1Rank == null) { + if (o2Rank == null) { + int idComparison = o1Type.getId().compareTo(o2Type.getId()); + if (idComparison != 0) { + return idComparison; + } + return String.valueOf(o1Type).compareTo(String.valueOf(o2Type)); + } + return 1; + } else if (o2Rank == null) { + return -1; + } + return o1Rank - o2Rank; + } + }); + return new X500Name(rdNs).toString(); + } + + /** + * Reverses the X500Name in order make the certificate be in the right order + * [see http://stackoverflow.com/questions/7567837/attributes-reversed-in-certificate-subject-and-issuer/12645265] + * + * @param x500Name the X500Name created with the intended order + * @return the X500Name reversed + */ + private static X500Name reverseX500Name(X500Name x500Name) { + List<RDN> rdns = Arrays.asList(x500Name.getRDNs()); + Collections.reverse(rdns); + return new X500Name(rdns.toArray(new RDN[rdns.size()])); + } + + /** * Generates a self-signed {@link X509Certificate} suitable for use as a Certificate Authority. * * @param keyPair the {@link KeyPair} to generate the {@link X509Certificate} for @@ -368,10 +457,10 @@ public final class CertificateUtils { Date endDate = new Date(startDate.getTime() + TimeUnit.DAYS.toMillis(certificateDurationDays)); X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder( - new X500Name(dn), + reverseX500Name(new X500Name(dn)), BigInteger.valueOf(System.currentTimeMillis()), startDate, endDate, - new X500Name(dn), + reverseX500Name(new X500Name(dn)), subPubKeyInfo); // Set certificate extensions @@ -417,10 +506,10 @@ public final class CertificateUtils { Date endDate = new Date(startDate.getTime() + TimeUnit.DAYS.toMillis(days)); X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder( - new X500Name(issuer.getSubjectDN().getName()), + reverseX500Name(new X500Name(issuer.getSubjectX500Principal().getName())), BigInteger.valueOf(System.currentTimeMillis()), startDate, endDate, - new X500Name(dn), + reverseX500Name(new X500Name(dn)), subPubKeyInfo); certBuilder.addExtension(Extension.subjectKeyIdentifier, false, new JcaX509ExtensionUtils().createSubjectKeyIdentifier(publicKey)); http://git-wip-us.apache.org/repos/asf/nifi/blob/fa5da543/nifi-commons/nifi-security-utils/src/test/groovy/org/apache/nifi/security/util/CertificateUtilsTest.groovy ---------------------------------------------------------------------- diff --git a/nifi-commons/nifi-security-utils/src/test/groovy/org/apache/nifi/security/util/CertificateUtilsTest.groovy b/nifi-commons/nifi-security-utils/src/test/groovy/org/apache/nifi/security/util/CertificateUtilsTest.groovy index 7f93f51..6727364 100644 --- a/nifi-commons/nifi-security-utils/src/test/groovy/org/apache/nifi/security/util/CertificateUtilsTest.groovy +++ b/nifi-commons/nifi-security-utils/src/test/groovy/org/apache/nifi/security/util/CertificateUtilsTest.groovy @@ -443,7 +443,7 @@ class CertificateUtilsTest extends GroovyTestCase { assertTrue(notBefore.after(inFuture(-1))); assertTrue(notBefore.before(inFuture(1))); - assertEquals(dn, x509Certificate.getIssuerDN().getName()); + assertEquals(dn, x509Certificate.getIssuerX500Principal().getName()); assertEquals(SIGNATURE_ALGORITHM.toUpperCase(), x509Certificate.getSigAlgName().toUpperCase()); assertEquals("RSA", x509Certificate.getPublicKey().getAlgorithm()); @@ -458,12 +458,12 @@ class CertificateUtilsTest extends GroovyTestCase { KeyPair issuerKeyPair = generateKeyPair(); X509Certificate issuer = CertificateUtils.generateSelfSignedX509Certificate(issuerKeyPair, "CN=testCa,O=testOrg", SIGNATURE_ALGORITHM, days); - String dn = "CN=testIssued,O=testOrg"; + String dn = "CN=testIssued, O=testOrg"; KeyPair keyPair = generateKeyPair(); X509Certificate x509Certificate = CertificateUtils.generateIssuedCertificate(dn, keyPair.getPublic(), issuer, issuerKeyPair, SIGNATURE_ALGORITHM, days); - assertEquals(dn, x509Certificate.getSubjectDN().toString()); - assertEquals(issuer.getSubjectDN().toString(), x509Certificate.getIssuerDN().toString()); + assertEquals(dn, x509Certificate.getSubjectX500Principal().toString()); + assertEquals(issuer.getSubjectX500Principal().toString(), x509Certificate.getIssuerX500Principal().toString()); assertEquals(keyPair.getPublic(), x509Certificate.getPublicKey()); Date notAfter = x509Certificate.getNotAfter(); @@ -479,4 +479,22 @@ class CertificateUtilsTest extends GroovyTestCase { x509Certificate.verify(issuerKeyPair.getPublic()); } + + @Test + public void reorderShouldPutElementsInCorrectOrder() { + String cn = "CN=testcn"; + String l = "L=testl"; + String st = "ST=testst"; + String o = "O=testo"; + String ou = "OU=testou"; + String c = "C=testc"; + String street = "STREET=teststreet"; + String dc = "DC=testdc"; + String uid = "UID=testuid"; + String surname = "SURNAME=testsurname"; + String initials = "INITIALS=testinitials"; + String givenName = "GIVENNAME=testgivenname"; + assertEquals("$cn,$l,$st,$o,$ou,$c,$street,$dc,$uid,$surname,$givenName,$initials".toString(), + CertificateUtils.reorderDn("$surname,$st,$o,$initials,$givenName,$uid,$street,$c,$cn,$ou,$l,$dc")); + } } http://git-wip-us.apache.org/repos/asf/nifi/blob/fa5da543/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/commandLine/ExitCode.java ---------------------------------------------------------------------- diff --git a/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/commandLine/ExitCode.java b/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/commandLine/ExitCode.java index b99b1af..f06ac2d 100644 --- a/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/commandLine/ExitCode.java +++ b/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/commandLine/ExitCode.java @@ -24,7 +24,6 @@ public enum ExitCode { SERVICE_ERROR, ERROR_PARSING_COMMAND_LINE, ERROR_GENERATING_CONFIG, - ERROR_SAME_KEY_AND_KEY_PASSWORD, ERROR_INCORRECT_NUMBER_OF_PASSWORDS, ERROR_PARSING_INT_ARG, ERROR_TOKEN_ARG_EMPTY, http://git-wip-us.apache.org/repos/asf/nifi/blob/fa5da543/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/configuration/StandaloneConfig.java ---------------------------------------------------------------------- diff --git a/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/configuration/StandaloneConfig.java b/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/configuration/StandaloneConfig.java new file mode 100644 index 0000000..342e1e5 --- /dev/null +++ b/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/configuration/StandaloneConfig.java @@ -0,0 +1,125 @@ +/* + * 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.configuration; + +import org.apache.nifi.toolkit.tls.properties.NiFiPropertiesWriterFactory; + +import java.io.File; +import java.util.List; + +public class StandaloneConfig extends TlsConfig { + private File baseDir; + private NiFiPropertiesWriterFactory niFiPropertiesWriterFactory; + private List<String> hostnames; + private List<String> keyStorePasswords; + private List<String> keyPasswords; + private List<String> trustStorePasswords; + private List<String> clientDns; + private List<String> clientPasswords; + private boolean clientPasswordsGenerated; + private int httpsPort; + private boolean overwrite; + + public List<String> getClientDns() { + return clientDns; + } + + public void setClientDns(List<String> clientDns) { + this.clientDns = clientDns; + } + + public boolean isOverwrite() { + return overwrite; + } + + public void setOverwrite(boolean overwrite) { + this.overwrite = overwrite; + } + + public File getBaseDir() { + return baseDir; + } + + public void setBaseDir(File baseDir) { + this.baseDir = baseDir; + } + + public NiFiPropertiesWriterFactory getNiFiPropertiesWriterFactory() { + return niFiPropertiesWriterFactory; + } + + public void setNiFiPropertiesWriterFactory(NiFiPropertiesWriterFactory niFiPropertiesWriterFactory) { + this.niFiPropertiesWriterFactory = niFiPropertiesWriterFactory; + } + + public List<String> getHostnames() { + return hostnames; + } + + public void setHostnames(List<String> hostnames) { + this.hostnames = hostnames; + } + + public List<String> getKeyStorePasswords() { + return keyStorePasswords; + } + + public void setKeyStorePasswords(List<String> keyStorePasswords) { + this.keyStorePasswords = keyStorePasswords; + } + + public List<String> getKeyPasswords() { + return keyPasswords; + } + + public void setKeyPasswords(List<String> keyPasswords) { + this.keyPasswords = keyPasswords; + } + + public List<String> getTrustStorePasswords() { + return trustStorePasswords; + } + + public void setTrustStorePasswords(List<String> trustStorePasswords) { + this.trustStorePasswords = trustStorePasswords; + } + + public List<String> getClientPasswords() { + return clientPasswords; + } + + public void setClientPasswords(List<String> clientPasswords) { + this.clientPasswords = clientPasswords; + } + + public int getHttpsPort() { + return httpsPort; + } + + public void setHttpsPort(int httpsPort) { + this.httpsPort = httpsPort; + } + + public boolean isClientPasswordsGenerated() { + return clientPasswordsGenerated; + } + + public void setClientPasswordsGenerated(boolean clientPasswordsGenerated) { + this.clientPasswordsGenerated = clientPasswordsGenerated; + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/fa5da543/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/configuration/TlsConfig.java ---------------------------------------------------------------------- diff --git a/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/configuration/TlsConfig.java b/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/configuration/TlsConfig.java index 819b41b..8aa3e40 100644 --- a/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/configuration/TlsConfig.java +++ b/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/configuration/TlsConfig.java @@ -17,6 +17,7 @@ package org.apache.nifi.toolkit.tls.configuration; +import org.apache.nifi.security.util.CertificateUtils; import org.apache.nifi.util.StringUtils; public class TlsConfig { @@ -43,7 +44,7 @@ public class TlsConfig { private int port = DEFAULT_PORT; public static String calcDefaultDn(String hostname) { - return "CN=" + hostname + ",OU=NIFI"; + return CertificateUtils.reorderDn("CN=" + hostname + ",OU=NIFI"); } public int getPort() { http://git-wip-us.apache.org/repos/asf/nifi/blob/fa5da543/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/manager/BaseTlsManager.java ---------------------------------------------------------------------- diff --git a/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/manager/BaseTlsManager.java b/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/manager/BaseTlsManager.java index 5a5e049..6215fc0 100644 --- a/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/manager/BaseTlsManager.java +++ b/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/manager/BaseTlsManager.java @@ -22,6 +22,7 @@ import org.apache.nifi.toolkit.tls.manager.writer.ConfigurationWriter; import org.apache.nifi.toolkit.tls.util.InputStreamFactory; import org.apache.nifi.toolkit.tls.util.OutputStreamFactory; import org.apache.nifi.toolkit.tls.util.PasswordUtil; +import org.apache.nifi.toolkit.tls.util.TlsHelper; import org.apache.nifi.util.StringUtils; import org.bouncycastle.jce.provider.BouncyCastleProvider; @@ -29,7 +30,6 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; import java.security.GeneralSecurityException; import java.security.KeyPair; import java.security.KeyStore; @@ -38,7 +38,6 @@ import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.UnrecoverableEntryException; import java.security.cert.Certificate; -import java.security.cert.CertificateException; import java.util.ArrayList; import java.util.List; @@ -50,6 +49,7 @@ public class BaseTlsManager { private final KeyStore keyStore; private final List<ConfigurationWriter<TlsConfig>> configurationWriters; private boolean differentKeyAndKeyStorePassword = false; + private boolean keyStorePasswordGenerated = false; public BaseTlsManager(TlsConfig tlsConfig) throws GeneralSecurityException, IOException { this(tlsConfig, new PasswordUtil(), FileInputStream::new); @@ -107,13 +107,14 @@ public class BaseTlsManager { String result = tlsConfig.getKeyStorePassword(); if (StringUtils.isEmpty(result)) { result = passwordUtil.generatePassword(); + keyStorePasswordGenerated = true; tlsConfig.setKeyStorePassword(result); } return result; } private KeyStore getInstance(String keyStoreType) throws KeyStoreException, NoSuchProviderException { - if (PKCS_12.equals(keyStoreType)) { + if (PKCS_12.equalsIgnoreCase(keyStoreType)) { return KeyStore.getInstance(keyStoreType, BouncyCastleProvider.PROVIDER_NAME); } else { return KeyStore.getInstance(keyStoreType); @@ -133,12 +134,9 @@ public class BaseTlsManager { return result; } - public void write(OutputStreamFactory outputStreamFactory) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException { + public void write(OutputStreamFactory outputStreamFactory) throws IOException, GeneralSecurityException { String keyStorePassword = getKeyStorePassword(); - - try (OutputStream outputStream = outputStreamFactory.create(new File(tlsConfig.getKeyStore()))) { - keyStore.store(outputStream, keyStorePassword.toCharArray()); - } + tlsConfig.setKeyStorePassword(TlsHelper.writeKeyStore(keyStore, outputStreamFactory, new File(tlsConfig.getKeyStore()), keyStorePassword, keyStorePasswordGenerated)); for (ConfigurationWriter<TlsConfig> configurationWriter : configurationWriters) { configurationWriter.write(tlsConfig); http://git-wip-us.apache.org/repos/asf/nifi/blob/fa5da543/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/manager/TlsCertificateAuthorityManager.java ---------------------------------------------------------------------- diff --git a/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/manager/TlsCertificateAuthorityManager.java b/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/manager/TlsCertificateAuthorityManager.java index 39faf28..2fa0534 100644 --- a/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/manager/TlsCertificateAuthorityManager.java +++ b/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/manager/TlsCertificateAuthorityManager.java @@ -38,7 +38,7 @@ public class TlsCertificateAuthorityManager extends BaseTlsManager { if (entry == null) { TlsConfig tlsConfig = getTlsConfig(); KeyPair keyPair = TlsHelper.generateKeyPair(tlsConfig.getKeyPairAlgorithm(), tlsConfig.getKeySize()); - X509Certificate caCert = CertificateUtils.generateSelfSignedX509Certificate(keyPair, tlsConfig.getDn(), tlsConfig.getSigningAlgorithm(), tlsConfig.getDays()); + X509Certificate caCert = CertificateUtils.generateSelfSignedX509Certificate(keyPair, CertificateUtils.reorderDn(tlsConfig.getDn()), tlsConfig.getSigningAlgorithm(), tlsConfig.getDays()); entry = addPrivateKeyToKeyStore(keyPair, TlsToolkitStandalone.NIFI_KEY, caCert); } else if (!KeyStore.PrivateKeyEntry.class.isInstance(entry)) { throw new IOException("Expected " + TlsToolkitStandalone.NIFI_KEY + " alias to contain a private key entry"); http://git-wip-us.apache.org/repos/asf/nifi/blob/fa5da543/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/manager/TlsClientManager.java ---------------------------------------------------------------------- diff --git a/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/manager/TlsClientManager.java b/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/manager/TlsClientManager.java index 52ea5db..3113701 100644 --- a/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/manager/TlsClientManager.java +++ b/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/manager/TlsClientManager.java @@ -22,6 +22,7 @@ import org.apache.nifi.toolkit.tls.manager.writer.ConfigurationWriter; import org.apache.nifi.toolkit.tls.util.InputStreamFactory; import org.apache.nifi.toolkit.tls.util.OutputStreamFactory; import org.apache.nifi.toolkit.tls.util.PasswordUtil; +import org.apache.nifi.toolkit.tls.util.TlsHelper; import org.apache.nifi.util.StringUtils; import org.bouncycastle.openssl.jcajce.JcaMiscPEMGenerator; import org.bouncycastle.util.io.pem.PemWriter; @@ -34,10 +35,8 @@ import java.io.OutputStreamWriter; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableEntryException; import java.security.cert.Certificate; -import java.security.cert.CertificateException; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -73,18 +72,18 @@ public class TlsClientManager extends BaseTlsManager { } @Override - public void write(OutputStreamFactory outputStreamFactory) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException { + public void write(OutputStreamFactory outputStreamFactory) throws IOException, GeneralSecurityException { super.write(outputStreamFactory); String trustStorePassword = tlsClientConfig.getTrustStorePassword(); + boolean trustStorePasswordGenerated = false; if (StringUtils.isEmpty(trustStorePassword)) { trustStorePassword = getPasswordUtil().generatePassword(); - tlsClientConfig.setTrustStorePassword(trustStorePassword); + trustStorePasswordGenerated = true; } - try (OutputStream outputStream = outputStreamFactory.create(new File(tlsClientConfig.getTrustStore()))) { - trustStore.store(outputStream, trustStorePassword.toCharArray()); - } + trustStorePassword = TlsHelper.writeKeyStore(trustStore, outputStreamFactory, new File(tlsClientConfig.getTrustStore()), trustStorePassword, trustStorePasswordGenerated); + tlsClientConfig.setTrustStorePassword(trustStorePassword); for (ConfigurationWriter<TlsClientConfig> configurationWriter : configurationWriters) { configurationWriter.write(tlsClientConfig); http://git-wip-us.apache.org/repos/asf/nifi/blob/fa5da543/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/service/client/TlsCertificateSigningRequestPerformer.java ---------------------------------------------------------------------- diff --git a/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/service/client/TlsCertificateSigningRequestPerformer.java b/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/service/client/TlsCertificateSigningRequestPerformer.java index 2c65964..889f217 100644 --- a/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/service/client/TlsCertificateSigningRequestPerformer.java +++ b/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/service/client/TlsCertificateSigningRequestPerformer.java @@ -28,6 +28,7 @@ import org.apache.http.entity.ByteArrayEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.ssl.SSLContextBuilder; +import org.apache.nifi.security.util.CertificateUtils; import org.apache.nifi.toolkit.tls.configuration.TlsClientConfig; import org.apache.nifi.toolkit.tls.service.dto.TlsCertificateAuthorityRequest; import org.apache.nifi.toolkit.tls.service.dto.TlsCertificateAuthorityResponse; @@ -38,6 +39,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.io.StringReader; import java.nio.charset.StandardCharsets; import java.security.KeyPair; import java.security.MessageDigest; @@ -73,7 +75,7 @@ public class TlsCertificateSigningRequestPerformer { private TlsCertificateSigningRequestPerformer(Supplier<HttpClientBuilder> httpClientBuilderSupplier, String caHostname, String dn, String token, int port, String signingAlgorithm) { this.httpClientBuilderSupplier = httpClientBuilderSupplier; this.caHostname = caHostname; - this.dn = dn; + this.dn = CertificateUtils.reorderDn(dn); this.token = token; this.port = port; this.objectMapper = new ObjectMapper(); @@ -141,10 +143,10 @@ public class TlsCertificateSigningRequestPerformer { if (!tlsCertificateAuthorityResponse.hasCertificate()) { throw new IOException(EXPECTED_RESPONSE_TO_CONTAIN_CERTIFICATE); } - X509Certificate x509Certificate = TlsHelper.parseCertificate(tlsCertificateAuthorityResponse.getPemEncodedCertificate()); + X509Certificate x509Certificate = TlsHelper.parseCertificate(new StringReader(tlsCertificateAuthorityResponse.getPemEncodedCertificate())); x509Certificate.verify(caCertificate.getPublicKey()); if (logger.isInfoEnabled()) { - logger.info("Got certificate with dn " + x509Certificate.getSubjectDN()); + logger.info("Got certificate with dn " + x509Certificate.getSubjectX500Principal()); } return new X509Certificate[]{x509Certificate, caCertificate}; } catch (IOException e) { http://git-wip-us.apache.org/repos/asf/nifi/blob/fa5da543/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/service/server/TlsCertificateAuthorityServiceHandler.java ---------------------------------------------------------------------- diff --git a/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/service/server/TlsCertificateAuthorityServiceHandler.java b/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/service/server/TlsCertificateAuthorityServiceHandler.java index fb83498..27d995e 100644 --- a/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/service/server/TlsCertificateAuthorityServiceHandler.java +++ b/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/service/server/TlsCertificateAuthorityServiceHandler.java @@ -82,7 +82,11 @@ public class TlsCertificateAuthorityServiceHandler extends AbstractHandler { byte[] expectedHmac = TlsHelper.calculateHMac(token, jcaPKCS10CertificationRequest.getPublicKey()); if (MessageDigest.isEqual(expectedHmac, tlsCertificateAuthorityRequest.getHmac())) { - X509Certificate x509Certificate = CertificateUtils.generateIssuedCertificate(jcaPKCS10CertificationRequest.getSubject().toString(), + String dn = jcaPKCS10CertificationRequest.getSubject().toString(); + if (logger.isInfoEnabled()) { + logger.info("Received CSR with DN " + dn); + } + X509Certificate x509Certificate = CertificateUtils.generateIssuedCertificate(dn, jcaPKCS10CertificationRequest.getPublicKey(), caCert, keyPair, signingAlgorithm, days); writeResponse(objectMapper, request, response, new TlsCertificateAuthorityResponse(TlsHelper.calculateHMac(token, caCert.getPublicKey()), TlsHelper.pemEncodeJcaObject(x509Certificate)), Response.SC_OK); http://git-wip-us.apache.org/repos/asf/nifi/blob/fa5da543/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/standalone/TlsToolkitStandalone.java ---------------------------------------------------------------------- diff --git a/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/standalone/TlsToolkitStandalone.java b/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/standalone/TlsToolkitStandalone.java index 0136e64..c91e7fa 100644 --- a/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/standalone/TlsToolkitStandalone.java +++ b/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/standalone/TlsToolkitStandalone.java @@ -18,14 +18,17 @@ package org.apache.nifi.toolkit.tls.standalone; import org.apache.nifi.security.util.CertificateUtils; +import org.apache.nifi.toolkit.tls.configuration.StandaloneConfig; import org.apache.nifi.toolkit.tls.configuration.TlsClientConfig; import org.apache.nifi.toolkit.tls.configuration.TlsConfig; +import org.apache.nifi.toolkit.tls.manager.BaseTlsManager; import org.apache.nifi.toolkit.tls.manager.TlsCertificateAuthorityManager; import org.apache.nifi.toolkit.tls.manager.TlsClientManager; import org.apache.nifi.toolkit.tls.manager.writer.NifiPropertiesTlsClientConfigWriter; import org.apache.nifi.toolkit.tls.properties.NiFiPropertiesWriterFactory; import org.apache.nifi.toolkit.tls.util.OutputStreamFactory; import org.apache.nifi.toolkit.tls.util.TlsHelper; +import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openssl.jcajce.JcaMiscPEMGenerator; import org.bouncycastle.util.io.pem.PemWriter; import org.slf4j.Logger; @@ -33,11 +36,14 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.FileWriter; import java.io.IOException; import java.io.OutputStreamWriter; import java.security.GeneralSecurityException; import java.security.KeyPair; import java.security.KeyStore; +import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.util.List; @@ -57,17 +63,8 @@ public class TlsToolkitStandalone { this.outputStreamFactory = outputStreamFactory; } - public void createNifiKeystoresAndTrustStores(File baseDir, TlsConfig tlsConfig, NiFiPropertiesWriterFactory niFiPropertiesWriterFactory, List<String> hostnames, List<String> keyStorePasswords, - List<String> keyPasswords, List<String> trustStorePasswords, int httpsPort) throws GeneralSecurityException, IOException { - String signingAlgorithm = tlsConfig.getSigningAlgorithm(); - int days = tlsConfig.getDays(); - String keyPairAlgorithm = tlsConfig.getKeyPairAlgorithm(); - int keySize = tlsConfig.getKeySize(); - TlsCertificateAuthorityManager tlsCertificateAuthorityManager = new TlsCertificateAuthorityManager(tlsConfig); - KeyStore.PrivateKeyEntry privateKeyEntry = tlsCertificateAuthorityManager.getOrGenerateCertificateAuthority(); - X509Certificate certificate = (X509Certificate) privateKeyEntry.getCertificateChain()[0]; - KeyPair caKeyPair = new KeyPair(certificate.getPublicKey(), privateKeyEntry.getPrivateKey()); - + public void createNifiKeystoresAndTrustStores(StandaloneConfig standaloneConfig) throws GeneralSecurityException, IOException { + File baseDir = standaloneConfig.getBaseDir(); if (!baseDir.exists() && !baseDir.mkdirs()) { throw new IOException(baseDir + " doesn't exist and unable to create it."); } @@ -76,48 +73,107 @@ public class TlsToolkitStandalone { throw new IOException("Expected directory to output to"); } - if (logger.isInfoEnabled()) { - logger.info("Running standalone certificate generation with output directory " + baseDir + " and hostnames " + hostnames); - } + String signingAlgorithm = standaloneConfig.getSigningAlgorithm(); + int days = standaloneConfig.getDays(); + String keyPairAlgorithm = standaloneConfig.getKeyPairAlgorithm(); + int keySize = standaloneConfig.getKeySize(); File nifiCert = new File(baseDir, NIFI_CERT + ".pem"); - if (nifiCert.exists()) { - throw new IOException(nifiCert.getAbsolutePath() + " exists already."); - } - File nifiKey = new File(baseDir, NIFI_KEY + ".key"); - if (nifiKey.exists()) { - throw new IOException(nifiKey.getAbsolutePath() + " exists already."); + + X509Certificate certificate; + KeyPair caKeyPair; + + List<String> hostnames = standaloneConfig.getHostnames(); + if (logger.isInfoEnabled()) { + logger.info("Running standalone certificate generation with output directory " + baseDir); } + if (nifiCert.exists()) { + if (!nifiKey.exists()) { + throw new IOException(nifiCert + " exists already, but " + nifiKey + " does not, we need both certificate and key to continue with an existing CA."); + } + try (FileReader pemEncodedCertificate = new FileReader(nifiCert)) { + certificate = TlsHelper.parseCertificate(pemEncodedCertificate); + } + try (FileReader pemEncodedKeyPair = new FileReader(nifiKey)) { + caKeyPair = TlsHelper.parseKeyPair(pemEncodedKeyPair); + } - for (String hostname : hostnames) { - File hostDirectory = new File(baseDir, hostname); - if (hostDirectory.exists()) { - throw new IOException("Output destination for host " + hostname + " (" + hostDirectory.getAbsolutePath() + ") exists already."); + certificate.verify(caKeyPair.getPublic()); + if (!caKeyPair.getPublic().equals(certificate.getPublicKey())) { + throw new IOException("Expected " + nifiKey + " to correspond to CA certificate at " + nifiCert); } - } - try (PemWriter pemWriter = new PemWriter(new OutputStreamWriter(outputStreamFactory.create(nifiCert)))) { - pemWriter.writeObject(new JcaMiscPEMGenerator(certificate)); - } + if (logger.isInfoEnabled()) { + logger.info("Using existing CA certificate " + nifiCert + " and key " + nifiKey); + } + } else if (nifiKey.exists()) { + throw new IOException(nifiKey + " exists already, but " + nifiCert + " does not, we need both certificate and key to continue with an existing CA."); + } else { + TlsCertificateAuthorityManager tlsCertificateAuthorityManager = new TlsCertificateAuthorityManager(standaloneConfig); + KeyStore.PrivateKeyEntry privateKeyEntry = tlsCertificateAuthorityManager.getOrGenerateCertificateAuthority(); + certificate = (X509Certificate) privateKeyEntry.getCertificateChain()[0]; + caKeyPair = new KeyPair(certificate.getPublicKey(), privateKeyEntry.getPrivateKey()); + + try (PemWriter pemWriter = new PemWriter(new OutputStreamWriter(outputStreamFactory.create(nifiCert)))) { + pemWriter.writeObject(new JcaMiscPEMGenerator(certificate)); + } - try (PemWriter pemWriter = new PemWriter(new OutputStreamWriter(outputStreamFactory.create(nifiKey)))) { - pemWriter.writeObject(new JcaMiscPEMGenerator(caKeyPair)); + try (PemWriter pemWriter = new PemWriter(new OutputStreamWriter(outputStreamFactory.create(nifiKey)))) { + pemWriter.writeObject(new JcaMiscPEMGenerator(caKeyPair)); + } + + if (logger.isInfoEnabled()) { + logger.info("Generated new CA certificate " + nifiCert + " and key " + nifiKey); + } } + List<String> keyStorePasswords = standaloneConfig.getKeyStorePasswords(); + List<String> keyPasswords = standaloneConfig.getKeyPasswords(); + List<String> trustStorePasswords = standaloneConfig.getTrustStorePasswords(); + NiFiPropertiesWriterFactory niFiPropertiesWriterFactory = standaloneConfig.getNiFiPropertiesWriterFactory(); + int httpsPort = standaloneConfig.getHttpsPort(); + boolean overwrite = standaloneConfig.isOverwrite(); + + if (hostnames.isEmpty() && logger.isInfoEnabled()) { + logger.info("No " + TlsToolkitStandaloneCommandLine.HOSTNAMES_ARG + " specified, not generating any host certificates or configuration."); + } for (int i = 0; i < hostnames.size(); i++) { String hostname = hostnames.get(i); File hostDir = new File(baseDir, hostname); - if (!hostDir.mkdirs()) { + TlsClientConfig tlsClientConfig = new TlsClientConfig(standaloneConfig); + File keystore = new File(hostDir, "keystore." + tlsClientConfig.getKeyStoreType().toLowerCase()); + File truststore = new File(hostDir, "truststore." + tlsClientConfig.getTrustStoreType().toLowerCase()); + + if (hostDir.exists()) { + if (!hostDir.isDirectory()) { + throw new IOException(hostDir + " exists but is not a directory."); + } else if (overwrite) { + if (logger.isInfoEnabled()) { + logger.info("Overwriting any existing ssl configuration in " + hostDir); + } + keystore.delete(); + if (keystore.exists()) { + throw new IOException("Keystore " + keystore + " already exists and couldn't be deleted."); + } + truststore.delete(); + if (truststore.exists()) { + throw new IOException("Truststore " + truststore + " already exists and couldn't be deleted."); + } + } else { + throw new IOException(hostDir + " exists and overwrite is not set."); + } + } else if (!hostDir.mkdirs()) { throw new IOException("Unable to make directory: " + hostDir.getAbsolutePath()); + } else if (logger.isInfoEnabled()) { + logger.info("Writing new ssl configuration to " + hostDir); } - TlsClientConfig tlsClientConfig = new TlsClientConfig(tlsConfig); - tlsClientConfig.setKeyStore(new File(hostDir, "keystore." + tlsClientConfig.getKeyStoreType().toLowerCase()).getAbsolutePath()); + tlsClientConfig.setKeyStore(keystore.getAbsolutePath()); tlsClientConfig.setKeyStorePassword(keyStorePasswords.get(i)); tlsClientConfig.setKeyPassword(keyPasswords.get(i)); - tlsClientConfig.setTrustStore(new File(hostDir, "truststore." + tlsClientConfig.getTrustStoreType().toLowerCase()).getAbsolutePath()); + tlsClientConfig.setTrustStore(truststore.getAbsolutePath()); tlsClientConfig.setTrustStorePassword(trustStorePasswords.get(i)); TlsClientManager tlsClientManager = new TlsClientManager(tlsClientConfig); KeyPair keyPair = TlsHelper.generateKeyPair(keyPairAlgorithm, keySize); @@ -132,8 +188,50 @@ public class TlsToolkitStandalone { } } + List<String> clientDns = standaloneConfig.getClientDns(); + if (standaloneConfig.getClientDns().isEmpty() && logger.isInfoEnabled()) { + logger.info("No " + TlsToolkitStandaloneCommandLine.CLIENT_CERT_DN_ARG + " specified, not generating any client certificates."); + } + + List<String> clientPasswords = standaloneConfig.getClientPasswords(); + for (int i = 0; i < clientDns.size(); i++) { + String reorderedDn = CertificateUtils.reorderDn(clientDns.get(i)); + String clientDnFile = getClientDnFile(reorderedDn); + File clientCertFile = new File(baseDir, clientDnFile + ".p12"); + + if (clientCertFile.exists()) { + if (overwrite) { + if (logger.isInfoEnabled()) { + logger.info("Overwriting existing client cert " + clientCertFile); + } + } else { + throw new IOException(clientCertFile + " exists and overwrite is not set."); + } + } else if (logger.isInfoEnabled()) { + logger.info("Generating new client certificate " + clientCertFile); + } + KeyPair keyPair = TlsHelper.generateKeyPair(keyPairAlgorithm, keySize); + X509Certificate clientCert = CertificateUtils.generateIssuedCertificate(reorderedDn, keyPair.getPublic(), certificate, caKeyPair, signingAlgorithm, days); + KeyStore keyStore = KeyStore.getInstance(BaseTlsManager.PKCS_12, BouncyCastleProvider.PROVIDER_NAME); + keyStore.load(null, null); + keyStore.setKeyEntry(NIFI_KEY, keyPair.getPrivate(), null, new Certificate[]{clientCert, certificate}); + String password = TlsHelper.writeKeyStore(keyStore, outputStreamFactory, clientCertFile, clientPasswords.get(i), standaloneConfig.isClientPasswordsGenerated()); + + try (FileWriter fileWriter = new FileWriter(new File(baseDir, clientDnFile + ".password"))) { + fileWriter.write(password); + } + + if (logger.isInfoEnabled()) { + logger.info("Successfully generated client certificate " + clientCertFile); + } + } + if (logger.isInfoEnabled()) { - logger.info("Successfully generated TLS configuration for all hosts"); + logger.info("tls-toolkit standalone completed successfully"); } } + + protected static String getClientDnFile(String clientDn) { + return clientDn.replace(',', '_').replace(' ', '_'); + } } http://git-wip-us.apache.org/repos/asf/nifi/blob/fa5da543/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/standalone/TlsToolkitStandaloneCommandLine.java ---------------------------------------------------------------------- diff --git a/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/standalone/TlsToolkitStandaloneCommandLine.java b/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/standalone/TlsToolkitStandaloneCommandLine.java index 697148f..602fce4 100644 --- a/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/standalone/TlsToolkitStandaloneCommandLine.java +++ b/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/standalone/TlsToolkitStandaloneCommandLine.java @@ -21,7 +21,7 @@ import org.apache.commons.cli.CommandLine; import org.apache.nifi.toolkit.tls.commandLine.BaseCommandLine; import org.apache.nifi.toolkit.tls.commandLine.CommandLineParseException; import org.apache.nifi.toolkit.tls.commandLine.ExitCode; -import org.apache.nifi.toolkit.tls.configuration.TlsConfig; +import org.apache.nifi.toolkit.tls.configuration.StandaloneConfig; import org.apache.nifi.toolkit.tls.properties.NiFiPropertiesWriterFactory; import org.apache.nifi.toolkit.tls.util.PasswordUtil; import org.apache.nifi.toolkit.tls.util.TlsHelper; @@ -48,9 +48,12 @@ public class TlsToolkitStandaloneCommandLine extends BaseCommandLine { public static final String KEY_PASSWORD_ARG = "keyPassword"; public static final String HOSTNAMES_ARG = "hostnames"; public static final String HTTPS_PORT_ARG = "httpsPort"; + public static final String OVERWRITE_ARG = "isOverwrite"; + public static final String CLIENT_CERT_DN_ARG = "clientCertDn"; + public static final String CLIENT_CERT_PASSWORD_ARG = "clientCertPassword"; public static final String DEFAULT_OUTPUT_DIRECTORY = "../" + Paths.get(".").toAbsolutePath().normalize().getFileName().toString(); - public static final int DEFAULT_HTTPS_PORT = 10443; + public static final int DEFAULT_HTTPS_PORT = 9091; public static final String DESCRIPTION = "Creates certificates and config files for nifi cluster."; @@ -64,6 +67,10 @@ public class TlsToolkitStandaloneCommandLine extends BaseCommandLine { private List<String> keyStorePasswords; private List<String> keyPasswords; private List<String> trustStorePasswords; + private List<String> clientDns; + private List<String> clientPasswords; + private boolean clientPasswordsGenerated; + private boolean overwrite; public TlsToolkitStandaloneCommandLine() { this(new PasswordUtil()); @@ -73,12 +80,15 @@ public class TlsToolkitStandaloneCommandLine extends BaseCommandLine { super(DESCRIPTION); this.passwordUtil = passwordUtil; addOptionWithArg("o", OUTPUT_DIRECTORY_ARG, "The directory to output keystores, truststore, config files.", DEFAULT_OUTPUT_DIRECTORY); - addOptionWithArg("n", HOSTNAMES_ARG, "Comma separated list of hostnames.", TlsConfig.DEFAULT_HOSTNAME); + addOptionWithArg("n", HOSTNAMES_ARG, "Comma separated list of hostnames."); addOptionWithArg("p", HTTPS_PORT_ARG, "Https port to use.", DEFAULT_HTTPS_PORT); addOptionWithArg("f", NIFI_PROPERTIES_FILE_ARG, "Base nifi.properties file to update. (Embedded file identical to the one in a default NiFi install will be used if not specified.)"); addOptionWithArg("S", KEY_STORE_PASSWORD_ARG, "Keystore password to use. Must either be one value or one for each host. (autogenerate if not specified)"); addOptionWithArg("K", KEY_PASSWORD_ARG, "Key password to use. Must either be one value or one for each host. (autogenerate if not specified)"); addOptionWithArg("P", TRUST_STORE_PASSWORD_ARG, "Keystore password to use. Must either be one value or one for each host. (autogenerate if not specified)"); + addOptionWithArg("C", CLIENT_CERT_DN_ARG, "Generate client certificate suitable for use in browser with specified DN. (Can be specified multiple times.)"); + addOptionWithArg("B", CLIENT_CERT_PASSWORD_ARG, "Password for client certificate. Must either be one value or one for each client DN. (autogenerate if not specified)"); + addOptionNoArg("O", OVERWRITE_ARG, "Overwrite existing host output."); } public static void main(String[] args) { @@ -90,9 +100,7 @@ public class TlsToolkitStandaloneCommandLine extends BaseCommandLine { System.exit(e.getExitCode()); } try { - new TlsToolkitStandalone().createNifiKeystoresAndTrustStores(tlsToolkitStandaloneCommandLine.getBaseDir(), tlsToolkitStandaloneCommandLine.createConfig(), - tlsToolkitStandaloneCommandLine.getNiFiPropertiesWriterFactory(), tlsToolkitStandaloneCommandLine.getHostnames(), tlsToolkitStandaloneCommandLine.getKeyStorePasswords(), - tlsToolkitStandaloneCommandLine.getKeyPasswords(), tlsToolkitStandaloneCommandLine.getTrustStorePasswords(), tlsToolkitStandaloneCommandLine.getHttpsPort()); + new TlsToolkitStandalone().createNifiKeystoresAndTrustStores(tlsToolkitStandaloneCommandLine.createConfig()); } catch (Exception e) { tlsToolkitStandaloneCommandLine.printUsage("Error creating generating tls configuration. (" + e.getMessage() + ")"); System.exit(ExitCode.ERROR_GENERATING_CONFIG.ordinal()); @@ -105,13 +113,29 @@ public class TlsToolkitStandaloneCommandLine extends BaseCommandLine { CommandLine commandLine = super.doParse(args); String outputDirectory = commandLine.getOptionValue(OUTPUT_DIRECTORY_ARG, DEFAULT_OUTPUT_DIRECTORY); baseDir = new File(outputDirectory); - hostnames = Arrays.stream(commandLine.getOptionValue(HOSTNAMES_ARG, TlsConfig.DEFAULT_HOSTNAME).split(",")).map(String::trim).collect(Collectors.toList()); + + if (commandLine.hasOption(HOSTNAMES_ARG)) { + hostnames = Collections.unmodifiableList(Arrays.stream(commandLine.getOptionValue(HOSTNAMES_ARG).split(",")).map(String::trim).collect(Collectors.toList())); + } else { + hostnames = Collections.emptyList(); + } + + String[] clientDnValues = commandLine.getOptionValues(CLIENT_CERT_DN_ARG); + if (clientDnValues != null) { + clientDns = Collections.unmodifiableList(Arrays.stream(clientDnValues).collect(Collectors.toList())); + } else { + clientDns = Collections.emptyList(); + } + httpsPort = getIntValue(commandLine, HTTPS_PORT_ARG, DEFAULT_HTTPS_PORT); int numHosts = hostnames.size(); - keyStorePasswords = Collections.unmodifiableList(getPasswords(KEY_STORE_PASSWORD_ARG, commandLine, numHosts)); + keyStorePasswords = Collections.unmodifiableList(getPasswords(KEY_STORE_PASSWORD_ARG, commandLine, numHosts, HOSTNAMES_ARG)); keyPasswords = Collections.unmodifiableList(getKeyPasswords(commandLine, keyStorePasswords)); - trustStorePasswords = Collections.unmodifiableList(getPasswords(TRUST_STORE_PASSWORD_ARG, commandLine, numHosts)); + trustStorePasswords = Collections.unmodifiableList(getPasswords(TRUST_STORE_PASSWORD_ARG, commandLine, numHosts, HOSTNAMES_ARG)); + clientPasswords = Collections.unmodifiableList(getPasswords(CLIENT_CERT_PASSWORD_ARG, commandLine, clientDns.size(), CLIENT_CERT_DN_ARG)); + clientPasswordsGenerated = commandLine.getOptionValues(CLIENT_CERT_PASSWORD_ARG) == null; + overwrite = commandLine.hasOption(OVERWRITE_ARG); String nifiPropertiesFile = commandLine.getOptionValue(NIFI_PROPERTIES_FILE_ARG, ""); try { @@ -128,64 +152,50 @@ public class TlsToolkitStandaloneCommandLine extends BaseCommandLine { return commandLine; } - private List<String> getPasswords(String arg, CommandLine commandLine, int numHosts) throws CommandLineParseException { + private List<String> getPasswords(String arg, CommandLine commandLine, int num, String numArg) throws CommandLineParseException { String[] optionValues = commandLine.getOptionValues(arg); if (optionValues == null) { - return IntStream.range(0, numHosts).mapToObj(operand -> passwordUtil.generatePassword()).collect(Collectors.toList()); + return IntStream.range(0, num).mapToObj(operand -> passwordUtil.generatePassword()).collect(Collectors.toList()); } if (optionValues.length == 1) { - return IntStream.range(0, numHosts).mapToObj(value -> optionValues[0]).collect(Collectors.toList()); - } else if (optionValues.length == numHosts) { + return IntStream.range(0, num).mapToObj(value -> optionValues[0]).collect(Collectors.toList()); + } else if (optionValues.length == num) { return Arrays.stream(optionValues).collect(Collectors.toList()); } - return printUsageAndThrow("Expected either 1 value or " + numHosts + " (the number of hostnames) values for " + arg, ExitCode.ERROR_INCORRECT_NUMBER_OF_PASSWORDS); + return printUsageAndThrow("Expected either 1 value or " + num + " (the number of " + numArg + ") values for " + arg, ExitCode.ERROR_INCORRECT_NUMBER_OF_PASSWORDS); } private List<String> getKeyPasswords(CommandLine commandLine, List<String> keyStorePasswords) throws CommandLineParseException { if (differentPasswordForKeyAndKeystore() || commandLine.hasOption(KEY_PASSWORD_ARG)) { - return getPasswords(KEY_PASSWORD_ARG, commandLine, keyStorePasswords.size()); + return getPasswords(KEY_PASSWORD_ARG, commandLine, keyStorePasswords.size(), HOSTNAMES_ARG); } return new ArrayList<>(keyStorePasswords); } - public File getBaseDir() { - return baseDir; - } - - public List<String> getHostnames() { - return hostnames; - } - - public int getHttpsPort() { - return httpsPort; - } - - public NiFiPropertiesWriterFactory getNiFiPropertiesWriterFactory() { - return niFiPropertiesWriterFactory; - } - - public List<String> getKeyStorePasswords() { - return keyStorePasswords; - } - - public List<String> getKeyPasswords() { - return keyPasswords; - } - - public List<String> getTrustStorePasswords() { - return trustStorePasswords; - } - - public TlsConfig createConfig() throws IOException { - TlsConfig tlsConfig = new TlsConfig(); - tlsConfig.setCaHostname(getCertificateAuthorityHostname()); - tlsConfig.setKeyStore("nifi-ca-" + KEYSTORE + getKeyStoreType().toLowerCase()); - tlsConfig.setKeyStoreType(getKeyStoreType()); - tlsConfig.setKeySize(getKeySize()); - tlsConfig.setKeyPairAlgorithm(getKeyAlgorithm()); - tlsConfig.setSigningAlgorithm(getSigningAlgorithm()); - tlsConfig.setDays(getDays()); - tlsConfig.initDefaults(); - return tlsConfig; + public StandaloneConfig createConfig() { + StandaloneConfig standaloneConfig = new StandaloneConfig(); + + standaloneConfig.setBaseDir(baseDir); + standaloneConfig.setNiFiPropertiesWriterFactory(niFiPropertiesWriterFactory); + standaloneConfig.setHostnames(hostnames); + standaloneConfig.setKeyStorePasswords(keyStorePasswords); + standaloneConfig.setKeyPasswords(keyPasswords); + standaloneConfig.setTrustStorePasswords(trustStorePasswords); + standaloneConfig.setHttpsPort(httpsPort); + standaloneConfig.setOverwrite(overwrite); + standaloneConfig.setClientDns(clientDns); + standaloneConfig.setClientPasswords(clientPasswords); + standaloneConfig.setClientPasswordsGenerated(clientPasswordsGenerated); + + standaloneConfig.setCaHostname(getCertificateAuthorityHostname()); + standaloneConfig.setKeyStore("nifi-ca-" + KEYSTORE + getKeyStoreType().toLowerCase()); + standaloneConfig.setKeyStoreType(getKeyStoreType()); + standaloneConfig.setKeySize(getKeySize()); + standaloneConfig.setKeyPairAlgorithm(getKeyAlgorithm()); + standaloneConfig.setSigningAlgorithm(getSigningAlgorithm()); + standaloneConfig.setDays(getDays()); + standaloneConfig.initDefaults(); + + return standaloneConfig; } } http://git-wip-us.apache.org/repos/asf/nifi/blob/fa5da543/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/util/TlsHelper.java ---------------------------------------------------------------------- diff --git a/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/util/TlsHelper.java b/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/util/TlsHelper.java index 0622b9e..05a5dcb 100644 --- a/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/util/TlsHelper.java +++ b/nifi-toolkit/nifi-toolkit-tls/src/main/java/org/apache/nifi/toolkit/tls/util/TlsHelper.java @@ -17,29 +17,38 @@ package org.apache.nifi.toolkit.tls.util; +import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils; import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openssl.PEMKeyPair; import org.bouncycastle.openssl.PEMParser; import org.bouncycastle.openssl.jcajce.JcaMiscPEMGenerator; +import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.bouncycastle.pkcs.PKCS10CertificationRequest; import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest; import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder; import org.bouncycastle.util.io.pem.PemWriter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import javax.crypto.Cipher; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; -import javax.security.auth.x500.X500Principal; +import java.io.File; import java.io.IOException; +import java.io.OutputStream; +import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; import java.security.KeyPair; import java.security.KeyPairGenerator; +import java.security.KeyStore; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.Security; @@ -47,10 +56,78 @@ import java.security.cert.CertificateException; import java.security.cert.X509Certificate; public class TlsHelper { + private static final Logger logger = LoggerFactory.getLogger(TlsHelper.class); + private static final int DEFAULT_MAX_ALLOWED_KEY_LENGTH = 128; + public static final String JCE_URL = "http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html"; + public static final String ILLEGAL_KEY_SIZE = "illegal key size"; + private static boolean isUnlimitedStrengthCryptographyEnabled; + + // Evaluate an unlimited strength algorithm to determine if we support the capability we have on the system + static { + try { + isUnlimitedStrengthCryptographyEnabled = (Cipher.getMaxAllowedKeyLength("AES") > DEFAULT_MAX_ALLOWED_KEY_LENGTH); + } catch (NoSuchAlgorithmException e) { + // if there are issues with this, we default back to the value established + isUnlimitedStrengthCryptographyEnabled = false; + } + } + + private static void logTruncationWarning(File file) { + String fileToString = file.toString(); + String fileName = file.getName(); + logger.warn("**********************************************************************************"); + logger.warn(" WARNING!!!!"); + logger.warn("**********************************************************************************"); + logger.warn("Unlimited JCE Policy is not installed which means we cannot utilize a"); + logger.warn("PKCS12 password longer than 7 characters."); + logger.warn("Autogenerated password has been reduced to 7 characters."); + logger.warn(""); + logger.warn("Please strongly consider installing Unlimited JCE Policy at"); + logger.warn(JCE_URL); + logger.warn(""); + logger.warn("Another alternative is to add a stronger password with the openssl tool to the"); + logger.warn("resulting client certificate: " + fileToString); + logger.warn(""); + logger.warn("openssl pkcs12 -in '" + fileToString + "' -out '/tmp/" + fileName + "'"); + logger.warn("openssl pkcs12 -export -in '/tmp/" + fileName + "' -out '" + fileToString + "'"); + logger.warn("rm -f '/tmp/" + fileName + "'"); + logger.warn(""); + logger.warn("**********************************************************************************"); + + } + private TlsHelper() { } + public static boolean isUnlimitedStrengthCryptographyEnabled() { + return isUnlimitedStrengthCryptographyEnabled; + } + + public static String writeKeyStore(KeyStore keyStore, OutputStreamFactory outputStreamFactory, File file, String password, boolean generatedPassword) throws IOException, GeneralSecurityException { + try (OutputStream fileOutputStream = outputStreamFactory.create(file)) { + keyStore.store(fileOutputStream, password.toCharArray()); + } catch (IOException e) { + if (e.getMessage().toLowerCase().contains(ILLEGAL_KEY_SIZE) && !isUnlimitedStrengthCryptographyEnabled()) { + if (generatedPassword) { + file.delete(); + String truncatedPassword = password.substring(0, 7); + try (OutputStream fileOutputStream = outputStreamFactory.create(file)) { + keyStore.store(fileOutputStream, truncatedPassword.toCharArray()); + } + logTruncationWarning(file); + return truncatedPassword; + } else { + throw new GeneralSecurityException("Specified password for " + file + " too long to work without unlimited JCE policy installed." + + System.lineSeparator() + "Please see " + JCE_URL); + } + } else { + throw e; + } + } + return password; + } + public static void addBouncyCastleProvider() { Security.addProvider(new BouncyCastleProvider()); } @@ -90,13 +167,21 @@ public class TlsHelper { } } - public static X509Certificate parseCertificate(String pemEncodedCertificate) throws IOException, CertificateException { - try (PEMParser pemParser = new PEMParser(new StringReader(pemEncodedCertificate))) { + public static X509Certificate parseCertificate(Reader pemEncodedCertificate) throws IOException, CertificateException { + return new JcaX509CertificateConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME).getCertificate(parsePem(X509CertificateHolder.class, pemEncodedCertificate)); + } + + public static KeyPair parseKeyPair(Reader pemEncodedKeyPair) throws IOException { + return new JcaPEMKeyConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME).getKeyPair(parsePem(PEMKeyPair.class, pemEncodedKeyPair)); + } + + public static <T> T parsePem(Class<T> clazz, Reader pemReader) throws IOException { + try (PEMParser pemParser = new PEMParser(pemReader)) { Object object = pemParser.readObject(); - if (!X509CertificateHolder.class.isInstance(object)) { - throw new IOException("Expected " + X509CertificateHolder.class); + if (!clazz.isInstance(object)) { + throw new IOException("Expected " + clazz); } - return new JcaX509CertificateConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME).getCertificate((X509CertificateHolder) object); + return (T) object; } } @@ -105,7 +190,7 @@ public class TlsHelper { } public static JcaPKCS10CertificationRequest generateCertificationRequest(String requestedDn, KeyPair keyPair, String signingAlgorithm) throws OperatorCreationException { - JcaPKCS10CertificationRequestBuilder jcaPKCS10CertificationRequestBuilder = new JcaPKCS10CertificationRequestBuilder(new X500Principal(requestedDn), keyPair.getPublic()); + JcaPKCS10CertificationRequestBuilder jcaPKCS10CertificationRequestBuilder = new JcaPKCS10CertificationRequestBuilder(new X500Name(requestedDn), keyPair.getPublic()); JcaContentSignerBuilder jcaContentSignerBuilder = new JcaContentSignerBuilder(signingAlgorithm); return new JcaPKCS10CertificationRequest(jcaPKCS10CertificationRequestBuilder.build(jcaContentSignerBuilder.build(keyPair.getPrivate()))); } http://git-wip-us.apache.org/repos/asf/nifi/blob/fa5da543/nifi-toolkit/nifi-toolkit-tls/src/test/java/org/apache/nifi/toolkit/tls/service/TlsCertificateAuthorityTest.java ---------------------------------------------------------------------- diff --git a/nifi-toolkit/nifi-toolkit-tls/src/test/java/org/apache/nifi/toolkit/tls/service/TlsCertificateAuthorityTest.java b/nifi-toolkit/nifi-toolkit-tls/src/test/java/org/apache/nifi/toolkit/tls/service/TlsCertificateAuthorityTest.java index 7881500..ad5fa12 100644 --- a/nifi-toolkit/nifi-toolkit-tls/src/test/java/org/apache/nifi/toolkit/tls/service/TlsCertificateAuthorityTest.java +++ b/nifi-toolkit/nifi-toolkit-tls/src/test/java/org/apache/nifi/toolkit/tls/service/TlsCertificateAuthorityTest.java @@ -107,7 +107,7 @@ public class TlsCertificateAuthorityTest { clientConfig = new TlsClientConfig(); clientConfig.setCaHostname("localhost"); - clientConfig.setDn("CN=otherHostname,OU=NIFI"); + clientConfig.setDn("OU=NIFI,CN=otherHostname"); clientConfig.setKeyStore(clientKeyStore); clientConfig.setTrustStore(clientTrustStore); clientConfig.setToken(myTestTokenUseSomethingStronger); @@ -227,7 +227,7 @@ public class TlsCertificateAuthorityTest { assertEquals(caCertificate, clientTrustStore.getCertificate(TlsToolkitStandalone.NIFI_CERT)); } - private void assertPrivateAndPublicKeyMatch(PrivateKey privateKey, PublicKey publicKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { + public static void assertPrivateAndPublicKeyMatch(PrivateKey privateKey, PublicKey publicKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { Signature signature = Signature.getInstance(TlsConfig.DEFAULT_SIGNING_ALGORITHM); signature.initSign(privateKey); byte[] bytes = "test string".getBytes(StandardCharsets.UTF_8); http://git-wip-us.apache.org/repos/asf/nifi/blob/fa5da543/nifi-toolkit/nifi-toolkit-tls/src/test/java/org/apache/nifi/toolkit/tls/service/server/TlsCertificateAuthorityServiceHandlerTest.java ---------------------------------------------------------------------- diff --git a/nifi-toolkit/nifi-toolkit-tls/src/test/java/org/apache/nifi/toolkit/tls/service/server/TlsCertificateAuthorityServiceHandlerTest.java b/nifi-toolkit/nifi-toolkit-tls/src/test/java/org/apache/nifi/toolkit/tls/service/server/TlsCertificateAuthorityServiceHandlerTest.java index bf355fa..09bc8f0 100644 --- a/nifi-toolkit/nifi-toolkit-tls/src/test/java/org/apache/nifi/toolkit/tls/service/server/TlsCertificateAuthorityServiceHandlerTest.java +++ b/nifi-toolkit/nifi-toolkit-tls/src/test/java/org/apache/nifi/toolkit/tls/service/server/TlsCertificateAuthorityServiceHandlerTest.java @@ -145,7 +145,7 @@ public class TlsCertificateAuthorityServiceHandlerTest { tlsCertificateAuthorityServiceHandler.handle(null, baseRequest, httpServletRequest, httpServletResponse); assertEquals(Response.SC_OK, statusCode); assertArrayEquals(testCaHmac, getResponse().getHmac()); - X509Certificate certificate = TlsHelper.parseCertificate(getResponse().getPemEncodedCertificate()); + X509Certificate certificate = TlsHelper.parseCertificate(new StringReader(getResponse().getPemEncodedCertificate())); assertEquals(certificateKeyPair.getPublic(), certificate.getPublicKey()); assertEquals(new X500Name(requestedDn), new X500Name(certificate.getSubjectDN().toString())); certificate.verify(caCert.getPublicKey()); http://git-wip-us.apache.org/repos/asf/nifi/blob/fa5da543/nifi-toolkit/nifi-toolkit-tls/src/test/java/org/apache/nifi/toolkit/tls/standalone/TlsToolkitStandaloneCommandLineTest.java ---------------------------------------------------------------------- diff --git a/nifi-toolkit/nifi-toolkit-tls/src/test/java/org/apache/nifi/toolkit/tls/standalone/TlsToolkitStandaloneCommandLineTest.java b/nifi-toolkit/nifi-toolkit-tls/src/test/java/org/apache/nifi/toolkit/tls/standalone/TlsToolkitStandaloneCommandLineTest.java index fd45eb4..82c67d9 100644 --- a/nifi-toolkit/nifi-toolkit-tls/src/test/java/org/apache/nifi/toolkit/tls/standalone/TlsToolkitStandaloneCommandLineTest.java +++ b/nifi-toolkit/nifi-toolkit-tls/src/test/java/org/apache/nifi/toolkit/tls/standalone/TlsToolkitStandaloneCommandLineTest.java @@ -19,6 +19,8 @@ package org.apache.nifi.toolkit.tls.standalone; import org.apache.nifi.toolkit.tls.commandLine.CommandLineParseException; import org.apache.nifi.toolkit.tls.commandLine.ExitCode; +import org.apache.nifi.toolkit.tls.configuration.StandaloneConfig; +import org.apache.nifi.toolkit.tls.configuration.TlsConfig; import org.apache.nifi.toolkit.tls.properties.NiFiPropertiesWriter; import org.apache.nifi.toolkit.tls.util.PasswordUtil; import org.junit.Assert; @@ -31,6 +33,7 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.security.SecureRandom; +import java.util.Collections; import java.util.List; import java.util.Properties; import java.util.Random; @@ -75,7 +78,7 @@ public class TlsToolkitStandaloneCommandLineTest { } @Test - public void testKeyAlgorithm() throws CommandLineParseException, IOException { + public void testKeyAlgorithm() throws CommandLineParseException { String testKeyAlgorithm = "testKeyAlgorithm"; tlsToolkitStandaloneCommandLine.parse("-a", testKeyAlgorithm); assertEquals(testKeyAlgorithm, tlsToolkitStandaloneCommandLine.createConfig().getKeyPairAlgorithm()); @@ -115,7 +118,7 @@ public class TlsToolkitStandaloneCommandLineTest { } @Test - public void testDays() throws CommandLineParseException, IOException { + public void testDays() throws CommandLineParseException { int testDays = 29; tlsToolkitStandaloneCommandLine.parse("-d", Integer.toString(testDays)); assertEquals(testDays, tlsToolkitStandaloneCommandLine.createConfig().getDays()); @@ -132,7 +135,7 @@ public class TlsToolkitStandaloneCommandLineTest { public void testOutputDirectory() throws CommandLineParseException { String testPath = File.separator + "fake" + File.separator + "path" + File.separator + "doesnt" + File.separator + "exist"; tlsToolkitStandaloneCommandLine.parse("-o", testPath); - assertEquals(testPath, tlsToolkitStandaloneCommandLine.getBaseDir().getPath()); + assertEquals(testPath, tlsToolkitStandaloneCommandLine.createConfig().getBaseDir().getPath()); } @Test @@ -142,7 +145,7 @@ public class TlsToolkitStandaloneCommandLineTest { tlsToolkitStandaloneCommandLine.parse("-n", nifi1 + " , " + nifi2); - List<String> hostnames = tlsToolkitStandaloneCommandLine.getHostnames(); + List<String> hostnames = tlsToolkitStandaloneCommandLine.createConfig().getHostnames(); assertEquals(2, hostnames.size()); assertEquals(nifi1, hostnames.get(0)); assertEquals(nifi2, hostnames.get(1)); @@ -152,7 +155,7 @@ public class TlsToolkitStandaloneCommandLineTest { public void testHttpsPort() throws CommandLineParseException { int testPort = 8998; tlsToolkitStandaloneCommandLine.parse("-p", Integer.toString(testPort)); - assertEquals(testPort, tlsToolkitStandaloneCommandLine.getHttpsPort()); + assertEquals(testPort, tlsToolkitStandaloneCommandLine.createConfig().getHttpsPort()); } @Test @@ -179,10 +182,10 @@ public class TlsToolkitStandaloneCommandLineTest { @Test public void testNotSameKeyAndKeystorePassword() throws CommandLineParseException { - tlsToolkitStandaloneCommandLine.parse("-g"); - List<String> keyStorePasswords = tlsToolkitStandaloneCommandLine.getKeyStorePasswords(); - List<String> keyPasswords = tlsToolkitStandaloneCommandLine.getKeyPasswords(); - assertEquals(1, tlsToolkitStandaloneCommandLine.getHostnames().size()); + tlsToolkitStandaloneCommandLine.parse("-g", "-n", TlsConfig.DEFAULT_HOSTNAME); + List<String> keyStorePasswords = tlsToolkitStandaloneCommandLine.createConfig().getKeyStorePasswords(); + List<String> keyPasswords = tlsToolkitStandaloneCommandLine.createConfig().getKeyPasswords(); + assertEquals(1, tlsToolkitStandaloneCommandLine.createConfig().getHostnames().size()); assertEquals(1, keyStorePasswords.size()); assertEquals(1, keyPasswords.size()); assertNotEquals(keyStorePasswords.get(0), keyPasswords.get(0)); @@ -190,10 +193,10 @@ public class TlsToolkitStandaloneCommandLineTest { @Test public void testSameKeyAndKeystorePassword() throws CommandLineParseException { - tlsToolkitStandaloneCommandLine.parse(); - List<String> keyStorePasswords = tlsToolkitStandaloneCommandLine.getKeyStorePasswords(); - List<String> keyPasswords = tlsToolkitStandaloneCommandLine.getKeyPasswords(); - assertEquals(1, tlsToolkitStandaloneCommandLine.getHostnames().size()); + tlsToolkitStandaloneCommandLine.parse("-n", TlsConfig.DEFAULT_HOSTNAME); + List<String> keyStorePasswords = tlsToolkitStandaloneCommandLine.createConfig().getKeyStorePasswords(); + List<String> keyPasswords = tlsToolkitStandaloneCommandLine.createConfig().getKeyPasswords(); + assertEquals(1, tlsToolkitStandaloneCommandLine.createConfig().getHostnames().size()); assertEquals(1, keyStorePasswords.size()); assertEquals(1, keyPasswords.size()); assertEquals(keyStorePasswords.get(0), keyPasswords.get(0)); @@ -202,19 +205,19 @@ public class TlsToolkitStandaloneCommandLineTest { @Test public void testSameKeyAndKeystorePasswordWithKeystorePasswordSpecified() throws CommandLineParseException { String testPassword = "testPassword"; - tlsToolkitStandaloneCommandLine.parse("-S", testPassword); - List<String> keyStorePasswords = tlsToolkitStandaloneCommandLine.getKeyStorePasswords(); + tlsToolkitStandaloneCommandLine.parse("-S", testPassword, "-n", TlsConfig.DEFAULT_HOSTNAME); + List<String> keyStorePasswords = tlsToolkitStandaloneCommandLine.createConfig().getKeyStorePasswords(); assertEquals(1, keyStorePasswords.size()); assertEquals(testPassword, keyStorePasswords.get(0)); - assertEquals(keyStorePasswords, tlsToolkitStandaloneCommandLine.getKeyPasswords()); + assertEquals(keyStorePasswords, tlsToolkitStandaloneCommandLine.createConfig().getKeyPasswords()); } @Test public void testSameKeyAndKeystorePasswordWithKeyPasswordSpecified() throws CommandLineParseException { String testPassword = "testPassword"; - tlsToolkitStandaloneCommandLine.parse("-K", testPassword); - List<String> keyPasswords = tlsToolkitStandaloneCommandLine.getKeyPasswords(); - assertNotEquals(tlsToolkitStandaloneCommandLine.getKeyStorePasswords(), keyPasswords); + tlsToolkitStandaloneCommandLine.parse("-K", testPassword, "-n", TlsConfig.DEFAULT_HOSTNAME); + List<String> keyPasswords = tlsToolkitStandaloneCommandLine.createConfig().getKeyPasswords(); + assertNotEquals(tlsToolkitStandaloneCommandLine.createConfig().getKeyStorePasswords(), keyPasswords); assertEquals(1, keyPasswords.size()); assertEquals(testPassword, keyPasswords.get(0)); } @@ -222,8 +225,8 @@ public class TlsToolkitStandaloneCommandLineTest { @Test public void testKeyStorePasswordArg() throws CommandLineParseException { String testPassword = "testPassword"; - tlsToolkitStandaloneCommandLine.parse("-S", testPassword); - List<String> keyStorePasswords = tlsToolkitStandaloneCommandLine.getKeyStorePasswords(); + tlsToolkitStandaloneCommandLine.parse("-S", testPassword, "-n", TlsConfig.DEFAULT_HOSTNAME); + List<String> keyStorePasswords = tlsToolkitStandaloneCommandLine.createConfig().getKeyStorePasswords(); assertEquals(1, keyStorePasswords.size()); assertEquals(testPassword, keyStorePasswords.get(0)); } @@ -233,7 +236,7 @@ public class TlsToolkitStandaloneCommandLineTest { String testPassword1 = "testPassword1"; String testPassword2 = "testPassword2"; tlsToolkitStandaloneCommandLine.parse("-n", "nifi1,nifi2", "-S", testPassword1, "-S", testPassword2); - List<String> keyStorePasswords = tlsToolkitStandaloneCommandLine.getKeyStorePasswords(); + List<String> keyStorePasswords = tlsToolkitStandaloneCommandLine.createConfig().getKeyStorePasswords(); assertEquals(2, keyStorePasswords.size()); assertEquals(testPassword1, keyStorePasswords.get(0)); assertEquals(testPassword2, keyStorePasswords.get(1)); @@ -254,8 +257,8 @@ public class TlsToolkitStandaloneCommandLineTest { @Test public void testKeyPasswordArg() throws CommandLineParseException { String testPassword = "testPassword"; - tlsToolkitStandaloneCommandLine.parse("-K", testPassword); - List<String> keyPasswords = tlsToolkitStandaloneCommandLine.getKeyPasswords(); + tlsToolkitStandaloneCommandLine.parse("-K", testPassword, "-n", TlsConfig.DEFAULT_HOSTNAME); + List<String> keyPasswords = tlsToolkitStandaloneCommandLine.createConfig().getKeyPasswords(); assertEquals(1, keyPasswords.size()); assertEquals(testPassword, keyPasswords.get(0)); } @@ -265,7 +268,7 @@ public class TlsToolkitStandaloneCommandLineTest { String testPassword1 = "testPassword1"; String testPassword2 = "testPassword2"; tlsToolkitStandaloneCommandLine.parse("-n", "nifi1,nifi2", "-K", testPassword1, "-K", testPassword2); - List<String> keyPasswords = tlsToolkitStandaloneCommandLine.getKeyPasswords(); + List<String> keyPasswords = tlsToolkitStandaloneCommandLine.createConfig().getKeyPasswords(); assertEquals(2, keyPasswords.size()); assertEquals(testPassword1, keyPasswords.get(0)); assertEquals(testPassword2, keyPasswords.get(1)); @@ -286,8 +289,8 @@ public class TlsToolkitStandaloneCommandLineTest { @Test public void testTruststorePasswordArg() throws CommandLineParseException { String testPassword = "testPassword"; - tlsToolkitStandaloneCommandLine.parse("-P", testPassword); - List<String> trustStorePasswords = tlsToolkitStandaloneCommandLine.getTrustStorePasswords(); + tlsToolkitStandaloneCommandLine.parse("-P", testPassword, "-n", TlsConfig.DEFAULT_HOSTNAME); + List<String> trustStorePasswords = tlsToolkitStandaloneCommandLine.createConfig().getTrustStorePasswords(); assertEquals(1, trustStorePasswords.size()); assertEquals(testPassword, trustStorePasswords.get(0)); } @@ -297,7 +300,7 @@ public class TlsToolkitStandaloneCommandLineTest { String testPassword1 = "testPassword1"; String testPassword2 = "testPassword2"; tlsToolkitStandaloneCommandLine.parse("-n", "nifi1,nifi2", "-P", testPassword1, "-P", testPassword2); - List<String> trustStorePasswords = tlsToolkitStandaloneCommandLine.getTrustStorePasswords(); + List<String> trustStorePasswords = tlsToolkitStandaloneCommandLine.createConfig().getTrustStorePasswords(); assertEquals(2, trustStorePasswords.size()); assertEquals(testPassword1, trustStorePasswords.get(0)); assertEquals(testPassword2, trustStorePasswords.get(1)); @@ -315,8 +318,54 @@ public class TlsToolkitStandaloneCommandLineTest { } } + @Test + public void testClientDnDefault() throws CommandLineParseException { + tlsToolkitStandaloneCommandLine.parse(); + assertEquals(Collections.emptyList(), tlsToolkitStandaloneCommandLine.createConfig().getClientDns()); + } + + @Test + public void testClientDnSingle() throws CommandLineParseException { + String testCn = "OU=NIFI,CN=testuser"; + tlsToolkitStandaloneCommandLine.parse("-C", testCn); + List<String> clientDns = tlsToolkitStandaloneCommandLine.createConfig().getClientDns(); + assertEquals(1, clientDns.size()); + assertEquals(testCn, clientDns.get(0)); + } + + @Test + public void testClientDnMulti() throws CommandLineParseException { + String testCn = "OU=NIFI,CN=testuser"; + String testCn2 = "OU=NIFI,CN=testuser2"; + tlsToolkitStandaloneCommandLine.parse("-C", testCn, "-C", testCn2); + StandaloneConfig standaloneConfig = tlsToolkitStandaloneCommandLine.createConfig(); + List<String> clientDns = standaloneConfig.getClientDns(); + assertEquals(2, clientDns.size()); + assertEquals(testCn, clientDns.get(0)); + assertEquals(testCn2, clientDns.get(1)); + assertEquals(2, standaloneConfig.getClientPasswords().size()); + } + + @Test + public void testClientPasswordMulti() throws CommandLineParseException { + String testCn = "OU=NIFI,CN=testuser"; + String testCn2 = "OU=NIFI,CN=testuser2"; + String testPass1 = "testPass1"; + String testPass2 = "testPass2"; + tlsToolkitStandaloneCommandLine.parse("-C", testCn, "-C", testCn2, "-B", testPass1, "-B", testPass2); + StandaloneConfig standaloneConfig = tlsToolkitStandaloneCommandLine.createConfig(); + List<String> clientDns = standaloneConfig.getClientDns(); + assertEquals(2, clientDns.size()); + assertEquals(testCn, clientDns.get(0)); + assertEquals(testCn2, clientDns.get(1)); + List<String> clientPasswords = standaloneConfig.getClientPasswords(); + assertEquals(2, clientPasswords.size()); + assertEquals(testPass1, clientPasswords.get(0)); + assertEquals(testPass2, clientPasswords.get(1)); + } + private Properties getProperties() throws IOException { - NiFiPropertiesWriter niFiPropertiesWriter = tlsToolkitStandaloneCommandLine.getNiFiPropertiesWriterFactory().create(); + NiFiPropertiesWriter niFiPropertiesWriter = tlsToolkitStandaloneCommandLine.createConfig().getNiFiPropertiesWriterFactory().create(); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); niFiPropertiesWriter.writeNiFiProperties(byteArrayOutputStream); Properties properties = new Properties();
