Repository: nifi
Updated Branches:
  refs/heads/master 2590c8831 -> d09145e3e


NIFI-4557 Added Expression Language support for PGP private keyring passphrase 
in EncryptContent.

Signed-off-by: Pierre Villard <[email protected]>

This closes #2566.


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

Branch: refs/heads/master
Commit: d09145e3e326e5e9a40251831bf00c9f90aba34f
Parents: 2590c88
Author: Andy LoPresto <[email protected]>
Authored: Mon Mar 19 10:46:11 2018 -0700
Committer: Pierre Villard <[email protected]>
Committed: Tue Mar 20 11:23:45 2018 +0100

----------------------------------------------------------------------
 .../processors/standard/EncryptContent.java     |  7 +-
 .../standard/TestEncryptContentGroovy.groovy    | 80 +++++++++++++++-----
 2 files changed, 64 insertions(+), 23 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/d09145e3/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EncryptContent.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EncryptContent.java
 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EncryptContent.java
index d12f036..058d48b 100644
--- 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EncryptContent.java
+++ 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EncryptContent.java
@@ -30,12 +30,12 @@ import org.apache.commons.codec.DecoderException;
 import org.apache.commons.codec.binary.Hex;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.annotation.behavior.EventDriven;
-import org.apache.nifi.annotation.behavior.SystemResourceConsideration;
 import org.apache.nifi.annotation.behavior.InputRequirement;
 import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
 import org.apache.nifi.annotation.behavior.SideEffectFree;
 import org.apache.nifi.annotation.behavior.SupportsBatching;
 import org.apache.nifi.annotation.behavior.SystemResource;
+import org.apache.nifi.annotation.behavior.SystemResourceConsideration;
 import org.apache.nifi.annotation.documentation.CapabilityDescription;
 import org.apache.nifi.annotation.documentation.Tags;
 import org.apache.nifi.components.AllowableValue;
