NIFI-2528 Added RestrictedSSLContextService interface with implementation. Changed ListenHTTP to allow only new StandardRestrictedSSLContextService.

This closes #1986.

Signed-off-by: Andy LoPresto <alopresto@apache.org>
This commit is contained in:
m-hogue 2017-07-06 11:42:46 -04:00 committed by Andy LoPresto
parent e62417ea6b
commit d28e61c5dd
No known key found for this signature in database
GPG Key ID: 6EC293152D90B61D
9 changed files with 370 additions and 57 deletions

View File

@ -34,6 +34,7 @@ import org.apache.nifi.processor.Relationship;
import org.apache.nifi.processor.util.StandardValidators;
import org.apache.nifi.processors.standard.servlets.ContentAcknowledgmentServlet;
import org.apache.nifi.processors.standard.servlets.ListenHTTPServlet;
import org.apache.nifi.ssl.RestrictedSSLContextService;
import org.apache.nifi.ssl.SSLContextService;
import org.apache.nifi.stream.io.LeakyBucketStreamThrottler;
import org.apache.nifi.stream.io.StreamThrottler;
@ -118,7 +119,7 @@ public class ListenHTTP extends AbstractSessionFactoryProcessor {
.name("SSL Context Service")
.description("The Controller Service to use in order to obtain an SSL Context")
.required(false)
.identifiesControllerService(SSLContextService.class)
.identifiesControllerService(RestrictedSSLContextService.class)
.build();
public static final PropertyDescriptor HEADERS_AS_ATTRIBUTES_REGEX = new PropertyDescriptor.Builder()
.name("HTTP Headers to receive as Attributes (Regex)")
@ -227,6 +228,10 @@ public class ListenHTTP extends AbstractSessionFactoryProcessor {
contextFactory.setKeyStoreType(keyStoreType);
}
if (sslContextService != null) {
contextFactory.setProtocol(sslContextService.getSslAlgorithm());
}
// thread pool for the jetty instance
final QueuedThreadPool threadPool = new QueuedThreadPool();
threadPool.setName(String.format("%s (%s) Web Server", getClass().getSimpleName(), getIdentifier()));
@ -249,6 +254,7 @@ public class ListenHTTP extends AbstractSessionFactoryProcessor {
httpConfiguration.addCustomizer(new SecureRequestCustomizer());
// build the connector
connector = new ServerConnector(server, new SslConnectionFactory(contextFactory, "http/1.1"), new HttpConnectionFactory(httpConfiguration));
}

View File

@ -20,11 +20,13 @@ import org.apache.nifi.processor.ProcessContext;
import org.apache.nifi.processor.ProcessSessionFactory;
import org.apache.nifi.remote.io.socket.NetworkUtils;
import org.apache.nifi.reporting.InitializationException;
import org.apache.nifi.ssl.StandardRestrictedSSLContextService;
import org.apache.nifi.ssl.SSLContextService;
import org.apache.nifi.ssl.StandardSSLContextService;
import org.apache.nifi.util.MockFlowFile;
import org.apache.nifi.util.TestRunner;
import org.apache.nifi.util.TestRunners;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@ -35,10 +37,15 @@ import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import static org.apache.nifi.processors.standard.ListenHTTP.RELATIONSHIP_SUCCESS;
import static org.junit.Assert.fail;
public class TestListenHTTP {
private static final String SSL_CONTEXT_SERVICE_IDENTIFIER = "ssl-context";
private static final String HTTP_POST_METHOD = "POST";
private static final String HTTP_BASE_PATH = "basePath";
@ -64,9 +71,13 @@ public class TestListenHTTP {
}
@After
public void teardown() {
proc.shutdownHttpServer();
}
@Test
public void testPOSTRequestsReceivedWithoutEL() throws Exception {
runner.setProperty(ListenHTTP.PORT, Integer.toString(availablePort));
runner.setProperty(ListenHTTP.BASE_PATH, HTTP_BASE_PATH);
@ -75,30 +86,79 @@ public class TestListenHTTP {
@Test
public void testPOSTRequestsReceivedWithEL() throws Exception {
runner.setProperty(ListenHTTP.PORT, HTTP_SERVER_PORT_EL);
runner.setProperty(ListenHTTP.BASE_PATH, HTTP_SERVER_BASEPATH_EL);
runner.assertValid();
testPOSTRequestsReceived();
}
@Test
public void testSecurePOSTRequestsReceivedWithoutEL() throws Exception {
SSLContextService sslContextService = configureProcessorSslContextService();
runner.setProperty(sslContextService, StandardRestrictedSSLContextService.RESTRICTED_SSL_ALGORITHM, "TLSv1.2");
runner.enableControllerService(sslContextService);
runner.setProperty(ListenHTTP.PORT, Integer.toString(availablePort));
runner.setProperty(ListenHTTP.BASE_PATH, HTTP_BASE_PATH);
runner.assertValid();
testPOSTRequestsReceived();
}
@Test
public void testSecurePOSTRequestsReceivedWithEL() throws Exception {
SSLContextService sslContextService = configureProcessorSslContextService();
runner.setProperty(sslContextService, StandardRestrictedSSLContextService.RESTRICTED_SSL_ALGORITHM, "TLSv1.2");
runner.enableControllerService(sslContextService);
runner.setProperty(ListenHTTP.PORT, HTTP_SERVER_PORT_EL);
runner.setProperty(ListenHTTP.BASE_PATH, HTTP_SERVER_BASEPATH_EL);
runner.assertValid();
testPOSTRequestsReceived();
}
@Test
public void testSecureInvalidSSLConfiguration() throws Exception {
SSLContextService sslContextService = configureInvalidProcessorSslContextService();
runner.setProperty(sslContextService, StandardSSLContextService.SSL_ALGORITHM, "TLSv1.2");
runner.enableControllerService(sslContextService);
runner.setProperty(ListenHTTP.PORT, HTTP_SERVER_PORT_EL);
runner.setProperty(ListenHTTP.BASE_PATH, HTTP_SERVER_BASEPATH_EL);
runner.assertNotValid();
}
private int executePOST(String message) throws Exception {
final SSLContextService sslContextService = runner.getControllerService(SSL_CONTEXT_SERVICE_IDENTIFIER, SSLContextService.class);
final boolean secure = (sslContextService != null);
final String scheme = secure ? "https" : "http";
final URL url = new URL(scheme + "://localhost:" + availablePort + "/" + HTTP_BASE_PATH);
HttpURLConnection connection;
URL url= new URL("http://localhost:" + availablePort + "/" + HTTP_BASE_PATH);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
if(secure) {
final HttpsURLConnection sslCon = (HttpsURLConnection) url.openConnection();
final SSLContext sslContext = sslContextService.createSSLContext(SSLContextService.ClientAuth.WANT);
sslCon.setSSLSocketFactory(sslContext.getSocketFactory());
connection = sslCon;
} else {
connection = (HttpURLConnection) url.openConnection();
}
connection.setRequestMethod(HTTP_POST_METHOD);
connection.setDoOutput(true);
final DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
con.setRequestMethod(HTTP_POST_METHOD);
con.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(con.getOutputStream());
if (message!=null) {
wr.writeBytes(message);
}
wr.flush();
wr.close();
return con.getResponseCode();
return connection.getResponseCode();
}
private void testPOSTRequestsReceived() throws Exception {
final List<String> messages = new ArrayList<>();
messages.add("payload 1");
@ -122,7 +182,7 @@ public class TestListenHTTP {
final ProcessSessionFactory processSessionFactory = runner.getProcessSessionFactory();
final ProcessContext context = runner.getProcessContext();
proc.createHttpServer(context);
proc.createHttpServer(context);
Runnable sendMessagestoWebServer = () -> {
try {
@ -151,18 +211,30 @@ public class TestListenHTTP {
}
private SSLContextService configureProcessorSslContextService() throws InitializationException {
final SSLContextService sslContextService = new StandardSSLContextService();
runner.addControllerService("ssl-context", sslContextService);
final SSLContextService sslContextService = new StandardRestrictedSSLContextService();
runner.addControllerService(SSL_CONTEXT_SERVICE_IDENTIFIER, sslContextService);
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE, "src/test/resources/localhost-ts.jks");
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE_PASSWORD, "localtest");
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE_TYPE, "JKS");
runner.setProperty(sslContextService, StandardSSLContextService.KEYSTORE, "src/test/resources/localhost-ks.jks");
runner.setProperty(sslContextService, StandardSSLContextService.KEYSTORE_PASSWORD, "localtest");
runner.setProperty(sslContextService, StandardSSLContextService.KEYSTORE_TYPE, "JKS");
runner.enableControllerService(sslContextService);
runner.setProperty(ListenHTTP.SSL_CONTEXT_SERVICE, "ssl-context");
runner.setProperty(ListenHTTP.SSL_CONTEXT_SERVICE, SSL_CONTEXT_SERVICE_IDENTIFIER);
return sslContextService;
}
private SSLContextService configureInvalidProcessorSslContextService() throws InitializationException {
final SSLContextService sslContextService = new StandardSSLContextService();
runner.addControllerService(SSL_CONTEXT_SERVICE_IDENTIFIER, sslContextService);
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE, "src/test/resources/localhost-ts.jks");
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE_PASSWORD, "localtest");
runner.setProperty(sslContextService, StandardSSLContextService.TRUSTSTORE_TYPE, "JKS");
runner.setProperty(sslContextService, StandardSSLContextService.KEYSTORE, "src/test/resources/localhost-ks.jks");
runner.setProperty(sslContextService, StandardSSLContextService.KEYSTORE_PASSWORD, "localtest");
runner.setProperty(sslContextService, StandardSSLContextService.KEYSTORE_TYPE, "JKS");
runner.setProperty(ListenHTTP.SSL_CONTEXT_SERVICE, SSL_CONTEXT_SERVICE_IDENTIFIER);
return sslContextService;
}
}

View File

@ -0,0 +1,81 @@
/*
* 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.ssl;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.nifi.annotation.documentation.CapabilityDescription;
import org.apache.nifi.annotation.documentation.Tags;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.components.ValidationContext;
import org.apache.nifi.processor.util.StandardValidators;
/**
* This class is functionally the same as {@link StandardSSLContextService}, but it restricts the allowable
* values that can be selected for TLS/SSL protocols.
*/
@Tags({"tls", "ssl", "secure", "certificate", "keystore", "truststore", "jks", "p12", "pkcs12", "pkcs"})
@CapabilityDescription("Restricted implementation of the SSLContextService. Provides the ability to configure "
+ "keystore and/or truststore properties once and reuse that configuration throughout the application, "
+ "but only allows a restricted set of TLS/SSL protocols to be chosen (no SSL protocols are supported). The set of protocols selectable will "
+ "evolve over time as new protocols emerge and older protocols are deprecated. This service is recommended "
+ "over StandardSSLContextService if a component doesn't expect to communicate with legacy systems since it is "
+ "unlikely that legacy systems will support these protocols.")
public class StandardRestrictedSSLContextService extends StandardSSLContextService implements RestrictedSSLContextService {
public static final PropertyDescriptor RESTRICTED_SSL_ALGORITHM = new PropertyDescriptor.Builder()
.name("SSL Protocol")
.displayName("TLS Protocol")
.defaultValue("TLS")
.required(false)
.allowableValues(RestrictedSSLContextService.buildAlgorithmAllowableValues())
.description("The algorithm to use for this SSL context. By default, this will choose the highest supported TLS protocol version.")
.addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
.sensitive(false)
.build();
private static final List<PropertyDescriptor> properties;
static {
List<PropertyDescriptor> props = new ArrayList<>();
props.add(KEYSTORE);
props.add(KEYSTORE_PASSWORD);
props.add(KEY_PASSWORD);
props.add(KEYSTORE_TYPE);
props.add(TRUSTSTORE);
props.add(TRUSTSTORE_PASSWORD);
props.add(TRUSTSTORE_TYPE);
props.add(RESTRICTED_SSL_ALGORITHM);
properties = Collections.unmodifiableList(props);
}
@Override
protected List<PropertyDescriptor> getSupportedPropertyDescriptors() {
return properties;
}
@Override
public String getSslAlgorithm() {
return configContext.getProperty(RESTRICTED_SSL_ALGORITHM).getValue();
}
@Override
protected String getSSLProtocolForValidation(final ValidationContext validationContext) {
return validationContext.getProperty(RESTRICTED_SSL_ALGORITHM).getValue();
}
}

View File

@ -18,20 +18,15 @@ package org.apache.nifi.ssl;
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;
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.PropertyValue;
import org.apache.nifi.components.ValidationContext;
@ -48,7 +43,10 @@ import org.apache.nifi.security.util.SslContextFactory;
@Tags({"ssl", "secure", "certificate", "keystore", "truststore", "jks", "p12", "pkcs12", "pkcs", "tls"})
@CapabilityDescription("Standard implementation of the SSLContextService. Provides the ability to configure "
+ "keystore and/or truststore properties once and reuse that configuration throughout the application")
+ "keystore and/or truststore properties once and reuse that configuration throughout the application. "
+ "This service can be used to communicate with both legacy and modern systems. If you only need to "
+ "communicate with non-legacy systems, then the StandardRestrictedSSLContextService is recommended as it only "
+ "allows a specific set of SSL protocols to be chosen.")
public class StandardSSLContextService extends AbstractControllerService implements SSLContextService {
public static final String STORE_TYPE_JKS = "JKS";
@ -110,14 +108,14 @@ public class StandardSSLContextService extends AbstractControllerService impleme
.displayName("TLS Protocol")
.defaultValue("TLS")
.required(false)
.allowableValues(buildAlgorithmAllowableValues())
.allowableValues(SSLContextService.buildAlgorithmAllowableValues())
.description("The algorithm to use for this TLS/SSL context")
.addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
.sensitive(false)
.build();
private static final List<PropertyDescriptor> properties;
private ConfigurationContext configContext;
protected ConfigurationContext configContext;
private boolean isValidated;
// TODO: This can be made configurable if necessary
@ -252,8 +250,12 @@ public class StandardSSLContextService extends AbstractControllerService impleme
return VALIDATION_CACHE_EXPIRATION;
}
protected String getSSLProtocolForValidation(final ValidationContext validationContext) {
return validationContext.getProperty(SSL_ALGORITHM).getValue();
}
private void verifySslConfig(final ValidationContext validationContext) throws ProcessException {
final String protocol = validationContext.getProperty(SSL_ALGORITHM).getValue();
final String protocol = getSSLProtocolForValidation(validationContext);
try {
final PropertyValue keyPasswdProp = validationContext.getProperty(KEY_PASSWORD);
final char[] keyPassword = keyPasswdProp.isSet() ? keyPasswdProp.getValue().toCharArray() : null;
@ -295,7 +297,7 @@ public class StandardSSLContextService extends AbstractControllerService impleme
@Override
public SSLContext createSSLContext(final ClientAuth clientAuth) throws ProcessException {
final String protocol = configContext.getProperty(SSL_ALGORITHM).getValue();
final String protocol = getSslAlgorithm();
try {
final PropertyValue keyPasswdProp = configContext.getProperty(KEY_PASSWORD);
final char[] keyPassword = keyPasswdProp.isSet() ? keyPasswdProp.getValue().toCharArray() : null;
@ -458,36 +460,6 @@ 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 configuration 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

@ -13,3 +13,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
org.apache.nifi.ssl.StandardSSLContextService
org.apache.nifi.ssl.StandardRestrictedSSLContextService

View File

@ -0,0 +1,44 @@
/*
* 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.ssl;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.junit.Assert.assertTrue;
import java.util.HashSet;
import java.util.Set;
import org.apache.nifi.components.AllowableValue;
import org.junit.Test;
public class RestrictedSSLContextServiceTest {
@Test
public void testTLSAlgorithms() {
final Set<String> expected = new HashSet<>();
expected.add("TLS");
expected.add("TLSv1.2");
final AllowableValue[] allowableValues = RestrictedSSLContextService.buildAlgorithmAllowableValues();
assertThat(allowableValues, notNullValue());
assertThat(allowableValues.length, equalTo(expected.size()));
for(final AllowableValue value : allowableValues) {
assertTrue(expected.contains(value.getValue()));
}
}
}

View File

@ -16,6 +16,9 @@
*/
package org.apache.nifi.ssl;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@ -23,9 +26,17 @@ import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.net.ssl.SSLContext;
import org.apache.nifi.components.AllowableValue;
import org.apache.nifi.components.ValidationContext;
import org.apache.nifi.components.ValidationResult;
import org.apache.nifi.reporting.InitializationException;
@ -311,4 +322,22 @@ public class SSLContextServiceTest {
Assert.fail("Should not have thrown a exception " + e.getMessage());
}
}
@Test
public void testSSLAlgorithms() throws NoSuchAlgorithmException {
final AllowableValue[] allowableValues = SSLContextService.buildAlgorithmAllowableValues();
// we expect TLS, SSL, and all available configured JVM protocols
final Set<String> expected = new HashSet<>();
expected.add("SSL");
expected.add("TLS");
final String[] supportedProtocols = SSLContext.getDefault().createSSLEngine().getSupportedProtocols();
expected.addAll(Arrays.asList(supportedProtocols));
assertThat(allowableValues, notNullValue());
assertThat(allowableValues.length, equalTo(expected.size()));
for(final AllowableValue value : allowableValues) {
assertTrue(expected.contains(value.getValue()));
}
}
}

View File

@ -0,0 +1,64 @@
/*
* 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.ssl;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.nifi.components.AllowableValue;
/**
* Simple extension of the regular {@link SSLContextService} to allow for restricted implementations
* of that interface.
*/
public interface RestrictedSSLContextService extends SSLContextService {
/**
* Build a restricted set of allowable TLS protocol algorithms.
*
* @return the computed set of allowable values
*/
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("TLS");
/*
* Add specifically supported TLS versions
*/
supportedProtocols.add("TLSv1.2");
final int numProtocols = supportedProtocols.size();
// Sort for consistent presentation in configuration 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]);
}
}

View File

@ -16,10 +16,19 @@
*/
package org.apache.nifi.ssl;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.net.ssl.SSLContext;
import org.apache.nifi.annotation.documentation.CapabilityDescription;
import org.apache.nifi.annotation.documentation.Tags;
import org.apache.nifi.components.AllowableValue;
import org.apache.nifi.controller.ControllerService;
import org.apache.nifi.processor.exception.ProcessException;
@ -60,4 +69,39 @@ public interface SSLContextService extends ControllerService {
public boolean isKeyStoreConfigured();
String getSslAlgorithm();
/**
* Build a set of allowable TLS/SSL protocol algorithms based on JVM configuration.
*
* @return the computed set of allowable values
*/
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("TLS");
supportedProtocols.add("SSL");
// 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 configuration 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]);
}
}