mirror of https://github.com/apache/nifi.git
NIFI-11488 Removed Deprecated Sensitive Properties Algorithms
Signed-off-by: Pierre Villard <pierre.villard.fr@gmail.com> This closes #7198.
This commit is contained in:
parent
d54940c397
commit
ee03db0e8f
|
@ -28,10 +28,6 @@ nifi.web.http.port=
|
||||||
nifi.web.https.host=test-host
|
nifi.web.https.host=test-host
|
||||||
nifi.web.https.port=8443
|
nifi.web.https.port=8443
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=key
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
|
|
||||||
nifi.security.keystore=./src/test/resources/keystore.p12
|
nifi.security.keystore=./src/test/resources/keystore.p12
|
||||||
nifi.security.keystoreType=PKCS12
|
nifi.security.keystoreType=PKCS12
|
||||||
nifi.security.keystorePasswd=
|
nifi.security.keystorePasswd=
|
||||||
|
|
|
@ -28,10 +28,6 @@ nifi.web.http.port=
|
||||||
nifi.web.https.host=1.2.3.4
|
nifi.web.https.host=1.2.3.4
|
||||||
nifi.web.https.port=8443
|
nifi.web.https.port=8443
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=key
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
|
|
||||||
nifi.security.keystore=./src/test/resources/keystore.p12
|
nifi.security.keystore=./src/test/resources/keystore.p12
|
||||||
nifi.security.keystoreType=PKCS12
|
nifi.security.keystoreType=PKCS12
|
||||||
nifi.security.keystorePasswd=
|
nifi.security.keystorePasswd=
|
||||||
|
|
|
@ -24,10 +24,6 @@ nifi.web.http.port=
|
||||||
nifi.web.https.host=
|
nifi.web.https.host=
|
||||||
nifi.web.https.port=8443
|
nifi.web.https.port=8443
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=key
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
|
|
||||||
nifi.security.keystore=./src/test/resources/keystore.p12
|
nifi.security.keystore=./src/test/resources/keystore.p12
|
||||||
nifi.security.keystoreType=PKCS12
|
nifi.security.keystoreType=PKCS12
|
||||||
nifi.security.keystorePasswd=12345
|
nifi.security.keystorePasswd=12345
|
||||||
|
|
|
@ -24,10 +24,6 @@ nifi.web.http.port=8080
|
||||||
nifi.web.https.host=
|
nifi.web.https.host=
|
||||||
nifi.web.https.port=
|
nifi.web.https.port=
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=key
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
|
|
||||||
nifi.security.keystore=./src/test/resources/keystore.p12
|
nifi.security.keystore=./src/test/resources/keystore.p12
|
||||||
nifi.security.keystoreType=PKCS12
|
nifi.security.keystoreType=PKCS12
|
||||||
nifi.security.keystorePasswd=
|
nifi.security.keystorePasswd=
|
||||||
|
|
|
@ -24,10 +24,6 @@ nifi.web.http.port=
|
||||||
nifi.web.https.host=
|
nifi.web.https.host=
|
||||||
nifi.web.https.port=8443
|
nifi.web.https.port=8443
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=key
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
|
|
||||||
nifi.security.keystore=./src/test/resources/keystore.p12
|
nifi.security.keystore=./src/test/resources/keystore.p12
|
||||||
nifi.security.keystoreType=
|
nifi.security.keystoreType=
|
||||||
nifi.security.keystorePasswd=
|
nifi.security.keystorePasswd=
|
||||||
|
|
|
@ -24,10 +24,6 @@ nifi.web.http.port=
|
||||||
nifi.web.https.host=
|
nifi.web.https.host=
|
||||||
nifi.web.https.port=8443
|
nifi.web.https.port=8443
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=key
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
|
|
||||||
nifi.security.keystore=
|
nifi.security.keystore=
|
||||||
nifi.security.keystoreType=PKCS12
|
nifi.security.keystoreType=PKCS12
|
||||||
nifi.security.keystorePasswd=
|
nifi.security.keystorePasswd=
|
||||||
|
|
|
@ -24,10 +24,6 @@ nifi.web.http.port=
|
||||||
nifi.web.https.host=
|
nifi.web.https.host=
|
||||||
nifi.web.https.port=8443
|
nifi.web.https.port=8443
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=key
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
|
|
||||||
nifi.security.keystore=./src/test/resources/existing-keystore.p12
|
nifi.security.keystore=./src/test/resources/existing-keystore.p12
|
||||||
nifi.security.keystoreType=PKCS12
|
nifi.security.keystoreType=PKCS12
|
||||||
nifi.security.keystorePasswd=
|
nifi.security.keystorePasswd=
|
||||||
|
|
|
@ -24,10 +24,6 @@ nifi.web.http.port=
|
||||||
nifi.web.https.host=
|
nifi.web.https.host=
|
||||||
nifi.web.https.port=8443
|
nifi.web.https.port=8443
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=key
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
|
|
||||||
nifi.security.keystore=./src/test/resources/keystore.p12
|
nifi.security.keystore=./src/test/resources/keystore.p12
|
||||||
nifi.security.keystoreType=PKCS12
|
nifi.security.keystoreType=PKCS12
|
||||||
nifi.security.keystorePasswd=
|
nifi.security.keystorePasswd=
|
||||||
|
|
|
@ -24,10 +24,6 @@ nifi.web.http.port=
|
||||||
nifi.web.https.host=
|
nifi.web.https.host=
|
||||||
nifi.web.https.port=8443
|
nifi.web.https.port=8443
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=key
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
|
|
||||||
nifi.security.keystore=./src/test/resources/existing-keystore.p12
|
nifi.security.keystore=./src/test/resources/existing-keystore.p12
|
||||||
nifi.security.keystoreType=PKCS12
|
nifi.security.keystoreType=PKCS12
|
||||||
nifi.security.keystorePasswd=
|
nifi.security.keystorePasswd=
|
||||||
|
|
|
@ -24,10 +24,6 @@ nifi.web.http.port=
|
||||||
nifi.web.https.host=
|
nifi.web.https.host=
|
||||||
nifi.web.https.port=8443
|
nifi.web.https.port=8443
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=key
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
|
|
||||||
nifi.security.keystore=./src/test/resources/keystore.p12
|
nifi.security.keystore=./src/test/resources/keystore.p12
|
||||||
nifi.security.keystoreType=PKCS12
|
nifi.security.keystoreType=PKCS12
|
||||||
nifi.security.keystorePasswd=
|
nifi.security.keystorePasswd=
|
||||||
|
|
|
@ -24,10 +24,6 @@ nifi.web.http.port=
|
||||||
nifi.web.https.host=
|
nifi.web.https.host=
|
||||||
nifi.web.https.port=8443
|
nifi.web.https.port=8443
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=key
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
|
|
||||||
nifi.security.keystore=./src/test/resources/keystore.p12
|
nifi.security.keystore=./src/test/resources/keystore.p12
|
||||||
nifi.security.keystoreType=PKCS12
|
nifi.security.keystoreType=PKCS12
|
||||||
nifi.security.keystorePasswd=
|
nifi.security.keystorePasswd=
|
||||||
|
|
|
@ -16,11 +16,11 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.nifi.flow.encryptor.command;
|
package org.apache.nifi.flow.encryptor.command;
|
||||||
|
|
||||||
|
import org.apache.nifi.encrypt.PropertyEncryptionMethod;
|
||||||
import org.apache.nifi.encrypt.PropertyEncryptor;
|
import org.apache.nifi.encrypt.PropertyEncryptor;
|
||||||
import org.apache.nifi.encrypt.PropertyEncryptorBuilder;
|
import org.apache.nifi.encrypt.PropertyEncryptorBuilder;
|
||||||
import org.apache.nifi.flow.encryptor.FlowEncryptor;
|
import org.apache.nifi.flow.encryptor.FlowEncryptor;
|
||||||
import org.apache.nifi.flow.encryptor.StandardFlowEncryptor;
|
import org.apache.nifi.flow.encryptor.StandardFlowEncryptor;
|
||||||
import org.apache.nifi.security.util.EncryptionMethod;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
|
@ -61,7 +61,7 @@ class FlowEncryptorCommand implements Runnable {
|
||||||
|
|
||||||
private static final String GZ_EXTENSION = ".gz";
|
private static final String GZ_EXTENSION = ".gz";
|
||||||
|
|
||||||
private static final String DEFAULT_PROPERTIES_ALGORITHM = EncryptionMethod.MD5_256AES.getAlgorithm();
|
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 DEFAULT_PROPERTIES_KEY = "nififtw!";
|
||||||
|
|
||||||
|
|
|
@ -16,9 +16,9 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.nifi.flow.encryptor;
|
package org.apache.nifi.flow.encryptor;
|
||||||
|
|
||||||
|
import org.apache.nifi.encrypt.PropertyEncryptionMethod;
|
||||||
import org.apache.nifi.encrypt.PropertyEncryptor;
|
import org.apache.nifi.encrypt.PropertyEncryptor;
|
||||||
import org.apache.nifi.encrypt.PropertyEncryptorBuilder;
|
import org.apache.nifi.encrypt.PropertyEncryptorBuilder;
|
||||||
import org.apache.nifi.security.util.EncryptionMethod;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
@ -55,8 +55,8 @@ public class StandardFlowEncryptorTest {
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setEncryptors() {
|
public void setEncryptors() {
|
||||||
inputEncryptor = getPropertyEncryptor(INPUT_KEY, EncryptionMethod.MD5_256AES.getAlgorithm());
|
inputEncryptor = getPropertyEncryptor(INPUT_KEY, PropertyEncryptionMethod.NIFI_PBKDF2_AES_GCM_256.name());
|
||||||
outputEncryptor = getPropertyEncryptor(OUTPUT_KEY, EncryptionMethod.SHA256_256AES.getAlgorithm());
|
outputEncryptor = getPropertyEncryptor(OUTPUT_KEY, PropertyEncryptionMethod.NIFI_ARGON2_AES_GCM_256.name());
|
||||||
flowEncryptor = new StandardFlowEncryptor();
|
flowEncryptor = new StandardFlowEncryptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.nifi.flow.encryptor.command;
|
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.AfterEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
@ -34,6 +33,7 @@ import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.zip.GZIPOutputStream;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
@ -56,8 +56,6 @@ public class FlowEncryptorCommandTest {
|
||||||
|
|
||||||
private static final String POPULATED_PROPERTIES = "/populated.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";
|
private static final String REQUESTED_ALGORITHM = "NIFI_PBKDF2_AES_GCM_256";
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
|
@ -85,20 +83,6 @@ public class FlowEncryptorCommandTest {
|
||||||
assertPropertiesKeyUpdated(propertiesPath, propertiesKey);
|
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
|
@Test
|
||||||
public void testRunPropertiesAlgorithmWithPropertiesKeyPopulatedProperties() throws IOException, URISyntaxException {
|
public void testRunPropertiesAlgorithmWithPropertiesKeyPopulatedProperties() throws IOException, URISyntaxException {
|
||||||
final Path propertiesPath = getPopulatedNiFiProperties();
|
final Path propertiesPath = getPopulatedNiFiProperties();
|
||||||
|
@ -150,11 +134,6 @@ public class FlowEncryptorCommandTest {
|
||||||
return getNiFiProperties(flowConfiguration, flowConfigurationJson, POPULATED_PROPERTIES);
|
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(
|
private static Path getNiFiProperties(
|
||||||
final Path flowConfigurationPath,
|
final Path flowConfigurationPath,
|
||||||
final Path flowConfigurationJsonPath,
|
final Path flowConfigurationJsonPath,
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
# 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.
|
|
||||||
nifi.sensitive.props.key=
|
|
||||||
nifi.sensitive.props.algorithm=
|
|
||||||
nifi.flow.configuration.file=
|
|
|
@ -71,7 +71,7 @@ nifi.web.jetty.working.directory=./target/work/jetty
|
||||||
|
|
||||||
# security properties #
|
# security properties #
|
||||||
nifi.sensitive.props.key=key
|
nifi.sensitive.props.key=key
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM_256
|
||||||
|
|
||||||
nifi.security.keystore=
|
nifi.security.keystore=
|
||||||
nifi.security.keystoreType=
|
nifi.security.keystoreType=
|
||||||
|
|
|
@ -69,7 +69,7 @@ nifi.web.jetty.working.directory=./target/work/jetty
|
||||||
|
|
||||||
# security properties #
|
# security properties #
|
||||||
nifi.sensitive.props.key=key
|
nifi.sensitive.props.key=key
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM_256
|
||||||
|
|
||||||
nifi.security.keystore=
|
nifi.security.keystore=
|
||||||
nifi.security.keystoreType=
|
nifi.security.keystoreType=
|
||||||
|
|
|
@ -71,7 +71,7 @@ nifi.web.jetty.working.directory=./target/work/jetty
|
||||||
|
|
||||||
# security properties #
|
# security properties #
|
||||||
nifi.sensitive.props.key=key
|
nifi.sensitive.props.key=key
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM_256
|
||||||
|
|
||||||
nifi.security.keystore=
|
nifi.security.keystore=
|
||||||
nifi.security.keystoreType=
|
nifi.security.keystoreType=
|
||||||
|
|
|
@ -24,17 +24,9 @@
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.nifi</groupId>
|
<groupId>org.apache.nifi</groupId>
|
||||||
<artifactId>nifi-security-utils</artifactId>
|
<artifactId>nifi-security-crypto-key</artifactId>
|
||||||
<version>2.0.0-SNAPSHOT</version>
|
<version>2.0.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.bouncycastle</groupId>
|
|
||||||
<artifactId>bcprov-jdk18on</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.commons</groupId>
|
|
||||||
<artifactId>commons-lang3</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-codec</groupId>
|
<groupId>commons-codec</groupId>
|
||||||
<artifactId>commons-codec</artifactId>
|
<artifactId>commons-codec</artifactId>
|
||||||
|
|
|
@ -18,15 +18,12 @@ package org.apache.nifi.encrypt;
|
||||||
|
|
||||||
import org.apache.commons.codec.DecoderException;
|
import org.apache.commons.codec.DecoderException;
|
||||||
import org.apache.commons.codec.binary.Hex;
|
import org.apache.commons.codec.binary.Hex;
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
|
||||||
import org.bouncycastle.util.Arrays;
|
|
||||||
|
|
||||||
import javax.crypto.BadPaddingException;
|
import javax.crypto.BadPaddingException;
|
||||||
import javax.crypto.Cipher;
|
import javax.crypto.Cipher;
|
||||||
import javax.crypto.IllegalBlockSizeException;
|
import javax.crypto.IllegalBlockSizeException;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.Security;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cipher Property Encryptor provides hexadecimal encoding and decoding around cipher operations
|
* Cipher Property Encryptor provides hexadecimal encoding and decoding around cipher operations
|
||||||
|
@ -34,10 +31,6 @@ import java.security.Security;
|
||||||
abstract class CipherPropertyEncryptor implements PropertyEncryptor {
|
abstract class CipherPropertyEncryptor implements PropertyEncryptor {
|
||||||
private static final Charset PROPERTY_CHARSET = StandardCharsets.UTF_8;
|
private static final Charset PROPERTY_CHARSET = StandardCharsets.UTF_8;
|
||||||
|
|
||||||
static {
|
|
||||||
Security.addProvider(new BouncyCastleProvider());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encrypt property and encode as a hexadecimal string
|
* Encrypt property and encode as a hexadecimal string
|
||||||
*
|
*
|
||||||
|
@ -52,7 +45,7 @@ abstract class CipherPropertyEncryptor implements PropertyEncryptor {
|
||||||
final Cipher cipher = getEncryptionCipher(encodedParameters);
|
final Cipher cipher = getEncryptionCipher(encodedParameters);
|
||||||
try {
|
try {
|
||||||
final byte[] encrypted = cipher.doFinal(binary);
|
final byte[] encrypted = cipher.doFinal(binary);
|
||||||
return Hex.encodeHexString(Arrays.concatenate(encodedParameters, encrypted));
|
return Hex.encodeHexString(getConcatenatedBinary(encodedParameters, encrypted));
|
||||||
} catch (final BadPaddingException | IllegalBlockSizeException e) {
|
} catch (final BadPaddingException | IllegalBlockSizeException e) {
|
||||||
final String message = String.format("Encryption Failed with Algorithm [%s]", cipher.getAlgorithm());
|
final String message = String.format("Encryption Failed with Algorithm [%s]", cipher.getAlgorithm());
|
||||||
throw new EncryptionException(message, e);
|
throw new EncryptionException(message, e);
|
||||||
|
@ -87,6 +80,17 @@ abstract class CipherPropertyEncryptor implements PropertyEncryptor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private byte[] getConcatenatedBinary(final byte[] encodedParameters, final byte[] encrypted) {
|
||||||
|
final int encodedParametersLength = encodedParameters.length;
|
||||||
|
final int encryptedLength = encrypted.length;
|
||||||
|
final int concatenatedLength = encodedParametersLength + encryptedLength;
|
||||||
|
|
||||||
|
final byte[] concatenated = new byte[concatenatedLength];
|
||||||
|
System.arraycopy(encodedParameters, 0, concatenated, 0, encodedParametersLength);
|
||||||
|
System.arraycopy(encrypted, 0, concatenated, encodedParametersLength, encryptedLength);
|
||||||
|
return concatenated;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Encoded Parameters based on cipher implementation
|
* Get Encoded Parameters based on cipher implementation
|
||||||
*
|
*
|
||||||
|
|
|
@ -24,10 +24,6 @@ public class EncryptionException extends RuntimeException {
|
||||||
|
|
||||||
private static final long serialVersionUID = 19802342398832L;
|
private static final long serialVersionUID = 19802342398832L;
|
||||||
|
|
||||||
public EncryptionException(Throwable cause) {
|
|
||||||
super(cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public EncryptionException(String message, Throwable cause) {
|
public EncryptionException(String message, Throwable cause) {
|
||||||
super(message, cause);
|
super(message, cause);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,169 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.encrypt;
|
|
||||||
|
|
||||||
import org.apache.nifi.security.util.EncryptionMethod;
|
|
||||||
import org.apache.nifi.security.util.crypto.CipherUtility;
|
|
||||||
import org.apache.nifi.security.util.crypto.PBECipherProvider;
|
|
||||||
|
|
||||||
import javax.crypto.Cipher;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Property Encryptor implementation using Password Based Encryption Cipher Provider
|
|
||||||
*/
|
|
||||||
class PasswordBasedCipherPropertyEncryptor extends CipherPropertyEncryptor {
|
|
||||||
private static final int ARRAY_START = 0;
|
|
||||||
|
|
||||||
private static final boolean ENCRYPT = true;
|
|
||||||
|
|
||||||
private static final boolean DECRYPT = false;
|
|
||||||
|
|
||||||
private final PBECipherProvider cipherProvider;
|
|
||||||
|
|
||||||
private final EncryptionMethod encryptionMethod;
|
|
||||||
|
|
||||||
private final String password;
|
|
||||||
|
|
||||||
private final int keyLength;
|
|
||||||
|
|
||||||
private final int saltLength;
|
|
||||||
|
|
||||||
private final String description;
|
|
||||||
|
|
||||||
protected PasswordBasedCipherPropertyEncryptor(final PBECipherProvider cipherProvider,
|
|
||||||
final EncryptionMethod encryptionMethod,
|
|
||||||
final String password) {
|
|
||||||
this.cipherProvider = cipherProvider;
|
|
||||||
this.encryptionMethod = encryptionMethod;
|
|
||||||
this.password = password;
|
|
||||||
this.keyLength = CipherUtility.parseKeyLengthFromAlgorithm(encryptionMethod.getAlgorithm());
|
|
||||||
this.saltLength = CipherUtility.getSaltLengthForAlgorithm(encryptionMethod.getAlgorithm());
|
|
||||||
this.description = String.format("%s Encryption Method [%s] Key Length [%d] Salt Length [%d]",
|
|
||||||
getClass().getSimpleName(),
|
|
||||||
encryptionMethod.getAlgorithm(),
|
|
||||||
keyLength,
|
|
||||||
saltLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Cipher for Decryption based on encrypted binary
|
|
||||||
*
|
|
||||||
* @param encryptedBinary Encrypted Binary
|
|
||||||
* @return Cipher for Decryption
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected Cipher getDecryptionCipher(final byte[] encryptedBinary) {
|
|
||||||
final byte[] salt = readSalt(encryptedBinary);
|
|
||||||
return getCipher(salt, DECRYPT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Cipher for Encryption using encoded parameters containing random salt generated for encoding parameters
|
|
||||||
*
|
|
||||||
* @param encodedParameters Binary encoded parameters containing random salt generated from Cipher Provider
|
|
||||||
* @return Cipher for Encryption
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected Cipher getEncryptionCipher(byte[] encodedParameters) {
|
|
||||||
return getCipher(encodedParameters, ENCRYPT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Cipher Binary from encrypted binary
|
|
||||||
*
|
|
||||||
* @param encryptedBinary Encrypted Binary containing cipher binary and other information
|
|
||||||
* @return Cipher Binary for decryption
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected byte[] getCipherBinary(byte[] encryptedBinary) {
|
|
||||||
return Arrays.copyOfRange(encryptedBinary, saltLength, encryptedBinary.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Encoded Parameters returns a random salt generated from the Cipher Provider
|
|
||||||
*
|
|
||||||
* @return Random Salt for encoded parameters
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
@Override
|
|
||||||
protected byte[] getEncodedParameters() {
|
|
||||||
final byte[] salt;
|
|
||||||
|
|
||||||
if (cipherProvider instanceof org.apache.nifi.security.util.crypto.NiFiLegacyCipherProvider) {
|
|
||||||
salt = ((org.apache.nifi.security.util.crypto.NiFiLegacyCipherProvider) cipherProvider).generateSalt(encryptionMethod);
|
|
||||||
} else {
|
|
||||||
salt = cipherProvider.generateSalt();
|
|
||||||
}
|
|
||||||
|
|
||||||
return salt;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Cipher getCipher(final byte[] salt, final boolean encrypt) {
|
|
||||||
try {
|
|
||||||
return cipherProvider.getCipher(encryptionMethod, password, salt, keyLength, encrypt);
|
|
||||||
} catch (final Exception e) {
|
|
||||||
final String message = String.format("Failed to get Cipher for Algorithm [%s]", encryptionMethod.getAlgorithm());
|
|
||||||
throw new EncryptionException(message, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] readSalt(final byte[] binary) {
|
|
||||||
final byte[] salt = new byte[saltLength];
|
|
||||||
System.arraycopy(binary, ARRAY_START, salt, ARRAY_START, saltLength);
|
|
||||||
return salt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return object equality based on Encryption Method and Password
|
|
||||||
*
|
|
||||||
* @param object Object for comparison
|
|
||||||
* @return Object equality status
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean equals(final Object object) {
|
|
||||||
boolean equals = false;
|
|
||||||
if (this == object) {
|
|
||||||
equals = true;
|
|
||||||
} else if (object instanceof PasswordBasedCipherPropertyEncryptor) {
|
|
||||||
final PasswordBasedCipherPropertyEncryptor encryptor = (PasswordBasedCipherPropertyEncryptor) object;
|
|
||||||
equals = Objects.equals(encryptionMethod, encryptor.encryptionMethod) && Objects.equals(password, encryptor.password);
|
|
||||||
}
|
|
||||||
return equals;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return hash code based on Encryption Method and Password
|
|
||||||
*
|
|
||||||
* @return Hash Code based on Encryption Method and Password
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(encryptionMethod, password);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return String containing object description
|
|
||||||
*
|
|
||||||
* @return Object description
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -16,61 +16,40 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.nifi.encrypt;
|
package org.apache.nifi.encrypt;
|
||||||
|
|
||||||
import org.apache.nifi.security.util.EncryptionMethod;
|
|
||||||
import org.apache.nifi.security.util.KeyDerivationFunction;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property Encryption Method enumerates supported values in addition to {@link org.apache.nifi.security.util.EncryptionMethod}
|
* Property Encryption Method enumerates supported values
|
||||||
*/
|
*/
|
||||||
public enum PropertyEncryptionMethod {
|
public enum PropertyEncryptionMethod {
|
||||||
NIFI_ARGON2_AES_GCM_128(KeyDerivationFunction.ARGON2, EncryptionMethod.AES_GCM,128),
|
NIFI_ARGON2_AES_GCM_256(256),
|
||||||
|
|
||||||
NIFI_ARGON2_AES_GCM_256(KeyDerivationFunction.ARGON2, EncryptionMethod.AES_GCM, 256),
|
NIFI_PBKDF2_AES_GCM_256(256);
|
||||||
|
|
||||||
NIFI_BCRYPT_AES_GCM_128(KeyDerivationFunction.BCRYPT, EncryptionMethod.AES_GCM, 128),
|
private static final int BYTE_LENGTH_DIVISOR = 8;
|
||||||
|
|
||||||
NIFI_BCRYPT_AES_GCM_256(KeyDerivationFunction.BCRYPT, EncryptionMethod.AES_GCM, 256),
|
|
||||||
|
|
||||||
NIFI_PBKDF2_AES_GCM_128(KeyDerivationFunction.PBKDF2, EncryptionMethod.AES_GCM, 128),
|
|
||||||
|
|
||||||
NIFI_PBKDF2_AES_GCM_256(KeyDerivationFunction.PBKDF2, EncryptionMethod.AES_GCM, 256),
|
|
||||||
|
|
||||||
NIFI_SCRYPT_AES_GCM_128(KeyDerivationFunction.SCRYPT, EncryptionMethod.AES_GCM, 128),
|
|
||||||
|
|
||||||
NIFI_SCRYPT_AES_GCM_256(KeyDerivationFunction.SCRYPT, EncryptionMethod.AES_GCM, 256);
|
|
||||||
|
|
||||||
private static final int HASH_LENGTH_DIVISOR = 8;
|
|
||||||
|
|
||||||
private final KeyDerivationFunction keyDerivationFunction;
|
|
||||||
|
|
||||||
private final EncryptionMethod encryptionMethod;
|
|
||||||
|
|
||||||
private final int keyLength;
|
private final int keyLength;
|
||||||
|
|
||||||
private final int hashLength;
|
private final int derivedKeyLength;
|
||||||
|
|
||||||
PropertyEncryptionMethod(final KeyDerivationFunction keyDerivationFunction,
|
PropertyEncryptionMethod(final int keyLength) {
|
||||||
final EncryptionMethod encryptionMethod,
|
|
||||||
final int keyLength) {
|
|
||||||
this.keyDerivationFunction = keyDerivationFunction;
|
|
||||||
this.encryptionMethod = encryptionMethod;
|
|
||||||
this.keyLength = keyLength;
|
this.keyLength = keyLength;
|
||||||
this.hashLength = keyLength / HASH_LENGTH_DIVISOR;
|
this.derivedKeyLength = keyLength / BYTE_LENGTH_DIVISOR;
|
||||||
}
|
|
||||||
|
|
||||||
public KeyDerivationFunction getKeyDerivationFunction() {
|
|
||||||
return keyDerivationFunction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public EncryptionMethod getEncryptionMethod() {
|
|
||||||
return encryptionMethod;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get key length in bits
|
||||||
|
*
|
||||||
|
* @return Key length in bites
|
||||||
|
*/
|
||||||
public int getKeyLength() {
|
public int getKeyLength() {
|
||||||
return keyLength;
|
return keyLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getHashLength() {
|
/**
|
||||||
return hashLength;
|
* Get derived key length in bytes
|
||||||
|
*
|
||||||
|
* @return Derived key length in bytes
|
||||||
|
*/
|
||||||
|
public int getDerivedKeyLength() {
|
||||||
|
return derivedKeyLength;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,6 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.nifi.encrypt;
|
package org.apache.nifi.encrypt;
|
||||||
|
|
||||||
import org.apache.nifi.security.util.EncryptionMethod;
|
|
||||||
import org.apache.nifi.security.util.crypto.PBECipherProvider;
|
|
||||||
|
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@ -61,24 +58,8 @@ public class PropertyEncryptorBuilder {
|
||||||
*/
|
*/
|
||||||
public PropertyEncryptor build() {
|
public PropertyEncryptor build() {
|
||||||
final PropertyEncryptionMethod propertyEncryptionMethod = findPropertyEncryptionAlgorithm(algorithm);
|
final PropertyEncryptionMethod propertyEncryptionMethod = findPropertyEncryptionAlgorithm(algorithm);
|
||||||
if (propertyEncryptionMethod == null) {
|
final SecretKey secretKey = SECRET_KEY_PROVIDER.getSecretKey(propertyEncryptionMethod, password);
|
||||||
return getPasswordBasedCipherPropertyEncryptor();
|
return new KeyedCipherPropertyEncryptor(secretKey);
|
||||||
} else {
|
|
||||||
final SecretKey secretKey = SECRET_KEY_PROVIDER.getSecretKey(propertyEncryptionMethod, password);
|
|
||||||
return new KeyedCipherPropertyEncryptor(secretKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
private PasswordBasedCipherPropertyEncryptor getPasswordBasedCipherPropertyEncryptor() {
|
|
||||||
final EncryptionMethod encryptionMethod = findEncryptionMethod(algorithm);
|
|
||||||
if (encryptionMethod.isPBECipher()) {
|
|
||||||
final PBECipherProvider cipherProvider = new org.apache.nifi.security.util.crypto.NiFiLegacyCipherProvider();
|
|
||||||
return new PasswordBasedCipherPropertyEncryptor(cipherProvider, encryptionMethod, password);
|
|
||||||
} else {
|
|
||||||
final String message = String.format("Algorithm [%s] not supported for Sensitive Properties", encryptionMethod.getAlgorithm());
|
|
||||||
throw new UnsupportedOperationException(message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private PropertyEncryptionMethod findPropertyEncryptionAlgorithm(final String algorithm) {
|
private PropertyEncryptionMethod findPropertyEncryptionAlgorithm(final String algorithm) {
|
||||||
|
@ -91,15 +72,11 @@ public class PropertyEncryptorBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (foundPropertyEncryptionMethod == null) {
|
||||||
|
final String message = String.format("Algorithm [%s] not supported for Sensitive Properties", algorithm);
|
||||||
|
throw new EncryptionException(message);
|
||||||
|
}
|
||||||
|
|
||||||
return foundPropertyEncryptionMethod;
|
return foundPropertyEncryptionMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
private EncryptionMethod findEncryptionMethod(final String algorithm) {
|
|
||||||
final EncryptionMethod encryptionMethod = EncryptionMethod.forAlgorithm(algorithm);
|
|
||||||
if (encryptionMethod == null) {
|
|
||||||
final String message = String.format("Encryption Method not found for Algorithm [%s]", algorithm);
|
|
||||||
throw new IllegalArgumentException(message);
|
|
||||||
}
|
|
||||||
return encryptionMethod;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,20 +16,18 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.nifi.encrypt;
|
package org.apache.nifi.encrypt;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.nifi.security.crypto.key.DerivedKey;
|
||||||
import org.apache.nifi.security.util.KeyDerivationFunction;
|
import org.apache.nifi.security.crypto.key.DerivedKeySpec;
|
||||||
import org.apache.nifi.security.util.crypto.Argon2SecureHasher;
|
import org.apache.nifi.security.crypto.key.StandardDerivedKeySpec;
|
||||||
import org.apache.nifi.security.util.crypto.KeyDerivationBcryptSecureHasher;
|
import org.apache.nifi.security.crypto.key.argon2.Argon2DerivedKeyParameterSpec;
|
||||||
import org.apache.nifi.security.util.crypto.PBKDF2SecureHasher;
|
import org.apache.nifi.security.crypto.key.argon2.Argon2DerivedKeyProvider;
|
||||||
import org.apache.nifi.security.util.crypto.ScryptSecureHasher;
|
import org.apache.nifi.security.crypto.key.pbkdf2.Pbkdf2DerivedKeyParameterSpec;
|
||||||
import org.apache.nifi.security.util.crypto.SecureHasher;
|
import org.apache.nifi.security.crypto.key.pbkdf2.Pbkdf2DerivedKeyProvider;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,7 +36,14 @@ import java.util.Objects;
|
||||||
class StandardPropertySecretKeyProvider implements PropertySecretKeyProvider {
|
class StandardPropertySecretKeyProvider implements PropertySecretKeyProvider {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(StandardPropertySecretKeyProvider.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(StandardPropertySecretKeyProvider.class);
|
||||||
|
|
||||||
private static final Charset PASSWORD_CHARSET = StandardCharsets.UTF_8;
|
/** Standard Application Salt supporting deterministic encrypted property comparison */
|
||||||
|
private static final byte[] APPLICATION_SALT = new byte[]{'N', 'i', 'F', 'i', ' ', 'S', 't', 'a', 't', 'i', 'c', ' ', 'S', 'a', 'l', 't'};
|
||||||
|
|
||||||
|
/** Argon2 Parameter Specification configured with settings introduced in 1.12.0 */
|
||||||
|
private static final Argon2DerivedKeyParameterSpec ARGON2_PARAMETER_SPEC = new Argon2DerivedKeyParameterSpec(65536, 5, 8, APPLICATION_SALT);
|
||||||
|
|
||||||
|
/** PBKDF2 Parameter Specification configured with settings introduced in 0.5.0 */
|
||||||
|
private static final Pbkdf2DerivedKeyParameterSpec PBKDF2_PARAMETER_SPEC = new Pbkdf2DerivedKeyParameterSpec(160000, APPLICATION_SALT);
|
||||||
|
|
||||||
private static final int MINIMUM_PASSWORD_LENGTH = 12;
|
private static final int MINIMUM_PASSWORD_LENGTH = 12;
|
||||||
|
|
||||||
|
@ -46,45 +51,44 @@ class StandardPropertySecretKeyProvider implements PropertySecretKeyProvider {
|
||||||
|
|
||||||
private static final String SECRET_KEY_ALGORITHM = "AES";
|
private static final String SECRET_KEY_ALGORITHM = "AES";
|
||||||
|
|
||||||
|
private static final Argon2DerivedKeyProvider argon2DerivedKeyProvider = new Argon2DerivedKeyProvider();
|
||||||
|
|
||||||
|
private static final Pbkdf2DerivedKeyProvider pbkdf2DerivedKeyProvider = new Pbkdf2DerivedKeyProvider();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Secret Key using Property Encryption Method with provided password
|
* Get Secret Key using Property Encryption Method with provided password
|
||||||
*
|
*
|
||||||
* @param propertyEncryptionMethod Property Encryption Method
|
* @param propertyEncryptionMethod Property Encryption Method
|
||||||
* @param password Password used to derive Secret Key
|
* @param password Password used to derive Secret Key
|
||||||
* @return Derived Secret Key
|
* @return Derived Secret Key
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public SecretKey getSecretKey(final PropertyEncryptionMethod propertyEncryptionMethod, final String password) {
|
public SecretKey getSecretKey(final PropertyEncryptionMethod propertyEncryptionMethod, final String password) {
|
||||||
Objects.requireNonNull(propertyEncryptionMethod, "Property Encryption Method is required");
|
Objects.requireNonNull(propertyEncryptionMethod, "Property Encryption Method is required");
|
||||||
Objects.requireNonNull(password, "Password is required");
|
Objects.requireNonNull(password, "Password is required");
|
||||||
if (StringUtils.length(password) < MINIMUM_PASSWORD_LENGTH) {
|
if (password.length() < MINIMUM_PASSWORD_LENGTH) {
|
||||||
throw new EncryptionException(PASSWORD_LENGTH_MESSAGE);
|
throw new EncryptionException(PASSWORD_LENGTH_MESSAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
final KeyDerivationFunction keyDerivationFunction = propertyEncryptionMethod.getKeyDerivationFunction();
|
|
||||||
final int keyLength = propertyEncryptionMethod.getKeyLength();
|
final int keyLength = propertyEncryptionMethod.getKeyLength();
|
||||||
LOGGER.debug("Generating [{}-{}] Secret Key using [{}]", SECRET_KEY_ALGORITHM, keyLength, keyDerivationFunction.getKdfName());
|
LOGGER.debug("Generating [{}-{}] Secret Key using [{}]", SECRET_KEY_ALGORITHM, keyLength, propertyEncryptionMethod.name());
|
||||||
|
|
||||||
final SecureHasher secureHasher = getSecureHasher(propertyEncryptionMethod);
|
final DerivedKey derivedKey = getDerivedKey(propertyEncryptionMethod, password);
|
||||||
final byte[] passwordBinary = password.getBytes(PASSWORD_CHARSET);
|
return new SecretKeySpec(derivedKey.getEncoded(), SECRET_KEY_ALGORITHM);
|
||||||
final byte[] hash = secureHasher.hashRaw(passwordBinary);
|
|
||||||
return new SecretKeySpec(hash, SECRET_KEY_ALGORITHM);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SecureHasher getSecureHasher(final PropertyEncryptionMethod propertyEncryptionMethod) {
|
private DerivedKey getDerivedKey(final PropertyEncryptionMethod propertyEncryptionMethod, final String password) {
|
||||||
final KeyDerivationFunction keyDerivationFunction = propertyEncryptionMethod.getKeyDerivationFunction();
|
final char[] characters = password.toCharArray();
|
||||||
final int hashLength = propertyEncryptionMethod.getHashLength();
|
final int derivedKeyLength = propertyEncryptionMethod.getDerivedKeyLength();
|
||||||
|
|
||||||
if (KeyDerivationFunction.ARGON2.equals(keyDerivationFunction)) {
|
if (PropertyEncryptionMethod.NIFI_ARGON2_AES_GCM_256 == propertyEncryptionMethod) {
|
||||||
return new Argon2SecureHasher(hashLength);
|
final DerivedKeySpec<Argon2DerivedKeyParameterSpec> derivedKeySpec = new StandardDerivedKeySpec<>(characters, derivedKeyLength, SECRET_KEY_ALGORITHM, ARGON2_PARAMETER_SPEC);
|
||||||
} else if (KeyDerivationFunction.BCRYPT.equals(keyDerivationFunction)) {
|
return argon2DerivedKeyProvider.getDerivedKey(derivedKeySpec);
|
||||||
return new KeyDerivationBcryptSecureHasher(hashLength);
|
} else if (PropertyEncryptionMethod.NIFI_PBKDF2_AES_GCM_256 == propertyEncryptionMethod) {
|
||||||
} else if (KeyDerivationFunction.PBKDF2.equals(keyDerivationFunction)) {
|
final DerivedKeySpec<Pbkdf2DerivedKeyParameterSpec> derivedKeySpec = new StandardDerivedKeySpec<>(characters, derivedKeyLength, SECRET_KEY_ALGORITHM, PBKDF2_PARAMETER_SPEC);
|
||||||
return new PBKDF2SecureHasher(hashLength);
|
return pbkdf2DerivedKeyProvider.getDerivedKey(derivedKeySpec);
|
||||||
} else if (KeyDerivationFunction.SCRYPT.equals(keyDerivationFunction)) {
|
|
||||||
return new ScryptSecureHasher(hashLength);
|
|
||||||
} else {
|
} else {
|
||||||
final String message = String.format("Key Derivation Function [%s] not supported", keyDerivationFunction.getKdfName());
|
final String message = String.format("Property Encryption Method [%s] not supported", propertyEncryptionMethod);
|
||||||
throw new EncryptionException(message);
|
throw new EncryptionException(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ package org.apache.nifi.encrypt;
|
||||||
|
|
||||||
import org.apache.commons.codec.DecoderException;
|
import org.apache.commons.codec.DecoderException;
|
||||||
import org.apache.commons.codec.binary.Hex;
|
import org.apache.commons.codec.binary.Hex;
|
||||||
import org.apache.nifi.util.StringUtils;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
@ -40,7 +39,7 @@ public class KeyedCipherPropertyEncryptorTest {
|
||||||
|
|
||||||
private static final String KEY_ALGORITHM = "AES";
|
private static final String KEY_ALGORITHM = "AES";
|
||||||
|
|
||||||
private static final byte[] STATIC_KEY = StringUtils.repeat("KEY", 8).getBytes(DEFAULT_CHARSET);
|
private static final byte[] STATIC_KEY = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6};
|
||||||
|
|
||||||
private static final SecretKey SECRET_KEY = new SecretKeySpec(STATIC_KEY, KEY_ALGORITHM);
|
private static final SecretKey SECRET_KEY = new SecretKeySpec(STATIC_KEY, KEY_ALGORITHM);
|
||||||
|
|
||||||
|
|
|
@ -1,87 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.encrypt;
|
|
||||||
|
|
||||||
import org.apache.commons.codec.DecoderException;
|
|
||||||
import org.apache.commons.codec.binary.Hex;
|
|
||||||
import org.apache.nifi.security.util.EncryptionMethod;
|
|
||||||
import org.apache.nifi.security.util.crypto.PBECipherProvider;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
|
|
||||||
public class PasswordBasedCipherPropertyEncryptorTest {
|
|
||||||
private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
|
|
||||||
|
|
||||||
private static final String PROPERTY = String.class.getName();
|
|
||||||
|
|
||||||
private static final int ENCRYPTED_BINARY_LENGTH = 48;
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
private static final PBECipherProvider CIPHER_PROVIDER = new org.apache.nifi.security.util.crypto.NiFiLegacyCipherProvider();
|
|
||||||
|
|
||||||
private static final EncryptionMethod ENCRYPTION_METHOD = EncryptionMethod.MD5_256AES;
|
|
||||||
|
|
||||||
private static final String PASSWORD = String.class.getName();
|
|
||||||
|
|
||||||
private PasswordBasedCipherPropertyEncryptor encryptor;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
public void setUp() {
|
|
||||||
encryptor = new PasswordBasedCipherPropertyEncryptor(CIPHER_PROVIDER, ENCRYPTION_METHOD, PASSWORD);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEncryptDecrypt() {
|
|
||||||
final String encrypted = encryptor.encrypt(PROPERTY);
|
|
||||||
final String decrypted = encryptor.decrypt(encrypted);
|
|
||||||
assertEquals(PROPERTY, decrypted);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEncryptHexadecimalEncoded() throws DecoderException {
|
|
||||||
final String encrypted = encryptor.encrypt(PROPERTY);
|
|
||||||
final byte[] decoded = Hex.decodeHex(encrypted);
|
|
||||||
assertEquals(ENCRYPTED_BINARY_LENGTH, decoded.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDecryptEncryptionException() {
|
|
||||||
final String encodedProperty = Hex.encodeHexString(PROPERTY.getBytes(DEFAULT_CHARSET));
|
|
||||||
assertThrows(EncryptionException.class, () -> encryptor.decrypt(encodedProperty));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEqualsHashCode() {
|
|
||||||
final PasswordBasedCipherPropertyEncryptor equivalentEncryptor = new PasswordBasedCipherPropertyEncryptor(CIPHER_PROVIDER, ENCRYPTION_METHOD, PASSWORD);
|
|
||||||
assertEquals(encryptor, equivalentEncryptor);
|
|
||||||
assertEquals(encryptor.hashCode(), equivalentEncryptor.hashCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEqualsHashCodeDifferentPassword() {
|
|
||||||
final PasswordBasedCipherPropertyEncryptor differentEncryptor = new PasswordBasedCipherPropertyEncryptor(CIPHER_PROVIDER, ENCRYPTION_METHOD, String.class.getSimpleName());
|
|
||||||
assertNotEquals(encryptor, differentEncryptor);
|
|
||||||
assertNotEquals(encryptor.hashCode(), differentEncryptor.hashCode());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.encrypt;
|
|
||||||
|
|
||||||
import org.apache.nifi.security.util.EncryptionMethod;
|
|
||||||
import org.apache.nifi.util.NiFiProperties;
|
|
||||||
import org.apache.nifi.util.StringUtils;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
|
|
||||||
public class PropertyEncryptorFactoryTest {
|
|
||||||
private static final EncryptionMethod ENCRYPTION_METHOD = EncryptionMethod.MD5_256AES;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetPropertyEncryptorUnsupportedEncryptionMethod() {
|
|
||||||
final Properties properties = new Properties();
|
|
||||||
properties.setProperty(NiFiProperties.SENSITIVE_PROPS_ALGORITHM, EncryptionMethod.AES_CBC_NO_PADDING.getAlgorithm());
|
|
||||||
properties.setProperty(NiFiProperties.SENSITIVE_PROPS_KEY, String.class.getName());
|
|
||||||
final NiFiProperties niFiProperties = NiFiProperties.createBasicNiFiProperties(null, properties);
|
|
||||||
|
|
||||||
assertThrows(UnsupportedOperationException.class, () -> PropertyEncryptorFactory.getPropertyEncryptor(niFiProperties));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetPropertyEncryptorPropertiesBlankPassword() {
|
|
||||||
final Properties properties = new Properties();
|
|
||||||
properties.setProperty(NiFiProperties.SENSITIVE_PROPS_ALGORITHM, ENCRYPTION_METHOD.getAlgorithm());
|
|
||||||
properties.setProperty(NiFiProperties.SENSITIVE_PROPS_KEY, StringUtils.EMPTY);
|
|
||||||
final NiFiProperties niFiProperties = NiFiProperties.createBasicNiFiProperties(null, properties);
|
|
||||||
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> PropertyEncryptorFactory.getPropertyEncryptor(niFiProperties));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetPropertyEncryptorPropertiesKeyedCipherPropertyEncryptor() {
|
|
||||||
final Properties properties = new Properties();
|
|
||||||
properties.setProperty(NiFiProperties.SENSITIVE_PROPS_ALGORITHM, PropertyEncryptionMethod.NIFI_ARGON2_AES_GCM_256.toString());
|
|
||||||
properties.setProperty(NiFiProperties.SENSITIVE_PROPS_KEY, String.class.getName());
|
|
||||||
final NiFiProperties niFiProperties = NiFiProperties.createBasicNiFiProperties(null, properties);
|
|
||||||
|
|
||||||
final PropertyEncryptor encryptor = PropertyEncryptorFactory.getPropertyEncryptor(niFiProperties);
|
|
||||||
assertNotNull(encryptor);
|
|
||||||
assertEquals(KeyedCipherPropertyEncryptor.class, encryptor.getClass());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -42,7 +42,7 @@ public class StandardPropertySecretKeyProviderTest {
|
||||||
final SecretKey secretKey = provider.getSecretKey(propertyEncryptionMethod, SEED);
|
final SecretKey secretKey = provider.getSecretKey(propertyEncryptionMethod, SEED);
|
||||||
final int secretKeyLength = secretKey.getEncoded().length;
|
final int secretKeyLength = secretKey.getEncoded().length;
|
||||||
final String message = String.format("Method [%s] Key Length not matched", propertyEncryptionMethod);
|
final String message = String.format("Method [%s] Key Length not matched", propertyEncryptionMethod);
|
||||||
assertEquals(propertyEncryptionMethod.getHashLength(), secretKeyLength, message);
|
assertEquals(propertyEncryptionMethod.getDerivedKeyLength(), secretKeyLength, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,10 +34,8 @@ public class SecureHasherFactory {
|
||||||
|
|
||||||
static {
|
static {
|
||||||
registeredSecureHashers = new HashMap<>();
|
registeredSecureHashers = new HashMap<>();
|
||||||
registeredSecureHashers.put(KeyDerivationFunction.PBKDF2, PBKDF2SecureHasher.class);
|
|
||||||
registeredSecureHashers.put(KeyDerivationFunction.BCRYPT, BcryptSecureHasher.class);
|
|
||||||
registeredSecureHashers.put(KeyDerivationFunction.SCRYPT, ScryptSecureHasher.class);
|
|
||||||
registeredSecureHashers.put(KeyDerivationFunction.ARGON2, Argon2SecureHasher.class);
|
registeredSecureHashers.put(KeyDerivationFunction.ARGON2, Argon2SecureHasher.class);
|
||||||
|
registeredSecureHashers.put(KeyDerivationFunction.PBKDF2, PBKDF2SecureHasher.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SecureHasher getSecureHasher(final String algorithm) {
|
public static SecureHasher getSecureHasher(final String algorithm) {
|
||||||
|
|
|
@ -26,46 +26,22 @@ public class SecureHasherFactoryTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSecureHasherFactoryArgon2() {
|
public void testSecureHasherFactoryArgon2() {
|
||||||
SecureHasher hasher = SecureHasherFactory.getSecureHasher("NIFI_ARGON2_AES_GCM_128");
|
SecureHasher hasher = SecureHasherFactory.getSecureHasher("NIFI_ARGON2_AES_GCM_256");
|
||||||
assertEquals(Argon2SecureHasher.class, hasher.getClass());
|
assertEquals(Argon2SecureHasher.class, hasher.getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSecureHasherFactoryPBKDF2() {
|
public void testSecureHasherFactoryPBKDF2() {
|
||||||
SecureHasher hasher = SecureHasherFactory.getSecureHasher("NIFI_PBKDF2_AES_GCM_128");
|
SecureHasher hasher = SecureHasherFactory.getSecureHasher("NIFI_PBKDF2_AES_GCM_256");
|
||||||
assertEquals(PBKDF2SecureHasher.class, hasher.getClass());
|
assertEquals(PBKDF2SecureHasher.class, hasher.getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSecureHasherFactoryBCrypt() {
|
|
||||||
SecureHasher hasher = SecureHasherFactory.getSecureHasher("NIFI_BCRYPT_AES_GCM_128");
|
|
||||||
assertEquals(BcryptSecureHasher.class, hasher.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSecureHasherFactorySCrypt() {
|
|
||||||
SecureHasher hasher = SecureHasherFactory.getSecureHasher("NIFI_SCRYPT_AES_GCM_128");
|
|
||||||
assertEquals(ScryptSecureHasher.class, hasher.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSecureHasherFactoryArgon2ShortName() {
|
public void testSecureHasherFactoryArgon2ShortName() {
|
||||||
SecureHasher hasher = SecureHasherFactory.getSecureHasher("ARGON2");
|
SecureHasher hasher = SecureHasherFactory.getSecureHasher("ARGON2");
|
||||||
assertEquals(Argon2SecureHasher.class, hasher.getClass());
|
assertEquals(Argon2SecureHasher.class, hasher.getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSecureHasherFactorySCryptShortName() {
|
|
||||||
SecureHasher hasher = SecureHasherFactory.getSecureHasher("SCRYPT");
|
|
||||||
assertEquals(ScryptSecureHasher.class, hasher.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSecureHasherFactoryLowerCaseName() {
|
|
||||||
SecureHasher hasher = SecureHasherFactory.getSecureHasher("scrypt");
|
|
||||||
assertEquals(ScryptSecureHasher.class, hasher.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSecureHasherFactoryArgon2SimilarName() {
|
public void testSecureHasherFactoryArgon2SimilarName() {
|
||||||
SecureHasher hasher = SecureHasherFactory.getSecureHasher("ARGON_2");
|
SecureHasher hasher = SecureHasherFactory.getSecureHasher("ARGON_2");
|
||||||
|
|
|
@ -83,10 +83,6 @@ nifi.web.https.host=
|
||||||
nifi.web.https.port=
|
nifi.web.https.port=
|
||||||
nifi.web.jetty.working.directory=./target/work/jetty
|
nifi.web.jetty.working.directory=./target/work/jetty
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=key
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
|
|
||||||
nifi.security.keystore=
|
nifi.security.keystore=
|
||||||
nifi.security.keystoreType=
|
nifi.security.keystoreType=
|
||||||
nifi.security.keystorePasswd=
|
nifi.security.keystorePasswd=
|
||||||
|
|
|
@ -68,10 +68,6 @@ nifi.web.https.host=
|
||||||
nifi.web.https.port=
|
nifi.web.https.port=
|
||||||
nifi.web.jetty.working.directory=./target/work/jetty
|
nifi.web.jetty.working.directory=./target/work/jetty
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=key
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
|
|
||||||
nifi.security.keystore=
|
nifi.security.keystore=
|
||||||
nifi.security.keystoreType=
|
nifi.security.keystoreType=
|
||||||
nifi.security.keystorePasswd=
|
nifi.security.keystorePasswd=
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.nifi.encrypt;
|
package org.apache.nifi.encrypt;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.apache.nifi.util.NiFiProperties;
|
import org.apache.nifi.util.NiFiProperties;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -38,7 +37,7 @@ public class PropertyEncryptorFactory {
|
||||||
final String algorithm = properties.getProperty(NiFiProperties.SENSITIVE_PROPS_ALGORITHM);
|
final String algorithm = properties.getProperty(NiFiProperties.SENSITIVE_PROPS_ALGORITHM);
|
||||||
String password = properties.getProperty(NiFiProperties.SENSITIVE_PROPS_KEY);
|
String password = properties.getProperty(NiFiProperties.SENSITIVE_PROPS_KEY);
|
||||||
|
|
||||||
if (StringUtils.isBlank(password)) {
|
if (password == null || password.isEmpty()) {
|
||||||
throw new IllegalArgumentException(KEY_REQUIRED);
|
throw new IllegalArgumentException(KEY_REQUIRED);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,6 @@ import org.apache.nifi.controller.ReportingTaskNode;
|
||||||
import org.apache.nifi.controller.repository.FlowFileEventRepository;
|
import org.apache.nifi.controller.repository.FlowFileEventRepository;
|
||||||
import org.apache.nifi.controller.status.history.StatusHistoryRepository;
|
import org.apache.nifi.controller.status.history.StatusHistoryRepository;
|
||||||
import org.apache.nifi.encrypt.PropertyEncryptor;
|
import org.apache.nifi.encrypt.PropertyEncryptor;
|
||||||
import org.apache.nifi.encrypt.PropertyEncryptorFactory;
|
|
||||||
import org.apache.nifi.nar.ExtensionDiscoveringManager;
|
import org.apache.nifi.nar.ExtensionDiscoveringManager;
|
||||||
import org.apache.nifi.nar.StandardExtensionDiscoveringManager;
|
import org.apache.nifi.nar.StandardExtensionDiscoveringManager;
|
||||||
import org.apache.nifi.nar.SystemBundle;
|
import org.apache.nifi.nar.SystemBundle;
|
||||||
|
@ -80,7 +79,7 @@ public class TestStandardReportingContext {
|
||||||
otherProps.put("nifi.remote.input.socket.port", "");
|
otherProps.put("nifi.remote.input.socket.port", "");
|
||||||
otherProps.put("nifi.remote.input.secure", "");
|
otherProps.put("nifi.remote.input.secure", "");
|
||||||
nifiProperties = NiFiProperties.createBasicNiFiProperties(propsFile, otherProps);
|
nifiProperties = NiFiProperties.createBasicNiFiProperties(propsFile, otherProps);
|
||||||
encryptor = PropertyEncryptorFactory.getPropertyEncryptor(nifiProperties);
|
encryptor = Mockito.mock(PropertyEncryptor.class);
|
||||||
|
|
||||||
// use the system bundle
|
// use the system bundle
|
||||||
systemBundle = SystemBundle.create(nifiProperties);
|
systemBundle = SystemBundle.create(nifiProperties);
|
||||||
|
|
|
@ -27,7 +27,6 @@ import org.apache.nifi.controller.ProcessorNode;
|
||||||
import org.apache.nifi.controller.repository.FlowFileEventRepository;
|
import org.apache.nifi.controller.repository.FlowFileEventRepository;
|
||||||
import org.apache.nifi.controller.status.history.StatusHistoryRepository;
|
import org.apache.nifi.controller.status.history.StatusHistoryRepository;
|
||||||
import org.apache.nifi.encrypt.PropertyEncryptor;
|
import org.apache.nifi.encrypt.PropertyEncryptor;
|
||||||
import org.apache.nifi.encrypt.PropertyEncryptorFactory;
|
|
||||||
import org.apache.nifi.nar.ExtensionDiscoveringManager;
|
import org.apache.nifi.nar.ExtensionDiscoveringManager;
|
||||||
import org.apache.nifi.nar.StandardExtensionDiscoveringManager;
|
import org.apache.nifi.nar.StandardExtensionDiscoveringManager;
|
||||||
import org.apache.nifi.nar.SystemBundle;
|
import org.apache.nifi.nar.SystemBundle;
|
||||||
|
@ -88,7 +87,7 @@ public class StandardFlowSerializerTest {
|
||||||
otherProps.put("nifi.remote.input.socket.port", "");
|
otherProps.put("nifi.remote.input.socket.port", "");
|
||||||
otherProps.put("nifi.remote.input.secure", "");
|
otherProps.put("nifi.remote.input.secure", "");
|
||||||
final NiFiProperties nifiProperties = NiFiProperties.createBasicNiFiProperties(propsFile, otherProps);
|
final NiFiProperties nifiProperties = NiFiProperties.createBasicNiFiProperties(propsFile, otherProps);
|
||||||
final PropertyEncryptor encryptor = PropertyEncryptorFactory.getPropertyEncryptor(nifiProperties);
|
final PropertyEncryptor encryptor = Mockito.mock(PropertyEncryptor.class);
|
||||||
|
|
||||||
// use the system bundle
|
// use the system bundle
|
||||||
systemBundle = SystemBundle.create(nifiProperties);
|
systemBundle = SystemBundle.create(nifiProperties);
|
||||||
|
|
|
@ -70,10 +70,6 @@ nifi.web.https.host=
|
||||||
nifi.web.https.port=
|
nifi.web.https.port=
|
||||||
nifi.web.jetty.working.directory=./target/work/jetty
|
nifi.web.jetty.working.directory=./target/work/jetty
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=key
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
|
|
||||||
nifi.security.keystore=
|
nifi.security.keystore=
|
||||||
nifi.security.keystoreType=
|
nifi.security.keystoreType=
|
||||||
nifi.security.keystorePasswd=
|
nifi.security.keystorePasswd=
|
||||||
|
|
|
@ -77,8 +77,8 @@ nifi.web.https.port=
|
||||||
nifi.web.jetty.working.directory=./target/flowcontrollertest/work/jetty
|
nifi.web.jetty.working.directory=./target/flowcontrollertest/work/jetty
|
||||||
|
|
||||||
# security properties #
|
# security properties #
|
||||||
nifi.sensitive.props.key=key
|
nifi.sensitive.props.key=SENSITIVE_PROPS_KEY
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM
|
||||||
|
|
||||||
nifi.security.keystore=
|
nifi.security.keystore=
|
||||||
nifi.security.keystoreType=
|
nifi.security.keystoreType=
|
||||||
|
|
|
@ -141,12 +141,6 @@ nifi.web.max.header.size=16 KB
|
||||||
nifi.web.proxy.context.path=
|
nifi.web.proxy.context.path=
|
||||||
nifi.web.proxy.host=
|
nifi.web.proxy.host=
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=
|
|
||||||
nifi.sensitive.props.key.protected=
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
nifi.sensitive.props.additional.keys=
|
|
||||||
|
|
||||||
nifi.security.keystore=
|
nifi.security.keystore=
|
||||||
nifi.security.keystoreType=
|
nifi.security.keystoreType=
|
||||||
nifi.security.keystorePasswd=
|
nifi.security.keystorePasswd=
|
||||||
|
|
|
@ -141,12 +141,6 @@ nifi.web.max.header.size=16 KB
|
||||||
nifi.web.proxy.context.path=
|
nifi.web.proxy.context.path=
|
||||||
nifi.web.proxy.host=
|
nifi.web.proxy.host=
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=
|
|
||||||
nifi.sensitive.props.key.protected=
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
nifi.sensitive.props.additional.keys=
|
|
||||||
|
|
||||||
nifi.security.keystore=
|
nifi.security.keystore=
|
||||||
nifi.security.keystoreType=
|
nifi.security.keystoreType=
|
||||||
nifi.security.keystorePasswd=
|
nifi.security.keystorePasswd=
|
||||||
|
|
|
@ -74,8 +74,8 @@ nifi.web.https.port=
|
||||||
nifi.web.jetty.working.directory=./target/lifecycletest/work/jetty
|
nifi.web.jetty.working.directory=./target/lifecycletest/work/jetty
|
||||||
|
|
||||||
# security properties #
|
# security properties #
|
||||||
nifi.sensitive.props.key=key
|
nifi.sensitive.props.key=SENSITIVE_PROPS_KEY
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM
|
||||||
|
|
||||||
nifi.security.keystore=
|
nifi.security.keystore=
|
||||||
nifi.security.keystoreType=
|
nifi.security.keystoreType=
|
||||||
|
|
|
@ -69,8 +69,8 @@ nifi.web.https.port=
|
||||||
nifi.web.jetty.working.directory=./target/work/jetty
|
nifi.web.jetty.working.directory=./target/work/jetty
|
||||||
|
|
||||||
# security properties #
|
# security properties #
|
||||||
nifi.sensitive.props.key=key
|
nifi.sensitive.props.key=SENSITIVE_PROPS_KEY
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM
|
||||||
|
|
||||||
nifi.security.keystore=
|
nifi.security.keystore=
|
||||||
nifi.security.keystoreType=
|
nifi.security.keystoreType=
|
||||||
|
|
|
@ -74,8 +74,8 @@ nifi.web.https.port=
|
||||||
nifi.web.jetty.working.directory=./target/standardflowserializertest/work/jetty
|
nifi.web.jetty.working.directory=./target/standardflowserializertest/work/jetty
|
||||||
|
|
||||||
# security properties #
|
# security properties #
|
||||||
nifi.sensitive.props.key=key
|
nifi.sensitive.props.key=SENSITIVE_PROPS_KEY
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM
|
||||||
|
|
||||||
nifi.security.keystore=
|
nifi.security.keystore=
|
||||||
nifi.security.keystoreType=
|
nifi.security.keystoreType=
|
||||||
|
|
|
@ -74,8 +74,8 @@ nifi.web.https.port=
|
||||||
nifi.web.jetty.working.directory=./target/standardflowsynchronizerspec/work/jetty
|
nifi.web.jetty.working.directory=./target/standardflowsynchronizerspec/work/jetty
|
||||||
|
|
||||||
# security properties #
|
# security properties #
|
||||||
nifi.sensitive.props.key=key
|
nifi.sensitive.props.key=SENSITIVE_PROPS_KEY
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM
|
||||||
|
|
||||||
nifi.security.keystore=
|
nifi.security.keystore=
|
||||||
nifi.security.keystoreType=
|
nifi.security.keystoreType=
|
||||||
|
|
|
@ -74,8 +74,8 @@ nifi.web.https.port=
|
||||||
nifi.web.jetty.working.directory=./target/standardprocessschedulertest/work/jetty
|
nifi.web.jetty.working.directory=./target/standardprocessschedulertest/work/jetty
|
||||||
|
|
||||||
# security properties #
|
# security properties #
|
||||||
nifi.sensitive.props.key=key
|
nifi.sensitive.props.key=SENSITIVE_PROPS_KEY
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM
|
||||||
|
|
||||||
nifi.security.keystore=
|
nifi.security.keystore=
|
||||||
nifi.security.keystoreType=
|
nifi.security.keystoreType=
|
||||||
|
|
|
@ -71,10 +71,6 @@ nifi.web.https.host=
|
||||||
nifi.web.https.port=
|
nifi.web.https.port=
|
||||||
nifi.web.jetty.working.directory=./target/work/jetty
|
nifi.web.jetty.working.directory=./target/work/jetty
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=key
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
|
|
||||||
nifi.security.keystore=
|
nifi.security.keystore=
|
||||||
nifi.security.keystoreType=
|
nifi.security.keystoreType=
|
||||||
nifi.security.keystorePasswd=
|
nifi.security.keystorePasswd=
|
||||||
|
|
|
@ -71,10 +71,6 @@ nifi.web.https.host=
|
||||||
nifi.web.https.port=
|
nifi.web.https.port=
|
||||||
nifi.web.jetty.working.directory=./target/work/jetty
|
nifi.web.jetty.working.directory=./target/work/jetty
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=key
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
|
|
||||||
nifi.security.keystore=
|
nifi.security.keystore=
|
||||||
nifi.security.keystoreType=
|
nifi.security.keystoreType=
|
||||||
nifi.security.keystorePasswd=
|
nifi.security.keystorePasswd=
|
||||||
|
|
|
@ -71,10 +71,6 @@ nifi.web.https.host=
|
||||||
nifi.web.https.port=
|
nifi.web.https.port=
|
||||||
nifi.web.jetty.working.directory=./target/work/jetty
|
nifi.web.jetty.working.directory=./target/work/jetty
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=key
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
|
|
||||||
nifi.security.keystore=
|
nifi.security.keystore=
|
||||||
nifi.security.keystoreType=
|
nifi.security.keystoreType=
|
||||||
nifi.security.keystorePasswd=
|
nifi.security.keystorePasswd=
|
||||||
|
|
|
@ -71,10 +71,6 @@ nifi.web.https.host=
|
||||||
nifi.web.https.port=
|
nifi.web.https.port=
|
||||||
nifi.web.jetty.working.directory=./target/work/jetty
|
nifi.web.jetty.working.directory=./target/work/jetty
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=key
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
|
|
||||||
nifi.security.keystore=
|
nifi.security.keystore=
|
||||||
nifi.security.keystoreType=
|
nifi.security.keystoreType=
|
||||||
nifi.security.keystorePasswd=
|
nifi.security.keystorePasswd=
|
||||||
|
|
|
@ -129,12 +129,6 @@ nifi.web.https.port=
|
||||||
nifi.web.jetty.working.directory=./work/jetty
|
nifi.web.jetty.working.directory=./work/jetty
|
||||||
nifi.web.jetty.threads=200
|
nifi.web.jetty.threads=200
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=
|
|
||||||
nifi.sensitive.props.key.protected=
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
nifi.sensitive.props.additional.keys=
|
|
||||||
|
|
||||||
nifi.security.keystore=
|
nifi.security.keystore=
|
||||||
nifi.security.keystoreType=
|
nifi.security.keystoreType=
|
||||||
nifi.security.keystorePasswd=
|
nifi.security.keystorePasswd=
|
||||||
|
|
|
@ -43,7 +43,7 @@ import org.apache.nifi.diagnostics.DiagnosticsFactory;
|
||||||
import org.apache.nifi.diagnostics.ThreadDumpTask;
|
import org.apache.nifi.diagnostics.ThreadDumpTask;
|
||||||
import org.apache.nifi.diagnostics.bootstrap.BootstrapDiagnosticsFactory;
|
import org.apache.nifi.diagnostics.bootstrap.BootstrapDiagnosticsFactory;
|
||||||
import org.apache.nifi.encrypt.PropertyEncryptor;
|
import org.apache.nifi.encrypt.PropertyEncryptor;
|
||||||
import org.apache.nifi.encrypt.PropertyEncryptorFactory;
|
import org.apache.nifi.encrypt.PropertyEncryptorBuilder;
|
||||||
import org.apache.nifi.events.VolatileBulletinRepository;
|
import org.apache.nifi.events.VolatileBulletinRepository;
|
||||||
import org.apache.nifi.nar.ExtensionManagerHolder;
|
import org.apache.nifi.nar.ExtensionManagerHolder;
|
||||||
import org.apache.nifi.nar.ExtensionMapping;
|
import org.apache.nifi.nar.ExtensionMapping;
|
||||||
|
@ -127,7 +127,9 @@ public class HeadlessNiFiServer implements NiFiServer {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PropertyEncryptor encryptor = PropertyEncryptorFactory.getPropertyEncryptor(props);
|
final String propertiesKey = props.getProperty(NiFiProperties.SENSITIVE_PROPS_KEY);
|
||||||
|
final String propertiesAlgorithm = props.getProperty(NiFiProperties.SENSITIVE_PROPS_ALGORITHM);
|
||||||
|
final PropertyEncryptor encryptor = new PropertyEncryptorBuilder(propertiesKey).setAlgorithm(propertiesAlgorithm).build();
|
||||||
VariableRegistry variableRegistry = new FileBasedVariableRegistry(props.getVariableRegistryPropertiesPaths());
|
VariableRegistry variableRegistry = new FileBasedVariableRegistry(props.getVariableRegistryPropertiesPaths());
|
||||||
BulletinRepository bulletinRepository = new VolatileBulletinRepository();
|
BulletinRepository bulletinRepository = new VolatileBulletinRepository();
|
||||||
|
|
||||||
|
|
|
@ -129,12 +129,6 @@ nifi.web.https.port=
|
||||||
nifi.web.jetty.working.directory=./work/jetty
|
nifi.web.jetty.working.directory=./work/jetty
|
||||||
nifi.web.jetty.threads=200
|
nifi.web.jetty.threads=200
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=
|
|
||||||
nifi.sensitive.props.key.protected=
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
nifi.sensitive.props.additional.keys=
|
|
||||||
|
|
||||||
nifi.security.keystore=
|
nifi.security.keystore=
|
||||||
nifi.security.keystoreType=
|
nifi.security.keystoreType=
|
||||||
nifi.security.keystorePasswd=
|
nifi.security.keystorePasswd=
|
||||||
|
|
|
@ -132,7 +132,7 @@ nifi.web.jetty.threads=200
|
||||||
# security properties #
|
# security properties #
|
||||||
nifi.sensitive.props.key=dQU402Mz4J+t+e18||6+ictR0Nssq3/rR/d8fq5CFAKmpakr9jCyPIJYxG7n6D86gxsu2TRp4M48ugUw==
|
nifi.sensitive.props.key=dQU402Mz4J+t+e18||6+ictR0Nssq3/rR/d8fq5CFAKmpakr9jCyPIJYxG7n6D86gxsu2TRp4M48ugUw==
|
||||||
nifi.sensitive.props.key.protected=aes/gcm/256
|
nifi.sensitive.props.key.protected=aes/gcm/256
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM_256
|
||||||
nifi.sensitive.props.additional.keys=nifi.ui.banner.text
|
nifi.sensitive.props.additional.keys=nifi.ui.banner.text
|
||||||
|
|
||||||
nifi.security.keystore=/path/to/keystore.jks
|
nifi.security.keystore=/path/to/keystore.jks
|
||||||
|
|
|
@ -128,11 +128,6 @@ nifi.web.https.port=
|
||||||
nifi.web.jetty.working.directory=./target/work/jetty
|
nifi.web.jetty.working.directory=./target/work/jetty
|
||||||
nifi.web.jetty.threads=200
|
nifi.web.jetty.threads=200
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
nifi.sensitive.props.additional.keys=
|
|
||||||
|
|
||||||
nifi.security.keystore=
|
nifi.security.keystore=
|
||||||
nifi.security.keystoreType=
|
nifi.security.keystoreType=
|
||||||
nifi.security.keystorePasswd=
|
nifi.security.keystorePasswd=
|
||||||
|
|
|
@ -34,8 +34,6 @@ nifi.flowcontroller.graceful.shutdown.seconds=10
|
||||||
nifi.nar.library.directory=./lib
|
nifi.nar.library.directory=./lib
|
||||||
nifi.nar.working.directory=./work/nar/
|
nifi.nar.working.directory=./work/nar/
|
||||||
nifi.flowservice.writedelay.seconds=2
|
nifi.flowservice.writedelay.seconds=2
|
||||||
nifi.sensitive.props.key=REPLACE_ME
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
nifi.h2.repository.maxmemoryrows=100000
|
nifi.h2.repository.maxmemoryrows=100000
|
||||||
nifi.h2.url.append=;LOCK_TIMEOUT=25000;WRITE_DELAY=0;AUTO_SERVER=FALSE
|
nifi.h2.url.append=;LOCK_TIMEOUT=25000;WRITE_DELAY=0;AUTO_SERVER=FALSE
|
||||||
nifi.h2.max.connections=20
|
nifi.h2.max.connections=20
|
||||||
|
|
|
@ -84,10 +84,6 @@ nifi.web.https.host=
|
||||||
nifi.web.https.port=8443
|
nifi.web.https.port=8443
|
||||||
nifi.web.jetty.working.directory=target/test-classes/access-control/jetty
|
nifi.web.jetty.working.directory=target/test-classes/access-control/jetty
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=REPLACE_ME
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
|
|
||||||
nifi.security.keystore=target/test-classes/access-control/keystore.jks
|
nifi.security.keystore=target/test-classes/access-control/keystore.jks
|
||||||
nifi.security.keystoreType=JKS
|
nifi.security.keystoreType=JKS
|
||||||
nifi.security.keystorePasswd=passwordpassword
|
nifi.security.keystorePasswd=passwordpassword
|
||||||
|
|
|
@ -84,10 +84,6 @@ nifi.web.https.host=
|
||||||
nifi.web.https.port=8443
|
nifi.web.https.port=8443
|
||||||
nifi.web.jetty.working.directory=target/test-classes/access-control/jetty
|
nifi.web.jetty.working.directory=target/test-classes/access-control/jetty
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=REPLACE_ME
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
|
|
||||||
nifi.security.keystore=target/test-classes/access-control/keystore.jks
|
nifi.security.keystore=target/test-classes/access-control/keystore.jks
|
||||||
nifi.security.keystoreType=JKS
|
nifi.security.keystoreType=JKS
|
||||||
nifi.security.keystorePasswd=passwordpassword
|
nifi.security.keystorePasswd=passwordpassword
|
||||||
|
|
|
@ -90,10 +90,6 @@ nifi.web.https.host=
|
||||||
nifi.web.https.port=8443
|
nifi.web.https.port=8443
|
||||||
nifi.web.jetty.working.directory=target/test-classes/access-control/jetty
|
nifi.web.jetty.working.directory=target/test-classes/access-control/jetty
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=REPLACE_ME
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
|
|
||||||
nifi.security.keystore=target/test-classes/access-control/keystore.jks
|
nifi.security.keystore=target/test-classes/access-control/keystore.jks
|
||||||
nifi.security.keystoreType=JKS
|
nifi.security.keystoreType=JKS
|
||||||
nifi.security.keystorePasswd=passwordpassword
|
nifi.security.keystorePasswd=passwordpassword
|
||||||
|
|
|
@ -84,10 +84,6 @@ nifi.web.https.host=
|
||||||
nifi.web.https.port=8443
|
nifi.web.https.port=8443
|
||||||
nifi.web.jetty.working.directory=target/test-classes/access-control/jetty
|
nifi.web.jetty.working.directory=target/test-classes/access-control/jetty
|
||||||
|
|
||||||
# security properties #
|
|
||||||
nifi.sensitive.props.key=REPLACE_ME
|
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
|
||||||
|
|
||||||
nifi.security.keystore=target/test-classes/access-control/keystore.jks
|
nifi.security.keystore=target/test-classes/access-control/keystore.jks
|
||||||
nifi.security.keystoreType=JKS
|
nifi.security.keystoreType=JKS
|
||||||
nifi.security.keystorePasswd=passwordpassword
|
nifi.security.keystorePasswd=passwordpassword
|
||||||
|
|
|
@ -19,7 +19,7 @@ package org.apache.nifi.tests.system.clustering;
|
||||||
import org.apache.nifi.controller.serialization.FlowEncodingVersion;
|
import org.apache.nifi.controller.serialization.FlowEncodingVersion;
|
||||||
import org.apache.nifi.controller.serialization.FlowFromDOMFactory;
|
import org.apache.nifi.controller.serialization.FlowFromDOMFactory;
|
||||||
import org.apache.nifi.encrypt.PropertyEncryptor;
|
import org.apache.nifi.encrypt.PropertyEncryptor;
|
||||||
import org.apache.nifi.encrypt.PropertyEncryptorFactory;
|
import org.apache.nifi.encrypt.PropertyEncryptorBuilder;
|
||||||
import org.apache.nifi.tests.system.InstanceConfiguration;
|
import org.apache.nifi.tests.system.InstanceConfiguration;
|
||||||
import org.apache.nifi.tests.system.NiFiInstance;
|
import org.apache.nifi.tests.system.NiFiInstance;
|
||||||
import org.apache.nifi.tests.system.NiFiInstanceFactory;
|
import org.apache.nifi.tests.system.NiFiInstanceFactory;
|
||||||
|
@ -246,7 +246,10 @@ public class JoinClusterWithDifferentFlow extends NiFiSystemIT {
|
||||||
|
|
||||||
private PropertyEncryptor createEncryptorFromProperties(Properties properties) {
|
private PropertyEncryptor createEncryptorFromProperties(Properties properties) {
|
||||||
final NiFiProperties niFiProperties = NiFiProperties.createBasicNiFiProperties(null, properties);
|
final NiFiProperties niFiProperties = NiFiProperties.createBasicNiFiProperties(null, properties);
|
||||||
return PropertyEncryptorFactory.getPropertyEncryptor(niFiProperties);
|
|
||||||
|
final String propertiesKey = niFiProperties.getProperty(NiFiProperties.SENSITIVE_PROPS_KEY);
|
||||||
|
final String propertiesAlgorithm = niFiProperties.getProperty(NiFiProperties.SENSITIVE_PROPS_ALGORITHM);
|
||||||
|
return new PropertyEncryptorBuilder(propertiesKey).setAlgorithm(propertiesAlgorithm).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String readFlow(final File file) throws IOException {
|
private String readFlow(final File file) throws IOException {
|
||||||
|
|
|
@ -30,7 +30,7 @@ import org.apache.commons.cli.Options
|
||||||
import org.apache.commons.cli.ParseException
|
import org.apache.commons.cli.ParseException
|
||||||
import org.apache.commons.codec.binary.Hex
|
import org.apache.commons.codec.binary.Hex
|
||||||
import org.apache.nifi.encrypt.PropertyEncryptor
|
import org.apache.nifi.encrypt.PropertyEncryptor
|
||||||
import org.apache.nifi.encrypt.PropertyEncryptorFactory
|
import org.apache.nifi.encrypt.PropertyEncryptorBuilder
|
||||||
import org.apache.nifi.flow.encryptor.FlowEncryptor
|
import org.apache.nifi.flow.encryptor.FlowEncryptor
|
||||||
import org.apache.nifi.flow.encryptor.StandardFlowEncryptor
|
import org.apache.nifi.flow.encryptor.StandardFlowEncryptor
|
||||||
import org.apache.nifi.properties.scheme.ProtectionScheme
|
import org.apache.nifi.properties.scheme.ProtectionScheme
|
||||||
|
@ -205,7 +205,7 @@ class ConfigEncryptionTool {
|
||||||
private static final String XML_DECLARATION_REGEX = /<\?xml version="1.0" encoding="UTF-8"\?>/
|
private static final String XML_DECLARATION_REGEX = /<\?xml version="1.0" encoding="UTF-8"\?>/
|
||||||
private static final String WRAPPED_FLOW_XML_CIPHER_TEXT_REGEX = /enc\{[a-fA-F0-9]+?\}/
|
private static final String WRAPPED_FLOW_XML_CIPHER_TEXT_REGEX = /enc\{[a-fA-F0-9]+?\}/
|
||||||
|
|
||||||
private static final String DEFAULT_FLOW_ALGORITHM = "PBEWITHMD5AND256BITAES-CBC-OPENSSL"
|
private static final String DEFAULT_FLOW_ALGORITHM = "NIFI_PBKDF2_AES_GCM_256"
|
||||||
|
|
||||||
private static final Map<String, String> PROPERTY_KEY_MAP = [
|
private static final Map<String, String> PROPERTY_KEY_MAP = [
|
||||||
"nifi.security.keystore" : "keystore",
|
"nifi.security.keystore" : "keystore",
|
||||||
|
@ -711,7 +711,7 @@ class ConfigEncryptionTool {
|
||||||
* @param flowXmlContent the original flow.xml.gz as an input stream
|
* @param flowXmlContent the original flow.xml.gz as an input stream
|
||||||
* @param existingFlowPassword the existing value of nifi.sensitive.props.key (not a raw key, but rather a password)
|
* @param existingFlowPassword the existing value of nifi.sensitive.props.key (not a raw key, but rather a password)
|
||||||
* @param newFlowPassword the password to use to for encryption (not a raw key, but rather a password)
|
* @param newFlowPassword the password to use to for encryption (not a raw key, but rather a password)
|
||||||
* @param existingAlgorithm the KDF algorithm to use (defaults to PBEWITHMD5AND256BITAES-CBC-OPENSSL)
|
* @param existingAlgorithm the KDF algorithm to use
|
||||||
* @param existingProvider the {@link java.security.Provider} to use (defaults to BC)
|
* @param existingProvider the {@link java.security.Provider} to use (defaults to BC)
|
||||||
* @return the encrypted XML content as an InputStream
|
* @return the encrypted XML content as an InputStream
|
||||||
*/
|
*/
|
||||||
|
@ -719,18 +719,8 @@ class ConfigEncryptionTool {
|
||||||
File tempFlowXmlFile = new File(getTemporaryFlowXmlFile(outputFlowXmlPath).toString())
|
File tempFlowXmlFile = new File(getTemporaryFlowXmlFile(outputFlowXmlPath).toString())
|
||||||
final OutputStream flowOutputStream = getFlowOutputStream(tempFlowXmlFile, flowXmlContent instanceof GZIPInputStream)
|
final OutputStream flowOutputStream = getFlowOutputStream(tempFlowXmlFile, flowXmlContent instanceof GZIPInputStream)
|
||||||
|
|
||||||
NiFiProperties inputProperties = NiFiProperties.createBasicNiFiProperties("", [
|
final PropertyEncryptor inputEncryptor = new PropertyEncryptorBuilder(existingFlowPassword).setAlgorithm(existingAlgorithm).build()
|
||||||
(NiFiProperties.SENSITIVE_PROPS_KEY): existingFlowPassword,
|
final PropertyEncryptor outputEncryptor = new PropertyEncryptorBuilder(newFlowPassword).setAlgorithm(newAlgorithm).build()
|
||||||
(NiFiProperties.SENSITIVE_PROPS_ALGORITHM): existingAlgorithm
|
|
||||||
])
|
|
||||||
|
|
||||||
NiFiProperties outputProperties = NiFiProperties.createBasicNiFiProperties("", [
|
|
||||||
(NiFiProperties.SENSITIVE_PROPS_KEY): newFlowPassword,
|
|
||||||
(NiFiProperties.SENSITIVE_PROPS_ALGORITHM): newAlgorithm
|
|
||||||
])
|
|
||||||
|
|
||||||
final PropertyEncryptor inputEncryptor = PropertyEncryptorFactory.getPropertyEncryptor(inputProperties)
|
|
||||||
final PropertyEncryptor outputEncryptor = PropertyEncryptorFactory.getPropertyEncryptor(outputProperties)
|
|
||||||
|
|
||||||
final FlowEncryptor flowEncryptor = new StandardFlowEncryptor()
|
final FlowEncryptor flowEncryptor = new StandardFlowEncryptor()
|
||||||
flowEncryptor.processFlow(flowXmlContent, flowOutputStream, inputEncryptor, outputEncryptor)
|
flowEncryptor.processFlow(flowXmlContent, flowOutputStream, inputEncryptor, outputEncryptor)
|
||||||
|
|
|
@ -22,12 +22,10 @@ import org.apache.commons.cli.CommandLineParser
|
||||||
import org.apache.commons.cli.DefaultParser
|
import org.apache.commons.cli.DefaultParser
|
||||||
import org.apache.commons.io.IOUtils
|
import org.apache.commons.io.IOUtils
|
||||||
import org.apache.commons.lang3.SystemUtils
|
import org.apache.commons.lang3.SystemUtils
|
||||||
import org.apache.nifi.security.util.EncryptionMethod
|
|
||||||
import org.apache.nifi.toolkit.tls.commandLine.CommandLineParseException
|
import org.apache.nifi.toolkit.tls.commandLine.CommandLineParseException
|
||||||
import org.apache.nifi.util.NiFiProperties
|
import org.apache.nifi.util.NiFiProperties
|
||||||
import org.apache.nifi.util.console.TextDevice
|
import org.apache.nifi.util.console.TextDevice
|
||||||
import org.apache.nifi.util.console.TextDevices
|
import org.apache.nifi.util.console.TextDevices
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.AfterClass
|
import org.junit.AfterClass
|
||||||
import org.junit.Assume
|
import org.junit.Assume
|
||||||
|
@ -52,7 +50,6 @@ import java.nio.charset.StandardCharsets
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.attribute.PosixFilePermission
|
import java.nio.file.attribute.PosixFilePermission
|
||||||
import java.security.KeyException
|
import java.security.KeyException
|
||||||
import java.security.Security
|
|
||||||
|
|
||||||
@RunWith(JUnit4.class)
|
@RunWith(JUnit4.class)
|
||||||
class ConfigEncryptionToolTest extends GroovyLogTestCase {
|
class ConfigEncryptionToolTest extends GroovyLogTestCase {
|
||||||
|
@ -71,7 +68,6 @@ class ConfigEncryptionToolTest extends GroovyLogTestCase {
|
||||||
private static final String KEY_HEX_256 = KEY_HEX_128 * 2
|
private static final String KEY_HEX_256 = KEY_HEX_128 * 2
|
||||||
public static final String KEY_HEX = isUnlimitedStrengthCryptoAvailable() ? KEY_HEX_256 : KEY_HEX_128
|
public static final String KEY_HEX = isUnlimitedStrengthCryptoAvailable() ? KEY_HEX_256 : KEY_HEX_128
|
||||||
private static final String PASSWORD = "thisIsABadPassword"
|
private static final String PASSWORD = "thisIsABadPassword"
|
||||||
private static final String ANOTHER_PASSWORD = "thisIsAnotherBadPassword"
|
|
||||||
|
|
||||||
private static final SensitivePropertyProviderFactory DEFAULT_PROVIDER_FACTORY = StandardSensitivePropertyProviderFactory.withKey(KEY_HEX)
|
private static final SensitivePropertyProviderFactory DEFAULT_PROVIDER_FACTORY = StandardSensitivePropertyProviderFactory.withKey(KEY_HEX)
|
||||||
|
|
||||||
|
@ -95,14 +91,11 @@ class ConfigEncryptionToolTest extends GroovyLogTestCase {
|
||||||
private final String PASSWORD_PROP_REGEX = "<property[^>]* name=\".* Password\""
|
private final String PASSWORD_PROP_REGEX = "<property[^>]* name=\".* Password\""
|
||||||
private final String SECRET_PROP_REGEX = "<property[^>]* name=\".* Secret\""
|
private final String SECRET_PROP_REGEX = "<property[^>]* name=\".* Secret\""
|
||||||
|
|
||||||
private static final EncryptionMethod DEFAULT_ENCRYPTION_METHOD = EncryptionMethod.MD5_256AES
|
|
||||||
private static final String WFXCTR = ConfigEncryptionTool.WRAPPED_FLOW_XML_CIPHER_TEXT_REGEX
|
private static final String WFXCTR = ConfigEncryptionTool.WRAPPED_FLOW_XML_CIPHER_TEXT_REGEX
|
||||||
private final String DEFAULT_LEGACY_SENSITIVE_PROPS_KEY = "nififtw!"
|
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
static void setUpOnce() throws Exception {
|
static void setUpOnce() throws Exception {
|
||||||
Assume.assumeTrue("Test only runs on *nix", !SystemUtils.IS_OS_WINDOWS)
|
Assume.assumeTrue("Test only runs on *nix", !SystemUtils.IS_OS_WINDOWS)
|
||||||
Security.addProvider(new BouncyCastleProvider())
|
|
||||||
|
|
||||||
logger.metaClass.methodMissing = { String name, args ->
|
logger.metaClass.methodMissing = { String name, args ->
|
||||||
logger.info("[${name?.toUpperCase()}] ${(args as List).join(" ")}")
|
logger.info("[${name?.toUpperCase()}] ${(args as List).join(" ")}")
|
||||||
|
@ -3410,800 +3403,6 @@ class ConfigEncryptionToolTest extends GroovyLogTestCase {
|
||||||
assert msg == "In order to migrate a flow.xml.gz, a nifi.properties file must also be specified via '-n'/'--niFiProperties'." as String
|
assert msg == "In order to migrate a flow.xml.gz, a nifi.properties file must also be specified via '-n'/'--niFiProperties'." as String
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Test different algs/providers
|
|
||||||
// TODO: Test reading sensitive props key from console
|
|
||||||
// TODO: All combo scenarios
|
|
||||||
@Test
|
|
||||||
void testShouldPerformFullOperationOnFlowXmlWithoutEncryptedNiFiProperties() {
|
|
||||||
// Arrange
|
|
||||||
exit.expectSystemExitWithStatus(0)
|
|
||||||
|
|
||||||
File tmpDir = setupTmpDir()
|
|
||||||
|
|
||||||
File emptyKeyFile = new File("src/test/resources/bootstrap_with_empty_root_key.conf")
|
|
||||||
File bootstrapFile = new File("target/tmp/tmp_bootstrap.conf")
|
|
||||||
bootstrapFile.delete()
|
|
||||||
|
|
||||||
Files.copy(emptyKeyFile.toPath(), bootstrapFile.toPath())
|
|
||||||
final List<String> originalBootstrapLines = bootstrapFile.readLines()
|
|
||||||
String originalKeyLine = originalBootstrapLines.find {
|
|
||||||
it.startsWith(ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX)
|
|
||||||
}
|
|
||||||
logger.info("Original key line from bootstrap.conf: ${originalKeyLine}")
|
|
||||||
assert originalKeyLine == ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX
|
|
||||||
|
|
||||||
final String EXPECTED_KEY_LINE = ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX
|
|
||||||
|
|
||||||
// Not "handling" NFP, so update in place (not source test resource)
|
|
||||||
String niFiPropertiesTemplatePath = "src/test/resources/nifi_default.properties"
|
|
||||||
File niFiPropertiesFile = new File(niFiPropertiesTemplatePath)
|
|
||||||
|
|
||||||
File workingNiFiPropertiesFile = new File("target/tmp/tmp-nifi.properties")
|
|
||||||
workingNiFiPropertiesFile.delete()
|
|
||||||
Files.copy(niFiPropertiesFile.toPath(), workingNiFiPropertiesFile.toPath())
|
|
||||||
|
|
||||||
File flowXmlFile = new File("src/test/resources/flow.xml.gz")
|
|
||||||
File workingFlowXmlFile = new File("target/tmp/tmp-flow.xml.gz")
|
|
||||||
workingFlowXmlFile.delete()
|
|
||||||
Files.copy(flowXmlFile.toPath(), workingFlowXmlFile.toPath())
|
|
||||||
|
|
||||||
// Read the uncompressed version to compare later
|
|
||||||
File originalFlowXmlFile = new File("src/test/resources/flow.xml")
|
|
||||||
final String ORIGINAL_FLOW_XML_CONTENT = originalFlowXmlFile.text
|
|
||||||
def originalFlowCipherTexts = ORIGINAL_FLOW_XML_CONTENT.findAll(WFXCTR)
|
|
||||||
final int CIPHER_TEXT_COUNT = originalFlowCipherTexts.size()
|
|
||||||
|
|
||||||
NiFiProperties inputProperties = new NiFiPropertiesLoader().load(workingNiFiPropertiesFile)
|
|
||||||
logger.info("Loaded ${inputProperties.size()} properties from input file")
|
|
||||||
ProtectedNiFiProperties protectedInputProperties = new ProtectedNiFiProperties(inputProperties)
|
|
||||||
def originalSensitiveValues = protectedInputProperties.getSensitivePropertyKeys().collectEntries { String key -> [(key): protectedInputProperties.getProperty(key)] }
|
|
||||||
logger.info("Original sensitive values: ${originalSensitiveValues}")
|
|
||||||
|
|
||||||
String newFlowPassword = FLOW_PASSWORD
|
|
||||||
|
|
||||||
String[] args = ["-n", workingNiFiPropertiesFile.path, "-f", workingFlowXmlFile.path, "-x", "-v", "-s", newFlowPassword]
|
|
||||||
|
|
||||||
exit.checkAssertionAfterwards(new Assertion() {
|
|
||||||
void checkAssertion() {
|
|
||||||
final List<String> updatedPropertiesLines = workingNiFiPropertiesFile.readLines()
|
|
||||||
logger.info("Updated nifi.properties:")
|
|
||||||
logger.info("\n" * 2 + updatedPropertiesLines.join("\n"))
|
|
||||||
|
|
||||||
// Check that the output values for everything is the same except the sensitive props key
|
|
||||||
NiFiProperties updatedProperties = new NiFiPropertiesLoader().loadProtectedProperties(workingNiFiPropertiesFile)
|
|
||||||
assert updatedProperties.size() == inputProperties.size()
|
|
||||||
assert updatedProperties.getProperty(NiFiProperties.SENSITIVE_PROPS_KEY) == newFlowPassword
|
|
||||||
originalSensitiveValues.every { String key, String originalValue ->
|
|
||||||
if (key != NiFiProperties.SENSITIVE_PROPS_KEY) {
|
|
||||||
assert updatedProperties.getProperty(key) == originalValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that bootstrap.conf did not change
|
|
||||||
final List<String> updatedBootstrapLines = bootstrapFile.readLines()
|
|
||||||
String updatedKeyLine = updatedBootstrapLines.find {
|
|
||||||
it.startsWith(ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX)
|
|
||||||
}
|
|
||||||
logger.info("Updated key line: ${updatedKeyLine}")
|
|
||||||
|
|
||||||
assert updatedKeyLine == EXPECTED_KEY_LINE
|
|
||||||
assert originalBootstrapLines.size() == updatedBootstrapLines.size()
|
|
||||||
|
|
||||||
// Verify the flow definition
|
|
||||||
def verifyTool = new ConfigEncryptionTool()
|
|
||||||
verifyTool.isVerbose = true
|
|
||||||
InputStream updatedFlowXmlContent = verifyTool.loadFlowXml(workingFlowXmlFile.path)
|
|
||||||
|
|
||||||
// Check that the flow.xml.gz content changed
|
|
||||||
assert updatedFlowXmlContent != ORIGINAL_FLOW_XML_CONTENT
|
|
||||||
|
|
||||||
// Verify that the cipher texts decrypt correctly
|
|
||||||
logger.info("Original flow.xml.gz cipher texts: ${originalFlowCipherTexts}")
|
|
||||||
|
|
||||||
def updatedFlowCipherTexts = findFieldsInStream(updatedFlowXmlContent, WFXCTR)
|
|
||||||
logger.info("Updated flow.xml.gz cipher texts: ${updatedFlowCipherTexts}")
|
|
||||||
assert updatedFlowCipherTexts.size() == CIPHER_TEXT_COUNT
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Act
|
|
||||||
ConfigEncryptionTool.main(args)
|
|
||||||
logger.info("Invoked #main with ${args.join(" ")}")
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
|
|
||||||
// Assertions defined above
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* In this scenario, the nifi.properties is not encrypted and the flow.xml.gz is "migrated" from Key X to the same key (the default key).
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void testShouldPerformFullOperationOnFlowXmlWithSameSensitivePropsKey() {
|
|
||||||
exit.expectSystemExitWithStatus(0)
|
|
||||||
|
|
||||||
File emptyKeyFile = new File("src/test/resources/bootstrap_with_empty_root_key.conf")
|
|
||||||
File bootstrapFile = new File("target/tmp/tmp_bootstrap.conf")
|
|
||||||
bootstrapFile.delete()
|
|
||||||
|
|
||||||
Files.copy(emptyKeyFile.toPath(), bootstrapFile.toPath())
|
|
||||||
final List<String> originalBootstrapLines = bootstrapFile.readLines()
|
|
||||||
String originalKeyLine = originalBootstrapLines.find {
|
|
||||||
it.startsWith(ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX)
|
|
||||||
}
|
|
||||||
assert originalKeyLine == ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX
|
|
||||||
|
|
||||||
final String EXPECTED_KEY_LINE = ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX
|
|
||||||
|
|
||||||
// Not "handling" NFP, so update in place (not source test resource)
|
|
||||||
String niFiPropertiesTemplatePath = "src/test/resources/nifi_default.properties"
|
|
||||||
File niFiPropertiesFile = new File(niFiPropertiesTemplatePath)
|
|
||||||
|
|
||||||
File workingNiFiPropertiesFile = new File("target/tmp/tmp-nifi.properties")
|
|
||||||
workingNiFiPropertiesFile.delete()
|
|
||||||
Files.copy(niFiPropertiesFile.toPath(), workingNiFiPropertiesFile.toPath())
|
|
||||||
|
|
||||||
File flowXmlFile = new File("src/test/resources/flow_default_key.xml.gz")
|
|
||||||
File workingFlowXmlFile = new File("target/tmp/tmp-flow.xml.gz")
|
|
||||||
workingFlowXmlFile.delete()
|
|
||||||
Files.copy(flowXmlFile.toPath(), workingFlowXmlFile.toPath())
|
|
||||||
|
|
||||||
// Read the uncompressed version to compare later
|
|
||||||
File originalFlowXmlFile = new File("src/test/resources/flow_default_key.xml")
|
|
||||||
final String ORIGINAL_FLOW_XML_CONTENT = originalFlowXmlFile.text
|
|
||||||
def originalFlowCipherTexts = ORIGINAL_FLOW_XML_CONTENT.findAll(WFXCTR)
|
|
||||||
final int CIPHER_TEXT_COUNT = originalFlowCipherTexts.size()
|
|
||||||
|
|
||||||
NiFiProperties inputProperties = new NiFiPropertiesLoader().load(workingNiFiPropertiesFile)
|
|
||||||
ProtectedNiFiProperties protectedInputProperties = new ProtectedNiFiProperties(inputProperties)
|
|
||||||
def originalSensitiveValues = protectedInputProperties.getSensitivePropertyKeys().collectEntries { String key -> [(key): protectedInputProperties.getProperty(key)] }
|
|
||||||
|
|
||||||
String newFlowPassword = DEFAULT_LEGACY_SENSITIVE_PROPS_KEY
|
|
||||||
|
|
||||||
String[] args = ["-n", workingNiFiPropertiesFile.path, "-f", workingFlowXmlFile.path, "-x", "-v", "-s", newFlowPassword]
|
|
||||||
|
|
||||||
exit.checkAssertionAfterwards(new Assertion() {
|
|
||||||
void checkAssertion() {
|
|
||||||
final List<String> updatedPropertiesLines = workingNiFiPropertiesFile.readLines()
|
|
||||||
|
|
||||||
// Check that the output values for everything is the same including the sensitive props key
|
|
||||||
NiFiProperties updatedProperties = new NiFiPropertiesLoader().loadProtectedProperties(workingNiFiPropertiesFile)
|
|
||||||
assert updatedProperties.size() == inputProperties.size()
|
|
||||||
originalSensitiveValues.every { String key, String originalValue ->
|
|
||||||
assert updatedProperties.getProperty(key) == originalValue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that bootstrap.conf did not change
|
|
||||||
final List<String> updatedBootstrapLines = bootstrapFile.readLines()
|
|
||||||
String updatedKeyLine = updatedBootstrapLines.find {
|
|
||||||
it.startsWith(ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX)
|
|
||||||
}
|
|
||||||
|
|
||||||
assert updatedKeyLine == EXPECTED_KEY_LINE
|
|
||||||
assert originalBootstrapLines.size() == updatedBootstrapLines.size()
|
|
||||||
|
|
||||||
// Verify the flow definition
|
|
||||||
def verifyTool = new ConfigEncryptionTool()
|
|
||||||
verifyTool.isVerbose = true
|
|
||||||
InputStream migratedFlowXmlContent = verifyTool.loadFlowXml(workingFlowXmlFile.path)
|
|
||||||
|
|
||||||
// Check that the flow.xml.gz cipher texts did change (new salt)
|
|
||||||
assert migratedFlowXmlContent != ORIGINAL_FLOW_XML_CONTENT
|
|
||||||
|
|
||||||
// Verify that the cipher texts decrypt correctly
|
|
||||||
def migratedFlowCipherTexts = findFieldsInStream(migratedFlowXmlContent, WFXCTR)
|
|
||||||
assert migratedFlowCipherTexts.size() == CIPHER_TEXT_COUNT
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
ConfigEncryptionTool.main(args)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* In this scenario, the nifi.properties file has a sensitive key value which is already encrypted. The goal is to provide a new provide a new sensitive key value, perform the migration of the flow.xml.gz, and update nifi.properties with a new encrypted sensitive key value without modifying any other nifi.properties values.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void testShouldPerformFullOperationOnFlowXmlWithPreviouslyEncryptedNiFiProperties() {
|
|
||||||
// Arrange
|
|
||||||
exit.expectSystemExitWithStatus(0)
|
|
||||||
|
|
||||||
File tmpDir = setupTmpDir()
|
|
||||||
|
|
||||||
File passwordKeyFile = new File("src/test/resources/bootstrap_with_root_key_password_128.conf")
|
|
||||||
File bootstrapFile = new File("target/tmp/tmp_bootstrap.conf")
|
|
||||||
bootstrapFile.delete()
|
|
||||||
|
|
||||||
Files.copy(passwordKeyFile.toPath(), bootstrapFile.toPath())
|
|
||||||
final List<String> originalBootstrapLines = bootstrapFile.readLines()
|
|
||||||
String originalKeyLine = originalBootstrapLines.find {
|
|
||||||
it.startsWith(ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX)
|
|
||||||
}
|
|
||||||
final String EXPECTED_KEY_LINE = ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX + PASSWORD_KEY_HEX_128
|
|
||||||
logger.info("Original key line from bootstrap.conf: ${originalKeyLine}")
|
|
||||||
assert originalKeyLine == ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX + PASSWORD_KEY_HEX_128
|
|
||||||
|
|
||||||
// Not "handling" NFP, so update in place (not source test resource)
|
|
||||||
String niFiPropertiesTemplatePath = "src/test/resources/nifi_with_few_sensitive_properties_protected_aes_password_128.properties"
|
|
||||||
File niFiPropertiesFile = new File(niFiPropertiesTemplatePath)
|
|
||||||
|
|
||||||
File workingNiFiPropertiesFile = new File("target/tmp/tmp-nifi.properties")
|
|
||||||
workingNiFiPropertiesFile.delete()
|
|
||||||
Files.copy(niFiPropertiesFile.toPath(), workingNiFiPropertiesFile.toPath())
|
|
||||||
|
|
||||||
// Use a flow definition that was encrypted with the hard-coded default SP key
|
|
||||||
File flowXmlFile = new File("src/test/resources/flow.xml.gz")
|
|
||||||
File workingFlowXmlFile = new File("target/tmp/tmp-flow.xml.gz")
|
|
||||||
workingFlowXmlFile.delete()
|
|
||||||
Files.copy(flowXmlFile.toPath(), workingFlowXmlFile.toPath())
|
|
||||||
|
|
||||||
// Read the uncompressed version to compare later
|
|
||||||
File originalFlowXmlFile = new File("src/test/resources/flow_default_key.xml")
|
|
||||||
final String ORIGINAL_FLOW_XML_CONTENT = originalFlowXmlFile.text
|
|
||||||
def originalFlowCipherTexts = ORIGINAL_FLOW_XML_CONTENT.findAll(WFXCTR)
|
|
||||||
final int CIPHER_TEXT_COUNT = originalFlowCipherTexts.size()
|
|
||||||
|
|
||||||
// Load both the encrypted and decrypted properties to compare later
|
|
||||||
NiFiPropertiesLoader niFiPropertiesLoader = NiFiPropertiesLoader.withKey(PASSWORD_KEY_HEX_128)
|
|
||||||
NiFiProperties inputProperties = niFiPropertiesLoader.load(workingNiFiPropertiesFile)
|
|
||||||
logger.info("Loaded ${inputProperties.size()} properties from input file")
|
|
||||||
ProtectedNiFiProperties protectedInputProperties = new ProtectedNiFiProperties(inputProperties)
|
|
||||||
def originalSensitiveValues = protectedInputProperties.getSensitivePropertyKeys().collectEntries { String key -> [(key): protectedInputProperties.getProperty(key)] }
|
|
||||||
logger.info("Original sensitive values: ${originalSensitiveValues}")
|
|
||||||
|
|
||||||
|
|
||||||
final String SENSITIVE_PROTECTION_KEY = ApplicationPropertiesProtector.getProtectionKey(NiFiProperties.SENSITIVE_PROPS_KEY)
|
|
||||||
ProtectedNiFiProperties encryptedProperties = niFiPropertiesLoader.loadProtectedProperties(workingNiFiPropertiesFile)
|
|
||||||
def originalEncryptedValues = encryptedProperties.getSensitivePropertyKeys().collectEntries { String key -> [(key): encryptedProperties.getProperty(key)] }
|
|
||||||
logger.info("Original encrypted values: ${originalEncryptedValues}")
|
|
||||||
String originalSensitiveKeyProtectionScheme = encryptedProperties.getProperty(SENSITIVE_PROTECTION_KEY)
|
|
||||||
logger.info("Sensitive property key originally protected with ${originalSensitiveKeyProtectionScheme}")
|
|
||||||
|
|
||||||
String newFlowPassword = FLOW_PASSWORD
|
|
||||||
|
|
||||||
// Bootstrap path must be provided to decrypt nifi.properties to get SP key
|
|
||||||
String[] args = ["-n", workingNiFiPropertiesFile.path, "-f", workingFlowXmlFile.path, "-b", bootstrapFile.path, "-x", "-v", "-s", newFlowPassword]
|
|
||||||
|
|
||||||
exit.checkAssertionAfterwards(new Assertion() {
|
|
||||||
void checkAssertion() {
|
|
||||||
final List<String> updatedPropertiesLines = workingNiFiPropertiesFile.readLines()
|
|
||||||
logger.info("Updated nifi.properties:")
|
|
||||||
logger.info("\n" * 2 + updatedPropertiesLines.join("\n"))
|
|
||||||
|
|
||||||
final SensitivePropertyProvider spp = StandardSensitivePropertyProviderFactory.withKey(PASSWORD_KEY_HEX_128)
|
|
||||||
.getProvider(ConfigEncryptionTool.DEFAULT_PROTECTION_SCHEME)
|
|
||||||
|
|
||||||
// Check that the output values for everything is the same except the sensitive props key
|
|
||||||
NiFiProperties updatedProperties = new NiFiPropertiesLoader().loadProtectedProperties(workingNiFiPropertiesFile)
|
|
||||||
assert updatedProperties.size() == inputProperties.size()
|
|
||||||
String newSensitivePropertyKey = updatedProperties.getProperty(NiFiProperties.SENSITIVE_PROPS_KEY)
|
|
||||||
|
|
||||||
// Check that the encrypted value changed
|
|
||||||
assert newSensitivePropertyKey != originalSensitiveValues.get(NiFiProperties.SENSITIVE_PROPS_KEY)
|
|
||||||
|
|
||||||
// Check that the decrypted value is the new password
|
|
||||||
assert spp.unprotect(newSensitivePropertyKey, nifiPropertiesContext(NiFiProperties.SENSITIVE_PROPS_KEY)) == newFlowPassword
|
|
||||||
|
|
||||||
// Check that all other values stayed the same
|
|
||||||
originalEncryptedValues.every { String key, String originalValue ->
|
|
||||||
if (key != NiFiProperties.SENSITIVE_PROPS_KEY) {
|
|
||||||
assert updatedProperties.getProperty(key) == originalValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that all other (decrypted) values stayed the same
|
|
||||||
originalSensitiveValues.every { String key, String originalValue ->
|
|
||||||
if (key != NiFiProperties.SENSITIVE_PROPS_KEY) {
|
|
||||||
assert spp.unprotect(updatedProperties.getProperty(key), nifiPropertiesContext(key)) == originalValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that the protection scheme did not change
|
|
||||||
String sensitiveKeyProtectionScheme = updatedProperties.getProperty(SENSITIVE_PROTECTION_KEY)
|
|
||||||
logger.info("Sensitive property key currently protected with ${sensitiveKeyProtectionScheme}")
|
|
||||||
assert sensitiveKeyProtectionScheme == originalSensitiveKeyProtectionScheme
|
|
||||||
|
|
||||||
// Check that bootstrap.conf did not change
|
|
||||||
final List<String> updatedBootstrapLines = bootstrapFile.readLines()
|
|
||||||
String updatedKeyLine = updatedBootstrapLines.find {
|
|
||||||
it.startsWith(ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX)
|
|
||||||
}
|
|
||||||
logger.info("Updated key line: ${updatedKeyLine}")
|
|
||||||
|
|
||||||
assert updatedKeyLine == EXPECTED_KEY_LINE
|
|
||||||
assert originalBootstrapLines.size() == updatedBootstrapLines.size()
|
|
||||||
|
|
||||||
// Verify the flow definition
|
|
||||||
def verifyTool = new ConfigEncryptionTool()
|
|
||||||
verifyTool.isVerbose = true
|
|
||||||
verifyTool.flowXmlPath = workingFlowXmlFile.path
|
|
||||||
InputStream updatedFlowXmlContent = verifyTool.loadFlowXml(workingFlowXmlFile.path)
|
|
||||||
|
|
||||||
def migratedFlowCipherTexts = findFieldsInStream(updatedFlowXmlContent, WFXCTR)
|
|
||||||
|
|
||||||
// Verify that the cipher texts decrypt correctly
|
|
||||||
logger.info("Original flow.xml.gz cipher texts: ${originalFlowCipherTexts}")
|
|
||||||
logger.info("Updated flow.xml.gz cipher texts: ${migratedFlowCipherTexts}")
|
|
||||||
assert migratedFlowCipherTexts.size() == CIPHER_TEXT_COUNT
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Act
|
|
||||||
ConfigEncryptionTool.main(args)
|
|
||||||
logger.info("Invoked #main with ${args.join(" ")}")
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* In this scenario, the nifi.properties file has a sensitive key value which is already encrypted. The goal is to provide a new provide a new sensitive key value, perform the migration of the flow.xml.gz, and update nifi.properties with a new encrypted sensitive key value without modifying any other nifi.properties values.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void testShouldPerformFullOperationOnAFlowXmlWithPreviouslyEncryptedNiFiProperties() {
|
|
||||||
// Arrange
|
|
||||||
exit.expectSystemExitWithStatus(0)
|
|
||||||
|
|
||||||
File tmpDir = setupTmpDir()
|
|
||||||
|
|
||||||
File passwordKeyFile = new File("src/test/resources/bootstrap_with_root_key_password_128.conf")
|
|
||||||
File bootstrapFile = new File("target/tmp/tmp_bootstrap.conf")
|
|
||||||
bootstrapFile.delete()
|
|
||||||
|
|
||||||
Files.copy(passwordKeyFile.toPath(), bootstrapFile.toPath())
|
|
||||||
final List<String> originalBootstrapLines = bootstrapFile.readLines()
|
|
||||||
String originalKeyLine = originalBootstrapLines.find {
|
|
||||||
it.startsWith(ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX)
|
|
||||||
}
|
|
||||||
final String EXPECTED_KEY_LINE = ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX + PASSWORD_KEY_HEX_128
|
|
||||||
logger.info("Original key line from bootstrap.conf: ${originalKeyLine}")
|
|
||||||
assert originalKeyLine == ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX + PASSWORD_KEY_HEX_128
|
|
||||||
|
|
||||||
// Not "handling" NFP, so update in place (not source test resource)
|
|
||||||
String niFiPropertiesTemplatePath = "src/test/resources/nifi_with_few_sensitive_properties_protected_aes_password_128.properties"
|
|
||||||
File niFiPropertiesFile = new File(niFiPropertiesTemplatePath)
|
|
||||||
|
|
||||||
File workingNiFiPropertiesFile = new File("target/tmp/tmp-nifi.properties")
|
|
||||||
workingNiFiPropertiesFile.delete()
|
|
||||||
Files.copy(niFiPropertiesFile.toPath(), workingNiFiPropertiesFile.toPath())
|
|
||||||
|
|
||||||
// Use a flow definition that was encrypted with the hard-coded default SP key
|
|
||||||
File flowXmlFile = new File("src/test/resources/flow.xml.gz")
|
|
||||||
File workingFlowXmlFile = new File("target/tmp/tmp-flow.xml.gz")
|
|
||||||
workingFlowXmlFile.delete()
|
|
||||||
Files.copy(flowXmlFile.toPath(), workingFlowXmlFile.toPath())
|
|
||||||
|
|
||||||
// Get the original ciphered fields to compare later
|
|
||||||
def verifyTool = new ConfigEncryptionTool()
|
|
||||||
verifyTool.isVerbose = true
|
|
||||||
def originalFlowCipherTexts = findFieldsInStream(verifyTool.loadFlowXml(flowXmlFile.path), WFXCTR)
|
|
||||||
final int CIPHER_TEXT_COUNT = originalFlowCipherTexts.size()
|
|
||||||
|
|
||||||
// Load both the encrypted and decrypted properties to compare later
|
|
||||||
NiFiPropertiesLoader niFiPropertiesLoader = NiFiPropertiesLoader.withKey(PASSWORD_KEY_HEX_128)
|
|
||||||
NiFiProperties inputProperties = niFiPropertiesLoader.load(workingNiFiPropertiesFile)
|
|
||||||
logger.info("Loaded ${inputProperties.size()} properties from input file")
|
|
||||||
ProtectedNiFiProperties protectedInputProperties = new ProtectedNiFiProperties(inputProperties)
|
|
||||||
def originalSensitiveValues = protectedInputProperties.getSensitivePropertyKeys().collectEntries { String key -> [(key): protectedInputProperties.getProperty(key)] }
|
|
||||||
logger.info("Original sensitive values: ${originalSensitiveValues}")
|
|
||||||
|
|
||||||
|
|
||||||
final String SENSITIVE_PROTECTION_KEY = ApplicationPropertiesProtector.getProtectionKey(NiFiProperties.SENSITIVE_PROPS_KEY)
|
|
||||||
ProtectedNiFiProperties encryptedProperties = niFiPropertiesLoader.loadProtectedProperties(workingNiFiPropertiesFile)
|
|
||||||
def originalEncryptedValues = encryptedProperties.getSensitivePropertyKeys().collectEntries { String key -> [(key): encryptedProperties.getProperty(key)] }
|
|
||||||
logger.info("Original encrypted values: ${originalEncryptedValues}")
|
|
||||||
String originalSensitiveKeyProtectionScheme = encryptedProperties.getProperty(SENSITIVE_PROTECTION_KEY)
|
|
||||||
logger.info("Sensitive property key originally protected with ${originalSensitiveKeyProtectionScheme}")
|
|
||||||
|
|
||||||
String newFlowPassword = FLOW_PASSWORD
|
|
||||||
|
|
||||||
// Bootstrap path must be provided to decrypt nifi.properties to get SP key
|
|
||||||
String[] args = ["-n", workingNiFiPropertiesFile.path, "-f", workingFlowXmlFile.path, "-b", bootstrapFile.path, "-x", "-v", "-s", newFlowPassword]
|
|
||||||
|
|
||||||
exit.checkAssertionAfterwards(new Assertion() {
|
|
||||||
void checkAssertion() {
|
|
||||||
final List<String> updatedPropertiesLines = workingNiFiPropertiesFile.readLines()
|
|
||||||
logger.info("Updated nifi.properties:")
|
|
||||||
logger.info("\n" * 2 + updatedPropertiesLines.join("\n"))
|
|
||||||
|
|
||||||
final SensitivePropertyProvider spp = StandardSensitivePropertyProviderFactory.withKey(PASSWORD_KEY_HEX_128)
|
|
||||||
.getProvider(ConfigEncryptionTool.DEFAULT_PROTECTION_SCHEME)
|
|
||||||
|
|
||||||
// Check that the output values for everything is the same except the sensitive props key
|
|
||||||
NiFiProperties updatedProperties = new NiFiPropertiesLoader().loadProtectedProperties(workingNiFiPropertiesFile)
|
|
||||||
assert updatedProperties.size() == inputProperties.size()
|
|
||||||
String newSensitivePropertyKey = updatedProperties.getProperty(NiFiProperties.SENSITIVE_PROPS_KEY)
|
|
||||||
|
|
||||||
// Check that the encrypted value changed
|
|
||||||
assert newSensitivePropertyKey != originalSensitiveValues.get(NiFiProperties.SENSITIVE_PROPS_KEY)
|
|
||||||
|
|
||||||
// Check that the decrypted value is the new password
|
|
||||||
assert spp.unprotect(newSensitivePropertyKey, nifiPropertiesContext(NiFiProperties.SENSITIVE_PROPS_KEY)) == newFlowPassword
|
|
||||||
|
|
||||||
// Check that all other values stayed the same
|
|
||||||
originalEncryptedValues.every { String key, String originalValue ->
|
|
||||||
if (key != NiFiProperties.SENSITIVE_PROPS_KEY) {
|
|
||||||
assert updatedProperties.getProperty(key) == originalValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that all other (decrypted) values stayed the same
|
|
||||||
originalSensitiveValues.every { String key, String originalValue ->
|
|
||||||
if (key != NiFiProperties.SENSITIVE_PROPS_KEY) {
|
|
||||||
assert spp.unprotect(updatedProperties.getProperty(key), nifiPropertiesContext(key)) == originalValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that the protection scheme did not change
|
|
||||||
String sensitiveKeyProtectionScheme = updatedProperties.getProperty(SENSITIVE_PROTECTION_KEY)
|
|
||||||
logger.info("Sensitive property key currently protected with ${sensitiveKeyProtectionScheme}")
|
|
||||||
assert sensitiveKeyProtectionScheme == originalSensitiveKeyProtectionScheme
|
|
||||||
|
|
||||||
// Check that bootstrap.conf did not change
|
|
||||||
final List<String> updatedBootstrapLines = bootstrapFile.readLines()
|
|
||||||
String updatedKeyLine = updatedBootstrapLines.find {
|
|
||||||
it.startsWith(ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX)
|
|
||||||
}
|
|
||||||
logger.info("Updated key line: ${updatedKeyLine}")
|
|
||||||
|
|
||||||
assert updatedKeyLine == EXPECTED_KEY_LINE
|
|
||||||
assert originalBootstrapLines.size() == updatedBootstrapLines.size()
|
|
||||||
|
|
||||||
// Verify the flow definition
|
|
||||||
verifyTool = new ConfigEncryptionTool()
|
|
||||||
verifyTool.isVerbose = true
|
|
||||||
InputStream migratedFlowXmlContent = verifyTool.loadFlowXml(workingFlowXmlFile.path)
|
|
||||||
|
|
||||||
def migratedFlowCipherTexts = findFieldsInStream(migratedFlowXmlContent, WFXCTR)
|
|
||||||
logger.info("Migrated flow cipher texts for: " + workingFlowXmlFile.path)
|
|
||||||
// Verify that the cipher texts decrypt correctly
|
|
||||||
logger.info("Original " + workingFlowXmlFile.path + " unique cipher texts: ${originalFlowCipherTexts}")
|
|
||||||
logger.info("Migrated " + workingFlowXmlFile.path + " unique cipher texts: ${migratedFlowCipherTexts}")
|
|
||||||
assert migratedFlowCipherTexts.size() == CIPHER_TEXT_COUNT
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Act
|
|
||||||
ConfigEncryptionTool.main(args)
|
|
||||||
logger.info("Invoked #main with ${args.join(" ")}")
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
|
|
||||||
// Assertions defined above
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* In this scenario, the nifi.properties file has a sensitive key value which is already encrypted. The goal is to provide a new provide a new sensitive key value, perform the migration of the flow.xml.gz, and update nifi.properties with a new encrypted sensitive key value without modifying any other nifi.properties values, and repeat this process multiple times to ensure no corruption of the keys.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void testShouldPerformFullOperationOnFlowXmlMultipleTimes() {
|
|
||||||
// Arrange
|
|
||||||
exit.expectSystemExitWithStatus(0)
|
|
||||||
|
|
||||||
File tmpDir = setupTmpDir()
|
|
||||||
|
|
||||||
File passwordKeyFile = new File("src/test/resources/bootstrap_with_root_key_password_128.conf")
|
|
||||||
File bootstrapFile = new File("target/tmp/tmp_bootstrap.conf")
|
|
||||||
bootstrapFile.delete()
|
|
||||||
|
|
||||||
Files.copy(passwordKeyFile.toPath(), bootstrapFile.toPath())
|
|
||||||
final List<String> originalBootstrapLines = bootstrapFile.readLines()
|
|
||||||
String originalKeyLine = originalBootstrapLines.find {
|
|
||||||
it.startsWith(ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX)
|
|
||||||
}
|
|
||||||
final String EXPECTED_KEY_LINE = ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX + PASSWORD_KEY_HEX_128
|
|
||||||
logger.info("Original key line from bootstrap.conf: ${originalKeyLine}")
|
|
||||||
assert originalKeyLine == ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX + PASSWORD_KEY_HEX_128
|
|
||||||
|
|
||||||
// Not "handling" NFP, so update in place (not source test resource)
|
|
||||||
String niFiPropertiesTemplatePath = "src/test/resources/nifi_with_few_sensitive_properties_protected_aes_password_128.properties"
|
|
||||||
File niFiPropertiesFile = new File(niFiPropertiesTemplatePath)
|
|
||||||
|
|
||||||
File workingNiFiPropertiesFile = new File("target/tmp/tmp-nifi.properties")
|
|
||||||
workingNiFiPropertiesFile.delete()
|
|
||||||
Files.copy(niFiPropertiesFile.toPath(), workingNiFiPropertiesFile.toPath())
|
|
||||||
|
|
||||||
// Use a flow definition that was encrypted with the hard-coded default SP key
|
|
||||||
File flowXmlFile = new File("src/test/resources/flow_default_key.xml.gz")
|
|
||||||
File workingFlowXmlFile = new File("target/tmp/tmp-flow.xml.gz")
|
|
||||||
workingFlowXmlFile.delete()
|
|
||||||
Files.copy(flowXmlFile.toPath(), workingFlowXmlFile.toPath())
|
|
||||||
|
|
||||||
// Read the uncompressed version to compare later
|
|
||||||
File originalFlowXmlFile = new File("src/test/resources/flow_default_key.xml")
|
|
||||||
final String ORIGINAL_FLOW_XML_CONTENT = originalFlowXmlFile.text
|
|
||||||
def originalFlowCipherTexts = ORIGINAL_FLOW_XML_CONTENT.findAll(WFXCTR).toSet()
|
|
||||||
final int CIPHER_TEXT_COUNT = originalFlowCipherTexts.size()
|
|
||||||
|
|
||||||
// Load both the encrypted and decrypted properties to compare later
|
|
||||||
NiFiPropertiesLoader niFiPropertiesLoader = NiFiPropertiesLoader.withKey(PASSWORD_KEY_HEX_128)
|
|
||||||
NiFiProperties inputProperties = niFiPropertiesLoader.load(workingNiFiPropertiesFile)
|
|
||||||
logger.info("Loaded ${inputProperties.size()} properties from input file")
|
|
||||||
ProtectedNiFiProperties protectedInputProperties = new ProtectedNiFiProperties(inputProperties)
|
|
||||||
def originalSensitiveValues = protectedInputProperties.getSensitivePropertyKeys().collectEntries { String key -> [(key): protectedInputProperties.getProperty(key)] }
|
|
||||||
logger.info("Original sensitive values: ${originalSensitiveValues}")
|
|
||||||
|
|
||||||
final String SENSITIVE_PROTECTION_KEY = ApplicationPropertiesProtector.getProtectionKey(NiFiProperties.SENSITIVE_PROPS_KEY)
|
|
||||||
ProtectedNiFiProperties encryptedProperties = niFiPropertiesLoader.loadProtectedProperties(workingNiFiPropertiesFile)
|
|
||||||
def originalEncryptedValues = encryptedProperties.getSensitivePropertyKeys().collectEntries { String key -> [(key): encryptedProperties.getProperty(key)] }
|
|
||||||
logger.info("Original encrypted values: ${originalEncryptedValues}")
|
|
||||||
String originalSensitiveKeyProtectionScheme = encryptedProperties.getProperty(SENSITIVE_PROTECTION_KEY)
|
|
||||||
logger.info("Sensitive property key originally protected with ${originalSensitiveKeyProtectionScheme}")
|
|
||||||
|
|
||||||
// Create a series of passwords with which to encrypt the flow XML, starting with the current password
|
|
||||||
def passwordProgression = [DEFAULT_LEGACY_SENSITIVE_PROPS_KEY] + (0..5).collect { "${FLOW_PASSWORD}${it}" }
|
|
||||||
|
|
||||||
// The root key is not changing
|
|
||||||
final SensitivePropertyProvider spp = StandardSensitivePropertyProviderFactory.withKey(PASSWORD_KEY_HEX_128)
|
|
||||||
.getProvider(ConfigEncryptionTool.DEFAULT_PROTECTION_SCHEME)
|
|
||||||
|
|
||||||
// Act
|
|
||||||
passwordProgression.eachWithIndex { String existingFlowPassword, int i ->
|
|
||||||
if (i < passwordProgression.size() - 1) {
|
|
||||||
exit.expectSystemExitWithStatus(0)
|
|
||||||
String newFlowPassword = passwordProgression[i + 1]
|
|
||||||
logger.info("Migrating from ${existingFlowPassword} to ${newFlowPassword}")
|
|
||||||
|
|
||||||
// Bootstrap path must be provided to decrypt nifi.properties to get SP key
|
|
||||||
String[] args = ["-n", workingNiFiPropertiesFile.path, "-f", workingFlowXmlFile.path, "-b", bootstrapFile.path, "-x", "-v", "-s", newFlowPassword]
|
|
||||||
|
|
||||||
def msg = shouldFail {
|
|
||||||
logger.info("Invoked #main with ${args.join(" ")}")
|
|
||||||
ConfigEncryptionTool.main(args)
|
|
||||||
}
|
|
||||||
logger.expected(msg)
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
// Get the updated nifi.properties and check the sensitive key
|
|
||||||
final List<String> updatedPropertiesLines = workingNiFiPropertiesFile.readLines()
|
|
||||||
String updatedSensitiveKeyLine = updatedPropertiesLines.find {
|
|
||||||
it.startsWith(NiFiProperties.SENSITIVE_PROPS_KEY)
|
|
||||||
}
|
|
||||||
logger.info("Updated key line: ${updatedSensitiveKeyLine}")
|
|
||||||
|
|
||||||
// Check that the output values for everything are the same except the sensitive props key
|
|
||||||
NiFiProperties updatedProperties = new NiFiPropertiesLoader().loadProtectedProperties(workingNiFiPropertiesFile)
|
|
||||||
assert updatedProperties.size() == inputProperties.size()
|
|
||||||
String newSensitivePropertyKey = updatedProperties.getProperty(NiFiProperties.SENSITIVE_PROPS_KEY)
|
|
||||||
|
|
||||||
// Check that the encrypted value changed
|
|
||||||
assert newSensitivePropertyKey != originalSensitiveValues.get(NiFiProperties.SENSITIVE_PROPS_KEY)
|
|
||||||
|
|
||||||
// Check that the decrypted value is the new password
|
|
||||||
assert spp.unprotect(newSensitivePropertyKey, nifiPropertiesContext(NiFiProperties.SENSITIVE_PROPS_KEY)) == newFlowPassword
|
|
||||||
|
|
||||||
// Check that all other values stayed the same
|
|
||||||
originalEncryptedValues.every { String key, String originalValue ->
|
|
||||||
if (key != NiFiProperties.SENSITIVE_PROPS_KEY) {
|
|
||||||
assert updatedProperties.getProperty(key) == originalValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that all other (decrypted) values stayed the same
|
|
||||||
originalSensitiveValues.every { String key, String originalValue ->
|
|
||||||
if (key != NiFiProperties.SENSITIVE_PROPS_KEY) {
|
|
||||||
assert spp.unprotect(updatedProperties.getProperty(key), nifiPropertiesContext(key)) == originalValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that the protection scheme did not change
|
|
||||||
String sensitiveKeyProtectionScheme = updatedProperties.getProperty(SENSITIVE_PROTECTION_KEY)
|
|
||||||
logger.info("Sensitive property key currently protected with ${sensitiveKeyProtectionScheme}")
|
|
||||||
assert sensitiveKeyProtectionScheme == originalSensitiveKeyProtectionScheme
|
|
||||||
|
|
||||||
// Check that bootstrap.conf did not change
|
|
||||||
final List<String> updatedBootstrapLines = bootstrapFile.readLines()
|
|
||||||
String updatedKeyLine = updatedBootstrapLines.find {
|
|
||||||
it.startsWith(ConfigEncryptionTool.BOOTSTRAP_KEY_PREFIX)
|
|
||||||
}
|
|
||||||
logger.info("Updated key line: ${updatedKeyLine}")
|
|
||||||
|
|
||||||
assert updatedKeyLine == EXPECTED_KEY_LINE
|
|
||||||
assert originalBootstrapLines.size() == updatedBootstrapLines.size()
|
|
||||||
|
|
||||||
// Verify the flow definition
|
|
||||||
def verifyTool = new ConfigEncryptionTool()
|
|
||||||
verifyTool.isVerbose = true
|
|
||||||
InputStream updatedFlowXmlContent = verifyTool.loadFlowXml(workingFlowXmlFile.path)
|
|
||||||
|
|
||||||
// Check that the flow.xml.gz content changed
|
|
||||||
// TODO assert updatedFlowXmlContent != ORIGINAL_FLOW_XML_CONTENT
|
|
||||||
|
|
||||||
// Verify that the cipher texts decrypt correctly
|
|
||||||
logger.info("Original flow.xml.gz cipher texts: ${originalFlowCipherTexts}")
|
|
||||||
def flowCipherTexts = findFieldsInStream(updatedFlowXmlContent, WFXCTR)
|
|
||||||
logger.info("Updated flow.xml.gz cipher texts: ${flowCipherTexts}")
|
|
||||||
assert flowCipherTexts.size() == CIPHER_TEXT_COUNT
|
|
||||||
|
|
||||||
// Update the "original" flow cipher texts for the next run to the current values
|
|
||||||
originalFlowCipherTexts = flowCipherTexts
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testShouldMigrateFlowXmlContent() {
|
|
||||||
// Arrange
|
|
||||||
String flowXmlPath = "src/test/resources/flow.xml"
|
|
||||||
File flowXmlFile = new File(flowXmlPath)
|
|
||||||
|
|
||||||
File tmpDir = setupTmpDir()
|
|
||||||
|
|
||||||
File workingFile = new File("target/tmp/tmp-flow.xml")
|
|
||||||
workingFile.delete()
|
|
||||||
Files.copy(flowXmlFile.toPath(), workingFile.toPath())
|
|
||||||
ConfigEncryptionTool tool = new ConfigEncryptionTool()
|
|
||||||
tool.isVerbose = true
|
|
||||||
tool.flowXmlPath = workingFile.path
|
|
||||||
tool.outputFlowXmlPath = workingFile.path
|
|
||||||
|
|
||||||
final String SENSITIVE_VALUE = "thisIsABadPassword"
|
|
||||||
|
|
||||||
String existingFlowPassword = DEFAULT_LEGACY_SENSITIVE_PROPS_KEY
|
|
||||||
String newFlowPassword = FLOW_PASSWORD
|
|
||||||
|
|
||||||
InputStream xmlContent = new FileInputStream(workingFile.path)
|
|
||||||
logger.info("Read flow.xml as input stream.")
|
|
||||||
|
|
||||||
// There are two encrypted passwords in this flow
|
|
||||||
int cipherTextCount = findFieldsInStream(xmlContent, WFXCTR).size()
|
|
||||||
logger.info("Found ${cipherTextCount} unique encrypted properties in the original flow.xml content")
|
|
||||||
|
|
||||||
// Act
|
|
||||||
xmlContent = new FileInputStream(workingFile.path)
|
|
||||||
tool.migrateFlowXmlContent(xmlContent, existingFlowPassword, newFlowPassword)
|
|
||||||
logger.info("Migrated flow.xml.")
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
InputStream migratedFlowXmlFile = new FileInputStream(workingFile.path)
|
|
||||||
def migratedCipherTexts = findFieldsInStream(migratedFlowXmlFile, WFXCTR)
|
|
||||||
|
|
||||||
assert migratedCipherTexts.size() == cipherTextCount
|
|
||||||
|
|
||||||
// Ensure that everything else is identical
|
|
||||||
assertEquals(removeXmlDeclarationAndComments(flowXmlFile.text).replaceAll(WFXCTR, "").trim(),
|
|
||||||
removeXmlDeclarationAndComments(workingFile.text).replaceAll(WFXCTR, "").trim())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testShouldMigrateFlowXmlContentMultipleTimes() {
|
|
||||||
// Arrange
|
|
||||||
String flowXmlPath = "src/test/resources/flow.xml"
|
|
||||||
File flowXmlFile = new File(flowXmlPath)
|
|
||||||
|
|
||||||
File tmpDir = setupTmpDir()
|
|
||||||
|
|
||||||
File workingFile = new File("target/tmp/tmp-flow.xml")
|
|
||||||
workingFile.delete()
|
|
||||||
Files.copy(flowXmlFile.toPath(), workingFile.toPath())
|
|
||||||
ConfigEncryptionTool tool = new ConfigEncryptionTool()
|
|
||||||
tool.isVerbose = true
|
|
||||||
tool.outputFlowXmlPath = workingFile.path
|
|
||||||
|
|
||||||
final String SENSITIVE_VALUE = "thisIsABadPassword"
|
|
||||||
|
|
||||||
// Create a series of passwords with which to encrypt the flow XML, starting with the current password
|
|
||||||
def passwordProgression = [DEFAULT_LEGACY_SENSITIVE_PROPS_KEY] + (0..5).collect { "${FLOW_PASSWORD}${it}" }
|
|
||||||
|
|
||||||
String xmlContent = workingFile.text
|
|
||||||
// logger.info("Read flow.xml: \n${xmlContent}")
|
|
||||||
|
|
||||||
// There are two encrypted passwords in this flow
|
|
||||||
final def ORIGINAL_CIPHER_TEXTS = xmlContent.findAll(WFXCTR)
|
|
||||||
logger.info("Cipher texts: \n${ORIGINAL_CIPHER_TEXTS.join("\n")}")
|
|
||||||
final int ORIGINAL_CIPHER_TEXT_COUNT = ORIGINAL_CIPHER_TEXTS.size()
|
|
||||||
logger.info("Found ${ORIGINAL_CIPHER_TEXT_COUNT} encrypted properties in the original flow.xml content")
|
|
||||||
|
|
||||||
InputStream currentXmlContent = new ByteArrayInputStream(xmlContent.bytes)
|
|
||||||
|
|
||||||
// Act
|
|
||||||
passwordProgression.eachWithIndex { String existingFlowPassword, int i ->
|
|
||||||
if (i < passwordProgression.size() - 1) {
|
|
||||||
String newFlowPassword = passwordProgression[i + 1]
|
|
||||||
logger.info("Migrating from ${existingFlowPassword} to ${newFlowPassword}")
|
|
||||||
|
|
||||||
InputStream migratedXmlContent = tool.migrateFlowXmlContent(currentXmlContent, existingFlowPassword, newFlowPassword)
|
|
||||||
// logger.info("Migrated flow.xml: \n${migratedXmlContent}")
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
def newCipherTexts = findFieldsInStream(migratedXmlContent, WFXCTR)
|
|
||||||
logger.info("Cipher texts for iteration ${i}: \n${newCipherTexts.join("\n")}")
|
|
||||||
|
|
||||||
assert newCipherTexts.size() == ORIGINAL_CIPHER_TEXT_COUNT
|
|
||||||
|
|
||||||
// Ensure that everything else is identical
|
|
||||||
assertEquals(removeXmlDeclarationAndComments(new File(workingFile.path).text).replaceAll(WFXCTR, "").trim(),
|
|
||||||
removeXmlDeclarationAndComments(flowXmlFile.text).replaceAll(WFXCTR, "").trim())
|
|
||||||
|
|
||||||
// Update the "source" XML content for the next iteration
|
|
||||||
currentXmlContent = tool.loadFlowXml(workingFile.path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testMigrateFlowXmlContentShouldUseConstantSalt() {
|
|
||||||
// Arrange
|
|
||||||
String flowXmlPath = "src/test/resources/flow.xml"
|
|
||||||
File flowXmlFile = new File(flowXmlPath)
|
|
||||||
|
|
||||||
File tmpDir = setupTmpDir()
|
|
||||||
|
|
||||||
File workingFile = new File("target/tmp/tmp-flow.xml")
|
|
||||||
workingFile.delete()
|
|
||||||
Files.copy(flowXmlFile.toPath(), workingFile.toPath())
|
|
||||||
ConfigEncryptionTool tool = new ConfigEncryptionTool()
|
|
||||||
tool.isVerbose = true
|
|
||||||
tool.outputFlowXmlPath = workingFile.path
|
|
||||||
|
|
||||||
String existingFlowPassword = DEFAULT_LEGACY_SENSITIVE_PROPS_KEY
|
|
||||||
String newFlowPassword = FLOW_PASSWORD
|
|
||||||
|
|
||||||
String xmlContent = workingFile.text
|
|
||||||
logger.info("Read flow.xml: \n${xmlContent}")
|
|
||||||
|
|
||||||
// There are two encrypted passwords in this flow
|
|
||||||
int cipherTextCount = xmlContent.findAll(WFXCTR).size()
|
|
||||||
logger.info("Found ${cipherTextCount} encrypted properties in the original flow.xml content")
|
|
||||||
|
|
||||||
// Act
|
|
||||||
InputStream migratedXmlContent = tool.migrateFlowXmlContent(new ByteArrayInputStream(xmlContent.bytes), existingFlowPassword, newFlowPassword)
|
|
||||||
logger.info("Migrated flow.xml.")
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
def newCipherTexts = findFieldsInStream(migratedXmlContent, WFXCTR)
|
|
||||||
|
|
||||||
assert newCipherTexts.size() == cipherTextCount
|
|
||||||
|
|
||||||
// Check that the same salt was used on all output
|
|
||||||
String saltHex = newCipherTexts.first()[4..<36]
|
|
||||||
logger.info("First detected salt: ${saltHex}")
|
|
||||||
newCipherTexts.every {
|
|
||||||
assert it[4..<36] == saltHex
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This test is scoped to the higher-level method to ensure that if a bad padding exception is thrown, the right errors are displayed.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void testHandleFlowXmlMigrationWithIncorrectExistingPasswordShouldProvideHelpfulErrorMessage() {
|
|
||||||
// Arrange
|
|
||||||
systemOutRule.clearLog()
|
|
||||||
|
|
||||||
String flowXmlPath = "src/test/resources/flow.xml"
|
|
||||||
File flowXmlFile = new File(flowXmlPath)
|
|
||||||
|
|
||||||
// Use the wrong existing password
|
|
||||||
String wrongExistingFlowPassword = DEFAULT_LEGACY_SENSITIVE_PROPS_KEY.reverse()
|
|
||||||
String newFlowPassword = FLOW_PASSWORD
|
|
||||||
|
|
||||||
def nifiProperties = wrapNFP([(NiFiProperties.SENSITIVE_PROPS_KEY): wrongExistingFlowPassword])
|
|
||||||
|
|
||||||
File workingFile = new File("target/tmp/tmp-flow.xml")
|
|
||||||
workingFile.delete()
|
|
||||||
Files.copy(flowXmlFile.toPath(), workingFile.toPath())
|
|
||||||
ConfigEncryptionTool tool = new ConfigEncryptionTool()
|
|
||||||
tool.isVerbose = true
|
|
||||||
tool.flowXmlInputStream = tool.loadFlowXml(workingFile.path)
|
|
||||||
tool.niFiProperties = nifiProperties
|
|
||||||
tool.flowPropertiesPassword = newFlowPassword
|
|
||||||
tool.handlingNiFiProperties = false
|
|
||||||
|
|
||||||
// Act
|
|
||||||
def message = shouldFail(Exception) {
|
|
||||||
tool.handleFlowXml()
|
|
||||||
logger.info("Migrated flow.xml.")
|
|
||||||
}
|
|
||||||
logger.expected(message)
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
// TODO: Assert that this message was in the log output (neither the STDOUT and STDERR buffers contain it, but it is printed)
|
|
||||||
assert message == "Encountered an error migrating flow content"
|
|
||||||
}
|
|
||||||
|
|
||||||
private static NiFiProperties wrapNFP(Map<String, String> map) {
|
|
||||||
new NiFiProperties(
|
|
||||||
new Properties(map))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testShouldLoadFlowXmlContent() {
|
void testShouldLoadFlowXmlContent() {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
|
@ -71,7 +71,7 @@ nifi.web.jetty.working.directory=./target/work/jetty
|
||||||
|
|
||||||
# security properties #
|
# security properties #
|
||||||
nifi.sensitive.props.key=
|
nifi.sensitive.props.key=
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM_256
|
||||||
nifi.sensitive.props.additional.keys=
|
nifi.sensitive.props.additional.keys=
|
||||||
|
|
||||||
nifi.security.keystore=
|
nifi.security.keystore=
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
# security properties #
|
# security properties #
|
||||||
nifi.sensitive.props.key=n2z+tTTbHuZ4V4V2||uWhdasyDXD4ZG2lMAes/vqh6u4vaz4xgL4aEbF4Y/dXevqk3ulRcOwf1vc4RDQ==
|
nifi.sensitive.props.key=n2z+tTTbHuZ4V4V2||uWhdasyDXD4ZG2lMAes/vqh6u4vaz4xgL4aEbF4Y/dXevqk3ulRcOwf1vc4RDQ==
|
||||||
nifi.sensitive.props.key.protected=aes/gcm/256
|
nifi.sensitive.props.key.protected=aes/gcm/256
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM_256
|
||||||
nifi.sensitive.props.additional.keys=
|
nifi.sensitive.props.additional.keys=
|
||||||
|
|
||||||
nifi.security.keystore=/path/to/keystore.jks
|
nifi.security.keystore=/path/to/keystore.jks
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
# security properties #
|
# security properties #
|
||||||
nifi.sensitive.props.key=UXcrW8T1UKAPJeun||ezUJSp30AvKGsRxJOOXoPUtZonv56Lx1
|
nifi.sensitive.props.key=UXcrW8T1UKAPJeun||ezUJSp30AvKGsRxJOOXoPUtZonv56Lx1
|
||||||
nifi.sensitive.props.key.protected=aes/gcm/128
|
nifi.sensitive.props.key.protected=aes/gcm/128
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM_256
|
||||||
nifi.sensitive.props.additional.keys=
|
nifi.sensitive.props.additional.keys=
|
||||||
|
|
||||||
nifi.security.keystore=/path/to/keystore.jks
|
nifi.security.keystore=/path/to/keystore.jks
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
# security properties #
|
# security properties #
|
||||||
nifi.sensitive.props.key=thisIsABadSensitiveKeyPassword
|
nifi.sensitive.props.key=thisIsABadSensitiveKeyPassword
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM_256
|
||||||
nifi.sensitive.props.additional.keys=
|
nifi.sensitive.props.additional.keys=
|
||||||
|
|
||||||
nifi.security.keystore=/path/to/keystore.jks
|
nifi.security.keystore=/path/to/keystore.jks
|
||||||
|
|
|
@ -72,7 +72,7 @@ nifi.web.jetty.working.directory=./target/work/jetty
|
||||||
# security properties #
|
# security properties #
|
||||||
nifi.sensitive.props.key=n2z+tTTbHuZ4V4V2||uWhdasyDXD4ZG2lMAes/vqh6u4vaz4xgL4aEbF4Y/dXevqk3ulRcOwf1vc4RDQ==
|
nifi.sensitive.props.key=n2z+tTTbHuZ4V4V2||uWhdasyDXD4ZG2lMAes/vqh6u4vaz4xgL4aEbF4Y/dXevqk3ulRcOwf1vc4RDQ==
|
||||||
nifi.sensitive.props.key.protected=aes/gcm/256
|
nifi.sensitive.props.key.protected=aes/gcm/256
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM_256
|
||||||
nifi.sensitive.props.additional.keys=
|
nifi.sensitive.props.additional.keys=
|
||||||
|
|
||||||
nifi.security.keystore=/path/to/keystore.jks
|
nifi.security.keystore=/path/to/keystore.jks
|
||||||
|
|
|
@ -72,7 +72,7 @@ nifi.web.jetty.working.directory=./target/work/jetty
|
||||||
# security properties #
|
# security properties #
|
||||||
nifi.sensitive.props.key=xPqEWK8a34r19J4z||UOFzOfZE/NQK4Xua8WWblf1/Ld+Pf7eQ1zg0U/qYW2sPwxyhhOXWwQmrUft6qA
|
nifi.sensitive.props.key=xPqEWK8a34r19J4z||UOFzOfZE/NQK4Xua8WWblf1/Ld+Pf7eQ1zg0U/qYW2sPwxyhhOXWwQmrUft6qA
|
||||||
nifi.sensitive.props.key.protected=aes/gcm/128
|
nifi.sensitive.props.key.protected=aes/gcm/128
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM_256
|
||||||
nifi.sensitive.props.additional.keys=
|
nifi.sensitive.props.additional.keys=
|
||||||
|
|
||||||
nifi.security.keystore=/path/to/keystore.jks
|
nifi.security.keystore=/path/to/keystore.jks
|
||||||
|
|
|
@ -72,7 +72,7 @@ nifi.web.jetty.working.directory=./target/work/jetty
|
||||||
# security properties #
|
# security properties #
|
||||||
nifi.sensitive.props.key=n6ZO5Y9zv4CGElB2||e0SwwiJqNOZ8drLl30+dbiSYYMgd+Vx7rFjwCYEkJpF4Vh+Tx8+7Oek96kpoxQ
|
nifi.sensitive.props.key=n6ZO5Y9zv4CGElB2||e0SwwiJqNOZ8drLl30+dbiSYYMgd+Vx7rFjwCYEkJpF4Vh+Tx8+7Oek96kpoxQ
|
||||||
nifi.sensitive.props.key.protected=aes/gcm/256
|
nifi.sensitive.props.key.protected=aes/gcm/256
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM_256
|
||||||
nifi.sensitive.props.additional.keys=
|
nifi.sensitive.props.additional.keys=
|
||||||
|
|
||||||
nifi.security.keystore=/path/to/keystore.jks
|
nifi.security.keystore=/path/to/keystore.jks
|
||||||
|
|
|
@ -73,7 +73,7 @@ nifi.web.jetty.working.directory=./target/work/jetty
|
||||||
# security properties #
|
# security properties #
|
||||||
nifi.sensitive.props.key=xwc0atbb2krNWE8i||NLuzY6uraSVnONQEhA6hxfVntOTPhzG7yiKOysopYzfBTYY5Um1oNgnyvrCadw
|
nifi.sensitive.props.key=xwc0atbb2krNWE8i||NLuzY6uraSVnONQEhA6hxfVntOTPhzG7yiKOysopYzfBTYY5Um1oNgnyvrCadw
|
||||||
nifi.sensitive.props.key.protected=aes/gcm/128
|
nifi.sensitive.props.key.protected=aes/gcm/128
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM_256
|
||||||
nifi.sensitive.props.additional.keys=
|
nifi.sensitive.props.additional.keys=
|
||||||
|
|
||||||
nifi.security.keystore=/path/to/keystore.jks
|
nifi.security.keystore=/path/to/keystore.jks
|
||||||
|
|
|
@ -71,7 +71,7 @@ nifi.web.jetty.working.directory=./target/work/jetty
|
||||||
|
|
||||||
# security properties #
|
# security properties #
|
||||||
nifi.sensitive.props.key=thisIsABadSensitiveKeyPassword
|
nifi.sensitive.props.key=thisIsABadSensitiveKeyPassword
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM_256
|
||||||
nifi.sensitive.props.additional.keys=
|
nifi.sensitive.props.additional.keys=
|
||||||
|
|
||||||
nifi.security.keystore=/path/to/keystore.jks
|
nifi.security.keystore=/path/to/keystore.jks
|
||||||
|
|
|
@ -73,7 +73,7 @@ nifi.web.jetty.working.directory=./target/work/jetty
|
||||||
# security properties #
|
# security properties #
|
||||||
nifi.sensitive.props.key=thisIsABadSensitiveKeyPassword
|
nifi.sensitive.props.key=thisIsABadSensitiveKeyPassword
|
||||||
nifi.sensitive.props.key.protected=
|
nifi.sensitive.props.key.protected=
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM_256
|
||||||
nifi.sensitive.props.additional.keys=
|
nifi.sensitive.props.additional.keys=
|
||||||
|
|
||||||
nifi.security.keystore=/path/to/keystore.jks
|
nifi.security.keystore=/path/to/keystore.jks
|
||||||
|
|
|
@ -130,7 +130,7 @@ nifi.web.jetty.threads=200
|
||||||
|
|
||||||
# security properties #
|
# security properties #
|
||||||
nifi.sensitive.props.key=
|
nifi.sensitive.props.key=
|
||||||
nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
|
nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM_256
|
||||||
|
|
||||||
nifi.security.keystore=./conf/localhost.jks
|
nifi.security.keystore=./conf/localhost.jks
|
||||||
nifi.security.keystoreType=jks
|
nifi.security.keystoreType=jks
|
||||||
|
|
Loading…
Reference in New Issue