@@ -134,6 +134,7 @@ public class EncryptContent extends AbstractProcessor {
             .description("In a PGP decrypt mode, this is the private keyring 
passphrase")
             .required(false)
             .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+            .expressionLanguageSupported(true)
             .sensitive(true)
             .build();
     public static final PropertyDescriptor RAW_KEY_HEX = new 
PropertyDescriptor.Builder()
@@ -253,7 +254,7 @@ public class EncryptContent extends AbstractProcessor {
             final String publicKeyring = 
context.getProperty(PUBLIC_KEYRING).getValue();
             final String publicUserId = 
context.getProperty(PUBLIC_KEY_USERID).getValue();
             final String privateKeyring = 
context.getProperty(PRIVATE_KEYRING).getValue();
-            final String privateKeyringPassphrase = 
context.getProperty(PRIVATE_KEYRING_PASSPHRASE).getValue();
+            final String privateKeyringPassphrase = 
context.getProperty(PRIVATE_KEYRING_PASSPHRASE).evaluateAttributeExpressions().getValue();
             validationResults.addAll(validatePGP(encryptionMethod, password, 
encrypt, publicKeyring, publicUserId, privateKeyring, 
privateKeyringPassphrase));
         } else { // Not PGP
             if (encryptionMethod.isKeyedCipher()) { // Raw key
@@ -476,7 +477,7 @@ public class EncryptContent extends AbstractProcessor {
                     final String publicUserId = 
context.getProperty(PUBLIC_KEY_USERID).getValue();
                     encryptor = new OpenPGPKeyBasedEncryptor(algorithm, 
providerName, publicKeyring, publicUserId, null, filename);
                 } else if (!encrypt && privateKeyring != null) {
-                    final char[] keyringPassphrase = 
context.getProperty(PRIVATE_KEYRING_PASSPHRASE).getValue().toCharArray();
+                    final char[] keyringPassphrase = 
context.getProperty(PRIVATE_KEYRING_PASSPHRASE).evaluateAttributeExpressions().getValue().toCharArray();
                     encryptor = new OpenPGPKeyBasedEncryptor(algorithm, 
providerName, privateKeyring, null, keyringPassphrase,
                             filename);
                 } else {

http://git-wip-us.apache.org/repos/asf/nifi/blob/d09145e3/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/processors/standard/TestEncryptContentGroovy.groovy
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/processors/standard/TestEncryptContentGroovy.groovy
 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/processors/standard/TestEncryptContentGroovy.groovy
index f940640..ca908a1 100644
--- 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/processors/standard/TestEncryptContentGroovy.groovy
+++ 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/processors/standard/TestEncryptContentGroovy.groovy
@@ -41,14 +41,14 @@ import java.nio.file.Paths
 import java.security.Security
 
 @RunWith(JUnit4.class)
-public class TestEncryptContentGroovy {
+class TestEncryptContentGroovy {
     private static final Logger logger = 
LoggerFactory.getLogger(TestEncryptContentGroovy.class)
 
     private static final String WEAK_CRYPTO_ALLOWED = 
EncryptContent.WEAK_CRYPTO_ALLOWED_NAME
     private static final String WEAK_CRYPTO_NOT_ALLOWED = 
EncryptContent.WEAK_CRYPTO_NOT_ALLOWED_NAME
 
     @BeforeClass
-    public static void setUpOnce() throws Exception {
+    static void setUpOnce() throws Exception {
         Security.addProvider(new BouncyCastleProvider())
 
         logger.metaClass.methodMissing = { String name, args ->
@@ -57,18 +57,18 @@ public class TestEncryptContentGroovy {
     }
 
     @Before
-    public void setUp() throws Exception {
+    void setUp() throws Exception {
     }
 
     @After
-    public void tearDown() throws Exception {
+    void tearDown() throws Exception {
     }
 
     @Test
-    public void 
testShouldValidateMaxKeySizeForAlgorithmsOnUnlimitedStrengthJVM() throws 
IOException {
+    void testShouldValidateMaxKeySizeForAlgorithmsOnUnlimitedStrengthJVM() 
throws IOException {
         // Arrange
         Assume.assumeTrue("Test is being skipped due to this JVM lacking JCE 
Unlimited Strength Jurisdiction Policy file.",
-                PasswordBasedEncryptor.supportsUnlimitedStrength());
+                PasswordBasedEncryptor.supportsUnlimitedStrength())
 
         final TestRunner runner = 
TestRunners.newTestRunner(EncryptContent.class)
         Collection<ValidationResult> results
@@ -103,10 +103,10 @@ public class TestEncryptContentGroovy {
     }
 
     @Test
-    public void 
testShouldValidateMaxKeySizeForAlgorithmsOnLimitedStrengthJVM() throws 
IOException {
+    void testShouldValidateMaxKeySizeForAlgorithmsOnLimitedStrengthJVM() 
throws IOException {
         // Arrange
         Assume.assumeTrue("Test is being skipped because this JVM supports 
unlimited strength crypto.",
-                !PasswordBasedEncryptor.supportsUnlimitedStrength());
+                !PasswordBasedEncryptor.supportsUnlimitedStrength())
 
         final TestRunner runner = 
TestRunners.newTestRunner(EncryptContent.class)
         Collection<ValidationResult> results
@@ -147,7 +147,7 @@ public class TestEncryptContentGroovy {
     }
 
     @Test
-    public void testShouldValidateKeyFormatAndSizeForAlgorithms() throws 
IOException {
+    void testShouldValidateKeyFormatAndSizeForAlgorithms() throws IOException {
         // Arrange
         final TestRunner runner = 
TestRunners.newTestRunner(EncryptContent.class)
         Collection<ValidationResult> results
@@ -181,7 +181,7 @@ public class TestEncryptContentGroovy {
     }
 
     @Test
-    public void testShouldValidateKDFWhenKeyedCipherSelected() {
+    void testShouldValidateKDFWhenKeyedCipherSelected() {
         // Arrange
         final TestRunner runner = 
TestRunners.newTestRunner(EncryptContent.class)
         Collection<ValidationResult> results
@@ -223,7 +223,8 @@ public class TestEncryptContentGroovy {
                 Assert.assertTrue(message, 
keyLengthInvalidVR.toString().contains(expectedResult))
             }
 
-            final def VALID_KDFS = [KeyDerivationFunction.NONE, 
KeyDerivationFunction.BCRYPT, KeyDerivationFunction.SCRYPT, 
KeyDerivationFunction.PBKDF2]
+            final
+            def VALID_KDFS = [KeyDerivationFunction.NONE, 
KeyDerivationFunction.BCRYPT, KeyDerivationFunction.SCRYPT, 
KeyDerivationFunction.PBKDF2]
             VALID_KDFS.each { KeyDerivationFunction validKDF ->
                 logger.info("Trying KDF ${validKDF.name()}")
 
@@ -242,7 +243,7 @@ public class TestEncryptContentGroovy {
     }
 
     @Test
-    public void testShouldValidateKDFWhenPBECipherSelected() {
+    void testShouldValidateKDFWhenPBECipherSelected() {
         // Arrange
         final TestRunner runner = 
TestRunners.newTestRunner(EncryptContent.class)
         Collection<ValidationResult> results
@@ -263,7 +264,8 @@ public class TestEncryptContentGroovy {
             logger.info("Trying encryption method ${encryptionMethod.name()}")
             runner.setProperty(EncryptContent.ENCRYPTION_ALGORITHM, 
encryptionMethod.name())
 
-            final def INVALID_KDFS = [KeyDerivationFunction.NONE, 
KeyDerivationFunction.BCRYPT, KeyDerivationFunction.SCRYPT, 
KeyDerivationFunction.PBKDF2]
+            final
+            def INVALID_KDFS = [KeyDerivationFunction.NONE, 
KeyDerivationFunction.BCRYPT, KeyDerivationFunction.SCRYPT, 
KeyDerivationFunction.PBKDF2]
             INVALID_KDFS.each { KeyDerivationFunction invalidKDF ->
                 logger.info("Trying KDF ${invalidKDF.name()}")
 
@@ -305,7 +307,7 @@ public class TestEncryptContentGroovy {
     }
 
     @Test
-    public void testRoundTrip() throws IOException {
+    void testRoundTrip() throws IOException {
         final TestRunner testRunner = TestRunners.newTestRunner(new 
EncryptContent())
         final String RAW_KEY_HEX = "ab" * 16
         testRunner.setProperty(EncryptContent.RAW_KEY_HEX, RAW_KEY_HEX)
@@ -341,7 +343,7 @@ public class TestEncryptContentGroovy {
     }
 
     @Test
-    public void 
testShouldCheckMaximumLengthOfPasswordOnLimitedStrengthCryptoJVM() throws 
IOException {
+    void testShouldCheckMaximumLengthOfPasswordOnLimitedStrengthCryptoJVM() 
throws IOException {
         // Arrange
         Assume.assumeTrue("Only run on systems with limited strength crypto", 
!PasswordBasedEncryptor.supportsUnlimitedStrength())
 
@@ -359,7 +361,8 @@ public class TestEncryptContentGroovy {
             def invalidPasswordLength = 
CipherUtility.getMaximumPasswordLengthForAlgorithmOnLimitedStrengthCrypto(encryptionMethod)
 + 1
             String tooLongPassword = "x" * invalidPasswordLength
             if (encryptionMethod.isUnlimitedStrength() || 
encryptionMethod.isKeyedCipher()) {
-                return false   // cannot test unlimited strength in unit tests 
because it's not enabled by the JVM by default.
+                return false
+                // cannot test unlimited strength in unit tests because it's 
not enabled by the JVM by default.
             }
 
             testRunner.setProperty(EncryptContent.PASSWORD, tooLongPassword)
@@ -387,7 +390,7 @@ public class TestEncryptContentGroovy {
     }
 
     @Test
-    public void testShouldCheckLengthOfPasswordWhenNotAllowed() throws 
IOException {
+    void testShouldCheckLengthOfPasswordWhenNotAllowed() throws IOException {
         // Arrange
         final TestRunner testRunner = TestRunners.newTestRunner(new 
EncryptContent())
         testRunner.setProperty(EncryptContent.KEY_DERIVATION_FUNCTION, 
KeyDerivationFunction.NIFI_LEGACY.name())
@@ -407,7 +410,8 @@ public class TestEncryptContentGroovy {
             def shortPasswordLength = 
[PasswordBasedEncryptor.getMinimumSafePasswordLength() - 1, 
CipherUtility.getMaximumPasswordLengthForAlgorithmOnLimitedStrengthCrypto(encryptionMethod)
 - 1].min()
             String shortPassword = "x" * shortPasswordLength
             if (encryptionMethod.isUnlimitedStrength() || 
encryptionMethod.isKeyedCipher()) {
-                return false   // cannot test unlimited strength in unit tests 
because it's not enabled by the JVM by default.
+                return false
+                // cannot test unlimited strength in unit tests because it's 
not enabled by the JVM by default.
             }
 
             testRunner.setProperty(EncryptContent.PASSWORD, shortPassword)
@@ -436,7 +440,7 @@ public class TestEncryptContentGroovy {
     }
 
     @Test
-    public void testShouldNotCheckLengthOfPasswordWhenAllowed() throws 
IOException {
+    void testShouldNotCheckLengthOfPasswordWhenAllowed() throws IOException {
         // Arrange
         final TestRunner testRunner = TestRunners.newTestRunner(new 
EncryptContent())
         testRunner.setProperty(EncryptContent.KEY_DERIVATION_FUNCTION, 
KeyDerivationFunction.NIFI_LEGACY.name())
@@ -456,7 +460,8 @@ public class TestEncryptContentGroovy {
             def shortPasswordLength = 
[PasswordBasedEncryptor.getMinimumSafePasswordLength() - 1, 
CipherUtility.getMaximumPasswordLengthForAlgorithmOnLimitedStrengthCrypto(encryptionMethod)
 - 1].min()
             String shortPassword = "x" * shortPasswordLength
             if (encryptionMethod.isUnlimitedStrength() || 
encryptionMethod.isKeyedCipher()) {
-                return false   // cannot test unlimited strength in unit tests 
because it's not enabled by the JVM by default.
+                return false
+                // cannot test unlimited strength in unit tests because it's 
not enabled by the JVM by default.
             }
 
             testRunner.setProperty(EncryptContent.PASSWORD, shortPassword)
@@ -476,4 +481,39 @@ public class TestEncryptContentGroovy {
             Assert.assertEquals(results.toString(), 0, results.size())
         }
     }
+
+    @Test
+    void testPGPPasswordShouldSupportExpressionLanguage() throws IOException {
+        // Arrange
+        final TestRunner testRunner = TestRunners.newTestRunner(new 
EncryptContent())
+        testRunner.setProperty(EncryptContent.MODE, 
EncryptContent.DECRYPT_MODE)
+        testRunner.setProperty(EncryptContent.ENCRYPTION_ALGORITHM, 
EncryptionMethod.PGP.name())
+        testRunner.setProperty(EncryptContent.PRIVATE_KEYRING, 
"src/test/resources/TestEncryptContent/secring.gpg")
+
+        Collection<ValidationResult> results
+        MockProcessContext pc
+
+        // Verify this is the correct password
+        final String passphraseWithoutEL = "thisIsABadPassword"
+        testRunner.setProperty(EncryptContent.PRIVATE_KEYRING_PASSPHRASE, 
passphraseWithoutEL)
+
+        testRunner.clearTransferState()
+        testRunner.enqueue(new byte[0])
+        pc = (MockProcessContext) testRunner.getProcessContext()
+
+        results = pc.validate()
+        Assert.assertEquals(results.toString(), 0, results.size())
+
+        final String passphraseWithEL = "\${literal('thisIsABadPassword')}"
+        testRunner.setProperty(EncryptContent.PRIVATE_KEYRING_PASSPHRASE, 
passphraseWithEL)
+
+        testRunner.clearTransferState()
+        testRunner.enqueue(new byte[0])
+
+        // Act
+        results = pc.validate()
+
+        // Assert
+        Assert.assertEquals(results.toString(), 0, results.size())
+    }
 }

Reply via email to