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()) + } }
