mirror of https://github.com/apache/nifi.git
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 <bbende@apache.org>
This commit is contained in:
parent
fd0dd51ff5
commit
fa5da543e6
|
@ -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"),
|
||||
|
@ -349,6 +374,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.
|
||||
*
|
||||
|
@ -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));
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.");
|
||||
}
|
||||
|
||||
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.");
|
||||
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);
|
||||
}
|
||||
|
||||
certificate.verify(caKeyPair.getPublic());
|
||||
if (!caKeyPair.getPublic().equals(certificate.getPublicKey())) {
|
||||
throw new IOException("Expected " + nifiKey + " to correspond to CA certificate at " + nifiCert);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Generated new CA certificate " + nifiCert + " and key " + nifiKey);
|
||||
}
|
||||
}
|
||||
|
||||
try (PemWriter pemWriter = new PemWriter(new OutputStreamWriter(outputStreamFactory.create(nifiCert)))) {
|
||||
pemWriter.writeObject(new JcaMiscPEMGenerator(certificate));
|
||||
}
|
||||
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();
|
||||
|
||||
try (PemWriter pemWriter = new PemWriter(new OutputStreamWriter(outputStreamFactory.create(nifiKey)))) {
|
||||
pemWriter.writeObject(new JcaMiscPEMGenerator(caKeyPair));
|
||||
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(' ', '_');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 StandaloneConfig createConfig() {
|
||||
StandaloneConfig standaloneConfig = new StandaloneConfig();
|
||||
|
||||
public List<String> getHostnames() {
|
||||
return hostnames;
|
||||
}
|
||||
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);
|
||||
|
||||
public int getHttpsPort() {
|
||||
return httpsPort;
|
||||
}
|
||||
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();
|
||||
|
||||
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;
|
||||
return standaloneConfig;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -18,27 +18,36 @@
|
|||
package org.apache.nifi.toolkit.tls.standalone;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.nifi.security.util.CertificateUtils;
|
||||
import org.apache.nifi.toolkit.tls.commandLine.BaseCommandLine;
|
||||
import org.apache.nifi.toolkit.tls.commandLine.ExitCode;
|
||||
import org.apache.nifi.toolkit.tls.configuration.TlsConfig;
|
||||
import org.apache.nifi.toolkit.tls.manager.BaseTlsManager;
|
||||
import org.apache.nifi.toolkit.tls.service.TlsCertificateAuthorityTest;
|
||||
import org.apache.nifi.toolkit.tls.util.TlsHelperTest;
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyStore;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.Permission;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.UUID;
|
||||
|
||||
|
@ -95,18 +104,18 @@ public class TlsToolkitStandaloneTest {
|
|||
|
||||
@Test
|
||||
public void testBadParse() {
|
||||
runAndAssertExitCode(ExitCode.ERROR_PARSING_COMMAND_LINE.ordinal(), "--unknownArgument");
|
||||
runAndAssertExitCode(ExitCode.ERROR_PARSING_COMMAND_LINE, "--unknownArgument");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHelp() {
|
||||
runAndAssertExitCode(ExitCode.HELP.ordinal(), "-h");
|
||||
runAndAssertExitCode(ExitCode.HELP.ordinal(), "--help");
|
||||
runAndAssertExitCode(ExitCode.HELP, "-h");
|
||||
runAndAssertExitCode(ExitCode.HELP, "--help");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDirOutput() throws Exception {
|
||||
runAndAssertExitCode(0, "-o", tempDir.getAbsolutePath());
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", TlsConfig.DEFAULT_HOSTNAME);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
|
||||
Properties nifiProperties = checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
|
||||
|
@ -116,7 +125,7 @@ public class TlsToolkitStandaloneTest {
|
|||
|
||||
@Test
|
||||
public void testDifferentArg() throws Exception {
|
||||
runAndAssertExitCode(0, "-o", tempDir.getAbsolutePath(), "-g");
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-g", "-n", TlsConfig.DEFAULT_HOSTNAME);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
|
||||
Properties nifiProperties = checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
|
||||
|
@ -126,7 +135,7 @@ public class TlsToolkitStandaloneTest {
|
|||
|
||||
@Test
|
||||
public void testFileArg() throws Exception {
|
||||
runAndAssertExitCode(0, "-o", tempDir.getAbsolutePath(), "-f", TEST_NIFI_PROPERTIES);
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-f", TEST_NIFI_PROPERTIES, "-n", TlsConfig.DEFAULT_HOSTNAME);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
|
||||
Properties nifiProperties = checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
|
||||
|
@ -134,23 +143,36 @@ public class TlsToolkitStandaloneTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testHostnamesArgument() throws Exception {
|
||||
public void testHostnamesArgumentOverwrite() throws Exception {
|
||||
String nifi1 = "nifi1";
|
||||
String nifi2 = "nifi2";
|
||||
String nifi3 = "nifi3";
|
||||
|
||||
runAndAssertExitCode(0, "-o", tempDir.getAbsolutePath(), "-n", nifi1 + "," + nifi2 + "," + nifi3);
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nifi1 + "," + nifi2);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nifi3);
|
||||
|
||||
checkHostDirAndReturnNifiProperties(nifi1, x509Certificate);
|
||||
checkHostDirAndReturnNifiProperties(nifi2, x509Certificate);
|
||||
checkHostDirAndReturnNifiProperties(nifi3, x509Certificate);
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-O", "-n", nifi3);
|
||||
checkHostDirAndReturnNifiProperties(nifi3, x509Certificate);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHostnamesArgumentNoOverwrite() throws Exception {
|
||||
String nifi = "nifi";
|
||||
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-n", nifi);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
checkHostDirAndReturnNifiProperties(nifi, x509Certificate);
|
||||
runAndAssertExitCode(ExitCode.ERROR_GENERATING_CONFIG, "-o", tempDir.getAbsolutePath(), "-n", nifi);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKeyPasswordArg() throws Exception {
|
||||
String testKey = "testKey";
|
||||
runAndAssertExitCode(0, "-o", tempDir.getAbsolutePath(), "-K", testKey);
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-K", testKey, "-n", TlsConfig.DEFAULT_HOSTNAME);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
|
||||
Properties nifiProperties = checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
|
||||
|
@ -160,7 +182,7 @@ public class TlsToolkitStandaloneTest {
|
|||
@Test
|
||||
public void testKeyStorePasswordArg() throws Exception {
|
||||
String testKeyStore = "testKeyStore";
|
||||
runAndAssertExitCode(0, "-o", tempDir.getAbsolutePath(), "-S", testKeyStore);
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-S", testKeyStore, "-n", TlsConfig.DEFAULT_HOSTNAME);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
|
||||
Properties nifiProperties = checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
|
||||
|
@ -170,13 +192,38 @@ public class TlsToolkitStandaloneTest {
|
|||
@Test
|
||||
public void testTrustStorePasswordArg() throws Exception {
|
||||
String testTrustStore = "testTrustStore";
|
||||
runAndAssertExitCode(0, "-o", tempDir.getAbsolutePath(), "-P", testTrustStore);
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-P", testTrustStore, "-n", TlsConfig.DEFAULT_HOSTNAME);
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
|
||||
Properties nifiProperties = checkHostDirAndReturnNifiProperties(TlsConfig.DEFAULT_HOSTNAME, x509Certificate);
|
||||
assertEquals(testTrustStore, nifiProperties.getProperty(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientDnsArg() throws Exception {
|
||||
String clientDn = "OU=NIFI,CN=testuser";
|
||||
String clientDn2 = "OU=NIFI,CN=testuser2";
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-C", clientDn, "-C", clientDn2, "-B", "pass1", "-P", "pass2");
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
|
||||
checkClientCert(clientDn, x509Certificate);
|
||||
checkClientCert(clientDn2, x509Certificate);
|
||||
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-O", "-C", clientDn2, "-B", "pass3");
|
||||
checkClientCert(clientDn2, x509Certificate);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientDnsArgNoOverwrite() throws Exception {
|
||||
String clientDn = "OU=NIFI,CN=testuser";
|
||||
runAndAssertExitCode(ExitCode.SUCCESS, "-o", tempDir.getAbsolutePath(), "-C", clientDn, "-B", "passwor");
|
||||
X509Certificate x509Certificate = checkLoadCertPrivateKey(TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM);
|
||||
|
||||
checkClientCert(clientDn, x509Certificate);
|
||||
|
||||
runAndAssertExitCode(ExitCode.ERROR_GENERATING_CONFIG, "-o", tempDir.getAbsolutePath(), "-C", clientDn);
|
||||
}
|
||||
|
||||
private X509Certificate checkLoadCertPrivateKey(String algorithm) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, CertificateException {
|
||||
KeyPair keyPair = TlsHelperTest.loadKeyPair(new File(tempDir, TlsToolkitStandalone.NIFI_KEY + ".key"));
|
||||
|
||||
|
@ -227,15 +274,40 @@ public class TlsToolkitStandaloneTest {
|
|||
assertEquals(rootCert, certificateChain[1]);
|
||||
certificateChain[1].verify(rootCert.getPublicKey());
|
||||
certificateChain[0].verify(rootCert.getPublicKey());
|
||||
TlsCertificateAuthorityTest.assertPrivateAndPublicKeyMatch(privateKeyEntry.getPrivateKey(), certificateChain[0].getPublicKey());
|
||||
return nifiProperties;
|
||||
}
|
||||
|
||||
private void runAndAssertExitCode(int exitCode, String... args) {
|
||||
private void checkClientCert(String clientDn, X509Certificate rootCert) throws Exception {
|
||||
String clientDnFile = TlsToolkitStandalone.getClientDnFile(CertificateUtils.reorderDn(clientDn));
|
||||
String password;
|
||||
try (FileReader fileReader = new FileReader(new File(tempDir, clientDnFile + ".password"))) {
|
||||
List<String> lines = IOUtils.readLines(fileReader);
|
||||
assertEquals(1, lines.size());
|
||||
password = lines.get(0);
|
||||
}
|
||||
|
||||
KeyStore keyStore = KeyStore.getInstance(BaseTlsManager.PKCS_12, BouncyCastleProvider.PROVIDER_NAME);
|
||||
try (FileInputStream fileInputStream = new FileInputStream(new File(tempDir, clientDnFile + ".p12"))) {
|
||||
keyStore.load(fileInputStream, password.toCharArray());
|
||||
}
|
||||
PrivateKey privateKey = (PrivateKey) keyStore.getKey(TlsToolkitStandalone.NIFI_KEY, new char[0]);
|
||||
Certificate[] certificateChain = keyStore.getCertificateChain(TlsToolkitStandalone.NIFI_KEY);
|
||||
assertEquals(2, certificateChain.length);
|
||||
assertEquals(rootCert, certificateChain[1]);
|
||||
certificateChain[1].verify(rootCert.getPublicKey());
|
||||
certificateChain[0].verify(rootCert.getPublicKey());
|
||||
PublicKey publicKey = certificateChain[0].getPublicKey();
|
||||
TlsCertificateAuthorityTest.assertPrivateAndPublicKeyMatch(privateKey, publicKey);
|
||||
|
||||
}
|
||||
|
||||
private void runAndAssertExitCode(ExitCode exitCode, String... args) {
|
||||
try {
|
||||
TlsToolkitStandaloneCommandLine.main(args);
|
||||
fail("Expecting exit code: " + exitCode);
|
||||
} catch (ExitException e) {
|
||||
assertEquals(exitCode, e.getExitCode());
|
||||
assertEquals(exitCode, ExitCode.values()[e.getExitCode()]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,23 +25,32 @@ import org.bouncycastle.openssl.PEMKeyPair;
|
|||
import org.bouncycastle.openssl.PEMParser;
|
||||
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
|
||||
import org.bouncycastle.operator.OperatorCreationException;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.AdditionalMatchers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreSpi;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
import java.security.SignatureException;
|
||||
import java.security.cert.CertificateException;
|
||||
|
@ -51,9 +60,17 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class TlsHelperTest {
|
||||
private static final boolean originalUnlimitedCrypto = TlsHelper.isUnlimitedStrengthCryptographyEnabled();
|
||||
|
||||
private int days;
|
||||
|
||||
private int keySize;
|
||||
|
@ -62,12 +79,33 @@ public class TlsHelperTest {
|
|||
|
||||
private String signingAlgorithm;
|
||||
|
||||
private String keyStoreType;
|
||||
|
||||
private SecureRandom secureRandom;
|
||||
|
||||
private KeyPairGenerator keyPairGenerator;
|
||||
|
||||
private KeyStore keyStore;
|
||||
|
||||
@Mock
|
||||
KeyStoreSpi keyStoreSpi;
|
||||
|
||||
@Mock
|
||||
Provider keyStoreProvider;
|
||||
|
||||
@Mock
|
||||
OutputStreamFactory outputStreamFactory;
|
||||
|
||||
private ByteArrayOutputStream tmpFileOutputStream;
|
||||
|
||||
private File file;
|
||||
|
||||
private static void setUnlimitedCrypto(boolean value) {
|
||||
try {
|
||||
Field isUnlimitedStrengthCryptographyEnabled = TlsHelper.class.getDeclaredField("isUnlimitedStrengthCryptographyEnabled");
|
||||
isUnlimitedStrengthCryptographyEnabled.setAccessible(true);
|
||||
isUnlimitedStrengthCryptographyEnabled.set(null, value);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static KeyPair loadKeyPair(Reader reader) throws IOException {
|
||||
try (PEMParser pemParser = new PEMParser(reader)) {
|
||||
Object object = pemParser.readObject();
|
||||
|
@ -98,15 +136,25 @@ public class TlsHelperTest {
|
|||
}
|
||||
|
||||
@Before
|
||||
public void setup() throws NoSuchAlgorithmException {
|
||||
public void setup() throws Exception {
|
||||
days = 360;
|
||||
keySize = 2048;
|
||||
keyPairAlgorithm = "RSA";
|
||||
signingAlgorithm = "SHA1WITHRSA";
|
||||
keyStoreType = KeyStore.getDefaultType();
|
||||
secureRandom = mock(SecureRandom.class);
|
||||
keyPairGenerator = KeyPairGenerator.getInstance(keyPairAlgorithm);
|
||||
keyPairGenerator.initialize(keySize);
|
||||
Constructor<KeyStore> keyStoreConstructor = KeyStore.class.getDeclaredConstructor(KeyStoreSpi.class, Provider.class, String.class);
|
||||
keyStoreConstructor.setAccessible(true);
|
||||
keyStore = keyStoreConstructor.newInstance(keyStoreSpi, keyStoreProvider, "faketype");
|
||||
keyStore.load(null, null);
|
||||
file = File.createTempFile("keystore", "file");
|
||||
when(outputStreamFactory.create(file)).thenReturn(tmpFileOutputStream);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
setUnlimitedCrypto(originalUnlimitedCrypto);
|
||||
file.delete();
|
||||
}
|
||||
|
||||
private Date inFuture(int days) {
|
||||
|
@ -127,7 +175,7 @@ public class TlsHelperTest {
|
|||
assertTrue(notBefore.after(inFuture(-1)));
|
||||
assertTrue(notBefore.before(inFuture(1)));
|
||||
|
||||
assertEquals(dn, x509Certificate.getIssuerDN().getName());
|
||||
assertEquals(dn, x509Certificate.getIssuerX500Principal().getName());
|
||||
assertEquals(signingAlgorithm, x509Certificate.getSigAlgName());
|
||||
assertEquals(keyPairAlgorithm, x509Certificate.getPublicKey().getAlgorithm());
|
||||
|
||||
|
@ -139,12 +187,12 @@ public class TlsHelperTest {
|
|||
X509Certificate issuer = loadCertificate(new InputStreamReader(getClass().getClassLoader().getResourceAsStream("rootCert.crt")));
|
||||
KeyPair issuerKeyPair = loadKeyPair(new InputStreamReader(getClass().getClassLoader().getResourceAsStream("rootCert.key")));
|
||||
|
||||
String dn = "CN=testIssued,O=testOrg";
|
||||
String dn = "CN=testIssued, O=testOrg";
|
||||
|
||||
KeyPair keyPair = TlsHelper.generateKeyPair(keyPairAlgorithm, keySize);
|
||||
X509Certificate x509Certificate = CertificateUtils.generateIssuedCertificate(dn, keyPair.getPublic(), issuer, issuerKeyPair, signingAlgorithm, 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();
|
||||
|
@ -160,4 +208,83 @@ public class TlsHelperTest {
|
|||
|
||||
x509Certificate.verify(issuerKeyPair.getPublic());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteKeyStoreSuccess() throws IOException, GeneralSecurityException {
|
||||
setUnlimitedCrypto(false);
|
||||
String testPassword = "testPassword";
|
||||
assertEquals(testPassword, TlsHelper.writeKeyStore(keyStore, outputStreamFactory, file, testPassword, false));
|
||||
verify(keyStoreSpi, times(1)).engineStore(eq(tmpFileOutputStream), AdditionalMatchers.aryEq(testPassword.toCharArray()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteKeyStoreFailure() throws IOException, GeneralSecurityException {
|
||||
setUnlimitedCrypto(false);
|
||||
String testPassword = "testPassword";
|
||||
IOException ioException = new IOException("Fail");
|
||||
doThrow(ioException).when(keyStoreSpi).engineStore(eq(tmpFileOutputStream), AdditionalMatchers.aryEq(testPassword.toCharArray()));
|
||||
try {
|
||||
TlsHelper.writeKeyStore(keyStore, outputStreamFactory, file, testPassword, true);
|
||||
fail("Expected " + ioException);
|
||||
} catch (IOException e) {
|
||||
assertEquals(ioException, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteKeyStoreTruncate() throws IOException, GeneralSecurityException {
|
||||
setUnlimitedCrypto(false);
|
||||
String testPassword = "testPassword";
|
||||
String truncatedPassword = testPassword.substring(0, 7);
|
||||
IOException ioException = new IOException(TlsHelper.ILLEGAL_KEY_SIZE);
|
||||
doThrow(ioException).when(keyStoreSpi).engineStore(eq(tmpFileOutputStream), AdditionalMatchers.aryEq(testPassword.toCharArray()));
|
||||
assertEquals(truncatedPassword, TlsHelper.writeKeyStore(keyStore, outputStreamFactory, file, testPassword, true));
|
||||
verify(keyStoreSpi, times(1)).engineStore(eq(tmpFileOutputStream), AdditionalMatchers.aryEq(testPassword.toCharArray()));
|
||||
verify(keyStoreSpi, times(1)).engineStore(eq(tmpFileOutputStream), AdditionalMatchers.aryEq(truncatedPassword.toCharArray()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteKeyStoreUnlimitedWontTruncate() throws GeneralSecurityException, IOException {
|
||||
setUnlimitedCrypto(true);
|
||||
String testPassword = "testPassword";
|
||||
IOException ioException = new IOException(TlsHelper.ILLEGAL_KEY_SIZE);
|
||||
doThrow(ioException).when(keyStoreSpi).engineStore(eq(tmpFileOutputStream), AdditionalMatchers.aryEq(testPassword.toCharArray()));
|
||||
try {
|
||||
TlsHelper.writeKeyStore(keyStore, outputStreamFactory, file, testPassword, true);
|
||||
fail("Expected " + ioException);
|
||||
} catch (IOException e) {
|
||||
assertEquals(ioException, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteKeyStoreNoTruncate() throws IOException, GeneralSecurityException {
|
||||
setUnlimitedCrypto(false);
|
||||
String testPassword = "testPassword";
|
||||
IOException ioException = new IOException(TlsHelper.ILLEGAL_KEY_SIZE);
|
||||
doThrow(ioException).when(keyStoreSpi).engineStore(eq(tmpFileOutputStream), AdditionalMatchers.aryEq(testPassword.toCharArray()));
|
||||
try {
|
||||
TlsHelper.writeKeyStore(keyStore, outputStreamFactory, file, testPassword, false);
|
||||
fail("Expected " + GeneralSecurityException.class);
|
||||
} catch (GeneralSecurityException e) {
|
||||
assertTrue("Expected exception to contain " + TlsHelper.JCE_URL, e.getMessage().contains(TlsHelper.JCE_URL));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteKeyStoreTruncateFailure() throws IOException, GeneralSecurityException {
|
||||
setUnlimitedCrypto(false);
|
||||
String testPassword = "testPassword";
|
||||
String truncatedPassword = testPassword.substring(0, 7);
|
||||
IOException ioException = new IOException(TlsHelper.ILLEGAL_KEY_SIZE);
|
||||
IOException ioException2 = new IOException(TlsHelper.ILLEGAL_KEY_SIZE);
|
||||
doThrow(ioException).when(keyStoreSpi).engineStore(eq(tmpFileOutputStream), AdditionalMatchers.aryEq(testPassword.toCharArray()));
|
||||
doThrow(ioException2).when(keyStoreSpi).engineStore(eq(tmpFileOutputStream), AdditionalMatchers.aryEq(truncatedPassword.toCharArray()));
|
||||
try {
|
||||
TlsHelper.writeKeyStore(keyStore, outputStreamFactory, file, testPassword, true);
|
||||
fail("Expected " + ioException2);
|
||||
} catch (IOException e) {
|
||||
assertEquals(ioException2, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
log4j.rootLogger=INFO,console
|
||||
|
||||
log4j.appender.console=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.console.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.console.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss} %p %c{2}: %m%n
|
Loading…
Reference in New Issue