mirror of
https://github.com/apache/nifi.git
synced 2025-02-13 21:45:26 +00:00
NIFI-9724 Added set-sensitive-properties-algorithm command
Signed-off-by: Joe Gresock <jgresock@gmail.com> This closes #5801.
This commit is contained in:
parent
a6aba3bf8e
commit
49d1c747ca
nifi-commons/nifi-flow-encryptor/src
main/java/org/apache/nifi/flow/encryptor/command
test/java/org/apache/nifi/flow/encryptor/command
nifi-docs/src/main/asciidoc
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/bin
198
nifi-commons/nifi-flow-encryptor/src/main/java/org/apache/nifi/flow/encryptor/command/FlowEncryptorCommand.java
Normal file
198
nifi-commons/nifi-flow-encryptor/src/main/java/org/apache/nifi/flow/encryptor/command/FlowEncryptorCommand.java
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.nifi.flow.encryptor.command;
|
||||
|
||||
import org.apache.nifi.encrypt.PropertyEncryptor;
|
||||
import org.apache.nifi.encrypt.PropertyEncryptorBuilder;
|
||||
import org.apache.nifi.flow.encryptor.FlowEncryptor;
|
||||
import org.apache.nifi.flow.encryptor.StandardFlowEncryptor;
|
||||
import org.apache.nifi.security.util.EncryptionMethod;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
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;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
/**
|
||||
* Flow Encryptor Command capable of updating Sensitive Properties Key or Algorithm as well as Flow Configuration
|
||||
*/
|
||||
class FlowEncryptorCommand implements Runnable {
|
||||
protected static final String PROPERTIES_FILE_PATH = "nifi.properties.file.path";
|
||||
|
||||
protected static final String PROPS_KEY = "nifi.sensitive.props.key";
|
||||
|
||||
protected static final String PROPS_ALGORITHM = "nifi.sensitive.props.algorithm";
|
||||
|
||||
protected static final String CONFIGURATION_FILE = "nifi.flow.configuration.file";
|
||||
|
||||
protected static final String CONFIGURATION_JSON_FILE = "nifi.flow.configuration.json.file";
|
||||
|
||||
private static final List<String> CONFIGURATION_FILES = Arrays.asList(CONFIGURATION_FILE, CONFIGURATION_JSON_FILE);
|
||||
|
||||
private static final String FLOW_PREFIX = "nifi.flow.";
|
||||
|
||||
private static final String GZ_EXTENSION = ".gz";
|
||||
|
||||
private static final String DEFAULT_PROPERTIES_ALGORITHM = EncryptionMethod.MD5_256AES.getAlgorithm();
|
||||
|
||||
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);
|
||||
|
||||
private String requestedPropertiesKey;
|
||||
|
||||
private String requestedPropertiesAlgorithm;
|
||||
|
||||
void setRequestedPropertiesKey(final String requestedPropertiesKey) {
|
||||
this.requestedPropertiesKey = Objects.requireNonNull(requestedPropertiesKey, "Key required");
|
||||
}
|
||||
|
||||
void setRequestedPropertiesAlgorithm(final String requestedPropertiesAlgorithm) {
|
||||
this.requestedPropertiesAlgorithm = Objects.requireNonNull(requestedPropertiesAlgorithm, "Algorithm required");
|
||||
}
|
||||
|
||||
/**
|
||||
* Run command using nifi.properties location read from System Properties
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
final String propertiesFilePath = System.getProperty(PROPERTIES_FILE_PATH);
|
||||
if (propertiesFilePath == null) {
|
||||
throw new IllegalStateException(String.format("System property not defined [%s]", PROPERTIES_FILE_PATH));
|
||||
}
|
||||
final File propertiesFile = new File(propertiesFilePath);
|
||||
final Properties properties = loadProperties(propertiesFile);
|
||||
|
||||
processFlowConfigurationFiles(properties);
|
||||
|
||||
try {
|
||||
storeProperties(propertiesFile);
|
||||
System.out.printf("NiFi Properties Processed [%s]%n", propertiesFilePath);
|
||||
} catch (final IOException e) {
|
||||
final String message = String.format("Failed to Process NiFi Properties [%s]", propertiesFilePath);
|
||||
throw new UncheckedIOException(message, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void processFlowConfigurationFiles(final Properties properties) {
|
||||
final String outputAlgorithm = requestedPropertiesAlgorithm == null ? getAlgorithm(properties) : requestedPropertiesAlgorithm;
|
||||
final String outputKey = requestedPropertiesKey == null ? getKey(properties) : 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);
|
||||
} else {
|
||||
final File configurationFile = new File(configurationFileProperty);
|
||||
if (configurationFile.exists()) {
|
||||
processFlowConfiguration(configurationFile, properties, outputEncryptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processFlowConfiguration(final File flowConfigurationFile, final Properties properties, final PropertyEncryptor outputEncryptor) {
|
||||
try (final InputStream flowInputStream = new GZIPInputStream(new FileInputStream(flowConfigurationFile))) {
|
||||
final File flowOutputFile = getFlowOutputFile();
|
||||
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 PropertyEncryptor inputEncryptor = getPropertyEncryptor(inputPropertiesKey, inputAlgorithm);
|
||||
|
||||
final FlowEncryptor flowEncryptor = new StandardFlowEncryptor();
|
||||
flowEncryptor.processFlow(flowInputStream, flowOutputStream, inputEncryptor, outputEncryptor);
|
||||
}
|
||||
|
||||
final Path flowConfigurationPath = flowConfigurationFile.toPath();
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
private String getAlgorithm(final Properties properties) {
|
||||
String algorithm = properties.getProperty(PROPS_ALGORITHM, DEFAULT_PROPERTIES_ALGORITHM);
|
||||
if (algorithm.length() == 0) {
|
||||
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;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
private File getFlowOutputFile() throws IOException {
|
||||
final File flowOutputFile = File.createTempFile(FLOW_PREFIX, GZ_EXTENSION);
|
||||
flowOutputFile.deleteOnExit();
|
||||
return flowOutputFile;
|
||||
}
|
||||
|
||||
private Properties loadProperties(final File propertiesFile) {
|
||||
final Properties properties = new Properties();
|
||||
try (final FileReader reader = new FileReader(propertiesFile)) {
|
||||
properties.load(reader);
|
||||
} catch (final IOException e) {
|
||||
final String message = String.format("Failed to read NiFi Properties [%s]", propertiesFile);
|
||||
throw new UncheckedIOException(message, e);
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
private void storeProperties(final File propertiesFile) throws IOException {
|
||||
final Path propertiesFilePath = propertiesFile.toPath();
|
||||
final List<String> lines = Files.readAllLines(propertiesFilePath);
|
||||
final List<String> updatedLines = lines.stream().map(line -> {
|
||||
if (line.startsWith(SENSITIVE_PROPERTIES_KEY)) {
|
||||
return requestedPropertiesKey == null ? line : SENSITIVE_PROPERTIES_KEY + requestedPropertiesKey;
|
||||
} else if (line.startsWith(SENSITIVE_PROPERTIES_ALGORITHM)) {
|
||||
return requestedPropertiesAlgorithm == null ? line : SENSITIVE_PROPERTIES_ALGORITHM + requestedPropertiesAlgorithm;
|
||||
} else {
|
||||
return line;
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
Files.write(propertiesFilePath, updatedLines);
|
||||
}
|
||||
|
||||
private PropertyEncryptor getPropertyEncryptor(final String propertiesKey, final String propertiesAlgorithm) {
|
||||
return new PropertyEncryptorBuilder(propertiesKey).setAlgorithm(propertiesAlgorithm).build();
|
||||
}
|
||||
}
|
35
nifi-commons/nifi-flow-encryptor/src/main/java/org/apache/nifi/flow/encryptor/command/SetSensitivePropertiesAlgorithm.java
Normal file
35
nifi-commons/nifi-flow-encryptor/src/main/java/org/apache/nifi/flow/encryptor/command/SetSensitivePropertiesAlgorithm.java
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.nifi.flow.encryptor.command;
|
||||
|
||||
/**
|
||||
* Set Sensitive Properties Algorithm for NiFi Properties and update encrypted Flow Configuration
|
||||
*/
|
||||
public class SetSensitivePropertiesAlgorithm {
|
||||
|
||||
public static void main(final String[] arguments) {
|
||||
if (arguments.length == 1) {
|
||||
final String algorithm = arguments[0];
|
||||
final FlowEncryptorCommand command = new FlowEncryptorCommand();
|
||||
command.setRequestedPropertiesAlgorithm(algorithm);
|
||||
command.run();
|
||||
} else {
|
||||
System.err.printf("Unexpected number of arguments [%d]%n", arguments.length);
|
||||
System.err.printf("Usage: %s <algorithm>%n", SetSensitivePropertiesAlgorithm.class.getSimpleName());
|
||||
}
|
||||
}
|
||||
}
|
@ -16,174 +16,25 @@
|
||||
*/
|
||||
package org.apache.nifi.flow.encryptor.command;
|
||||
|
||||
import org.apache.nifi.encrypt.PropertyEncryptor;
|
||||
import org.apache.nifi.encrypt.PropertyEncryptorBuilder;
|
||||
import org.apache.nifi.flow.encryptor.FlowEncryptor;
|
||||
import org.apache.nifi.flow.encryptor.StandardFlowEncryptor;
|
||||
import org.apache.nifi.security.util.EncryptionMethod;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
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.Properties;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
/**
|
||||
* Set Sensitive Properties Key for NiFi Properties and update encrypted Flow Configuration
|
||||
*/
|
||||
public class SetSensitivePropertiesKey {
|
||||
protected static final String PROPERTIES_FILE_PATH = "nifi.properties.file.path";
|
||||
|
||||
protected static final String PROPS_KEY = "nifi.sensitive.props.key";
|
||||
|
||||
protected static final String PROPS_ALGORITHM = "nifi.sensitive.props.algorithm";
|
||||
|
||||
protected static final String CONFIGURATION_FILE = "nifi.flow.configuration.file";
|
||||
|
||||
protected static final String CONFIGURATION_JSON_FILE = "nifi.flow.configuration.json.file";
|
||||
|
||||
private static final List<String> CONFIGURATION_FILES = Arrays.asList(CONFIGURATION_FILE, CONFIGURATION_JSON_FILE);
|
||||
|
||||
private static final int MINIMUM_REQUIRED_LENGTH = 12;
|
||||
|
||||
private static final String FLOW_PREFIX = "nifi.flow.";
|
||||
|
||||
private static final String GZ_EXTENSION = ".gz";
|
||||
|
||||
private static final String DEFAULT_PROPERTIES_ALGORITHM = EncryptionMethod.MD5_256AES.getAlgorithm();
|
||||
|
||||
private static final String DEFAULT_PROPERTIES_KEY = "nififtw!";
|
||||
|
||||
private static final String SENSITIVE_PROPERTIES_KEY = String.format("%s=", PROPS_KEY);
|
||||
|
||||
public static void main(final String[] arguments) {
|
||||
if (arguments.length == 1) {
|
||||
final String outputPropertiesKey = arguments[0];
|
||||
if (outputPropertiesKey.length() < MINIMUM_REQUIRED_LENGTH) {
|
||||
System.err.printf("Sensitive Properties Key length less than required [%d]%n", MINIMUM_REQUIRED_LENGTH);
|
||||
} else {
|
||||
run(outputPropertiesKey);
|
||||
final FlowEncryptorCommand command = new FlowEncryptorCommand();
|
||||
command.setRequestedPropertiesKey(outputPropertiesKey);
|
||||
command.run();
|
||||
}
|
||||
} else {
|
||||
System.err.printf("Unexpected number of arguments [%d]%n", arguments.length);
|
||||
System.err.printf("Usage: %s <sensitivePropertiesKey>%n", SetSensitivePropertiesKey.class.getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
private static void run(final String outputPropertiesKey) {
|
||||
final String propertiesFilePath = System.getProperty(PROPERTIES_FILE_PATH);
|
||||
final File propertiesFile = new File(propertiesFilePath);
|
||||
final Properties properties = loadProperties(propertiesFile);
|
||||
|
||||
try {
|
||||
storeProperties(propertiesFile, outputPropertiesKey);
|
||||
System.out.printf("NiFi Properties Processed [%s]%n", propertiesFilePath);
|
||||
} catch (final IOException e) {
|
||||
final String message = String.format("Failed to Process NiFi Properties [%s]", propertiesFilePath);
|
||||
throw new UncheckedIOException(message, e);
|
||||
}
|
||||
|
||||
processFlowConfigurationFiles(properties, outputPropertiesKey);
|
||||
}
|
||||
|
||||
private static void processFlowConfigurationFiles(final Properties properties, final String outputPropertiesKey) {
|
||||
final String algorithm = getAlgorithm(properties);
|
||||
final PropertyEncryptor outputEncryptor = getPropertyEncryptor(outputPropertiesKey, algorithm);
|
||||
|
||||
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);
|
||||
} else {
|
||||
final File configurationFile = new File(configurationFileProperty);
|
||||
if (configurationFile.exists()) {
|
||||
processFlowConfiguration(configurationFile, properties, outputEncryptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void processFlowConfiguration(final File flowConfigurationFile, final Properties properties, final PropertyEncryptor outputEncryptor) {
|
||||
try (final InputStream flowInputStream = new GZIPInputStream(new FileInputStream(flowConfigurationFile))) {
|
||||
final File flowOutputFile = getFlowOutputFile();
|
||||
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 PropertyEncryptor inputEncryptor = getPropertyEncryptor(inputPropertiesKey, inputAlgorithm);
|
||||
|
||||
final FlowEncryptor flowEncryptor = new StandardFlowEncryptor();
|
||||
flowEncryptor.processFlow(flowInputStream, flowOutputStream, inputEncryptor, outputEncryptor);
|
||||
}
|
||||
|
||||
final Path flowConfigurationPath = flowConfigurationFile.toPath();
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
private static String getAlgorithm(final Properties properties) {
|
||||
String algorithm = properties.getProperty(PROPS_ALGORITHM, DEFAULT_PROPERTIES_ALGORITHM);
|
||||
if (algorithm.length() == 0) {
|
||||
algorithm = DEFAULT_PROPERTIES_ALGORITHM;
|
||||
}
|
||||
return algorithm;
|
||||
}
|
||||
|
||||
private static String getKey(final Properties properties) {
|
||||
String key = properties.getProperty(PROPS_KEY, DEFAULT_PROPERTIES_KEY);
|
||||
if (key.length() == 0) {
|
||||
key = DEFAULT_PROPERTIES_KEY;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
private static File getFlowOutputFile() throws IOException {
|
||||
final File flowOutputFile = File.createTempFile(FLOW_PREFIX, GZ_EXTENSION);
|
||||
flowOutputFile.deleteOnExit();
|
||||
return flowOutputFile;
|
||||
}
|
||||
|
||||
private static Properties loadProperties(final File propertiesFile) {
|
||||
final Properties properties = new Properties();
|
||||
try (final FileReader reader = new FileReader(propertiesFile)) {
|
||||
properties.load(reader);
|
||||
} catch (final IOException e) {
|
||||
final String message = String.format("Failed to read NiFi Properties [%s]", propertiesFile);
|
||||
throw new UncheckedIOException(message, e);
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
private static void storeProperties(final File propertiesFile, final String propertiesKey) throws IOException {
|
||||
final Path propertiesFilePath = propertiesFile.toPath();
|
||||
final List<String> lines = Files.readAllLines(propertiesFilePath);
|
||||
final List<String> updatedLines = lines.stream().map(line -> {
|
||||
if (line.startsWith(SENSITIVE_PROPERTIES_KEY)) {
|
||||
return SENSITIVE_PROPERTIES_KEY + propertiesKey;
|
||||
} else {
|
||||
return line;
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
Files.write(propertiesFilePath, updatedLines);
|
||||
}
|
||||
|
||||
private static PropertyEncryptor getPropertyEncryptor(final String propertiesKey, final String propertiesAlgorithm) {
|
||||
return new PropertyEncryptorBuilder(propertiesKey).setAlgorithm(propertiesAlgorithm).build();
|
||||
}
|
||||
}
|
||||
|
199
nifi-commons/nifi-flow-encryptor/src/test/java/org/apache/nifi/flow/encryptor/command/FlowEncryptorCommandTest.java
Normal file
199
nifi-commons/nifi-flow-encryptor/src/test/java/org/apache/nifi/flow/encryptor/command/FlowEncryptorCommandTest.java
Normal file
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.nifi.flow.encryptor.command;
|
||||
|
||||
import org.apache.nifi.stream.io.GZIPOutputStream;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class FlowEncryptorCommandTest {
|
||||
private static final String TEMP_FILE_PREFIX = SetSensitivePropertiesKeyTest.class.getSimpleName();
|
||||
|
||||
private static final String FLOW_CONTENTS_JSON = "{\"property\":\"value\"}";
|
||||
|
||||
private static final String FLOW_CONTENTS_XML = "<property><value>PROPERTY</value></property>";
|
||||
|
||||
private static final String JSON_GZ = ".json.gz";
|
||||
|
||||
private static final String XML_GZ = ".xml.gz";
|
||||
|
||||
private static final String PROPERTIES_EXTENSION = ".properties";
|
||||
|
||||
private static final String BLANK_PROPERTIES = "/blank.nifi.properties";
|
||||
|
||||
private static final String POPULATED_PROPERTIES = "/populated.nifi.properties";
|
||||
|
||||
private static final String LEGACY_BLANK_PROPERTIES = "/legacy-blank.nifi.properties";
|
||||
|
||||
private static final String REQUESTED_ALGORITHM = "NIFI_PBKDF2_AES_GCM_256";
|
||||
|
||||
@AfterEach
|
||||
public void clearProperties() {
|
||||
System.clearProperty(FlowEncryptorCommand.PROPERTIES_FILE_PATH);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRunSystemPropertyNotDefined() {
|
||||
final FlowEncryptorCommand command = new FlowEncryptorCommand();
|
||||
assertThrows(IllegalStateException.class, command::run);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRunPropertiesKeyBlankProperties() throws IOException, URISyntaxException {
|
||||
final Path propertiesPath = getBlankNiFiProperties();
|
||||
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);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRunPropertiesKeyLegacyPropertiesWithoutFlowJson() throws IOException, URISyntaxException {
|
||||
final Path propertiesPath = getLegacyNiFiPropertiesWithoutFlowJson();
|
||||
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);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRunPropertiesAlgorithmWithPropertiesKeyPopulatedProperties() throws IOException, URISyntaxException {
|
||||
final Path propertiesPath = getPopulatedNiFiProperties();
|
||||
System.setProperty(FlowEncryptorCommand.PROPERTIES_FILE_PATH, propertiesPath.toString());
|
||||
|
||||
final FlowEncryptorCommand command = new FlowEncryptorCommand();
|
||||
|
||||
final String propertiesKey = UUID.randomUUID().toString();
|
||||
|
||||
command.setRequestedPropertiesAlgorithm(REQUESTED_ALGORITHM);
|
||||
command.setRequestedPropertiesKey(propertiesKey);
|
||||
command.run();
|
||||
|
||||
assertPropertiesKeyUpdated(propertiesPath, propertiesKey);
|
||||
assertPropertiesAlgorithmUpdated(propertiesPath, REQUESTED_ALGORITHM);
|
||||
}
|
||||
|
||||
protected static void assertPropertiesAlgorithmUpdated(final Path propertiesPath, final String sensitivePropertiesAlgorithm) throws IOException {
|
||||
final Optional<String> keyProperty = Files.readAllLines(propertiesPath)
|
||||
.stream()
|
||||
.filter(line -> line.startsWith(FlowEncryptorCommand.PROPS_ALGORITHM))
|
||||
.findFirst();
|
||||
assertTrue(keyProperty.isPresent(), "Sensitive Algorithm Property not found");
|
||||
|
||||
final String expectedProperty = String.format("%s=%s", FlowEncryptorCommand.PROPS_ALGORITHM, sensitivePropertiesAlgorithm);
|
||||
assertEquals(expectedProperty, keyProperty.get(), "Sensitive Algorithm Property not updated");
|
||||
}
|
||||
|
||||
protected static void assertPropertiesKeyUpdated(final Path propertiesPath, final String sensitivePropertiesKey) throws IOException {
|
||||
final Optional<String> keyProperty = Files.readAllLines(propertiesPath)
|
||||
.stream()
|
||||
.filter(line -> line.startsWith(FlowEncryptorCommand.PROPS_KEY))
|
||||
.findFirst();
|
||||
assertTrue(keyProperty.isPresent(), "Sensitive Key Property not found");
|
||||
|
||||
final String expectedProperty = String.format("%s=%s", FlowEncryptorCommand.PROPS_KEY, sensitivePropertiesKey);
|
||||
assertEquals(expectedProperty, keyProperty.get(), "Sensitive Key Property not updated");
|
||||
}
|
||||
|
||||
protected static Path getBlankNiFiProperties() throws IOException, URISyntaxException {
|
||||
final Path flowConfiguration = getFlowConfiguration(FLOW_CONTENTS_XML, XML_GZ);
|
||||
final Path flowConfigurationJson = getFlowConfiguration(FLOW_CONTENTS_JSON, JSON_GZ);
|
||||
return getNiFiProperties(flowConfiguration, flowConfigurationJson, BLANK_PROPERTIES);
|
||||
}
|
||||
|
||||
protected static Path getPopulatedNiFiProperties() throws IOException, URISyntaxException {
|
||||
final Path flowConfiguration = getFlowConfiguration(FLOW_CONTENTS_XML, XML_GZ);
|
||||
final Path flowConfigurationJson = getFlowConfiguration(FLOW_CONTENTS_JSON, JSON_GZ);
|
||||
return getNiFiProperties(flowConfiguration, flowConfigurationJson, POPULATED_PROPERTIES);
|
||||
}
|
||||
|
||||
protected static Path getLegacyNiFiPropertiesWithoutFlowJson() throws IOException, URISyntaxException {
|
||||
final Path flowConfiguration = getFlowConfiguration(FLOW_CONTENTS_XML, XML_GZ);
|
||||
return getNiFiProperties(flowConfiguration, null, LEGACY_BLANK_PROPERTIES);
|
||||
}
|
||||
|
||||
private static Path getNiFiProperties(
|
||||
final Path flowConfigurationPath,
|
||||
final Path flowConfigurationJsonPath,
|
||||
String propertiesResource
|
||||
) 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 line + flowConfigurationPath;
|
||||
} else if (line.startsWith(FlowEncryptorCommand.CONFIGURATION_JSON_FILE)) {
|
||||
return flowConfigurationJsonPath == null ? line : line + flowConfigurationJsonPath;
|
||||
} else {
|
||||
return line;
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
final Path propertiesPath = Files.createTempFile(TEMP_FILE_PREFIX, PROPERTIES_EXTENSION);
|
||||
propertiesPath.toFile().deleteOnExit();
|
||||
Files.write(propertiesPath, flowProperties);
|
||||
return propertiesPath;
|
||||
}
|
||||
|
||||
private static URL getResourceUrl(String resource) throws FileNotFoundException {
|
||||
final URL resourceUrl = FlowEncryptorCommand.class.getResource(resource);
|
||||
if (resourceUrl == null) {
|
||||
throw new FileNotFoundException(String.format("Resource [%s] not found", resource));
|
||||
}
|
||||
return resourceUrl;
|
||||
}
|
||||
|
||||
private static Path getFlowConfiguration(final String contents, final String extension) throws IOException {
|
||||
final Path flowConfigurationPath = Files.createTempFile(TEMP_FILE_PREFIX, extension);
|
||||
final File flowConfigurationFile = flowConfigurationPath.toFile();
|
||||
flowConfigurationFile.deleteOnExit();
|
||||
|
||||
try (final GZIPOutputStream outputStream = new GZIPOutputStream(new FileOutputStream(flowConfigurationFile))) {
|
||||
outputStream.write(contents.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
return flowConfigurationPath;
|
||||
}
|
||||
}
|
48
nifi-commons/nifi-flow-encryptor/src/test/java/org/apache/nifi/flow/encryptor/command/SetSensitivePropertiesAlgorithmTest.java
Normal file
48
nifi-commons/nifi-flow-encryptor/src/test/java/org/apache/nifi/flow/encryptor/command/SetSensitivePropertiesAlgorithmTest.java
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.nifi.flow.encryptor.command;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class SetSensitivePropertiesAlgorithmTest {
|
||||
private static final String REQUESTED_ALGORITHM = "NIFI_PBKDF2_AES_GCM_256";
|
||||
|
||||
@AfterEach
|
||||
public void clearProperties() {
|
||||
System.clearProperty(FlowEncryptorCommand.PROPERTIES_FILE_PATH);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMainNoArguments() {
|
||||
SetSensitivePropertiesAlgorithm.main(new String[]{});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMainPopulatedKeyAndAlgorithm() throws IOException, URISyntaxException {
|
||||
final Path propertiesPath = FlowEncryptorCommandTest.getPopulatedNiFiProperties();
|
||||
System.setProperty(FlowEncryptorCommand.PROPERTIES_FILE_PATH, propertiesPath.toString());
|
||||
|
||||
SetSensitivePropertiesAlgorithm.main(new String[]{REQUESTED_ALGORITHM});
|
||||
|
||||
FlowEncryptorCommandTest.assertPropertiesAlgorithmUpdated(propertiesPath, REQUESTED_ALGORITHM);
|
||||
}
|
||||
}
|
@ -16,50 +16,19 @@
|
||||
*/
|
||||
package org.apache.nifi.flow.encryptor.command;
|
||||
|
||||
import org.apache.nifi.stream.io.GZIPOutputStream;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class SetSensitivePropertiesKeyTest {
|
||||
private static final String TEMP_FILE_PREFIX = SetSensitivePropertiesKeyTest.class.getSimpleName();
|
||||
|
||||
private static final String FLOW_CONTENTS_JSON = "{\"property\":\"value\"}";
|
||||
|
||||
private static final String FLOW_CONTENTS_XML = "<property><value>PROPERTY</value></property>";
|
||||
|
||||
private static final String JSON_GZ = ".json.gz";
|
||||
|
||||
private static final String XML_GZ = ".xml.gz";
|
||||
|
||||
private static final String PROPERTIES_EXTENSION = ".properties";
|
||||
|
||||
private static final String BLANK_PROPERTIES = "/blank.nifi.properties";
|
||||
|
||||
private static final String POPULATED_PROPERTIES = "/populated.nifi.properties";
|
||||
|
||||
private static final String LEGACY_BLANK_PROPERTIES = "/legacy-blank.nifi.properties";
|
||||
|
||||
@AfterEach
|
||||
public void clearProperties() {
|
||||
System.clearProperty(SetSensitivePropertiesKey.PROPERTIES_FILE_PATH);
|
||||
System.clearProperty(FlowEncryptorCommand.PROPERTIES_FILE_PATH);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -69,95 +38,12 @@ public class SetSensitivePropertiesKeyTest {
|
||||
|
||||
@Test
|
||||
public void testMainBlankKeyAndAlgorithm() throws IOException, URISyntaxException {
|
||||
final Path flowConfiguration = getFlowConfiguration(FLOW_CONTENTS_XML, XML_GZ);
|
||||
final Path flowConfigurationJson = getFlowConfiguration(FLOW_CONTENTS_JSON, JSON_GZ);
|
||||
final Path propertiesPath = getNiFiProperties(flowConfiguration, flowConfigurationJson, BLANK_PROPERTIES);
|
||||
|
||||
System.setProperty(SetSensitivePropertiesKey.PROPERTIES_FILE_PATH, propertiesPath.toString());
|
||||
final Path propertiesPath = FlowEncryptorCommandTest.getBlankNiFiProperties();
|
||||
System.setProperty(FlowEncryptorCommand.PROPERTIES_FILE_PATH, propertiesPath.toString());
|
||||
|
||||
final String sensitivePropertiesKey = UUID.randomUUID().toString();
|
||||
SetSensitivePropertiesKey.main(new String[]{sensitivePropertiesKey});
|
||||
|
||||
assertPropertiesKeyUpdated(propertiesPath, sensitivePropertiesKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMainPopulatedKeyAndAlgorithm() throws IOException, URISyntaxException {
|
||||
final Path flowConfiguration = getFlowConfiguration(FLOW_CONTENTS_XML, XML_GZ);
|
||||
final Path flowConfigurationJson = getFlowConfiguration(FLOW_CONTENTS_JSON, JSON_GZ);
|
||||
final Path propertiesPath = getNiFiProperties(flowConfiguration, flowConfigurationJson, POPULATED_PROPERTIES);
|
||||
|
||||
System.setProperty(SetSensitivePropertiesKey.PROPERTIES_FILE_PATH, propertiesPath.toString());
|
||||
|
||||
final String sensitivePropertiesKey = UUID.randomUUID().toString();
|
||||
SetSensitivePropertiesKey.main(new String[]{sensitivePropertiesKey});
|
||||
|
||||
assertPropertiesKeyUpdated(propertiesPath, sensitivePropertiesKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMainLegacyBlankKeyAndAlgorithm() throws IOException, URISyntaxException {
|
||||
final Path flowConfiguration = getFlowConfiguration(FLOW_CONTENTS_XML, XML_GZ);
|
||||
final Path propertiesPath = getNiFiProperties(flowConfiguration, null, LEGACY_BLANK_PROPERTIES);
|
||||
|
||||
System.setProperty(SetSensitivePropertiesKey.PROPERTIES_FILE_PATH, propertiesPath.toString());
|
||||
|
||||
final String sensitivePropertiesKey = UUID.randomUUID().toString();
|
||||
SetSensitivePropertiesKey.main(new String[]{sensitivePropertiesKey});
|
||||
|
||||
assertPropertiesKeyUpdated(propertiesPath, sensitivePropertiesKey);
|
||||
}
|
||||
|
||||
private void assertPropertiesKeyUpdated(final Path propertiesPath, final String sensitivePropertiesKey) throws IOException {
|
||||
final Optional<String> keyProperty = Files.readAllLines(propertiesPath)
|
||||
.stream()
|
||||
.filter(line -> line.startsWith(SetSensitivePropertiesKey.PROPS_KEY))
|
||||
.findFirst();
|
||||
assertTrue(keyProperty.isPresent(), "Sensitive Key Property not found");
|
||||
|
||||
final String expectedProperty = String.format("%s=%s", SetSensitivePropertiesKey.PROPS_KEY, sensitivePropertiesKey);
|
||||
assertEquals(expectedProperty, keyProperty.get(), "Sensitive Key Property not updated");
|
||||
}
|
||||
|
||||
private Path getNiFiProperties(
|
||||
final Path flowConfigurationPath,
|
||||
final Path flowConfigurationJsonPath,
|
||||
String propertiesResource
|
||||
) 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(SetSensitivePropertiesKey.CONFIGURATION_FILE)) {
|
||||
return line + flowConfigurationPath;
|
||||
} else if (line.startsWith(SetSensitivePropertiesKey.CONFIGURATION_JSON_FILE)) {
|
||||
return flowConfigurationJsonPath == null ? line : line + flowConfigurationJsonPath;
|
||||
} else {
|
||||
return line;
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
final Path propertiesPath = Files.createTempFile(TEMP_FILE_PREFIX, PROPERTIES_EXTENSION);
|
||||
propertiesPath.toFile().deleteOnExit();
|
||||
Files.write(propertiesPath, flowProperties);
|
||||
return propertiesPath;
|
||||
}
|
||||
|
||||
private Path getFlowConfiguration(final String contents, final String extension) throws IOException {
|
||||
final Path flowConfigurationPath = Files.createTempFile(TEMP_FILE_PREFIX, extension);
|
||||
final File flowConfigurationFile = flowConfigurationPath.toFile();
|
||||
flowConfigurationFile.deleteOnExit();
|
||||
|
||||
try (final GZIPOutputStream outputStream = new GZIPOutputStream(new FileOutputStream(flowConfigurationFile))) {
|
||||
outputStream.write(contents.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
return flowConfigurationPath;
|
||||
}
|
||||
|
||||
private URL getResourceUrl(String resource) throws FileNotFoundException {
|
||||
final URL resourceUrl = SetSensitivePropertiesKey.class.getResource(resource);
|
||||
if (resourceUrl == null) {
|
||||
throw new FileNotFoundException(String.format("Resource [%s] not found", resource));
|
||||
}
|
||||
return resourceUrl;
|
||||
FlowEncryptorCommandTest.assertPropertiesKeyUpdated(propertiesPath, sensitivePropertiesKey);
|
||||
}
|
||||
}
|
||||
|
@ -1757,6 +1757,8 @@ These algorithms use a strong Key Derivation Function to derive a secret key of
|
||||
Each Key Derivation Function uses a static salt in order to support flow configuration comparison across cluster nodes.
|
||||
Each Key Derivation Function also uses default iteration and cost parameters as defined in the associated secure hashing implementation class.
|
||||
|
||||
[[property-encryption-algorithms]]
|
||||
=== Property Encryption Algorithms
|
||||
The following strong encryption methods can be configured in the `nifi.sensitive.props.algorithm` property:
|
||||
|
||||
* `NIFI_ARGON2_AES_GCM_128`
|
||||
@ -4332,6 +4334,23 @@ where:
|
||||
|
||||
For more information see the <<toolkit-guide.adoc#encrypt_config_tool,Encrypt-Config Tool>> section in the NiFi Toolkit Guide.
|
||||
|
||||
==== Updating the Sensitive Properties Algorithm
|
||||
|
||||
The following command can be used to read an existing flow configuration and set a new sensitive properties algorithm in _nifi.properties_:
|
||||
|
||||
```
|
||||
$ ./bin/nifi.sh set-sensitive-properties-algorithm <algorithm>
|
||||
```
|
||||
|
||||
The command reads the following flow configuration file properties from _nifi.properties_:
|
||||
|
||||
- `nifi.flow.configuration.file`
|
||||
- `nifi.flow.configuration.json.file`
|
||||
|
||||
The command checks for the existence of each file and updates the sensitive property values found.
|
||||
|
||||
See <<property-encryption-algorithms>> for supported values.
|
||||
|
||||
==== Updating the Sensitive Properties Key
|
||||
|
||||
Starting with version 1.14.0, NiFi requires a value for `nifi.sensitive.props.key` in _nifi.properties_.
|
||||
|
14
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/bin/nifi.sh
14
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/bin/nifi.sh
@ -344,6 +344,16 @@ run() {
|
||||
run_nifi_cmd="exec ${run_nifi_cmd}"
|
||||
fi
|
||||
|
||||
if [ "$1" = "set-sensitive-properties-algorithm" ]; then
|
||||
run_command="'${JAVA}' -cp '${BOOTSTRAP_CLASSPATH}' '-Dnifi.properties.file.path=${NIFI_HOME}/conf/nifi.properties' 'org.apache.nifi.flow.encryptor.command.SetSensitivePropertiesAlgorithm'"
|
||||
eval "cd ${NIFI_HOME}"
|
||||
shift
|
||||
eval "${run_command}" '"$@"'
|
||||
EXIT_STATUS=$?
|
||||
echo
|
||||
return;
|
||||
fi
|
||||
|
||||
if [ "$1" = "set-sensitive-properties-key" ]; then
|
||||
run_command="'${JAVA}' -cp '${BOOTSTRAP_CLASSPATH}' '-Dnifi.properties.file.path=${NIFI_HOME}/conf/nifi.properties' 'org.apache.nifi.flow.encryptor.command.SetSensitivePropertiesKey'"
|
||||
eval "cd ${NIFI_HOME}"
|
||||
@ -460,7 +470,7 @@ case "$1" in
|
||||
install "$@"
|
||||
;;
|
||||
|
||||
start|stop|decommission|run|status|is_loaded|dump|diagnostics|status-history|env|stateless|set-sensitive-properties-key|set-single-user-credentials)
|
||||
start|stop|decommission|run|status|is_loaded|dump|diagnostics|status-history|env|stateless|set-sensitive-properties-algorithm|set-sensitive-properties-key|set-single-user-credentials)
|
||||
main "$@"
|
||||
;;
|
||||
|
||||
@ -470,6 +480,6 @@ case "$1" in
|
||||
run "start"
|
||||
;;
|
||||
*)
|
||||
echo "Usage nifi {start|stop|decommission|run|restart|status|dump|diagnostics|status-history|install|stateless|set-sensitive-properties-key|set-single-user-credentials}"
|
||||
echo "Usage nifi {start|stop|decommission|run|restart|status|dump|diagnostics|status-history|install|stateless|set-sensitive-properties-algorithm|set-sensitive-properties-key|set-single-user-credentials}"
|
||||
;;
|
||||
esac
|
||||
|
Loading…
x
Reference in New Issue
Block a user