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 dc11df46fc..07b1f7c2cc 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 @@ -34,6 +34,7 @@ import org.bouncycastle.crypto.generators.SCrypt import org.bouncycastle.jce.provider.BouncyCastleProvider import org.slf4j.Logger import org.slf4j.LoggerFactory +import org.xml.sax.SAXException import javax.crypto.Cipher import java.nio.charset.StandardCharsets @@ -687,19 +688,25 @@ class ConfigEncryptionTool { out.toString().split("\n") } - - private static List serializeLoginIdentityProvidersAndPreserveFormat(String xmlContent, File originalLoginIdentityProvidersFile) { - def parsedXml = new XmlSlurper().parseText(xmlContent) - def provider = parsedXml.provider.find { it.identifier == "ldap-provider" } - def serializedProvider = new XmlUtil().serialize(provider) - // Remove XML declaration from top - serializedProvider = serializedProvider.replaceFirst(XML_DECLARATION_REGEX, "") - // Find the provider element of the new XML in the file contents String fileContents = originalLoginIdentityProvidersFile.text - fileContents = fileContents.replaceFirst(LDAP_PROVIDER_REGEX, serializedProvider) - fileContents.split("\n") + try { + def parsedXml = new XmlSlurper().parseText(xmlContent) + def provider = parsedXml.provider.find { it.identifier == "ldap-provider" } + if (provider) { + def serializedProvider = new XmlUtil().serialize(provider) + // Remove XML declaration from top + serializedProvider = serializedProvider.replaceFirst(XML_DECLARATION_REGEX, "") + fileContents = fileContents.replaceFirst(LDAP_PROVIDER_REGEX, serializedProvider) + return fileContents.split("\n") + } else { + throw new SAXException("No ldap-provider element found") + } + } catch (SAXException e) { + logger.error("No provider element with identifier ldap-provider found in XML content; the file could be empty or the element may be missing or commented out") + return fileContents.split("\n") + } } /** 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 17847483fc..a018edde4e 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 @@ -2165,6 +2165,68 @@ class ConfigEncryptionToolTest extends GroovyTestCase { assert encryptedLines == lines } + @Test + void testSerializeLoginIdentityProvidersAndPreserveFormatShouldHandleCommentedFile() { + // Arrange + String loginIdentityProvidersPath = "src/test/resources/login-identity-providers-commented.xml" + File loginIdentityProvidersFile = new File(loginIdentityProvidersPath) + + File tmpDir = setupTmpDir() + + File workingFile = new File("target/tmp/tmp-login-identity-providers.xml") + workingFile.delete() + Files.copy(loginIdentityProvidersFile.toPath(), workingFile.toPath()) + ConfigEncryptionTool tool = new ConfigEncryptionTool() + tool.isVerbose = true + + tool.keyHex = KEY_HEX_128 + + def lines = workingFile.readLines() + logger.info("Read lines: \n${lines.join("\n")}") + + // If no sensitive properties are found, the original input text is just returned (comments and formatting in tact) + def encryptedLines = tool.encryptLoginIdentityProviders(lines.join("\n")).split("\n") + logger.info("Encrypted lines: \n${encryptedLines.join("\n")}") + assert encryptedLines == lines + + // Act + def serializedLines = ConfigEncryptionTool.serializeLoginIdentityProvidersAndPreserveFormat(encryptedLines.join("\n"), workingFile) + logger.info("Serialized lines: \n${serializedLines.join("\n")}") + + // Assert + assert serializedLines == encryptedLines + assert TestAppender.events.any { it =~ "No provider element with identifier ldap-provider found in XML content; the file could be empty or the element may be missing or commented out" } + } + + @Test + void testSerializeLoginIdentityProvidersAndPreserveFormatShouldHandleEmptyFile() { + // Arrange + File tmpDir = setupTmpDir() + + File workingFile = new File("target/tmp/tmp-login-identity-providers.xml") + workingFile.delete() + workingFile.createNewFile() + ConfigEncryptionTool tool = new ConfigEncryptionTool() + tool.isVerbose = true + + tool.keyHex = KEY_HEX_128 + + def lines = workingFile.readLines() + logger.info("Read lines: \n${lines.join("\n")}") + + // If no sensitive properties are found, the original input text is just returned (comments and formatting in tact) + def encryptedLines = lines + logger.info("Encrypted lines: \n${encryptedLines.join("\n")}") + + // Act + def serializedLines = ConfigEncryptionTool.serializeLoginIdentityProvidersAndPreserveFormat(encryptedLines.join("\n"), workingFile) + logger.info("Serialized lines: \n${serializedLines.join("\n")}") + + // Assert + assert serializedLines.findAll { it }.isEmpty() + assert TestAppender.events.any { it =~ "No provider element with identifier ldap-provider found in XML content; the file could be empty or the element may be missing or commented out" } + } + @Test void testShouldPerformFullOperationForLoginIdentityProviders() { // Arrange @@ -2356,7 +2418,7 @@ class ConfigEncryptionToolTest extends GroovyTestCase { // Assert // Some empty lines will be removed - def trimmedLines = lines.collect {it.trim() }.findAll { it } + def trimmedLines = lines.collect { it.trim() }.findAll { it } def trimmedSerializedLines = serializedLines.collect { it.trim() }.findAll { it } assert trimmedLines.size() == trimmedSerializedLines.size() } @@ -2445,7 +2507,7 @@ class ConfigEncryptionToolTest extends GroovyTestCase { } // Check that the comments are still there - def trimmedLines = inputLIPFile.readLines().collect {it.trim() }.findAll { it } + def trimmedLines = inputLIPFile.readLines().collect { it.trim() }.findAll { it } def trimmedSerializedLines = updatedXmlContent.split("\n").collect { it.trim() }.findAll { it } assert trimmedLines.size() == trimmedSerializedLines.size()