NIFI-419 Providing a user configurable selection of the SSL Protocol algorithm used for connections withing an SSL Context controller service. This provides defaults of TLS/SSL values as well as performs a look up of the available items within the JVM.

This commit is contained in:
Aldrin Piri 2015-06-09 00:54:26 -04:00
parent 8b5a8ab054
commit 64502d0e10
4 changed files with 91 additions and 26 deletions

View File

@ -163,6 +163,8 @@ public class SSLProperties {
KEYSTORE, TRUSTSTORE
}
private static final String DEFAULT_SSL_PROTOCOL_ALGORITHM = "TLS";
public static List<PropertyDescriptor> getKeystoreDescriptors(final boolean required) {
final List<PropertyDescriptor> descriptors = new ArrayList<>();
for (final PropertyDescriptor descriptor : KEYSTORE_DESCRIPTORS) {
@ -196,14 +198,15 @@ public class SSLProperties {
return SslContextFactory.createTrustSslContext(
context.getProperty(TRUSTSTORE).getValue(),
context.getProperty(TRUSTSTORE_PASSWORD).getValue().toCharArray(),
context.getProperty(TRUSTSTORE_TYPE).getValue());
context.getProperty(TRUSTSTORE_TYPE).getValue(),
DEFAULT_SSL_PROTOCOL_ALGORITHM);
} else {
final String truststoreFile = context.getProperty(TRUSTSTORE).getValue();
if (truststoreFile == null) {
return SslContextFactory.createSslContext(
context.getProperty(KEYSTORE).getValue(),
context.getProperty(KEYSTORE_PASSWORD).getValue().toCharArray(),
context.getProperty(KEYSTORE_TYPE).getValue());
context.getProperty(KEYSTORE_TYPE).getValue(), DEFAULT_SSL_PROTOCOL_ALGORITHM);
} else {
return SslContextFactory.createSslContext(
context.getProperty(KEYSTORE).getValue(),
@ -212,7 +215,8 @@ public class SSLProperties {
context.getProperty(TRUSTSTORE).getValue(),
context.getProperty(TRUSTSTORE_PASSWORD).getValue().toCharArray(),
context.getProperty(TRUSTSTORE_TYPE).getValue(),
clientAuth);
clientAuth,
DEFAULT_SSL_PROTOCOL_ALGORITHM);
}
}
}

View File

