From 26c98c551e5294b0cae2c4a2a7aabeb0fb68ef45 Mon Sep 17 00:00:00 2001 From: exceptionfactory Date: Mon, 3 Feb 2025 22:30:33 -0600 Subject: [PATCH] NIFI-14228 Removed fallback Sensitive Properties Key from Commands Signed-off-by: Pierre Villard This closes #9691. --- .../command/FlowEncryptorCommand.java | 50 +++++++++++-------- .../command/FlowEncryptorCommandTest.java | 49 ++++++++++-------- .../SetSensitivePropertiesAlgorithmTest.java | 5 +- .../SetSensitivePropertiesKeyTest.java | 5 +- 4 files changed, 63 insertions(+), 46 deletions(-) diff --git a/nifi-commons/nifi-flow-encryptor/src/main/java/org/apache/nifi/flow/encryptor/command/FlowEncryptorCommand.java b/nifi-commons/nifi-flow-encryptor/src/main/java/org/apache/nifi/flow/encryptor/command/FlowEncryptorCommand.java index b5f8cd03cb8f..2aa7d9e41579 100644 --- a/nifi-commons/nifi-flow-encryptor/src/main/java/org/apache/nifi/flow/encryptor/command/FlowEncryptorCommand.java +++ b/nifi-commons/nifi-flow-encryptor/src/main/java/org/apache/nifi/flow/encryptor/command/FlowEncryptorCommand.java @@ -27,7 +27,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; -import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Properties; @@ -52,16 +51,12 @@ class FlowEncryptorCommand implements Runnable { protected static final String CONFIGURATION_FILE = "nifi.flow.configuration.file"; - private static final List CONFIGURATION_FILES = Arrays.asList(CONFIGURATION_FILE); - private static final String FLOW_PREFIX = "nifi.flow."; private static final String GZ_EXTENSION = ".gz"; private static final String DEFAULT_PROPERTIES_ALGORITHM = PropertyEncryptionMethod.NIFI_PBKDF2_AES_GCM_256.name(); - private static final String DEFAULT_PROPERTIES_KEY = "nififtw!"; - private static final String SENSITIVE_PROPERTIES_KEY = String.format("%s=", PROPS_KEY); private static final String SENSITIVE_PROPERTIES_ALGORITHM = String.format("%s=", PROPS_ALGORITHM); @@ -103,18 +98,30 @@ public void run() { private void processFlowConfigurationFiles(final Properties properties) { final String outputAlgorithm = requestedPropertiesAlgorithm == null ? getAlgorithm(properties) : requestedPropertiesAlgorithm; - final String outputKey = requestedPropertiesKey == null ? getKey(properties) : requestedPropertiesKey; + final String outputKey; + + if (requestedPropertiesKey == null) { + final String inputKey = properties.getProperty(PROPS_KEY); + if (inputKey == null || inputKey.isBlank()) { + throw new IllegalStateException("Sensitive Properties Key [%s] not specified".formatted(PROPS_KEY)); + } else { + outputKey = inputKey; + } + } else { + outputKey = requestedPropertiesKey; + } + final PropertyEncryptor outputEncryptor = getPropertyEncryptor(outputKey, outputAlgorithm); - for (final String configurationFilePropertyName : CONFIGURATION_FILES) { - final String configurationFileProperty = properties.getProperty(configurationFilePropertyName); - if (configurationFileProperty == null || configurationFileProperty.isEmpty()) { - System.out.printf("Flow Configuration Property not specified [%s]%n", configurationFileProperty); + final String configurationFileProperty = properties.getProperty(CONFIGURATION_FILE); + if (configurationFileProperty == null || configurationFileProperty.isEmpty()) { + throw new IllegalStateException("Flow Configuration Property not specified [%s]".formatted(configurationFileProperty)); + } else { + final File configurationFile = new File(configurationFileProperty); + if (configurationFile.exists()) { + processFlowConfiguration(configurationFile, properties, outputEncryptor); } else { - final File configurationFile = new File(configurationFileProperty); - if (configurationFile.exists()) { - processFlowConfiguration(configurationFile, properties, outputEncryptor); - } + throw new IllegalStateException("Flow Configuration File not found [%s]".formatted(configurationFileProperty)); } } } @@ -125,7 +132,7 @@ private void processFlowConfiguration(final File flowConfigurationFile, final Pr final Path flowOutputPath = flowOutputFile.toPath(); try (final OutputStream flowOutputStream = new GZIPOutputStream(new FileOutputStream(flowOutputFile))) { final String inputAlgorithm = getAlgorithm(properties); - final String inputPropertiesKey = getKey(properties); + final String inputPropertiesKey = getInputPropertiesKey(properties); final PropertyEncryptor inputEncryptor = getPropertyEncryptor(inputPropertiesKey, inputAlgorithm); final FlowEncryptor flowEncryptor = new JsonFlowEncryptor(); @@ -136,23 +143,22 @@ private void processFlowConfiguration(final File flowConfigurationFile, final Pr Files.move(flowOutputPath, flowConfigurationPath, StandardCopyOption.REPLACE_EXISTING); System.out.printf("Flow Configuration Processed [%s]%n", flowConfigurationPath); } catch (final IOException | RuntimeException e) { - System.err.printf("Failed to process Flow Configuration [%s]%n", flowConfigurationFile); - e.printStackTrace(); + throw new IllegalStateException("Failed to process Flow Configuration [%s]".formatted(flowConfigurationFile), e); } } private String getAlgorithm(final Properties properties) { String algorithm = properties.getProperty(PROPS_ALGORITHM, DEFAULT_PROPERTIES_ALGORITHM); - if (algorithm.length() == 0) { + if (algorithm.isEmpty()) { algorithm = DEFAULT_PROPERTIES_ALGORITHM; } return algorithm; } - private String getKey(final Properties properties) { - String key = properties.getProperty(PROPS_KEY, DEFAULT_PROPERTIES_KEY); - if (key.length() == 0) { - key = DEFAULT_PROPERTIES_KEY; + private String getInputPropertiesKey(final Properties properties) { + final String key = properties.getProperty(PROPS_KEY); + if (key == null || key.isBlank()) { + throw new IllegalStateException("Sensitive Properties Key [%s] not found".formatted(PROPS_KEY)); } return key; } diff --git a/nifi-commons/nifi-flow-encryptor/src/test/java/org/apache/nifi/flow/encryptor/command/FlowEncryptorCommandTest.java b/nifi-commons/nifi-flow-encryptor/src/test/java/org/apache/nifi/flow/encryptor/command/FlowEncryptorCommandTest.java index 1f37379bdd82..d4a3d5b50f24 100644 --- a/nifi-commons/nifi-flow-encryptor/src/test/java/org/apache/nifi/flow/encryptor/command/FlowEncryptorCommandTest.java +++ b/nifi-commons/nifi-flow-encryptor/src/test/java/org/apache/nifi/flow/encryptor/command/FlowEncryptorCommandTest.java @@ -18,6 +18,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import java.io.File; import java.io.FileNotFoundException; @@ -54,6 +55,10 @@ public class FlowEncryptorCommandTest { private static final String REQUESTED_ALGORITHM = "NIFI_PBKDF2_AES_GCM_256"; + private static final String BACKSLASH_PATTERN = "\\\\"; + + private static final String ESCAPED_BACKSLASH = "\\\\\\\\"; + @AfterEach public void clearProperties() { System.clearProperty(FlowEncryptorCommand.PROPERTIES_FILE_PATH); @@ -66,22 +71,20 @@ public void testRunSystemPropertyNotDefined() { } @Test - public void testRunPropertiesKeyBlankProperties() throws IOException, URISyntaxException { - final Path propertiesPath = getBlankNiFiProperties(); + public void testRunPropertiesKeyBlankProperties(@TempDir final Path tempDir) throws IOException, URISyntaxException { + final Path propertiesPath = getBlankNiFiProperties(tempDir); System.setProperty(FlowEncryptorCommand.PROPERTIES_FILE_PATH, propertiesPath.toString()); final FlowEncryptorCommand command = new FlowEncryptorCommand(); final String propertiesKey = UUID.randomUUID().toString(); command.setRequestedPropertiesKey(propertiesKey); - command.run(); - - assertPropertiesKeyUpdated(propertiesPath, propertiesKey); + assertThrows(IllegalStateException.class, command::run); } @Test - public void testRunPropertiesAlgorithmWithPropertiesKeyPopulatedProperties() throws IOException, URISyntaxException { - final Path propertiesPath = getPopulatedNiFiProperties(); + public void testRunPropertiesAlgorithmWithPropertiesKeyPopulatedProperties(@TempDir final Path tempDir) throws IOException, URISyntaxException { + final Path propertiesPath = getPopulatedNiFiProperties(tempDir); System.setProperty(FlowEncryptorCommand.PROPERTIES_FILE_PATH, propertiesPath.toString()); final FlowEncryptorCommand command = new FlowEncryptorCommand(); @@ -118,36 +121,42 @@ protected static void assertPropertiesKeyUpdated(final Path propertiesPath, fina assertEquals(expectedProperty, keyProperty.get(), "Sensitive Key Property not updated"); } - protected static Path getBlankNiFiProperties() throws IOException, URISyntaxException { - final Path flowConfigurationJson = getFlowConfiguration(FLOW_CONTENTS_JSON, JSON_GZ); - return getNiFiProperties(flowConfigurationJson, BLANK_PROPERTIES); + protected static Path getBlankNiFiProperties(final Path tempDir) throws IOException, URISyntaxException { + final Path flowConfigurationJson = getFlowConfiguration(); + return getNiFiProperties(flowConfigurationJson, BLANK_PROPERTIES, tempDir); } - protected static Path getPopulatedNiFiProperties() throws IOException, URISyntaxException { - final Path flowConfigurationJson = getFlowConfiguration(FLOW_CONTENTS_JSON, JSON_GZ); - return getNiFiProperties(flowConfigurationJson, POPULATED_PROPERTIES); + protected static Path getPopulatedNiFiProperties(final Path tempDir) throws IOException, URISyntaxException { + final Path flowConfigurationJson = getFlowConfiguration(); + return getNiFiProperties(flowConfigurationJson, POPULATED_PROPERTIES, tempDir); } private static Path getNiFiProperties( final Path flowConfigurationJsonPath, - String propertiesResource + final String propertiesResource, + final Path tempDir ) throws IOException, URISyntaxException { final Path sourcePropertiesPath = Paths.get(getResourceUrl(propertiesResource).toURI()); final List sourceProperties = Files.readAllLines(sourcePropertiesPath); final List flowProperties = sourceProperties.stream().map(line -> { if (line.startsWith(FlowEncryptorCommand.CONFIGURATION_FILE)) { - return flowConfigurationJsonPath == null ? line : line + flowConfigurationJsonPath; + return flowConfigurationJsonPath == null ? line : line + getPropertyFormattedPath(flowConfigurationJsonPath); } else { return line; } }).collect(Collectors.toList()); - final Path propertiesPath = Files.createTempFile(TEMP_FILE_PREFIX, PROPERTIES_EXTENSION); - propertiesPath.toFile().deleteOnExit(); + final Path propertiesPath = Files.createTempFile(tempDir, TEMP_FILE_PREFIX, PROPERTIES_EXTENSION); Files.write(propertiesPath, flowProperties); return propertiesPath; } + private static String getPropertyFormattedPath(final Path path) { + final String formattedPath = path.toString(); + // Escape backslash characters for path property value on Windows + return formattedPath.replaceAll(BACKSLASH_PATTERN, ESCAPED_BACKSLASH); + } + private static URL getResourceUrl(String resource) throws FileNotFoundException { final URL resourceUrl = FlowEncryptorCommand.class.getResource(resource); if (resourceUrl == null) { @@ -156,13 +165,13 @@ private static URL getResourceUrl(String resource) throws FileNotFoundException return resourceUrl; } - private static Path getFlowConfiguration(final String contents, final String extension) throws IOException { - final Path flowConfigurationPath = Files.createTempFile(TEMP_FILE_PREFIX, extension); + private static Path getFlowConfiguration() throws IOException { + final Path flowConfigurationPath = Files.createTempFile(TEMP_FILE_PREFIX, JSON_GZ); final File flowConfigurationFile = flowConfigurationPath.toFile(); flowConfigurationFile.deleteOnExit(); try (final GZIPOutputStream outputStream = new GZIPOutputStream(new FileOutputStream(flowConfigurationFile))) { - outputStream.write(contents.getBytes(StandardCharsets.UTF_8)); + outputStream.write(FLOW_CONTENTS_JSON.getBytes(StandardCharsets.UTF_8)); } return flowConfigurationPath; } diff --git a/nifi-commons/nifi-flow-encryptor/src/test/java/org/apache/nifi/flow/encryptor/command/SetSensitivePropertiesAlgorithmTest.java b/nifi-commons/nifi-flow-encryptor/src/test/java/org/apache/nifi/flow/encryptor/command/SetSensitivePropertiesAlgorithmTest.java index 8c2eeebf270c..aac84d1122b4 100644 --- a/nifi-commons/nifi-flow-encryptor/src/test/java/org/apache/nifi/flow/encryptor/command/SetSensitivePropertiesAlgorithmTest.java +++ b/nifi-commons/nifi-flow-encryptor/src/test/java/org/apache/nifi/flow/encryptor/command/SetSensitivePropertiesAlgorithmTest.java @@ -18,6 +18,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import java.io.IOException; import java.net.URISyntaxException; @@ -37,8 +38,8 @@ public void testMainNoArguments() { } @Test - public void testMainPopulatedKeyAndAlgorithm() throws IOException, URISyntaxException { - final Path propertiesPath = FlowEncryptorCommandTest.getPopulatedNiFiProperties(); + public void testMainPopulatedKeyAndAlgorithm(@TempDir final Path tempDir) throws IOException, URISyntaxException { + final Path propertiesPath = FlowEncryptorCommandTest.getPopulatedNiFiProperties(tempDir); System.setProperty(FlowEncryptorCommand.PROPERTIES_FILE_PATH, propertiesPath.toString()); SetSensitivePropertiesAlgorithm.main(new String[]{REQUESTED_ALGORITHM}); diff --git a/nifi-commons/nifi-flow-encryptor/src/test/java/org/apache/nifi/flow/encryptor/command/SetSensitivePropertiesKeyTest.java b/nifi-commons/nifi-flow-encryptor/src/test/java/org/apache/nifi/flow/encryptor/command/SetSensitivePropertiesKeyTest.java index c2c89a0ee1fd..21e1bc9c32ab 100644 --- a/nifi-commons/nifi-flow-encryptor/src/test/java/org/apache/nifi/flow/encryptor/command/SetSensitivePropertiesKeyTest.java +++ b/nifi-commons/nifi-flow-encryptor/src/test/java/org/apache/nifi/flow/encryptor/command/SetSensitivePropertiesKeyTest.java @@ -18,6 +18,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import java.io.IOException; import java.net.URISyntaxException; @@ -37,8 +38,8 @@ public void testMainNoArguments() { } @Test - public void testMainBlankKeyAndAlgorithm() throws IOException, URISyntaxException { - final Path propertiesPath = FlowEncryptorCommandTest.getBlankNiFiProperties(); + public void testMainPopulatedKeyAndAlgorithm(@TempDir final Path tempDir) throws IOException, URISyntaxException { + final Path propertiesPath = FlowEncryptorCommandTest.getPopulatedNiFiProperties(tempDir); System.setProperty(FlowEncryptorCommand.PROPERTIES_FILE_PATH, propertiesPath.toString()); final String sensitivePropertiesKey = UUID.randomUUID().toString();