diff --git a/minifi/minifi-bootstrap/pom.xml b/minifi/minifi-bootstrap/pom.xml
index 787f2b77e3..379e407122 100644
--- a/minifi/minifi-bootstrap/pom.xml
+++ b/minifi/minifi-bootstrap/pom.xml
@@ -60,6 +60,11 @@ limitations under the License.
org.apache.nifi
nifi-utils
+
+ org.apache.nifi
+ nifi-properties
+ provided
+
org.yaml
snakeyaml
diff --git a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/util/ConfigTransformer.java b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/util/ConfigTransformer.java
index cc14dca007..10458bedd3 100644
--- a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/util/ConfigTransformer.java
+++ b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/util/ConfigTransformer.java
@@ -17,7 +17,6 @@
package org.apache.nifi.minifi.bootstrap.util;
-
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.minifi.bootstrap.configuration.ConfigurationChangeException;
@@ -46,6 +45,7 @@ import org.apache.nifi.minifi.commons.schema.common.ConvertableSchema;
import org.apache.nifi.minifi.commons.schema.common.Schema;
import org.apache.nifi.minifi.commons.schema.common.StringUtil;
import org.apache.nifi.minifi.commons.schema.serialization.SchemaLoader;
+import org.apache.nifi.util.NiFiProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.DOMException;
@@ -69,7 +69,9 @@ import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.security.SecureRandom;
import java.util.Arrays;
+import java.util.Base64;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
@@ -80,9 +82,10 @@ import java.util.zip.GZIPOutputStream;
public final class ConfigTransformer {
// Underlying version of NIFI will be using
- public static final String NIFI_VERSION = "1.8.0";
public static final String ROOT_GROUP = "Root-Group";
- public static final String NIFI_VERSION_KEY = "nifi.version";
+
+ private static final Base64.Encoder KEY_ENCODER = Base64.getEncoder().withoutPadding();
+ private static final int SENSITIVE_PROPERTIES_KEY_LENGTH = 24;
public static final Logger logger = LoggerFactory.getLogger(ConfigTransformer.class);
@@ -178,8 +181,7 @@ public final class ConfigTransformer {
ProvenanceRepositorySchema provenanceRepositorySchema = configSchema.getProvenanceRepositorySchema();
OrderedProperties orderedProperties = new OrderedProperties();
- orderedProperties.setProperty(NIFI_VERSION_KEY, NIFI_VERSION, "# Core Properties #" + System.lineSeparator());
- orderedProperties.setProperty("nifi.flow.configuration.file", "./conf/flow.xml.gz");
+ orderedProperties.setProperty("nifi.flow.configuration.file", "./conf/flow.xml.gz", "# Core Properties #" + System.lineSeparator());
orderedProperties.setProperty("nifi.flow.configuration.archive.enabled", "false");
orderedProperties.setProperty("nifi.flow.configuration.archive.dir", "./conf/archive/");
orderedProperties.setProperty("nifi.flowcontroller.autoResumeState", "true");
@@ -258,7 +260,17 @@ public final class ConfigTransformer {
orderedProperties.setProperty("nifi.web.jetty.threads", "200");
final String sensitivePropertiesKey = sensitiveProperties.getKey();
- final String notnullSensitivePropertiesKey = sensitivePropertiesKey != null ? sensitivePropertiesKey : "";
+ final String notnullSensitivePropertiesKey;
+ // Auto-generate the sensitive properties key if not provided, NiFi security libraries require it
+ if (StringUtil.isNullOrEmpty(sensitivePropertiesKey)) {
+ logger.warn("Generating Random Sensitive Properties Key [{}]", NiFiProperties.SENSITIVE_PROPS_KEY);
+ final SecureRandom secureRandom = new SecureRandom();
+ final byte[] sensitivePropertiesKeyBinary = new byte[SENSITIVE_PROPERTIES_KEY_LENGTH];
+ secureRandom.nextBytes(sensitivePropertiesKeyBinary);
+ notnullSensitivePropertiesKey = KEY_ENCODER.encodeToString(sensitivePropertiesKeyBinary);
+ } else {
+ notnullSensitivePropertiesKey = sensitivePropertiesKey;
+ }
orderedProperties.setProperty("nifi.sensitive.props.key", notnullSensitivePropertiesKey, System.lineSeparator() + "# security properties #");
orderedProperties.setProperty("nifi.sensitive.props.algorithm", sensitiveProperties.getAlgorithm());
@@ -719,19 +731,19 @@ public final class ConfigTransformer {
public static final String PROPERTIES_FILE_APACHE_2_0_LICENSE =
" Licensed to the Apache Software Foundation (ASF) under one or more\n" +
- "# contributor license agreements. See the NOTICE file distributed with\n" +
- "# this work for additional information regarding copyright ownership.\n" +
- "# The ASF licenses this file to You under the Apache License, Version 2.0\n" +
- "# (the \"License\"); you may not use this file except in compliance with\n" +
- "# the License. You may obtain a copy of the License at\n" +
- "#\n" +
- "# http://www.apache.org/licenses/LICENSE-2.0\n" +
- "#\n" +
- "# Unless required by applicable law or agreed to in writing, software\n" +
- "# distributed under the License is distributed on an \"AS IS\" BASIS,\n" +
- "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" +
- "# See the License for the specific language governing permissions and\n" +
- "# limitations under the License.\n" +
- "\n";
+ "# contributor license agreements. See the NOTICE file distributed with\n" +
+ "# this work for additional information regarding copyright ownership.\n" +
+ "# The ASF licenses this file to You under the Apache License, Version 2.0\n" +
+ "# (the \"License\"); you may not use this file except in compliance with\n" +
+ "# the License. You may obtain a copy of the License at\n" +
+ "#\n" +
+ "# http://www.apache.org/licenses/LICENSE-2.0\n" +
+ "#\n" +
+ "# Unless required by applicable law or agreed to in writing, software\n" +
+ "# distributed under the License is distributed on an \"AS IS\" BASIS,\n" +
+ "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" +
+ "# See the License for the specific language governing permissions and\n" +
+ "# limitations under the License.\n" +
+ "\n";
}
diff --git a/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/util/ConfigTransformerTest.java b/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/util/ConfigTransformerTest.java
index 7c621cb2ab..bb01784f8b 100644
--- a/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/util/ConfigTransformerTest.java
+++ b/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/util/ConfigTransformerTest.java
@@ -33,6 +33,7 @@ import org.apache.nifi.minifi.commons.schema.ReportingSchema;
import org.apache.nifi.minifi.commons.schema.common.StringUtil;
import org.apache.nifi.minifi.commons.schema.exception.SchemaLoaderException;
import org.apache.nifi.minifi.commons.schema.serialization.SchemaLoader;
+import org.apache.nifi.util.StringUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -78,7 +79,6 @@ public class ConfigTransformerTest {
public static final Map PG_ELEMENT_ORDER_MAP = generateOrderMap(
Arrays.asList("processor", "inputPort", "outputPort", "funnel", "processGroup", "remoteProcessGroup", "connection"));
private XPathFactory xPathFactory;
- private Document document;
private Element config;
private DocumentBuilder documentBuilder;
@@ -88,7 +88,7 @@ public class ConfigTransformerTest {
@Before
public void setup() throws ParserConfigurationException {
documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
- document = documentBuilder.newDocument();
+ final Document document = documentBuilder.newDocument();
config = document.createElement("config");
xPathFactory = XPathFactory.newInstance();
}
@@ -169,8 +169,6 @@ public class ConfigTransformerTest {
try (InputStream pre216PropertiesStream = ConfigTransformerTest.class.getClassLoader().getResourceAsStream("MINIFI-216/nifi.properties.before")) {
pre216Properties.load(pre216PropertiesStream);
}
- pre216Properties.setProperty(ConfigTransformer.NIFI_VERSION_KEY, ConfigTransformer.NIFI_VERSION);
-
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try (InputStream configStream = ConfigTransformerTest.class.getClassLoader().getResourceAsStream("MINIFI-216/config.yml")) {
ConfigTransformer.writeNiFiProperties(SchemaLoader.loadConfigSchemaFromYaml(configStream), outputStream);
@@ -189,8 +187,6 @@ public class ConfigTransformerTest {
try (InputStream pre216PropertiesStream = ConfigTransformerTest.class.getClassLoader().getResourceAsStream("MINIFI-216/nifi.properties.before")) {
pre216Properties.load(pre216PropertiesStream);
}
- pre216Properties.setProperty(ConfigTransformer.NIFI_VERSION_KEY, ConfigTransformer.NIFI_VERSION);
-
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try (InputStream configStream = ConfigTransformerTest.class.getClassLoader().getResourceAsStream("MINIFI-216/configOverrides.yml")) {
ConfigSchema configSchema = SchemaLoader.loadConfigSchemaFromYaml(configStream);
@@ -214,8 +210,6 @@ public class ConfigTransformerTest {
try (InputStream pre216PropertiesStream = ConfigTransformerTest.class.getClassLoader().getResourceAsStream("MINIFI-277/nifi.properties")) {
initialProperties.load(pre216PropertiesStream);
}
- initialProperties.setProperty(ConfigTransformer.NIFI_VERSION_KEY, ConfigTransformer.NIFI_VERSION);
-
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try (InputStream configStream = ConfigTransformerTest.class.getClassLoader().getResourceAsStream("MINIFI-277/config.yml")) {
ConfigSchema configSchema = SchemaLoader.loadConfigSchemaFromYaml(configStream);
@@ -421,7 +415,7 @@ public class ConfigTransformerTest {
File inputFile = new File("./src/test/resources/config-invalid.yml");
ConfigTransformer.transformConfigFile(new FileInputStream(inputFile), "./target/", null);
fail("Invalid configuration file was not detected.");
- } catch (SchemaLoaderException e){
+ } catch (SchemaLoaderException e) {
assertEquals("Provided YAML configuration is not a Map", e.getMessage());
}
}
@@ -432,7 +426,7 @@ public class ConfigTransformerTest {
File inputFile = new File("./src/test/resources/config-malformed-field.yml");
ConfigTransformer.transformConfigFile(new FileInputStream(inputFile), "./target/", null);
fail("Invalid configuration file was not detected.");
- } catch (InvalidConfigurationException e){
+ } catch (InvalidConfigurationException e) {
assertEquals("Failed to transform config file due to:['threshold' in section 'Swap' because it is found but could not be parsed as a Number]", e.getMessage());
}
}
@@ -443,7 +437,7 @@ public class ConfigTransformerTest {
File inputFile = new File("./src/test/resources/config-empty.yml");
ConfigTransformer.transformConfigFile(new FileInputStream(inputFile), "./target/", null);
fail("Invalid configuration file was not detected.");
- } catch (SchemaLoaderException e){
+ } catch (SchemaLoaderException e) {
assertEquals("Provided YAML configuration is not a Map", e.getMessage());
}
}
@@ -454,7 +448,7 @@ public class ConfigTransformerTest {
File inputFile = new File("./src/test/resources/config-missing-required-field.yml");
ConfigTransformer.transformConfigFile(new FileInputStream(inputFile), "./target/", null);
fail("Invalid configuration file was not detected.");
- } catch (InvalidConfigurationException e){
+ } catch (InvalidConfigurationException e) {
assertEquals("Failed to transform config file due to:['class' in section 'Processors' because it was not found and it is required]", e.getMessage());
}
}
@@ -465,7 +459,7 @@ public class ConfigTransformerTest {
File inputFile = new File("./src/test/resources/config-multiple-problems.yml");
ConfigTransformer.transformConfigFile(new FileInputStream(inputFile), "./target/", null);
fail("Invalid configuration file was not detected.");
- } catch (InvalidConfigurationException e){
+ } catch (InvalidConfigurationException e) {
assertEquals("Failed to transform config file due to:['class' in section 'Processors' because it was not found and it is required], " +
"['scheduling strategy' in section 'Provenance Reporting' because it is not a valid scheduling strategy], " +
"['source name' in section 'Connections' because it was not found and it is required]", e.getMessage());
@@ -699,8 +693,6 @@ public class ConfigTransformerTest {
try (InputStream pre216PropertiesStream = ConfigTransformerTest.class.getClassLoader().getResourceAsStream("MINIFI-245/nifi.properties.before")) {
pre216Properties.load(pre216PropertiesStream);
}
- pre216Properties.setProperty(ConfigTransformer.NIFI_VERSION_KEY, ConfigTransformer.NIFI_VERSION);
-
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try (InputStream configStream = ConfigTransformerTest.class.getClassLoader().getResourceAsStream("MINIFI-245/config.yml")) {
ConfigTransformer.writeNiFiProperties(SchemaLoader.loadConfigSchemaFromYaml(configStream), outputStream);
@@ -710,7 +702,7 @@ public class ConfigTransformerTest {
for (String name : pre216Properties.stringPropertyNames()) {
// Verify the Content Repo property was overridden
- if("nifi.content.repository.implementation".equals(name)) {
+ if ("nifi.content.repository.implementation".equals(name)) {
assertNotEquals("Property key " + name + " was not overridden.", pre216Properties.getProperty(name), properties.getProperty(name));
} else {
assertEquals("Property key " + name + " doesn't match.", pre216Properties.getProperty(name), properties.getProperty(name));
@@ -724,8 +716,6 @@ public class ConfigTransformerTest {
try (InputStream pre216PropertiesStream = ConfigTransformerTest.class.getClassLoader().getResourceAsStream("NIFI-8753/nifi.properties.before")) {
pre216Properties.load(pre216PropertiesStream);
}
- pre216Properties.setProperty(ConfigTransformer.NIFI_VERSION_KEY, ConfigTransformer.NIFI_VERSION);
-
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try (InputStream configStream = ConfigTransformerTest.class.getClassLoader().getResourceAsStream("NIFI-8753/config.yml")) {
ConfigTransformer.writeNiFiProperties(SchemaLoader.loadConfigSchemaFromYaml(configStream), outputStream);
@@ -735,7 +725,7 @@ public class ConfigTransformerTest {
for (String name : pre216Properties.stringPropertyNames()) {
// Verify the Content Repo property was overridden
- if("nifi.flowfile.repository.implementation".equals(name)) {
+ if ("nifi.flowfile.repository.implementation".equals(name)) {
assertNotEquals("Property key " + name + " was not overridden.", pre216Properties.getProperty(name), properties.getProperty(name));
} else {
assertEquals("Property key " + name + " doesn't match.", pre216Properties.getProperty(name), properties.getProperty(name));
@@ -751,7 +741,8 @@ public class ConfigTransformerTest {
}
final Properties properties = new Properties();
properties.load(new ByteArrayInputStream(outputStream.toByteArray()));
- assertEquals("", properties.getProperty("nifi.sensitive.props.key"));
+ // The property should not be empty/null as it is auto-generated when missing
+ assertTrue(StringUtils.isNotEmpty(properties.getProperty("nifi.sensitive.props.key")));
}
private String getText(Element element, String path) throws XPathExpressionException {
@@ -780,7 +771,7 @@ public class ConfigTransformerTest {
if (index != null) {
if (elementOrderList > index) {
fail("Found " + nodeName + " after " + lastOrderedElementName + "; expected all " + nodeName + " elements to come before the following elements: " + orderMap.entrySet().stream()
- .filter(e -> e.getValue() > index ).sorted(Comparator.comparingInt(e -> e.getValue())).map(e -> e.getKey()).collect(Collectors.joining(", ")));
+ .filter(e -> e.getValue() > index).sorted(Comparator.comparingInt(e -> e.getValue())).map(e -> e.getKey()).collect(Collectors.joining(", ")));
}
lastOrderedElementName = nodeName;
elementOrderList = index;
diff --git a/minifi/minifi-bootstrap/src/test/resources/MINIFI-216/nifi.properties.before b/minifi/minifi-bootstrap/src/test/resources/MINIFI-216/nifi.properties.before
index 2de01159d6..0c60b4be9f 100644
--- a/minifi/minifi-bootstrap/src/test/resources/MINIFI-216/nifi.properties.before
+++ b/minifi/minifi-bootstrap/src/test/resources/MINIFI-216/nifi.properties.before
@@ -15,7 +15,6 @@
# Core Properties #
-nifi.version=1.1.0
nifi.flow.configuration.file=./conf/flow.xml.gz
nifi.flow.configuration.archive.enabled=false
nifi.flow.configuration.archive.dir=./conf/archive/
@@ -92,7 +91,7 @@ nifi.web.jetty.working.directory=./work/jetty
nifi.web.jetty.threads=200
# security properties #
-nifi.sensitive.props.key=
+# This needs to be ignored during unit testing: nifi.sensitive.props.key=
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
nifi.security.keystore=/tmp/ssl/localhost-ks.jks
diff --git a/minifi/minifi-bootstrap/src/test/resources/MINIFI-245/nifi.properties.before b/minifi/minifi-bootstrap/src/test/resources/MINIFI-245/nifi.properties.before
index 2de01159d6..0c60b4be9f 100644
--- a/minifi/minifi-bootstrap/src/test/resources/MINIFI-245/nifi.properties.before
+++ b/minifi/minifi-bootstrap/src/test/resources/MINIFI-245/nifi.properties.before
@@ -15,7 +15,6 @@
# Core Properties #
-nifi.version=1.1.0
nifi.flow.configuration.file=./conf/flow.xml.gz
nifi.flow.configuration.archive.enabled=false
nifi.flow.configuration.archive.dir=./conf/archive/
@@ -92,7 +91,7 @@ nifi.web.jetty.working.directory=./work/jetty
nifi.web.jetty.threads=200
# security properties #
-nifi.sensitive.props.key=
+# This needs to be ignored during unit testing: nifi.sensitive.props.key=
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
nifi.security.keystore=/tmp/ssl/localhost-ks.jks
diff --git a/minifi/minifi-bootstrap/src/test/resources/MINIFI-277/nifi.properties b/minifi/minifi-bootstrap/src/test/resources/MINIFI-277/nifi.properties
index 984214366d..5b2b1a7be4 100644
--- a/minifi/minifi-bootstrap/src/test/resources/MINIFI-277/nifi.properties
+++ b/minifi/minifi-bootstrap/src/test/resources/MINIFI-277/nifi.properties
@@ -15,8 +15,6 @@
# Core Properties #
-nifi.version=1.1.0
-
nifi.flow.configuration.file=./conf/flow.xml.gz
nifi.flow.configuration.archive.enabled=false
nifi.flow.configuration.archive.dir=./conf/archive/
@@ -94,7 +92,7 @@ nifi.web.jetty.working.directory=./work/jetty
nifi.web.jetty.threads=200
# security properties #
-nifi.sensitive.props.key=
+# This needs to be ignored during unit testing: nifi.sensitive.props.key=
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
nifi.security.keystore=/tmp/ssl/localhost-ks.jks
diff --git a/minifi/minifi-bootstrap/src/test/resources/NIFI-8753/nifi.properties.before b/minifi/minifi-bootstrap/src/test/resources/NIFI-8753/nifi.properties.before
index 2de01159d6..0c60b4be9f 100644
--- a/minifi/minifi-bootstrap/src/test/resources/NIFI-8753/nifi.properties.before
+++ b/minifi/minifi-bootstrap/src/test/resources/NIFI-8753/nifi.properties.before
@@ -15,7 +15,6 @@
# Core Properties #
-nifi.version=1.1.0
nifi.flow.configuration.file=./conf/flow.xml.gz
nifi.flow.configuration.archive.enabled=false
nifi.flow.configuration.archive.dir=./conf/archive/
@@ -92,7 +91,7 @@ nifi.web.jetty.working.directory=./work/jetty
nifi.web.jetty.threads=200
# security properties #
-nifi.sensitive.props.key=
+# This needs to be ignored during unit testing: nifi.sensitive.props.key=
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
nifi.security.keystore=/tmp/ssl/localhost-ks.jks