@ -57,6 +57,7 @@ public final class SslContextFactory {
* @param truststorePasswd the truststore password
* @param truststoreType the type of truststore (e.g., PKCS12, JKS)
* @param clientAuth the type of client authentication
* @param protocol the protocol to use for the SSL connection
*
* @return a SSLContext instance
* @throws java.security.KeyStoreException if any issues accessing the keystore
@ -69,7 +70,7 @@ public final class SslContextFactory {
public static SSLContext createSslContext(
final String keystore, final char[] keystorePasswd, final String keystoreType,
final String truststore, final char[] truststorePasswd, final String truststoreType,
final ClientAuth clientAuth)
final ClientAuth clientAuth, final String protocol)
throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException,
UnrecoverableKeyException, KeyManagementException {
@ -90,7 +91,7 @@ public final class SslContextFactory {
trustManagerFactory.init(trustStore);
// initialize the ssl context
final SSLContext sslContext = SSLContext.getInstance("TLS");
final SSLContext sslContext = SSLContext.getInstance(protocol);
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
if (ClientAuth.REQUIRED == clientAuth) {
sslContext.getDefaultSSLParameters().setNeedClientAuth(true);
@ -110,6 +111,7 @@ public final class SslContextFactory {
* @param keystore the full path to the keystore
* @param keystorePasswd the keystore password
* @param keystoreType the type of keystore (e.g., PKCS12, JKS)
* @param protocol the protocol to use for the SSL connection
*
* @return a SSLContext instance
* @throws java.security.KeyStoreException if any issues accessing the keystore
@ -120,7 +122,7 @@ public final class SslContextFactory {
* @throws java.security.KeyManagementException if unable to manage the key
*/
public static SSLContext createSslContext(
final String keystore, final char[] keystorePasswd, final String keystoreType)
final String keystore, final char[] keystorePasswd, final String keystoreType, final String protocol)
throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException,
UnrecoverableKeyException, KeyManagementException {
@ -133,7 +135,7 @@ public final class SslContextFactory {
keyManagerFactory.init(keyStore, keystorePasswd);
// initialize the ssl context
final SSLContext ctx = SSLContext.getInstance("TLS");
final SSLContext ctx = SSLContext.getInstance(protocol);
ctx.init(keyManagerFactory.getKeyManagers(), new TrustManager[0], new SecureRandom());
return ctx;
@ -146,6 +148,7 @@ public final class SslContextFactory {
* @param truststore the full path to the truststore
* @param truststorePasswd the truststore password
* @param truststoreType the type of truststore (e.g., PKCS12, JKS)
* @param protocol the protocol to use for the SSL connection
*
* @return a SSLContext instance
* @throws java.security.KeyStoreException if any issues accessing the keystore
@ -156,7 +159,7 @@ public final class SslContextFactory {
* @throws java.security.KeyManagementException if unable to manage the key
*/
public static SSLContext createTrustSslContext(
final String truststore, final char[] truststorePasswd, final String truststoreType)
final String truststore, final char[] truststorePasswd, final String truststoreType, final String protocol)
throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException,
UnrecoverableKeyException, KeyManagementException {
@ -169,7 +172,7 @@ public final class SslContextFactory {
trustManagerFactory.init(trustStore);
// initialize the ssl context
final SSLContext ctx = SSLContext.getInstance("TLS");
final SSLContext ctx = SSLContext.getInstance(protocol);
ctx.init(new KeyManager[0], trustManagerFactory.getTrustManagers(), new SecureRandom());
return ctx;

View File

@ -16,19 +16,10 @@
*/
package org.apache.nifi.ssl;
import java.io.File;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.net.ssl.SSLContext;
import org.apache.nifi.annotation.documentation.CapabilityDescription;
import org.apache.nifi.annotation.documentation.Tags;
import org.apache.nifi.annotation.lifecycle.OnEnabled;
import org.apache.nifi.components.AllowableValue;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.components.ValidationContext;
import org.apache.nifi.components.ValidationResult;
@ -42,6 +33,19 @@ import org.apache.nifi.security.util.CertificateUtils;
import org.apache.nifi.security.util.KeystoreType;
import org.apache.nifi.security.util.SslContextFactory;
import javax.net.ssl.SSLContext;
import java.io.File;
import java.net.MalformedURLException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@Tags({"ssl", "secure", "certificate", "keystore", "truststore", "jks", "p12", "pkcs12", "pkcs"})
@CapabilityDescription("Standard implementation of the SSLContextService. Provides the ability to configure "
+ "keystore and/or truststore properties once and reuse that configuration throughout the application")
@ -92,6 +96,15 @@ public class StandardSSLContextService extends AbstractControllerService impleme
.addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
.sensitive(true)
.build();
public static final PropertyDescriptor SSL_ALGORITHM = new PropertyDescriptor.Builder()
.name("SSL Protocol")
.defaultValue("TLS")
.required(false)
.allowableValues(buildAlgorithmAllowableValues())
.description("The algorithm to use for this SSL context")
.addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
.sensitive(false)
.build();
private static final List<PropertyDescriptor> properties;
private ConfigurationContext configContext;
@ -104,6 +117,7 @@ public class StandardSSLContextService extends AbstractControllerService impleme
props.add(TRUSTSTORE);
props.add(TRUSTSTORE_PASSWORD);
props.add(TRUSTSTORE_TYPE);
props.add(SSL_ALGORITHM);
properties = Collections.unmodifiableList(props);
}
@ -207,13 +221,15 @@ public class StandardSSLContextService extends AbstractControllerService impleme
}
private void verifySslConfig(final ValidationContext validationContext) throws ProcessException {
final String protocol = validationContext.getProperty(SSL_ALGORITHM).getValue();
try {
final String keystoreFile = validationContext.getProperty(KEYSTORE).getValue();
if (keystoreFile == null) {
SslContextFactory.createTrustSslContext(
validationContext.getProperty(TRUSTSTORE).getValue(),
validationContext.getProperty(TRUSTSTORE_PASSWORD).getValue().toCharArray(),
validationContext.getProperty(TRUSTSTORE_TYPE).getValue());
validationContext.getProperty(TRUSTSTORE_TYPE).getValue(),
protocol);
return;
}
final String truststoreFile = validationContext.getProperty(TRUSTSTORE).getValue();
@ -221,7 +237,8 @@ public class StandardSSLContextService extends AbstractControllerService impleme
SslContextFactory.createSslContext(
validationContext.getProperty(KEYSTORE).getValue(),
validationContext.getProperty(KEYSTORE_PASSWORD).getValue().toCharArray(),
validationContext.getProperty(KEYSTORE_TYPE).getValue());
validationContext.getProperty(KEYSTORE_TYPE).getValue(),
protocol);
return;
}
@ -232,7 +249,8 @@ public class StandardSSLContextService extends AbstractControllerService impleme
validationContext.getProperty(TRUSTSTORE).getValue(),
validationContext.getProperty(TRUSTSTORE_PASSWORD).getValue().toCharArray(),
validationContext.getProperty(TRUSTSTORE_TYPE).getValue(),
org.apache.nifi.security.util.SslContextFactory.ClientAuth.REQUIRED);
org.apache.nifi.security.util.SslContextFactory.ClientAuth.REQUIRED,
protocol);
} catch (final Exception e) {
throw new ProcessException(e);
}
@ -240,20 +258,23 @@ public class StandardSSLContextService extends AbstractControllerService impleme
@Override
public SSLContext createSSLContext(final ClientAuth clientAuth) throws ProcessException {
final String protocol = configContext.getProperty(SSL_ALGORITHM).getValue();
try {
final String keystoreFile = configContext.getProperty(KEYSTORE).getValue();
if (keystoreFile == null) {
return SslContextFactory.createTrustSslContext(
configContext.getProperty(TRUSTSTORE).getValue(),
configContext.getProperty(TRUSTSTORE_PASSWORD).getValue().toCharArray(),
configContext.getProperty(TRUSTSTORE_TYPE).getValue());
configContext.getProperty(TRUSTSTORE_TYPE).getValue(),
protocol);
}
final String truststoreFile = configContext.getProperty(TRUSTSTORE).getValue();
if (truststoreFile == null) {
return SslContextFactory.createSslContext(
configContext.getProperty(KEYSTORE).getValue(),
configContext.getProperty(KEYSTORE_PASSWORD).getValue().toCharArray(),
configContext.getProperty(KEYSTORE_TYPE).getValue());
configContext.getProperty(KEYSTORE_TYPE).getValue(),
protocol);
}
return SslContextFactory.createSslContext(
@ -263,7 +284,8 @@ public class StandardSSLContextService extends AbstractControllerService impleme
configContext.getProperty(TRUSTSTORE).getValue(),
configContext.getProperty(TRUSTSTORE_PASSWORD).getValue().toCharArray(),
configContext.getProperty(TRUSTSTORE_TYPE).getValue(),
org.apache.nifi.security.util.SslContextFactory.ClientAuth.valueOf(clientAuth.name()));
org.apache.nifi.security.util.SslContextFactory.ClientAuth.valueOf(clientAuth.name()),
protocol);
} catch (final Exception e) {
throw new ProcessException(e);
}
@ -309,8 +331,13 @@ public class StandardSSLContextService extends AbstractControllerService impleme
return getKeyStoreFile() != null && getKeyStorePassword() != null && getKeyStoreType() != null;
}
@Override
public String getSslAlgorithm() {
return configContext.getProperty(SSL_ALGORITHM).getValue();
}
private static Collection<ValidationResult> validateStore(final Map<PropertyDescriptor, String> properties,
final KeystoreValidationGroup keyStoreOrTrustStore) {
final KeystoreValidationGroup keyStoreOrTrustStore) {
final Collection<ValidationResult> results = new ArrayList<>();
final String filename;
@ -382,6 +409,36 @@ public class StandardSSLContextService extends AbstractControllerService impleme
KEYSTORE, TRUSTSTORE
}
private static AllowableValue[] buildAlgorithmAllowableValues() {
final Set<String> supportedProtocols = new HashSet<>();
/*
* Prepopulate protocols with generic instance types commonly used
* see: http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#SSLContext
*/
supportedProtocols.add("SSL");
supportedProtocols.add("TLS");
// Determine those provided by the JVM on the system
try {
supportedProtocols.addAll(Arrays.asList(SSLContext.getDefault().createSSLEngine().getSupportedProtocols()));
} catch (NoSuchAlgorithmException e) {
// ignored as default is used
}
final int numProtocols = supportedProtocols.size();
// Sort for consistent presentation in configuraiton views
final List<String> supportedProtocolList = new ArrayList<>(supportedProtocols);
Collections.sort(supportedProtocolList);
final List<AllowableValue> protocolAllowableValues = new ArrayList<>();
for (final String protocol : supportedProtocolList) {
protocolAllowableValues.add(new AllowableValue(protocol));
}
return protocolAllowableValues.toArray(new AllowableValue[numProtocols]);
}
@Override
public String toString() {
return "SSLContextService[id=" + getIdentifier() + "]";

View File

@ -57,4 +57,5 @@ public interface SSLContextService extends ControllerService {
public boolean isKeyStoreConfigured();
String getSslAlgorithm();
}