Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NIFI-14228 Remove fallback Sensitive Properties Key from Commands #9691

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -52,16 +51,12 @@ class FlowEncryptorCommand implements Runnable {

protected static final String CONFIGURATION_FILE = "nifi.flow.configuration.file";

private static final List<String> 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);
Expand Down Expand Up @@ -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));
}
}
}
Expand All @@ -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();
Expand All @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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();
Expand Down Expand Up @@ -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<String> sourceProperties = Files.readAllLines(sourcePropertiesPath);
final List<String> 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) {
Expand All @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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();
Expand Down