Repository: nifi
Updated Branches:
  refs/heads/master e62417ea6 -> d28e61c5d


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

This closes #1986.

Signed-off-by: Andy LoPresto <[email protected]>


Project: http://git-wip-us.apache.org/repos/asf/nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/d28e61c5
Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/d28e61c5
Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/d28e61c5

Branch: refs/heads/master
Commit: d28e61c5ddc7486747d431dfd82e17dc435ca817
Parents: e62417e
Author: m-hogue <[email protected]>
Authored: Thu Jul 6 11:42:46 2017 -0400
Committer: Andy LoPresto <[email protected]>
Committed: Wed Aug 30 20:17:01 2017 -0700

----------------------------------------------------------------------
 .../nifi/processors/standard/ListenHTTP.java    |   8 +-
 .../processors/standard/TestListenHTTP.java     | 100 ++++++++++++++++---
 .../StandardRestrictedSSLContextService.java    |  81 +++++++++++++++
 .../nifi/ssl/StandardSSLContextService.java     |  52 +++-------
 ...org.apache.nifi.controller.ControllerService |   3 +-
 .../ssl/RestrictedSSLContextServiceTest.java    |  44 ++++++++
 .../apache/nifi/ssl/SSLContextServiceTest.java  |  29 ++++++
 .../nifi/ssl/RestrictedSSLContextService.java   |  64 ++++++++++++
 .../org/apache/nifi/ssl/SSLContextService.java  |  44 ++++++++
 9 files changed, 369 insertions(+), 56 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/d28e61c5/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListenHTTP.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListenHTTP.java
 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListenHTTP.java
index d2bfa04..5d23370 100644
--- 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListenHTTP.java
+++ 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListenHTTP.java
@@ -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));
         }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/d28e61c5/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestListenHTTP.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestListenHTTP.java
 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestListenHTTP.java
index 9193f8e..c46d4cd 100644
--- 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestListenHTTP.java
+++ 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestListenHTTP.java
@@ -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;
+
+        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);
 
-        URL url= new URL("http://localhost:"; + availablePort + "/" + 
HTTP_BASE_PATH);
-        HttpURLConnection con = (HttpURLConnection) url.openConnection();
+        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;
+    }
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/d28e61c5/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/main/java/org/apache/nifi/ssl/StandardRestrictedSSLContextService.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/main/java/org/apache/nifi/ssl/StandardRestrictedSSLContextService.java
 
b/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/main/java/org/apache/nifi/ssl/StandardRestrictedSSLContextService.java
new file mode 100644
index 0000000..4ad7bbe
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/main/java/org/apache/nifi/ssl/StandardRestrictedSSLContextService.java
@@ -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();
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/d28e61c5/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/main/java/org/apache/nifi/ssl/StandardSSLContextService.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/main/java/org/apache/nifi/ssl/StandardSSLContextService.java
 
b/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/main/java/org/apache/nifi/ssl/StandardSSLContextService.java
index 2570855..6b267ac 100644
--- 
a/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/main/java/org/apache/nifi/ssl/StandardSSLContextService.java
+++ 
b/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/main/java/org/apache/nifi/ssl/StandardSSLContextService.java
@@ -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() + "]";

http://git-wip-us.apache.org/repos/asf/nifi/blob/d28e61c5/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/main/resources/META-INF/services/org.apache.nifi.controller.ControllerService
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/main/resources/META-INF/services/org.apache.nifi.controller.ControllerService
 
b/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/main/resources/META-INF/services/org.apache.nifi.controller.ControllerService
index b1b6124..115fe0d 100644
--- 
a/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/main/resources/META-INF/services/org.apache.nifi.controller.ControllerService
+++ 
b/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/main/resources/META-INF/services/org.apache.nifi.controller.ControllerService
@@ -12,4 +12,5 @@
 # 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.
-org.apache.nifi.ssl.StandardSSLContextService
\ No newline at end of file
+org.apache.nifi.ssl.StandardSSLContextService
+org.apache.nifi.ssl.StandardRestrictedSSLContextService
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/d28e61c5/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/test/java/org/apache/nifi/ssl/RestrictedSSLContextServiceTest.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/test/java/org/apache/nifi/ssl/RestrictedSSLContextServiceTest.java
 
b/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/test/java/org/apache/nifi/ssl/RestrictedSSLContextServiceTest.java
new file mode 100644
index 0000000..3a44ef4
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/test/java/org/apache/nifi/ssl/RestrictedSSLContextServiceTest.java
@@ -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()));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/d28e61c5/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/test/java/org/apache/nifi/ssl/SSLContextServiceTest.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/test/java/org/apache/nifi/ssl/SSLContextServiceTest.java
 
b/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/test/java/org/apache/nifi/ssl/SSLContextServiceTest.java
index 60b09bd..4c00bdc 100644
--- 
a/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/test/java/org/apache/nifi/ssl/SSLContextServiceTest.java
+++ 
b/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/test/java/org/apache/nifi/ssl/SSLContextServiceTest.java
@@ -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()));
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/d28e61c5/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-service-api/src/main/java/org/apache/nifi/ssl/RestrictedSSLContextService.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-service-api/src/main/java/org/apache/nifi/ssl/RestrictedSSLContextService.java
 
b/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-service-api/src/main/java/org/apache/nifi/ssl/RestrictedSSLContextService.java
new file mode 100644
index 0000000..b76f31d
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-service-api/src/main/java/org/apache/nifi/ssl/RestrictedSSLContextService.java
@@ -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]);
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/d28e61c5/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-service-api/src/main/java/org/apache/nifi/ssl/SSLContextService.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-service-api/src/main/java/org/apache/nifi/ssl/SSLContextService.java
 
b/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-service-api/src/main/java/org/apache/nifi/ssl/SSLContextService.java
index 94f8bda..61f3b81 100644
--- 
a/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-service-api/src/main/java/org/apache/nifi/ssl/SSLContextService.java
+++ 
b/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-service-api/src/main/java/org/apache/nifi/ssl/SSLContextService.java
@@ -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]);
+    }
 }

Reply via email to