Repository: nifi
Updated Branches:
  refs/heads/master 6ff8321cf -> 5150dff70


NIFI-4274 Removed EL evaluation logic from custom file validator.

Signed-off-by: Pierre Villard <pierre.villard...@gmail.com>

This closes #2071.


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

Branch: refs/heads/master
Commit: 5150dff70b4aa210abb86e6d8c1aeb03c8c364e3
Parents: 6ff8321
Author: Andy LoPresto <alopre...@apache.org>
Authored: Wed Aug 9 20:03:33 2017 -0700
Committer: Pierre Villard <pierre.villard...@gmail.com>
Committed: Thu Aug 10 10:05:16 2017 +0200

----------------------------------------------------------------------
 .../nifi/ssl/StandardSSLContextService.java     |  44 ++----
 .../ssl/StandardSSLContextServiceTest.groovy    | 157 +++++++++++++++++++
 2 files changed, 173 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/5150dff7/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 9ac27a3..2570855 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
@@ -16,6 +16,18 @@
  */
 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;
@@ -34,20 +46,7 @@ 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"})
+@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")
 public class StandardSSLContextService extends AbstractControllerService 
implements SSLContextService {
@@ -108,10 +107,11 @@ public class StandardSSLContextService extends 
AbstractControllerService impleme
             .build();
     public static final PropertyDescriptor SSL_ALGORITHM = new 
PropertyDescriptor.Builder()
             .name("SSL Protocol")
+            .displayName("TLS Protocol")
             .defaultValue("TLS")
             .required(false)
             .allowableValues(buildAlgorithmAllowableValues())
-            .description("The algorithm to use for this SSL context")
+            .description("The algorithm to use for this TLS/SSL context")
             .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
             .sensitive(false)
             .build();
@@ -178,19 +178,7 @@ public class StandardSSLContextService extends 
AbstractControllerService impleme
             // allow expression language
             @Override
             public ValidationResult validate(String subject, String input, 
ValidationContext context) {
-                final String substituted;
-                try {
-                    substituted = 
context.newPropertyValue(input).evaluateAttributeExpressions().getValue();
-                } catch (final Exception e) {
-                    return new ValidationResult.Builder()
-                            .subject(subject)
-                            .input(input)
-                            .valid(false)
-                            .explanation("Not a valid Expression Language 
value: " + e.getMessage())
-                            .build();
-                }
-
-                final File file = new File(substituted);
+                final File file = new File(input);
                 final boolean valid = file.exists() && file.canRead();
                 final String explanation = valid ? null : "File " + file + " 
does not exist or cannot be read";
                 return new ValidationResult.Builder()

http://git-wip-us.apache.org/repos/asf/nifi/blob/5150dff7/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/test/groovy/org/apache/nifi/ssl/StandardSSLContextServiceTest.groovy
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/test/groovy/org/apache/nifi/ssl/StandardSSLContextServiceTest.groovy
 
b/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/test/groovy/org/apache/nifi/ssl/StandardSSLContextServiceTest.groovy
new file mode 100644
index 0000000..881eb02
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-standard-services/nifi-ssl-context-bundle/nifi-ssl-context-service/src/test/groovy/org/apache/nifi/ssl/StandardSSLContextServiceTest.groovy
@@ -0,0 +1,157 @@
+/*
+ * 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 org.apache.nifi.components.ValidationContext
+import org.apache.nifi.components.ValidationResult
+import org.apache.nifi.components.Validator
+import org.apache.nifi.state.MockStateManager
+import org.apache.nifi.util.MockProcessContext
+import org.apache.nifi.util.MockValidationContext
+import org.apache.nifi.util.MockVariableRegistry
+import org.apache.nifi.util.TestRunner
+import org.apache.nifi.util.TestRunners
+import org.bouncycastle.jce.provider.BouncyCastleProvider
+import org.junit.After
+import org.junit.AfterClass
+import org.junit.Before
+import org.junit.BeforeClass
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TemporaryFolder
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+
+import java.security.Security
+
+import static groovy.test.GroovyAssert.shouldFail
+
+@RunWith(JUnit4.class)
+class StandardSSLContextServiceTest {
+    private static final Logger logger = 
LoggerFactory.getLogger(StandardSSLContextServiceTest.class)
+
+    private static final String KEYSTORE_PATH = 
"src/test/resources/localhost-ks.jks"
+    private static final String TRUSTSTORE_PATH = 
"src/test/resources/localhost-ts.jks"
+    private static final String TRUSTSTORE_PATH_WITH_EL = 
"\${someAttribute}/localhost-ts.jks"
+
+    private static final String KEYSTORE_PASSWORD = "localtest"
+    private static final String TRUSTSTORE_PASSWORD = "localtest"
+
+    private static final String KEYSTORE_TYPE = "JKS"
+    private static final String TRUSTSTORE_TYPE = "JKS"
+
+    @Rule
+    public TemporaryFolder tmp = new TemporaryFolder(new 
File("src/test/resources"))
+
+    @BeforeClass
+    static void setUpOnce() throws Exception {
+        Security.addProvider(new BouncyCastleProvider())
+
+        logger.metaClass.methodMissing = { String name, args ->
+            logger.info("[${name?.toUpperCase()}] ${(args as List).join(" ")}")
+        }
+    }
+
+    @Before
+    void setUp() throws Exception {
+    }
+
+    @After
+    void tearDown() throws Exception {
+    }
+
+    @AfterClass
+    static void tearDownOnce() throws Exception {
+    }
+
+    @Test
+    void testShouldValidateSimpleFileValidatorPath() {
+        // Arrange
+        TestRunner runner = TestRunners.newTestRunner(TestProcessor.class)
+        String controllerServiceId = "ssl-context"
+        final SSLContextService sslContextService = new 
StandardSSLContextService()
+        runner.addControllerService(controllerServiceId, sslContextService)
+        runner.setProperty(sslContextService, 
StandardSSLContextService.TRUSTSTORE, TRUSTSTORE_PATH)
+        runner.setProperty(sslContextService, 
StandardSSLContextService.TRUSTSTORE_PASSWORD, TRUSTSTORE_PASSWORD)
+        runner.setProperty(sslContextService, 
StandardSSLContextService.TRUSTSTORE_TYPE, TRUSTSTORE_TYPE)
+        runner.enableControllerService(sslContextService)
+
+        // Act
+        runner.assertValid(sslContextService)
+
+        // Assert
+        final MockProcessContext processContext = (MockProcessContext) 
runner.getProcessContext()
+        assert 
processContext.getControllerServiceProperties(sslContextService).get(StandardSSLContextService.TRUSTSTORE,
 "") == TRUSTSTORE_PATH
+    }
+
+    @Test
+    void testShouldNotValidateExpressionLanguageInFileValidator() {
+        // Arrange
+        TestRunner runner = TestRunners.newTestRunner(TestProcessor.class)
+        String controllerServiceId = "ssl-context"
+        final SSLContextService sslContextService = new 
StandardSSLContextService()
+        runner.addControllerService(controllerServiceId, sslContextService)
+        runner.setProperty(sslContextService, 
StandardSSLContextService.TRUSTSTORE, TRUSTSTORE_PATH_WITH_EL)
+        runner.setProperty(sslContextService, 
StandardSSLContextService.TRUSTSTORE_PASSWORD, TRUSTSTORE_PASSWORD)
+        runner.setProperty(sslContextService, 
StandardSSLContextService.TRUSTSTORE_TYPE, TRUSTSTORE_TYPE)
+
+        // Act
+        def msg = shouldFail {
+            runner.enableControllerService(sslContextService)
+        }
+
+        // Assert
+        assert msg =~ "invalid because Cannot access file"
+        runner.assertNotValid(sslContextService)
+    }
+
+    @Test
+    void testShouldNotEvaluateExpressionLanguageInFileValidator() {
+        // Arrange
+        final String VALID_TRUSTSTORE_PATH_WITH_EL = 
"\${literal(''):trim()}${TRUSTSTORE_PATH}"
+
+        TestRunner runner = TestRunners.newTestRunner(TestProcessor.class)
+        String controllerServiceId = "ssl-context"
+        final SSLContextService sslContextService = new 
StandardSSLContextService()
+        runner.addControllerService(controllerServiceId, sslContextService)
+        runner.setProperty(sslContextService, 
StandardSSLContextService.TRUSTSTORE, VALID_TRUSTSTORE_PATH_WITH_EL)
+        runner.setProperty(sslContextService, 
StandardSSLContextService.TRUSTSTORE_PASSWORD, TRUSTSTORE_PASSWORD)
+        runner.setProperty(sslContextService, 
StandardSSLContextService.TRUSTSTORE_TYPE, TRUSTSTORE_TYPE)
+
+        // The verifySslConfig and customValidate methods correctly do not 
evaluate EL, but the custom file validator does, so extract it alone and 
validate
+        Validator fileValidator = 
StandardSSLContextService.createFileExistsAndReadableValidator()
+        final ValidationContext mockValidationContext = new 
MockValidationContext(
+                runner.getProcessContext() as MockProcessContext,
+                new MockStateManager(sslContextService),
+                new MockVariableRegistry())
+
+        // Act
+        ValidationResult vr = 
fileValidator.validate(StandardSSLContextService.TRUSTSTORE.name, 
VALID_TRUSTSTORE_PATH_WITH_EL, mockValidationContext)
+        logger.info("Custom file validation result: ${vr}")
+
+        // Assert
+        final MockProcessContext processContext = (MockProcessContext) 
runner.getProcessContext()
+
+        // If the EL was evaluated, the paths would be identical
+        assert 
processContext.getControllerServiceProperties(sslContextService).get(StandardSSLContextService.TRUSTSTORE,
 "") != TRUSTSTORE_PATH
+
+        // If the EL was evaluated, the path would be valid
+        assert !vr.isValid()
+    }
+}

Reply via email to