This is an automated email from the ASF dual-hosted git repository.
thenatog pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/main by this push:
new 1c361d4 NIFI-6999 - Made changes to load flow.xml files using
streams. Updated tests.
1c361d4 is described below
commit 1c361d45ae94f155b6e2def7bd4430b1c9ca8b3b
Author: Nathan Gough <[email protected]>
AuthorDate: Fri Dec 4 19:05:52 2020 -0500
NIFI-6999 - Made changes to load flow.xml files using streams. Updated
tests.
NIFI-6999 - Slight change to test to check for WARN message.
NIFI-6999 - Removed very large flow file and test that uses it. This test
ran for about 2 minutes so was excessive to keep in. The other changed tests to
handle streams proves the functionality. A large file can be used on the
command line to manually test large flow files. Some other cleanup.
NIFI-6999 - Removed comments and altered the code a little bit for
readability as per code review.
NIFI-6999 - Removed commented code
NIFI-6999 - Renamed variable and removed assert comment.
Signed-off-by: Nathan Gough <[email protected]>
This closes #4715.
---
.../nifi/properties/ConfigEncryptionTool.groovy | 107 +++---
.../properties/ConfigEncryptionToolTest.groovy | 376 ++++++++++++++-------
.../src/test/resources/flow.xml | 4 +-
.../src/test/resources/flow.xml.gz | Bin 1674 -> 1652 bytes
.../src/test/resources/flow_default_key.xml | 4 +-
.../src/test/resources/flow_default_key.xml.gz | Bin 1686 -> 1654 bytes
6 files changed, 322 insertions(+), 169 deletions(-)
diff --git
a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/groovy/org/apache/nifi/properties/ConfigEncryptionTool.groovy
b/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/groovy/org/apache/nifi/properties/ConfigEncryptionTool.groovy
index 2a10043..919687f 100644
---
a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/groovy/org/apache/nifi/properties/ConfigEncryptionTool.groovy
+++
b/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/groovy/org/apache/nifi/properties/ConfigEncryptionTool.groovy
@@ -27,7 +27,6 @@ import org.apache.commons.cli.Option
import org.apache.commons.cli.Options
import org.apache.commons.cli.ParseException
import org.apache.commons.codec.binary.Hex
-import org.apache.commons.io.IOUtils
import org.apache.nifi.security.kms.CryptoUtils
import org.apache.nifi.toolkit.tls.commandLine.CommandLineParseException
import org.apache.nifi.toolkit.tls.commandLine.ExitCode
@@ -47,12 +46,17 @@ import javax.crypto.SecretKeyFactory
import javax.crypto.spec.PBEKeySpec
import javax.crypto.spec.PBEParameterSpec
import java.nio.charset.StandardCharsets
+import java.nio.file.Path
+import java.nio.file.Paths
+import java.nio.file.StandardCopyOption;
import java.security.KeyException
import java.security.SecureRandom
import java.security.Security
import java.util.regex.Matcher
import java.util.zip.GZIPInputStream
import java.util.zip.GZIPOutputStream
+import java.util.zip.ZipException
+import java.nio.file.Files;
class ConfigEncryptionTool {
private static final Logger logger =
LoggerFactory.getLogger(ConfigEncryptionTool.class)
@@ -64,8 +68,8 @@ class ConfigEncryptionTool {
public String outputLoginIdentityProvidersPath
public String authorizersPath
public String outputAuthorizersPath
- public String flowXmlPath
- public String outputFlowXmlPath
+ public static flowXmlPath
+ public outputFlowXmlPath
private String keyHex
private String migrationKeyHex
@@ -81,7 +85,7 @@ class ConfigEncryptionTool {
private NiFiProperties niFiProperties
private String loginIdentityProviders
private String authorizers
- private String flowXml
+ private InputStream flowXmlInputStream
private boolean usingPassword = true
private boolean usingPasswordMigration = true
@@ -657,26 +661,24 @@ class ConfigEncryptionTool {
/**
* Loads the flow definition from the provided file path, handling the
GZIP file compression. Unlike {@link #loadLoginIdentityProviders()} this method
does not decrypt the content (for performance and separation of concern
reasons).
*
- * @return the file content
+ * @param The path to the XML file
+ * @return The file content
* @throw IOException if the flow.xml.gz file cannot be read
*/
- private String loadFlowXml() throws IOException {
- if (flowXmlPath && (new File(flowXmlPath)).exists()) {
+ private InputStream loadFlowXml(String filePath) throws IOException {
+ if (filePath && (new File(filePath)).exists()) {
try {
- new FileInputStream(flowXmlPath).withCloseable {
- new GZIPInputStream(it).withCloseable {
- String xmlContent = IOUtils.toString(it,
StandardCharsets.UTF_8)
- return xmlContent
- }
- }
+ return new GZIPInputStream(new FileInputStream(filePath))
+ } catch (ZipException e) {
+ return new FileInputStream(filePath)
} catch (RuntimeException e) {
if (isVerbose) {
logger.error("Encountered an error", e)
}
- throw new IOException("Cannot load flow from
[${flowXmlPath}]", e)
+ throw new IOException("Cannot load flow from [${filePath}]", e)
}
} else {
- printUsageAndThrow("Cannot load flow from [${flowXmlPath}]",
ExitCode.ERROR_READING_NIFI_PROPERTIES)
+ printUsageAndThrow("Cannot load flow from [${filePath}]",
ExitCode.ERROR_READING_NIFI_PROPERTIES)
}
}
@@ -790,14 +792,14 @@ class ConfigEncryptionTool {
/**
* Scans XML content and decrypts each encrypted element, then re-encrypts
it with the new key, and returns the final XML content.
*
- * @param flowXmlContent the original flow.xml.gz content
+ * @param flowXmlContent the original flow.xml.gz as an input stream
* @param existingFlowPassword the existing value of
nifi.sensitive.props.key (not a raw key, but rather a password)
* @param newFlowPassword the password to use to for encryption (not a raw
key, but rather a password)
* @param existingAlgorithm the KDF algorithm to use (defaults to
PBEWITHMD5AND256BITAES-CBC-OPENSSL)
* @param existingProvider the {@link java.security.Provider} to use
(defaults to BC)
- * @return the encrypted XML content
+ * @return the encrypted XML content as an InputStream
*/
- private String migrateFlowXmlContent(String flowXmlContent, String
existingFlowPassword, String newFlowPassword, String existingAlgorithm =
DEFAULT_FLOW_ALGORITHM, String existingProvider = DEFAULT_PROVIDER, String
newAlgorithm = DEFAULT_FLOW_ALGORITHM, String newProvider = DEFAULT_PROVIDER) {
+ private InputStream migrateFlowXmlContent(InputStream flowXmlContent,
String existingFlowPassword, String newFlowPassword, String existingAlgorithm =
DEFAULT_FLOW_ALGORITHM, String existingProvider = DEFAULT_PROVIDER, String
newAlgorithm = DEFAULT_FLOW_ALGORITHM, String newProvider = DEFAULT_PROVIDER) {
/* For re-encryption, for performance reasons, we will use a fixed
salt for all of
* the operations. These values are stored in the same file and the
default key is in the
* source code (see NIFI-1465 and NIFI-1277), so the security
trade-off is minimal
@@ -810,21 +812,51 @@ class ConfigEncryptionTool {
Cipher encryptCipher = generateFlowEncryptionCipher(newFlowPassword,
encryptionSalt, newAlgorithm, newProvider)
int elementCount = 0
-
- // Scan the XML content and identify every encrypted element, decrypt
it, and replace it with the re-encrypted value
- String migratedFlowXmlContent =
flowXmlContent.replaceAll(WRAPPED_FLOW_XML_CIPHER_TEXT_REGEX) { String
wrappedCipherText ->
- String plaintext = decryptFlowElement(wrappedCipherText,
existingFlowPassword, existingAlgorithm, existingProvider)
- byte[] cipherBytes = encryptCipher.doFinal(plaintext.bytes)
- byte[] saltAndCipherBytes = concatByteArrays(encryptionSalt,
cipherBytes)
- elementCount++
- "enc{${Hex.encodeHex(saltAndCipherBytes)}}"
+ File tempFlowXmlFile = new
File(getTemporaryFlowXmlFile(outputFlowXmlPath).toString())
+ BufferedWriter tempFlowXmlWriter =
getFlowOutputStream(tempFlowXmlFile, flowXmlContent instanceof GZIPInputStream)
+
+ // Scan through XML content as a stream, decrypt and re-encrypt fields
with a new flow password
+ final BufferedReader reader = new BufferedReader(new
InputStreamReader(flowXmlContent))
+ String line;
+
+ while((line = reader.readLine()) != null) {
+ def matcher = line =~ WRAPPED_FLOW_XML_CIPHER_TEXT_REGEX
+ if(matcher.find()) {
+ String plaintext = decryptFlowElement(matcher.getAt(0),
existingFlowPassword, existingAlgorithm, existingProvider)
+ byte[] cipherBytes = encryptCipher.doFinal(plaintext.bytes)
+ byte[] saltAndCipherBytes = concatByteArrays(encryptionSalt,
cipherBytes)
+ elementCount++
+
tempFlowXmlWriter.writeLine(line.replaceFirst(WRAPPED_FLOW_XML_CIPHER_TEXT_REGEX,
"enc{${Hex.encodeHex(saltAndCipherBytes)}}"))
+ } else {
+ tempFlowXmlWriter.writeLine(line)
+ }
}
+ tempFlowXmlWriter.flush()
+ tempFlowXmlWriter.close()
+
+ // Overwrite the original flow file with the migrated flow file
+ Files.move(tempFlowXmlFile.toPath(), Paths.get(outputFlowXmlPath),
StandardCopyOption.ATOMIC_MOVE)
if (isVerbose) {
logger.info("Decrypted and re-encrypted ${elementCount} elements
for flow.xml.gz")
}
- migratedFlowXmlContent
+ loadFlowXml(outputFlowXmlPath)
+ }
+
+ private BufferedWriter getFlowOutputStream(File outputFlowXmlPath, boolean
isFileGZipped) {
+ OutputStream flowOutputStream = new FileOutputStream(outputFlowXmlPath)
+ if(isFileGZipped) {
+ flowOutputStream = new GZIPOutputStream(flowOutputStream)
+ }
+ new BufferedWriter(new OutputStreamWriter(flowOutputStream))
+ }
+
+ // Create a temporary output file we can write the stream to
+ private Path getTemporaryFlowXmlFile(String originalOutputFlowXmlPath) {
+ String outputFilename =
Paths.get(originalOutputFlowXmlPath).getFileName().toString()
+ String migratedFileName = "migrated-${outputFilename}"
+ Paths.get(originalOutputFlowXmlPath).resolveSibling(migratedFileName)
}
/**
@@ -861,19 +893,6 @@ class ConfigEncryptionTool {
encryptCipher
}
- /**
- * Writes the XML content to the {@link .outputFlowXmlPath} location,
handling the GZIP file compression.
- *
- * @param flowXmlContent the XML content to write
- */
- private void writeFlowXmlToFile(String flowXmlContent) {
- new FileOutputStream(outputFlowXmlPath).withCloseable {
- new GZIPOutputStream(it).withCloseable {
- IOUtils.write(flowXmlContent, it, StandardCharsets.UTF_8)
- }
- }
- }
-
String decryptLoginIdentityProviders(String encryptedXml, String
existingKeyHex = keyHex) {
AESSensitivePropertyProvider sensitivePropertyProvider = new
AESSensitivePropertyProvider(existingKeyHex)
@@ -1536,14 +1555,13 @@ class ConfigEncryptionTool {
if (tool.handlingFlowXml) {
try {
- tool.flowXml = tool.loadFlowXml()
+ tool.flowXmlInputStream = tool.loadFlowXml(flowXmlPath)
} catch (Exception e) {
if (tool.isVerbose) {
logger.error("Encountered an error: ", e)
}
tool.printUsageAndThrow("Cannot load flow.xml.gz",
ExitCode.ERROR_READING_NIFI_PROPERTIES)
}
- tool.handleFlowXml(existingNiFiPropertiesAreEncrypted)
}
if (tool.handlingNiFiProperties) {
@@ -1568,7 +1586,7 @@ class ConfigEncryptionTool {
tool.writeKeyToBootstrapConf()
}
if (tool.handlingFlowXml) {
- tool.writeFlowXmlToFile(tool.flowXml)
+ tool.handleFlowXml(tool.niFiPropertiesAreEncrypted())
}
if (tool.handlingNiFiProperties || tool.handlingFlowXml) {
tool.writeNiFiProperties()
@@ -1612,7 +1630,8 @@ class ConfigEncryptionTool {
String newProvider = newFlowProvider ?: existingProvider
try {
- flowXml = migrateFlowXmlContent(flowXml, existingFlowPassword,
newFlowPassword, existingAlgorithm, existingProvider, newAlgorithm, newProvider)
+ logger.info("Migrating flow.xml file at ${flowXmlPath}. This could
take a while if the flow XML is very large.")
+ migrateFlowXmlContent(flowXmlInputStream, existingFlowPassword,
newFlowPassword, existingAlgorithm, existingProvider, newAlgorithm, newProvider)
} catch (Exception e) {
logger.error("Encountered an error: ${e.getLocalizedMessage()}")
if (e instanceof BadPaddingException) {
diff --git
a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/groovy/org/apache/nifi/properties/ConfigEncryptionToolTest.groovy
b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/groovy/org/apache/nifi/properties/ConfigEncryptionToolTest.groovy
index 9a7f08a..a3c5d10 100644
---
a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/groovy/org/apache/nifi/properties/ConfigEncryptionToolTest.groovy
+++
b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/groovy/org/apache/nifi/properties/ConfigEncryptionToolTest.groovy
@@ -60,6 +60,9 @@ import java.nio.file.attribute.PosixFilePermission
import java.security.KeyException
import java.security.Security
+import org.apache.commons.io.IOUtils
+import java.nio.charset.StandardCharsets
+
@RunWith(JUnit4.class)
class ConfigEncryptionToolTest extends GroovyTestCase {
private static final Logger logger =
LoggerFactory.getLogger(ConfigEncryptionToolTest.class)
@@ -77,6 +80,7 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
private static final String KEY_HEX_256 = KEY_HEX_128 * 2
public static final String KEY_HEX = isUnlimitedStrengthCryptoAvailable()
? KEY_HEX_256 : KEY_HEX_128
private static final String PASSWORD = "thisIsABadPassword"
+ private static final String ANOTHER_PASSWORD = "thisIsAnotherBadPassword"
private static final String STATIC_SALT =
"\$s0\$40801\$ABCDEFGHIJKLMNOPQRSTUV"
private static final String SCRYPT_SALT_PATTERN =
/\$\w{2}\$\w{5,}\$[\w\/\=\+]+/
@@ -287,7 +291,9 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
// Assert
assert !TestAppender.events.isEmpty()
- assert TestAppender.events.first().message =~ "The source
nifi.properties and destination nifi.properties are identical \\[.*\\] so the
original will be overwritten"
+ assert TestAppender.events.stream().any() {
+ it.message =~ "The source nifi.properties and destination
nifi.properties are identical \\[.*\\] so the original will be overwritten"
+ }
}
@Test
@@ -3389,7 +3395,6 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
def originalParsedXml = new
XmlSlurper().parseText(originalXmlContent)
def updatedParsedXml = new
XmlSlurper().parseText(updatedXmlContent)
assert originalParsedXml != updatedParsedXml
-// assert originalParsedXml.'**'.findAll { it.@encryption } !=
updatedParsedXml.'**'.findAll { it.@encryption }
def encryptedValues = updatedParsedXml.userGroupProvider.find {
it.identifier == 'ldap-user-group-provider'
@@ -3806,19 +3811,21 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
// Verify the flow definition
def verifyTool = new ConfigEncryptionTool()
verifyTool.isVerbose = true
- verifyTool.flowXmlPath = workingFlowXmlFile.path
- String updatedFlowXmlContent = verifyTool.loadFlowXml()
+ InputStream updatedFlowXmlContent =
verifyTool.loadFlowXml(workingFlowXmlFile.path)
// Check that the flow.xml.gz content changed
assert updatedFlowXmlContent != ORIGINAL_FLOW_XML_CONTENT
// Verify that the cipher texts decrypt correctly
logger.info("Original flow.xml.gz cipher texts:
${originalFlowCipherTexts}")
- def flowCipherTexts = updatedFlowXmlContent.findAll(WFXCTR)
- logger.info("Updated flow.xml.gz cipher texts:
${flowCipherTexts}")
- assert flowCipherTexts.size() == CIPHER_TEXT_COUNT
- flowCipherTexts.every {
- assert ConfigEncryptionTool.decryptFlowElement(it,
newFlowPassword) == "thisIsABadPassword"
+
+ def updatedFlowCipherTexts =
findFieldsInStream(updatedFlowXmlContent, WFXCTR)
+ logger.info("Updated flow.xml.gz cipher texts:
${updatedFlowCipherTexts}")
+ assert updatedFlowCipherTexts.size() == CIPHER_TEXT_COUNT
+ updatedFlowCipherTexts.each {
+ String decryptedValue =
ConfigEncryptionTool.decryptFlowElement(it, newFlowPassword)
+ logger.info("Decrypted value of migrated
${workingFlowXmlFile.path} was: ${decryptedValue}")
+ assert decryptedValue == PASSWORD || decryptedValue ==
ANOTHER_PASSWORD
}
}
})
@@ -3911,19 +3918,20 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
// Verify the flow definition
def verifyTool = new ConfigEncryptionTool()
verifyTool.isVerbose = true
- verifyTool.flowXmlPath = workingFlowXmlFile.path
- String updatedFlowXmlContent = verifyTool.loadFlowXml()
+ InputStream migratedFlowXmlContent =
verifyTool.loadFlowXml(workingFlowXmlFile.path)
// Check that the flow.xml.gz cipher texts did change (new
salt)
- assert updatedFlowXmlContent != ORIGINAL_FLOW_XML_CONTENT
+ assert migratedFlowXmlContent != ORIGINAL_FLOW_XML_CONTENT
// Verify that the cipher texts decrypt correctly
logger.info("Original flow.xml.gz cipher texts:
${originalFlowCipherTexts}")
- def flowCipherTexts = updatedFlowXmlContent.findAll(WFXCTR)
- logger.info("Updated flow.xml.gz cipher texts:
${flowCipherTexts}")
- assert flowCipherTexts.size() == CIPHER_TEXT_COUNT
- flowCipherTexts.every {
- assert ConfigEncryptionTool.decryptFlowElement(it,
newFlowPassword) == "thisIsABadPassword"
+ def migratedFlowCipherTexts =
findFieldsInStream(migratedFlowXmlContent, WFXCTR)
+ logger.info("Updated flow.xml.gz cipher texts:
${migratedFlowCipherTexts}")
+ assert migratedFlowCipherTexts.size() == CIPHER_TEXT_COUNT
+ migratedFlowCipherTexts.each {
+ String decryptedValue =
ConfigEncryptionTool.decryptFlowElement(it, newFlowPassword)
+ logger.info("Decrypted value of migrated
${workingFlowXmlFile.path} was: ${decryptedValue}")
+ assert decryptedValue == PASSWORD || decryptedValue ==
ANOTHER_PASSWORD
}
}
})
@@ -3969,7 +3977,7 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
Files.copy(niFiPropertiesFile.toPath(),
workingNiFiPropertiesFile.toPath())
// Use a flow definition that was encrypted with the hard-coded
default SP key
- File flowXmlFile = new
File("src/test/resources/flow_default_key.xml.gz")
+ File flowXmlFile = new File("src/test/resources/flow.xml.gz")
File workingFlowXmlFile = new File("target/tmp/tmp-flow.xml.gz")
workingFlowXmlFile.delete()
Files.copy(flowXmlFile.toPath(), workingFlowXmlFile.toPath())
@@ -4053,18 +4061,154 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
def verifyTool = new ConfigEncryptionTool()
verifyTool.isVerbose = true
verifyTool.flowXmlPath = workingFlowXmlFile.path
- String updatedFlowXmlContent = verifyTool.loadFlowXml()
+ InputStream updatedFlowXmlContent =
verifyTool.loadFlowXml(workingFlowXmlFile.path)
- // Check that the flow.xml.gz content changed
- assert updatedFlowXmlContent != ORIGINAL_FLOW_XML_CONTENT
+ def migratedFlowCipherTexts =
findFieldsInStream(updatedFlowXmlContent, WFXCTR)
// Verify that the cipher texts decrypt correctly
logger.info("Original flow.xml.gz cipher texts:
${originalFlowCipherTexts}")
- def flowCipherTexts = updatedFlowXmlContent.findAll(WFXCTR)
- logger.info("Updated flow.xml.gz cipher texts:
${flowCipherTexts}")
- assert flowCipherTexts.size() == CIPHER_TEXT_COUNT
- flowCipherTexts.every {
- assert ConfigEncryptionTool.decryptFlowElement(it,
newFlowPassword) == "thisIsABadPassword"
+ logger.info("Updated flow.xml.gz cipher texts:
${migratedFlowCipherTexts}")
+ assert migratedFlowCipherTexts.size() == CIPHER_TEXT_COUNT
+ migratedFlowCipherTexts.each {
+ String decryptedValue =
ConfigEncryptionTool.decryptFlowElement(it, newFlowPassword)
+ logger.info("Decrypted value of migrated
${workingFlowXmlFile.path} was: ${decryptedValue}")
+ assert decryptedValue == PASSWORD || decryptedValue ==
ANOTHER_PASSWORD
+ }
+ }
+ })
+
+ // Act
+ ConfigEncryptionTool.main(args)
+ logger.info("Invoked #main with ${args.join(" ")}")
+ }
+
+ /**
+ * In this scenario, the nifi.properties file has a sensitive key value
which is already encrypted. The goal is to provide a new provide a new
sensitive key value, perform the migration of the flow.xml.gz, and update
nifi.properties with a new encrypted sensitive key value without modifying any
other nifi.properties values.
+ */
+ @Test
+ void
testShouldPerformFullOperationOnAFlowXmlWithPreviouslyEncryptedNiFiProperties()
{
+ // Arrange
+ exit.expectSystemExitWithStatus(0)
+
+ File tmpDir = setupTmpDir()
+
+ File passwordKeyFile = new
File("src/test/resources/bootstrap_with_root_key_password_128.conf")
+ File bootstrapFile = new File("target/tmp/tmp_bootstrap.conf")
+ bootstrapFile.delete()
+
+ Files.copy(passwordKeyFile.toPath(), bootstrapFile.toPath())
+ final List<String> originalBootstrapLines = bootstrapFile.readLines()
+ String originalKeyLine = originalBootstrapLines.find {
+ it.startsWith(ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX)
+ }
+ final String EXPECTED_KEY_LINE =
ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX + PASSWORD_KEY_HEX_128
+ logger.info("Original key line from bootstrap.conf:
${originalKeyLine}")
+ assert originalKeyLine == ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX +
PASSWORD_KEY_HEX_128
+
+ // Not "handling" NFP, so update in place (not source test resource)
+ String niFiPropertiesTemplatePath =
"src/test/resources/nifi_with_few_sensitive_properties_protected_aes_password_128.properties"
+ File niFiPropertiesFile = new File(niFiPropertiesTemplatePath)
+
+ File workingNiFiPropertiesFile = new
File("target/tmp/tmp-nifi.properties")
+ workingNiFiPropertiesFile.delete()
+ Files.copy(niFiPropertiesFile.toPath(),
workingNiFiPropertiesFile.toPath())
+
+ // Use a flow definition that was encrypted with the hard-coded
default SP key
+ File flowXmlFile = new File("src/test/resources/flow.xml.gz")
+ File workingFlowXmlFile = new File("target/tmp/tmp-flow.xml.gz")
+ workingFlowXmlFile.delete()
+ Files.copy(flowXmlFile.toPath(), workingFlowXmlFile.toPath())
+
+ // Get the original ciphered fields to compare later
+ def verifyTool = new ConfigEncryptionTool()
+ verifyTool.isVerbose = true
+ def originalFlowCipherTexts =
findFieldsInStream(verifyTool.loadFlowXml(flowXmlFile.path), WFXCTR)
+ final int CIPHER_TEXT_COUNT = originalFlowCipherTexts.size()
+
+ // Load both the encrypted and decrypted properties to compare later
+ NiFiPropertiesLoader niFiPropertiesLoader =
NiFiPropertiesLoader.withKey(PASSWORD_KEY_HEX_128)
+ NiFiProperties inputProperties =
niFiPropertiesLoader.load(workingNiFiPropertiesFile)
+ logger.info("Loaded ${inputProperties.size()} properties from input
file")
+ ProtectedNiFiProperties protectedInputProperties = new
ProtectedNiFiProperties(inputProperties)
+ def originalSensitiveValues =
protectedInputProperties.getSensitivePropertyKeys().collectEntries { String key
-> [(key): protectedInputProperties.getProperty(key)] }
+ logger.info("Original sensitive values: ${originalSensitiveValues}")
+
+
+ final String SENSITIVE_PROTECTION_KEY =
ProtectedNiFiProperties.getProtectionKey(NiFiProperties.SENSITIVE_PROPS_KEY)
+ ProtectedNiFiProperties encryptedProperties =
niFiPropertiesLoader.readProtectedPropertiesFromDisk(workingNiFiPropertiesFile)
+ def originalEncryptedValues =
encryptedProperties.getSensitivePropertyKeys().collectEntries { String key ->
[(key): encryptedProperties.getProperty(key)] }
+ logger.info("Original encrypted values: ${originalEncryptedValues}")
+ String originalSensitiveKeyProtectionScheme =
encryptedProperties.getProperty(SENSITIVE_PROTECTION_KEY)
+ logger.info("Sensitive property key originally protected with
${originalSensitiveKeyProtectionScheme}")
+
+ String newFlowPassword = FLOW_PASSWORD
+
+ // Bootstrap path must be provided to decrypt nifi.properties to get
SP key
+ String[] args = ["-n", workingNiFiPropertiesFile.path, "-f",
workingFlowXmlFile.path, "-b", bootstrapFile.path, "-x", "-v", "-s",
newFlowPassword]
+
+ exit.checkAssertionAfterwards(new Assertion() {
+ void checkAssertion() {
+ final List<String> updatedPropertiesLines =
workingNiFiPropertiesFile.readLines()
+ logger.info("Updated nifi.properties:")
+ logger.info("\n" * 2 + updatedPropertiesLines.join("\n"))
+
+ AESSensitivePropertyProvider spp = new
AESSensitivePropertyProvider(PASSWORD_KEY_HEX_128)
+
+ // Check that the output values for everything is the same
except the sensitive props key
+ NiFiProperties updatedProperties = new
NiFiPropertiesLoader().readProtectedPropertiesFromDisk(workingNiFiPropertiesFile)
+ assert updatedProperties.size() == inputProperties.size()
+ String newSensitivePropertyKey =
updatedProperties.getProperty(NiFiProperties.SENSITIVE_PROPS_KEY)
+
+ // Check that the encrypted value changed
+ assert newSensitivePropertyKey !=
originalSensitiveValues.get(NiFiProperties.SENSITIVE_PROPS_KEY)
+
+ // Check that the decrypted value is the new password
+ assert spp.unprotect(newSensitivePropertyKey) ==
newFlowPassword
+
+ // Check that all other values stayed the same
+ originalEncryptedValues.every { String key, String
originalValue ->
+ if (key != NiFiProperties.SENSITIVE_PROPS_KEY) {
+ assert updatedProperties.getProperty(key) ==
originalValue
+ }
+ }
+
+ // Check that all other (decrypted) values stayed the same
+ originalSensitiveValues.every { String key, String
originalValue ->
+ if (key != NiFiProperties.SENSITIVE_PROPS_KEY) {
+ assert
spp.unprotect(updatedProperties.getProperty(key)) == originalValue
+ }
+ }
+
+ // Check that the protection scheme did not change
+ String sensitiveKeyProtectionScheme =
updatedProperties.getProperty(SENSITIVE_PROTECTION_KEY)
+ logger.info("Sensitive property key currently protected with
${sensitiveKeyProtectionScheme}")
+ assert sensitiveKeyProtectionScheme ==
originalSensitiveKeyProtectionScheme
+
+ // Check that bootstrap.conf did not change
+ final List<String> updatedBootstrapLines =
bootstrapFile.readLines()
+ String updatedKeyLine = updatedBootstrapLines.find {
+ it.startsWith(ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX)
+ }
+ logger.info("Updated key line: ${updatedKeyLine}")
+
+ assert updatedKeyLine == EXPECTED_KEY_LINE
+ assert originalBootstrapLines.size() ==
updatedBootstrapLines.size()
+
+ // Verify the flow definition
+ verifyTool = new ConfigEncryptionTool()
+ verifyTool.isVerbose = true
+ InputStream migratedFlowXmlContent =
verifyTool.loadFlowXml(workingFlowXmlFile.path)
+
+ def migratedFlowCipherTexts =
findFieldsInStream(migratedFlowXmlContent, WFXCTR)
+ logger.info("Migrated flow cipher texts for: " +
workingFlowXmlFile.path)
+ // Verify that the cipher texts decrypt correctly
+ logger.info("Original " + workingFlowXmlFile.path + " unique
cipher texts: ${originalFlowCipherTexts}")
+ logger.info("Migrated " + workingFlowXmlFile.path + " unique
cipher texts: ${migratedFlowCipherTexts}")
+ assert migratedFlowCipherTexts.size() == CIPHER_TEXT_COUNT
+ migratedFlowCipherTexts.each {
+ String decryptedValue =
ConfigEncryptionTool.decryptFlowElement(it, newFlowPassword)
+ logger.info("Decrypted value of migrated
${workingFlowXmlFile.path} was: ${decryptedValue}")
+ assert decryptedValue == PASSWORD || decryptedValue ==
ANOTHER_PASSWORD
}
}
})
@@ -4118,7 +4262,7 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
// Read the uncompressed version to compare later
File originalFlowXmlFile = new
File("src/test/resources/flow_default_key.xml")
final String ORIGINAL_FLOW_XML_CONTENT = originalFlowXmlFile.text
- def originalFlowCipherTexts = ORIGINAL_FLOW_XML_CONTENT.findAll(WFXCTR)
+ def originalFlowCipherTexts =
ORIGINAL_FLOW_XML_CONTENT.findAll(WFXCTR).toSet()
final int CIPHER_TEXT_COUNT = originalFlowCipherTexts.size()
// Load both the encrypted and decrypted properties to compare later
@@ -4209,19 +4353,20 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
// Verify the flow definition
def verifyTool = new ConfigEncryptionTool()
verifyTool.isVerbose = true
- verifyTool.flowXmlPath = workingFlowXmlFile.path
- String updatedFlowXmlContent = verifyTool.loadFlowXml()
+ InputStream updatedFlowXmlContent =
verifyTool.loadFlowXml(workingFlowXmlFile.path)
// Check that the flow.xml.gz content changed
- assert updatedFlowXmlContent != ORIGINAL_FLOW_XML_CONTENT
+ // TODO assert updatedFlowXmlContent !=
ORIGINAL_FLOW_XML_CONTENT
// Verify that the cipher texts decrypt correctly
logger.info("Original flow.xml.gz cipher texts:
${originalFlowCipherTexts}")
- def flowCipherTexts = updatedFlowXmlContent.findAll(WFXCTR)
+ def flowCipherTexts =
findFieldsInStream(updatedFlowXmlContent, WFXCTR)
logger.info("Updated flow.xml.gz cipher texts:
${flowCipherTexts}")
assert flowCipherTexts.size() == CIPHER_TEXT_COUNT
- flowCipherTexts.every {
- assert ConfigEncryptionTool.decryptFlowElement(it,
newFlowPassword) == "thisIsABadPassword"
+ flowCipherTexts.each {
+ String decryptedValue =
ConfigEncryptionTool.decryptFlowElement(it, newFlowPassword)
+ logger.info("Decrypted value of migrated
${workingFlowXmlFile.path} was: ${decryptedValue}")
+ assert decryptedValue == PASSWORD || decryptedValue ==
ANOTHER_PASSWORD
}
// Update the "original" flow cipher texts for the next run to
the current values
@@ -4289,7 +4434,7 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
@Test
void testShouldDecryptFlowXmlContent() {
// Arrange
- String existingFlowPassword = "flowPassword"
+ String existingFlowPassword = "nififtw!"
final String DEFAULT_ALGORITHM = "PBEWITHMD5AND256BITAES-CBC-OPENSSL"
final String DEFAULT_PROVIDER = "BC"
@@ -4326,7 +4471,7 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
final String EXPECTED_PLAINTEXT = "thisIsABadPassword"
- final String ENCRYPTED_VALUE_FROM_FLOW =
"enc{2032416987A00D9FCD757528D7AE609D7E793CA5F956641DB53E14CDB9BFCD4037B73AC705CD3F5C1C1BDE18B8D7B281}"
+ final String ENCRYPTED_VALUE_FROM_FLOW =
"enc{5d8c45f04790e73cba72e5e3fbee1145f2e18256c3b33c283e17f5281611cb5e5f9e6cc988c5be0e8cca7b5dc8fa7cf7}"
// Act
String decryptedElement =
ConfigEncryptionTool.decryptFlowElement(ENCRYPTED_VALUE_FROM_FLOW,
existingFlowPassword, DEFAULT_ALGORITHM, DEFAULT_PROVIDER)
@@ -4339,8 +4484,8 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
@Test
void testShouldEncryptFlowXmlContent() {
// Arrange
- String flowPassword = "flowPassword"
- String sensitivePropertyValue = "thisIsABadProcessorPassword"
+ String flowPassword = "nififtw!"
+ String sensitivePropertyValue = "thisIsAnotherBadPassword"
byte[] saltBytes = "thisIsABadSalt..".bytes
StringEncryptor sanityEncryptor = new
StringEncryptor(DEFAULT_ALGORITHM, DEFAULT_PROVIDER, flowPassword)
@@ -4405,34 +4550,40 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
Files.copy(flowXmlFile.toPath(), workingFile.toPath())
ConfigEncryptionTool tool = new ConfigEncryptionTool()
tool.isVerbose = true
+ tool.flowXmlPath = workingFile.path
+ tool.outputFlowXmlPath = workingFile.path
final String SENSITIVE_VALUE = "thisIsABadPassword"
String existingFlowPassword = DEFAULT_LEGACY_SENSITIVE_PROPS_KEY
String newFlowPassword = FLOW_PASSWORD
- String xmlContent = workingFile.text
- logger.info("Read flow.xml: \n${xmlContent}")
+ InputStream xmlContent = new FileInputStream(workingFile.path)
+ logger.info("Read flow.xml as input stream.")
// There are two encrypted passwords in this flow
- int cipherTextCount = xmlContent.findAll(WFXCTR).size()
- logger.info("Found ${cipherTextCount} encrypted properties in the
original flow.xml content")
+ int cipherTextCount = findFieldsInStream(xmlContent, WFXCTR).size()
+ logger.info("Found ${cipherTextCount} unique encrypted properties in
the original flow.xml content")
// Act
- String migratedXmlContent = tool.migrateFlowXmlContent(xmlContent,
existingFlowPassword, newFlowPassword)
- logger.info("Migrated flow.xml: \n${migratedXmlContent}")
+ xmlContent = new FileInputStream(workingFile.path)
+ tool.migrateFlowXmlContent(xmlContent, existingFlowPassword,
newFlowPassword)
+ logger.info("Migrated flow.xml.")
// Assert
- def newCipherTexts = migratedXmlContent.findAll(WFXCTR)
-
- assert newCipherTexts.size() == cipherTextCount
- newCipherTexts.every {
- assert ConfigEncryptionTool.decryptFlowElement(it,
newFlowPassword) == SENSITIVE_VALUE
+ InputStream migratedFlowXmlFile = new FileInputStream(workingFile.path)
+ def migratedCipherTexts = findFieldsInStream(migratedFlowXmlFile,
WFXCTR)
+
+ assert migratedCipherTexts.size() == cipherTextCount
+ migratedCipherTexts.each {
+ String decryptedValue =
ConfigEncryptionTool.decryptFlowElement(it, newFlowPassword)
+ logger.info("Decrypted value of migrated " + workingFile.path + "
was: " + decryptedValue)
+ assert decryptedValue == PASSWORD || decryptedValue ==
ANOTHER_PASSWORD
}
// Ensure that everything else is identical
- assert migratedXmlContent.replaceAll(WFXCTR, "") ==
- xmlContent.replaceAll(WFXCTR, "")
+ assert flowXmlFile.text.replaceAll(WFXCTR, "") ==
+ workingFile.text.replaceAll(WFXCTR, "")
}
@@ -4449,6 +4600,7 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
Files.copy(flowXmlFile.toPath(), workingFile.toPath())
ConfigEncryptionTool tool = new ConfigEncryptionTool()
tool.isVerbose = true
+ tool.outputFlowXmlPath = workingFile.path
final String SENSITIVE_VALUE = "thisIsABadPassword"
@@ -4464,7 +4616,7 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
final int ORIGINAL_CIPHER_TEXT_COUNT = ORIGINAL_CIPHER_TEXTS.size()
logger.info("Found ${ORIGINAL_CIPHER_TEXT_COUNT} encrypted properties
in the original flow.xml content")
- String currentXmlContent = xmlContent
+ InputStream currentXmlContent = new
ByteArrayInputStream(xmlContent.bytes)
// Act
passwordProgression.eachWithIndex { String existingFlowPassword, int i
->
@@ -4472,24 +4624,26 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
String newFlowPassword = passwordProgression[i + 1]
logger.info("Migrating from ${existingFlowPassword} to
${newFlowPassword}")
- String migratedXmlContent =
tool.migrateFlowXmlContent(currentXmlContent, existingFlowPassword,
newFlowPassword)
+ InputStream migratedXmlContent =
tool.migrateFlowXmlContent(currentXmlContent, existingFlowPassword,
newFlowPassword)
// logger.info("Migrated flow.xml: \n${migratedXmlContent}")
// Assert
- def newCipherTexts = migratedXmlContent.findAll(WFXCTR)
+ def newCipherTexts = findFieldsInStream(migratedXmlContent,
WFXCTR)
logger.info("Cipher texts for iteration ${i}:
\n${newCipherTexts.join("\n")}")
assert newCipherTexts.size() == ORIGINAL_CIPHER_TEXT_COUNT
- newCipherTexts.every {
- assert ConfigEncryptionTool.decryptFlowElement(it,
newFlowPassword) == SENSITIVE_VALUE
+
+ newCipherTexts.each {
+ String decryptedValue =
ConfigEncryptionTool.decryptFlowElement(it, newFlowPassword)
+ assert decryptedValue == PASSWORD || decryptedValue ==
ANOTHER_PASSWORD
}
// Ensure that everything else is identical
- assert migratedXmlContent.replaceAll(WFXCTR, "") ==
- xmlContent.replaceAll(WFXCTR, "")
+ assert new File(workingFile.path).text.replaceAll(WFXCTR, "")
==
+ flowXmlFile.text.replaceAll(WFXCTR, "")
// Update the "source" XML content for the next iteration
- currentXmlContent = migratedXmlContent
+ currentXmlContent = tool.loadFlowXml(workingFile.path)
}
}
}
@@ -4507,6 +4661,7 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
Files.copy(flowXmlFile.toPath(), workingFile.toPath())
ConfigEncryptionTool tool = new ConfigEncryptionTool()
tool.isVerbose = true
+ tool.outputFlowXmlPath = workingFile.path
String existingFlowPassword = DEFAULT_LEGACY_SENSITIVE_PROPS_KEY
String newFlowPassword = FLOW_PASSWORD
@@ -4519,11 +4674,11 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
logger.info("Found ${cipherTextCount} encrypted properties in the
original flow.xml content")
// Act
- String migratedXmlContent = tool.migrateFlowXmlContent(xmlContent,
existingFlowPassword, newFlowPassword)
- logger.info("Migrated flow.xml: \n${migratedXmlContent}")
+ InputStream migratedXmlContent = tool.migrateFlowXmlContent(new
ByteArrayInputStream(xmlContent.bytes), existingFlowPassword, newFlowPassword)
+ logger.info("Migrated flow.xml.")
// Assert
- def newCipherTexts = migratedXmlContent.findAll(WFXCTR)
+ def newCipherTexts = findFieldsInStream(migratedXmlContent, WFXCTR)
assert newCipherTexts.size() == cipherTextCount
@@ -4551,17 +4706,19 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
Files.copy(flowXmlFile.toPath(), workingFile.toPath())
ConfigEncryptionTool tool = new ConfigEncryptionTool()
tool.isVerbose = true
+ tool.flowXmlPath = workingFile.path
+ tool.outputFlowXmlPath = workingFile.path
// Use the wrong existing password
String wrongExistingFlowPassword =
DEFAULT_LEGACY_SENSITIVE_PROPS_KEY.reverse()
String newFlowPassword = FLOW_PASSWORD
- String xmlContent = workingFile.text
+ InputStream xmlContent = new ByteArrayInputStream(workingFile.bytes)
// Act
def message = shouldFail(BadPaddingException) {
- String migratedXmlContent = tool.migrateFlowXmlContent(xmlContent,
wrongExistingFlowPassword, newFlowPassword)
- logger.info("Migrated flow.xml: \n${migratedXmlContent}")
+ InputStream migratedXmlContent =
tool.migrateFlowXmlContent(xmlContent, wrongExistingFlowPassword,
newFlowPassword)
+ logger.info("Migrated flow.xml.")
}
logger.expected(message)
@@ -4575,26 +4732,23 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
@Test
void
testHandleFlowXmlMigrationWithIncorrectExistingPasswordShouldProvideHelpfulErrorMessage()
{
// Arrange
-//
exit.expectSystemExitWithStatus(ExitCode.ERROR_MIGRATING_FLOW.ordinal())
systemOutRule.clearLog()
String flowXmlPath = "src/test/resources/flow.xml"
File flowXmlFile = new File(flowXmlPath)
- File tmpDir = setupTmpDir()
+ // Use the wrong existing password
+ String wrongExistingFlowPassword =
DEFAULT_LEGACY_SENSITIVE_PROPS_KEY.reverse()
+ String newFlowPassword = FLOW_PASSWORD
+
+ def nifiProperties = wrapNFP([(NiFiProperties.SENSITIVE_PROPS_KEY):
wrongExistingFlowPassword])
File workingFile = new File("target/tmp/tmp-flow.xml")
workingFile.delete()
Files.copy(flowXmlFile.toPath(), workingFile.toPath())
ConfigEncryptionTool tool = new ConfigEncryptionTool()
tool.isVerbose = true
-
- // Use the wrong existing password
- String wrongExistingFlowPassword =
DEFAULT_LEGACY_SENSITIVE_PROPS_KEY.reverse()
- String newFlowPassword = FLOW_PASSWORD
-
- tool.flowXml = workingFile.text
- def nifiProperties = wrapNFP([(NiFiProperties.SENSITIVE_PROPS_KEY):
wrongExistingFlowPassword])
+ tool.flowXmlInputStream = tool.loadFlowXml(workingFile.path)
tool.niFiProperties = nifiProperties
tool.flowPropertiesPassword = newFlowPassword
tool.handlingNiFiProperties = false
@@ -4602,23 +4756,12 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
// Act
def message = shouldFail(Exception) {
tool.handleFlowXml()
- logger.info("Migrated flow.xml: \n${tool.flowXml}")
+ logger.info("Migrated flow.xml.")
}
logger.expected(message)
-// final String standardOutput = systemOutRule.getLog()
-// List<String> lines = standardOutput.split("\n")
-// logger.info("Captured ${lines.size()} lines of log output")
-// lines.each { String l -> logger.info("\t$l") }
-
-// final String errorOutput = systemErrRule.getLog()
-// List<String> errorlines = errorOutput.split("\n")
-// logger.info("Captured ${errorlines.size()} lines of error log
output")
-// errorlines.each { String l -> logger.info("\t$l") }
-
// Assert
// TODO: Assert that this message was in the log output (neither the
STDOUT and STDERR buffers contain it, but it is printed)
-// assert message =~ "Error performing flow XML content migration
because some sensitive values could not be decrypted. Ensure that the existing
flow password \\[\\-p\\] is correct."
assert message == "Encountered an error migrating flow content"
}
@@ -4646,13 +4789,14 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
Files.copy(flowXmlGzFile.toPath(), workingGzFile.toPath())
ConfigEncryptionTool tool = new ConfigEncryptionTool()
tool.isVerbose = true
- tool.flowXmlPath = workingGzFile.path
String xmlContent = workingFile.text
logger.info("Read flow.xml: \n${xmlContent}")
// Act
- String readXmlContent = tool.loadFlowXml()
+ InputStream xmlContentStream = tool.loadFlowXml(workingGzFile.path)
+ String readXmlContent = IOUtils.toString(xmlContentStream,
StandardCharsets.UTF_8)
+
logger.info("Loaded flow.xml.gz: \n${readXmlContent}")
// Assert
@@ -4660,40 +4804,6 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
}
@Test
- void testShouldWriteFlowXmlToFile() {
- // Arrange
- String flowXmlPath = "src/test/resources/flow.xml"
- File flowXmlFile = new File(flowXmlPath)
-
- String flowXmlGzPath = "src/test/resources/flow.xml.gz"
- File flowXmlGzFile = new File(flowXmlGzPath)
-
- File tmpDir = setupTmpDir()
-
- File workingFile = new File("target/tmp/tmp-flow.xml")
- workingFile.delete()
- Files.copy(flowXmlFile.toPath(), workingFile.toPath())
- File workingGzFile = new File("target/tmp/tmp-flow.xml.gz")
- workingGzFile.delete()
- Files.copy(flowXmlGzFile.toPath(), workingGzFile.toPath())
- ConfigEncryptionTool tool = new ConfigEncryptionTool()
- tool.isVerbose = true
- tool.outputFlowXmlPath = workingGzFile.path.replaceAll("flow.xml.gz",
"output.xml.gz")
-
- String xmlContent = workingFile.text
- logger.info("Read flow.xml: \n${xmlContent}")
-
- // Act
- tool.writeFlowXmlToFile(xmlContent)
-
- // Assert
-
- // Set the input path to what was just written and rely on the
separately-tested load method to uncompress and read the contents
- tool.flowXmlPath = tool.outputFlowXmlPath
- assert tool.loadFlowXml() == xmlContent
- }
-
- @Test
void testShouldDetectActionFlags() {
// Arrange
final def HELP_AND_VERBOSE_ARGS = [["-h", "--help"], ["-v",
"--verbose"]]
@@ -5159,6 +5269,17 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
}
}
+ @Test
+ void testFindFieldsInStream() {
+ def verifyTool = new ConfigEncryptionTool()
+ verifyTool.isVerbose = true
+ verifyTool.flowXmlPath = new
File("src/test/resources/flow.xml.gz").path
+ InputStream updatedFlowXmlContent =
verifyTool.loadFlowXml(verifyTool.flowXmlPath)
+ Set<String> fieldsFound = findFieldsInStream(updatedFlowXmlContent,
WFXCTR)
+ logger.info("Found " + fieldsFound.size() + " fields in " +
verifyTool.flowXmlPath + " that matched " + WFXCTR)
+ assert(fieldsFound.size() > 0)
+ }
+
static boolean compareXMLFragments(String expectedXML, String actualXML) {
Diff diffSimilar = DiffBuilder.compare(expectedXML).withTest(actualXML)
.withNodeMatcher(new
DefaultNodeMatcher(ElementSelectors.byName))
@@ -5172,6 +5293,19 @@ class ConfigEncryptionToolTest extends GroovyTestCase {
!diffSimilar.hasDifferences()
}
+ static Set<String> findFieldsInStream(InputStream fileInputStream, String
pattern) {
+ Set<String> fieldsFound = new HashSet<String>()
+ Reader reader = new BufferedReader(new
InputStreamReader(fileInputStream))
+ String line
+ while((line = reader.readLine()) != null) {
+ def matcher = line =~ pattern
+ if(matcher.find()) {
+ fieldsFound.add(matcher.getAt(0))
+ }
+ }
+ fieldsFound
+ }
+
// TODO: Test with 128/256-bit available
}
diff --git
a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/flow.xml
b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/flow.xml
index f47a883..3e2067b 100644
--- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/flow.xml
+++ b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/flow.xml
@@ -60,7 +60,7 @@
</property>
<property>
<name>Password</name>
-
<value>enc{2032416987A00D9FCD757528D7AE609D7E793CA5F956641DB53E14CDB9BFCD4037B73AC705CD3F5C1C1BDE18B8D7B281}</value>
+
<value>enc{7468697349734142616453616c742e2e79ad38319f8069990c6ac60cad75639f9d2ab7dff1a0b8b488af2fff659cf353}</value>
</property>
<property>
<name>raw-key-hex</name>
@@ -112,7 +112,7 @@
</property>
<property>
<name>Password</name>
-
<value>enc{4B580C55B8355FE57A599B31B3B2ACA77429DBF6887C177417624026469E895F0C89FB0C9D9C64C5B2AD943035689C9C}</value>
+
<value>enc{7468697349734142616453616c742e2e63a2cd00e648c459e7e45223fefe8d38ab9ed3d71d94be57d5b0e4391980c858}</value>
</property>
<property>
<name>raw-key-hex</name>
diff --git
a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/flow.xml.gz
b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/flow.xml.gz
index 5ebf096..5cf5f8c 100644
Binary files
a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/flow.xml.gz and
b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/flow.xml.gz differ
diff --git
a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/flow_default_key.xml
b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/flow_default_key.xml
index f47a883..3e2067b 100644
---
a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/flow_default_key.xml
+++
b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/flow_default_key.xml
@@ -60,7 +60,7 @@
</property>
<property>
<name>Password</name>
-
<value>enc{2032416987A00D9FCD757528D7AE609D7E793CA5F956641DB53E14CDB9BFCD4037B73AC705CD3F5C1C1BDE18B8D7B281}</value>
+
<value>enc{7468697349734142616453616c742e2e79ad38319f8069990c6ac60cad75639f9d2ab7dff1a0b8b488af2fff659cf353}</value>
</property>
<property>
<name>raw-key-hex</name>
@@ -112,7 +112,7 @@
</property>
<property>
<name>Password</name>
-
<value>enc{4B580C55B8355FE57A599B31B3B2ACA77429DBF6887C177417624026469E895F0C89FB0C9D9C64C5B2AD943035689C9C}</value>
+
<value>enc{7468697349734142616453616c742e2e63a2cd00e648c459e7e45223fefe8d38ab9ed3d71d94be57d5b0e4391980c858}</value>
</property>
<property>
<name>raw-key-hex</name>
diff --git
a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/flow_default_key.xml.gz
b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/flow_default_key.xml.gz
index bb7c931..debbf15 100644
Binary files
a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/flow_default_key.xml.gz
and
b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/flow_default_key.xml.gz
differ