diff --git a/.github/workflows/docker-tests.yml b/.github/workflows/docker-tests.yml index fc36cc981b9c..b54ef30a3f7d 100644 --- a/.github/workflows/docker-tests.yml +++ b/.github/workflows/docker-tests.yml @@ -27,7 +27,6 @@ on: - 'nifi-registry/nifi-registry-docker-maven/**' - 'nifi-toolkit/nifi-toolkit-assembly/**' - 'nifi-toolkit/nifi-toolkit-cli/**' - - 'nifi-toolkit/nifi-toolkit-encrypt-config/**' - 'minifi/minifi-assembly/**' - 'minifi/minifi-docker/**' pull_request: @@ -39,7 +38,6 @@ on: - 'nifi-registry/nifi-registry-docker-maven/**' - 'nifi-toolkit/nifi-toolkit-assembly/**' - 'nifi-toolkit/nifi-toolkit-cli/**' - - 'nifi-toolkit/nifi-toolkit-encrypt-config/**' - 'minifi/minifi-assembly/**' - 'minifi/minifi-docker/**' @@ -77,7 +75,6 @@ env: -pl -nifi-registry/nifi-registry-assembly -pl -nifi-toolkit/nifi-toolkit-assembly -pl -nifi-toolkit/nifi-toolkit-cli - -pl -nifi-toolkit/nifi-toolkit-encrypt-config -pl -minifi/minifi-assembly MAVEN_DOCKER_ARGUMENTS: >- diff --git a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/BootstrapFileProvider.java b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/BootstrapFileProvider.java index 96cc04ad2906..36678017b929 100644 --- a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/BootstrapFileProvider.java +++ b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/BootstrapFileProvider.java @@ -120,7 +120,7 @@ public BootstrapProperties getBootstrapProperties() { } public BootstrapProperties getProtectedBootstrapProperties() { - return BootstrapPropertiesLoader.loadProtectedProperties(bootstrapConfigFile).getApplicationProperties(); + return BootstrapPropertiesLoader.loadProtectedProperties(bootstrapConfigFile); } public Properties getStatusProperties() { diff --git a/minifi/minifi-commons/minifi-commons-utils/src/main/java/org/apache/nifi/minifi/commons/utils/SensitivePropertyUtils.java b/minifi/minifi-commons/minifi-commons-utils/src/main/java/org/apache/nifi/minifi/commons/utils/SensitivePropertyUtils.java deleted file mode 100644 index 301f2637d8a8..000000000000 --- a/minifi/minifi-commons/minifi-commons-utils/src/main/java/org/apache/nifi/minifi/commons/utils/SensitivePropertyUtils.java +++ /dev/null @@ -1,83 +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.minifi.commons.utils; - -import static java.lang.String.format; - -import java.io.BufferedInputStream; -import java.io.FileInputStream; -import java.io.InputStream; -import java.util.Optional; -import java.util.Properties; - -public class SensitivePropertyUtils { - - public static final String MINIFI_BOOTSTRAP_SENSITIVE_KEY = "minifi.bootstrap.sensitive.key"; - private static final String EMPTY = ""; - - private SensitivePropertyUtils() { - } - - public static String getFormattedKey() { - String key = getKey(System.getProperty("minifi.bootstrap.conf.file.path")); - // Format the key (check hex validity and remove spaces) - return getFormattedKey(key); - } - - public static String getFormattedKey(String unformattedKey) { - String key = formatHexKey(unformattedKey); - - if (isNotEmpty(key) && !isHexKeyValid(key)) { - throw new IllegalArgumentException("The key was not provided in valid hex format and of the correct length"); - } else { - return key; - } - } - - private static String formatHexKey(String input) { - return Optional.ofNullable(input) - .map(String::trim) - .filter(SensitivePropertyUtils::isNotEmpty) - .map(str -> str.replaceAll("[^0-9a-fA-F]", EMPTY).toLowerCase()) - .orElse(EMPTY); - } - - private static boolean isHexKeyValid(String key) { - return Optional.ofNullable(key) - .map(String::trim) - .filter(SensitivePropertyUtils::isNotEmpty) - .filter(k -> k.matches("^[0-9a-fA-F]{64}$")) - .isPresent(); - } - - private static String getKey(String bootstrapConfigFilePath) { - Properties properties = new Properties(); - - try (InputStream inputStream = new BufferedInputStream(new FileInputStream(bootstrapConfigFilePath))) { - properties.load(inputStream); - } catch (Exception e) { - throw new RuntimeException(format("Loading Bootstrap Properties [%s] failed", bootstrapConfigFilePath), e); - } - - return properties.getProperty(MINIFI_BOOTSTRAP_SENSITIVE_KEY); - } - - private static boolean isNotEmpty(String keyFilePath) { - return keyFilePath != null && !keyFilePath.isBlank(); - } -} diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/pom.xml b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/pom.xml index 25383e636a05..4c9c828a2fbd 100644 --- a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/pom.xml +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/pom.xml @@ -31,19 +31,6 @@ org.slf4j slf4j-api - - org.apache.nifi - nifi-property-protection-loader - - - org.apache.nifi - nifi-property-protection-cipher - - - org.apache.nifi - nifi-property-protection-api - 2.0.0-SNAPSHOT - org.apache.nifi nifi-properties diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/BootstrapPropertiesLoader.java b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/BootstrapPropertiesLoader.java index 4c24394b8b97..7907bf59a331 100644 --- a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/BootstrapPropertiesLoader.java +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/BootstrapPropertiesLoader.java @@ -17,33 +17,15 @@ package org.apache.nifi.minifi.properties; -import static java.lang.String.format; -import static org.apache.nifi.minifi.commons.utils.SensitivePropertyUtils.MINIFI_BOOTSTRAP_SENSITIVE_KEY; -import static org.apache.nifi.minifi.commons.utils.SensitivePropertyUtils.getFormattedKey; - import java.io.File; -import org.apache.nifi.properties.AesGcmSensitivePropertyProvider; public class BootstrapPropertiesLoader { public static BootstrapProperties load(File file) { - ProtectedBootstrapProperties protectedProperties = loadProtectedProperties(file); - if (protectedProperties.hasProtectedKeys()) { - String sensitiveKey = protectedProperties.getApplicationProperties().getProperty(MINIFI_BOOTSTRAP_SENSITIVE_KEY); - validateSensitiveKeyProperty(sensitiveKey); - String keyHex = getFormattedKey(sensitiveKey); - protectedProperties.addSensitivePropertyProvider(new AesGcmSensitivePropertyProvider(keyHex)); - } - return protectedProperties.getUnprotectedProperties(); - } - - public static ProtectedBootstrapProperties loadProtectedProperties(File file) { - return new ProtectedBootstrapProperties(PropertiesLoader.load(file, "Bootstrap")); + return loadProtectedProperties(file); } - private static void validateSensitiveKeyProperty(String sensitiveKey) { - if (sensitiveKey == null || sensitiveKey.trim().isEmpty()) { - throw new IllegalArgumentException(format("bootstrap.conf contains protected properties but %s is not found", MINIFI_BOOTSTRAP_SENSITIVE_KEY)); - } + public static BootstrapProperties loadProtectedProperties(File file) { + return new BootstrapProperties(PropertiesLoader.load(file, "Bootstrap")); } } diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/MiNiFiPropertiesLoader.java b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/MiNiFiPropertiesLoader.java index d15fa3ee37f0..91ad422bff4d 100644 --- a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/MiNiFiPropertiesLoader.java +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/MiNiFiPropertiesLoader.java @@ -17,7 +17,8 @@ package org.apache.nifi.minifi.properties; import java.io.File; -import org.apache.nifi.properties.AesGcmSensitivePropertyProvider; +import java.util.Properties; + import org.apache.nifi.util.NiFiBootstrapUtils; import org.apache.nifi.util.NiFiProperties; @@ -26,40 +27,17 @@ public class MiNiFiPropertiesLoader { private static final String DEFAULT_APPLICATION_PROPERTIES_FILE_PATH = NiFiBootstrapUtils.getDefaultApplicationPropertiesFilePath(); private NiFiProperties instance; - private String keyHex; - - public MiNiFiPropertiesLoader(String keyHex) { - this.keyHex = keyHex; - } - - /** - * Returns a {@link ProtectedMiNiFiProperties} instance loaded from the - * serialized form in the file. Responsible for actually reading from disk - * and deserializing the properties. Returns a protected instance to allow - * for decryption operations. - * - * @param file the file containing serialized properties - * @return the ProtectedMiNiFiProperties instance - */ - ProtectedMiNiFiProperties loadProtectedProperties(File file) { - return new ProtectedMiNiFiProperties(PropertiesLoader.load(file, "Application")); - } /** * Returns an instance of {@link NiFiProperties} loaded from the provided - * {@link File}. If any properties are protected, will attempt to use the - * {@link AesGcmSensitivePropertyProvider} to unprotect them - * transparently. + * {@link File}. * * @param file the File containing the serialized properties * @return the NiFiProperties instance */ public NiFiProperties load(File file) { - ProtectedMiNiFiProperties protectedProperties = loadProtectedProperties(file); - if (protectedProperties.hasProtectedKeys()) { - protectedProperties.addSensitivePropertyProvider(new AesGcmSensitivePropertyProvider(keyHex)); - } - return new MultiSourceMinifiProperties(protectedProperties.getUnprotectedPropertiesAsMap()); + final Properties properties = PropertiesLoader.load(file, "Application"); + return new MultiSourceMinifiProperties(properties); } /** diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/MultiSourceMinifiProperties.java b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/MultiSourceMinifiProperties.java index f39a97dee5ec..53356f687508 100644 --- a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/MultiSourceMinifiProperties.java +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/MultiSourceMinifiProperties.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.minifi.properties; -import java.util.Map; +import java.util.Properties; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -29,7 +29,7 @@ */ public class MultiSourceMinifiProperties extends NiFiProperties { - public MultiSourceMinifiProperties(Map props) { + public MultiSourceMinifiProperties(Properties props) { super(props); } diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/PropertiesLoader.java b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/PropertiesLoader.java index 9785fda997cc..1ba6d434ceeb 100644 --- a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/PropertiesLoader.java +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/PropertiesLoader.java @@ -27,7 +27,7 @@ public interface PropertiesLoader { - static final Logger logger = LoggerFactory.getLogger(PropertiesLoader.class); + Logger logger = LoggerFactory.getLogger(PropertiesLoader.class); static Properties load(File file, String propertiesType) { if (file == null || !file.exists() || !file.canRead()) { diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/ProtectedBootstrapProperties.java b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/ProtectedBootstrapProperties.java deleted file mode 100644 index 486574a822b8..000000000000 --- a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/ProtectedBootstrapProperties.java +++ /dev/null @@ -1,134 +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.minifi.properties; - -import static org.apache.nifi.minifi.commons.api.MiNiFiProperties.ADDITIONAL_SENSITIVE_PROPERTIES_KEY; -import static org.apache.nifi.minifi.properties.ProtectedMiNiFiProperties.DEFAULT_SENSITIVE_PROPERTIES; - -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.apache.nifi.minifi.commons.api.MiNiFiProperties; -import org.apache.nifi.properties.ApplicationPropertiesProtector; -import org.apache.nifi.properties.ProtectedProperties; -import org.apache.nifi.properties.SensitivePropertyProtectionException; -import org.apache.nifi.properties.SensitivePropertyProtector; -import org.apache.nifi.properties.SensitivePropertyProvider; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ProtectedBootstrapProperties extends BootstrapProperties implements ProtectedProperties, - SensitivePropertyProtector { - - private static final Logger logger = LoggerFactory.getLogger(ProtectedBootstrapProperties.class); - - private BootstrapProperties bootstrapProperties; - - private final SensitivePropertyProtector propertyProtectionDelegate; - - public ProtectedBootstrapProperties(BootstrapProperties props) { - super(); - this.bootstrapProperties = props; - this.propertyProtectionDelegate = new ApplicationPropertiesProtector<>(this); - logger.debug("Loaded {} properties (including {} protection schemes) into ProtectedBootstrapProperties", getApplicationProperties().getPropertyKeys().size(), - getProtectedPropertyKeys().size()); - } - - public ProtectedBootstrapProperties(Properties rawProps) { - this(new BootstrapProperties(rawProps)); - } - - @Override - public Set getPropertyKeysIncludingProtectionSchemes() { - return propertyProtectionDelegate.getPropertyKeysIncludingProtectionSchemes(); - } - - @Override - public List getSensitivePropertyKeys() { - return propertyProtectionDelegate.getSensitivePropertyKeys(); - } - - @Override - public List getPopulatedSensitivePropertyKeys() { - return propertyProtectionDelegate.getPopulatedSensitivePropertyKeys(); - } - - @Override - public boolean hasProtectedKeys() { - return propertyProtectionDelegate.hasProtectedKeys(); - } - - @Override - public Map getProtectedPropertyKeys() { - return propertyProtectionDelegate.getProtectedPropertyKeys(); - } - - @Override - public boolean isPropertySensitive(String key) { - return propertyProtectionDelegate.isPropertySensitive(key); - } - - @Override - public boolean isPropertyProtected(String key) { - return propertyProtectionDelegate.isPropertyProtected(key); - } - - @Override - public BootstrapProperties getUnprotectedProperties() throws SensitivePropertyProtectionException { - return propertyProtectionDelegate.getUnprotectedProperties(); - } - - @Override - public void addSensitivePropertyProvider(SensitivePropertyProvider sensitivePropertyProvider) { - propertyProtectionDelegate.addSensitivePropertyProvider(sensitivePropertyProvider); - } - - @Override - public String getAdditionalSensitivePropertiesKeys() { - return getProperty(getAdditionalSensitivePropertiesKeysName()); - } - - @Override - public String getAdditionalSensitivePropertiesKeysName() { - return ADDITIONAL_SENSITIVE_PROPERTIES_KEY; - } - - @Override - public List getDefaultSensitiveProperties() { - return Stream.of(DEFAULT_SENSITIVE_PROPERTIES, Arrays.stream(MiNiFiProperties.values()).filter(MiNiFiProperties::isSensitive).map(MiNiFiProperties::getKey).collect(Collectors.toList())) - .flatMap(List::stream).distinct().collect(Collectors.toList()); - } - - @Override - public BootstrapProperties getApplicationProperties() { - if (this.bootstrapProperties == null) { - this.bootstrapProperties = new BootstrapProperties(); - } - - return this.bootstrapProperties; - } - - @Override - public BootstrapProperties createApplicationProperties(Properties rawProperties) { - return new BootstrapProperties(rawProperties); - } -} diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/ProtectedMiNiFiProperties.java b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/ProtectedMiNiFiProperties.java deleted file mode 100644 index 238a11041389..000000000000 --- a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/ProtectedMiNiFiProperties.java +++ /dev/null @@ -1,239 +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.minifi.properties; - -import static java.util.Arrays.asList; -import static org.apache.nifi.minifi.commons.api.MiNiFiProperties.ADDITIONAL_SENSITIVE_PROPERTIES_KEY; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.apache.nifi.minifi.commons.api.MiNiFiProperties; -import org.apache.nifi.properties.ApplicationPropertiesProtector; -import org.apache.nifi.properties.ProtectedProperties; -import org.apache.nifi.properties.SensitivePropertyProtectionException; -import org.apache.nifi.properties.SensitivePropertyProtector; -import org.apache.nifi.properties.SensitivePropertyProvider; -import org.apache.nifi.util.NiFiProperties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Decorator class for intermediate phase when {@link MiNiFiPropertiesLoader} loads the - * raw properties file and performs unprotection activities before returning a clean - * implementation of {@link NiFiProperties}. - * This encapsulates the sensitive property access logic from external consumers - * of {@code NiFiProperties}. - */ -public class ProtectedMiNiFiProperties extends NiFiProperties implements ProtectedProperties, - SensitivePropertyProtector { - private static final Logger logger = LoggerFactory.getLogger(ProtectedMiNiFiProperties.class); - public static final List DEFAULT_SENSITIVE_PROPERTIES = new ArrayList<>(asList( - SECURITY_KEY_PASSWD, - SECURITY_KEYSTORE_PASSWD, - SECURITY_TRUSTSTORE_PASSWD, - SENSITIVE_PROPS_KEY - )); - - private final SensitivePropertyProtector propertyProtectionDelegate; - - private NiFiProperties applicationProperties; - - public ProtectedMiNiFiProperties() { - this(new NiFiProperties()); - } - - /** - * Creates an instance containing the provided {@link NiFiProperties}. - * - * @param props the NiFiProperties to contain - */ - public ProtectedMiNiFiProperties(NiFiProperties props) { - this.applicationProperties = props; - this.propertyProtectionDelegate = new ApplicationPropertiesProtector<>(this); - logger.debug("Loaded {} properties (including {} protection schemes) into ProtectedNiFiProperties", getApplicationProperties() - .getPropertyKeys().size(), getProtectedPropertyKeys().size()); - } - - /** - * Creates an instance containing the provided raw {@link Properties}. - * - * @param rawProps the Properties to contain - */ - public ProtectedMiNiFiProperties(Properties rawProps) { - this(new NiFiProperties(rawProps)); - } - - @Override - public String getAdditionalSensitivePropertiesKeys() { - return getProperty(getAdditionalSensitivePropertiesKeysName()); - } - - @Override - public String getAdditionalSensitivePropertiesKeysName() { - return ADDITIONAL_SENSITIVE_PROPERTIES_KEY; - } - - @Override - public List getDefaultSensitiveProperties() { - return Stream.of(DEFAULT_SENSITIVE_PROPERTIES, - Arrays.stream(MiNiFiProperties.values()).filter(MiNiFiProperties::isSensitive).map(MiNiFiProperties::getKey).toList()).flatMap(List::stream).distinct().toList(); - } - - /** - * Returns the internal representation of the {@link NiFiProperties} -- protected - * or not as determined by the current state. No guarantee is made to the - * protection state of these properties. If the internal reference is null, a new - * {@link NiFiProperties} instance is created. - * - * @return the internal properties - */ - public NiFiProperties getApplicationProperties() { - if (this.applicationProperties == null) { - this.applicationProperties = new NiFiProperties(); - } - - return this.applicationProperties; - } - - @Override - public NiFiProperties createApplicationProperties(final Properties rawProperties) { - return new NiFiProperties(rawProperties); - } - - /** - * Retrieves the property value for the given property key. - * - * @param key the key of property value to lookup - * @return value of property at given key or null if not found - */ - @Override - public String getProperty(String key) { - return getApplicationProperties().getProperty(key); - } - - /** - * Retrieves all known property keys. - * - * @return all known property keys - */ - @Override - public Set getPropertyKeys() { - return propertyProtectionDelegate.getPropertyKeys(); - } - - /** - * Returns the number of properties, excluding protection scheme properties. - *

- * Example: - *

- * key: E(value, key) - * key.protected: aes/gcm/256 - * key2: value2 - *

- * would return size 2 - * - * @return the count of real properties - */ - @Override - public int size() { - return propertyProtectionDelegate.size(); - } - - @Override - public Set getPropertyKeysIncludingProtectionSchemes() { - return propertyProtectionDelegate.getPropertyKeysIncludingProtectionSchemes(); - } - - @Override - public List getSensitivePropertyKeys() { - return propertyProtectionDelegate.getSensitivePropertyKeys(); - } - - @Override - public List getPopulatedSensitivePropertyKeys() { - return propertyProtectionDelegate.getPopulatedSensitivePropertyKeys(); - } - - @Override - public boolean hasProtectedKeys() { - return propertyProtectionDelegate.hasProtectedKeys(); - } - - @Override - public Map getProtectedPropertyKeys() { - return propertyProtectionDelegate.getProtectedPropertyKeys(); - } - - @Override - public boolean isPropertySensitive(final String key) { - return propertyProtectionDelegate.isPropertySensitive(key); - } - - @Override - public boolean isPropertyProtected(final String key) { - return propertyProtectionDelegate.isPropertyProtected(key); - } - - @Override - public NiFiProperties getUnprotectedProperties() throws SensitivePropertyProtectionException { - return propertyProtectionDelegate.getUnprotectedProperties(); - } - - @Override - public void addSensitivePropertyProvider(final SensitivePropertyProvider sensitivePropertyProvider) { - propertyProtectionDelegate.addSensitivePropertyProvider(sensitivePropertyProvider); - } - - public Map getUnprotectedPropertiesAsMap() { - NiFiProperties niFiProperties = propertyProtectionDelegate.getUnprotectedProperties(); - return niFiProperties.getPropertyKeys().stream().collect(Collectors.toMap(Function.identity(), niFiProperties::getProperty)); - } - - /** - * Returns the number of properties that are marked as protected in the provided {@link NiFiProperties} instance without requiring external creation of a - * {@link ProtectedMiNiFiProperties} instance. - * - * @param plainProperties the instance to count protected properties - * @return the number of protected properties - */ - public static int countProtectedProperties(final NiFiProperties plainProperties) { - return new ProtectedMiNiFiProperties(plainProperties).getProtectedPropertyKeys().size(); - } - - /** - * Returns the number of properties that are marked as sensitive in the provided {@link NiFiProperties} instance without requiring external creation of a - * {@link ProtectedMiNiFiProperties} instance. - * - * @param plainProperties the instance to count sensitive properties - * @return the number of sensitive properties - */ - public static int countSensitiveProperties(final NiFiProperties plainProperties) { - return new ProtectedMiNiFiProperties(plainProperties).getSensitivePropertyKeys().size(); - } - - @Override - public String toString() { - return String.format("%s Size [%d]", getClass().getSimpleName(), size()); - } -} diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/java/org/apache/nifi/minifi/properties/BootstrapPropertiesLoaderTest.java b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/java/org/apache/nifi/minifi/properties/BootstrapPropertiesLoaderTest.java deleted file mode 100644 index c3d3febcac77..000000000000 --- a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/java/org/apache/nifi/minifi/properties/BootstrapPropertiesLoaderTest.java +++ /dev/null @@ -1,82 +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.minifi.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; - -import java.io.File; -import java.net.URL; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; -import org.junit.jupiter.api.Test; - -class BootstrapPropertiesLoaderTest { - - private static final String NON_EXISTING_FILE_PATH = "/conf/nonexisting.conf"; - private static final String DUPLICATED_ITEMS_FILE_PATH = "/conf/bootstrap_duplicated_items.conf"; - private static final String UNPROTECTED_ITEMS_FILE_PATH = "/conf/bootstrap_unprotected.conf"; - private static final String PROTECTED_ITEMS_FILE_PATH = "/conf/bootstrap_protected.conf"; - private static final String PROTECTED_ITEMS_WITHOUT_SENSITIVE_KEY_FILE_PATH = "/conf/bootstrap_protected_without_sensitive_key.conf"; - - private static final Map UNPROTECTED_PROPERTIES = Map.of("nifi.minifi.security.keystorePasswd", "testPassword", "nifi.minifi.sensitive.props.key", "testSensitivePropsKey"); - - @Test - void shouldThrowIllegalArgumentExceptionIfFileIsNotProvided() { - assertThrows(IllegalArgumentException.class, () -> BootstrapPropertiesLoader.load(null)); - } - - @Test - void shouldThrowIllegalArgumentExceptionIfFileDoesNotExists() { - assertThrows(IllegalArgumentException.class, () -> BootstrapPropertiesLoader.load(new File(NON_EXISTING_FILE_PATH))); - } - - @Test - void shouldThrowIllegalArgumentExceptionIfTheConfigFileContainsDuplicatedKeysWithDifferentValues() { - assertThrows(IllegalArgumentException.class, () -> BootstrapPropertiesLoader.load(getFile(DUPLICATED_ITEMS_FILE_PATH))); - } - - @Test - void shouldReturnPropertiesIfConfigFileDoesNotContainProtectedProperties() { - BootstrapProperties bootstrapProperties = BootstrapPropertiesLoader.load(getFile(UNPROTECTED_ITEMS_FILE_PATH)); - - assertEquals(UNPROTECTED_PROPERTIES, - bootstrapProperties.getPropertyKeys().stream().filter(UNPROTECTED_PROPERTIES::containsKey).collect(Collectors.toMap(Function.identity(), bootstrapProperties::getProperty))); - } - - @Test - void shouldReturnUnProtectedProperties() { - BootstrapProperties bootstrapProperties = BootstrapPropertiesLoader.load(getFile(PROTECTED_ITEMS_FILE_PATH)); - - assertEquals(UNPROTECTED_PROPERTIES, - bootstrapProperties.getPropertyKeys().stream().filter(UNPROTECTED_PROPERTIES::containsKey).collect(Collectors.toMap(Function.identity(), bootstrapProperties::getProperty))); - } - - @Test - void shouldThrowIllegalArgumentExceptionIfFileContainsProtectedPropertiesButSensitiveKeyIsMissing() { - assertThrows(IllegalArgumentException.class, () -> BootstrapPropertiesLoader.load(getFile(PROTECTED_ITEMS_WITHOUT_SENSITIVE_KEY_FILE_PATH))); - } - - private File getFile(String duplicatedItemsFilePath) { - URL resource = BootstrapPropertiesLoaderTest.class.getResource(duplicatedItemsFilePath); - assertNotNull(resource); - return new File(resource.getPath()); - } -} \ No newline at end of file diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/java/org/apache/nifi/minifi/properties/MiNiFiPropertiesLoaderTest.java b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/java/org/apache/nifi/minifi/properties/MiNiFiPropertiesLoaderTest.java deleted file mode 100644 index fd4c863dd0f2..000000000000 --- a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/java/org/apache/nifi/minifi/properties/MiNiFiPropertiesLoaderTest.java +++ /dev/null @@ -1,90 +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.minifi.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; - -import java.io.File; -import java.net.URL; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; -import org.apache.nifi.util.NiFiProperties; -import org.junit.jupiter.api.Test; - -class MiNiFiPropertiesLoaderTest { - private static final String NON_EXISTING_FILE_PATH = "/conf/nonexisting.properties"; - private static final String DUPLICATED_ITEMS_FILE_PATH = "/conf/bootstrap_duplicated_items.conf"; - private static final String UNPROTECTED_ITEMS_FILE_PATH = "/conf/minifi_unprotected.properties"; - private static final String PROTECTED_ITEMS_FILE_PATH = "/conf/minifi_protected.properties"; - private static final Map UNPROTECTED_PROPERTIES = Map.of("nifi.security.keystorePasswd", "testPassword", "nifi.security.keyPasswd", - "testSensitivePropsKey"); - private static final String PROTECTION_KEY = "00714ae7a77b24cde1d36bd19472777e0d4ab02c38913b7f9bf41f3963147b4f"; - - @Test - void shouldThrowIllegalArgumentExceptionIfFileIsNotProvided() { - MiNiFiPropertiesLoader miNiFiPropertiesLoader = new MiNiFiPropertiesLoader(""); - assertThrows(IllegalArgumentException.class, () -> miNiFiPropertiesLoader.load((String) null)); - } - - @Test - void shouldThrowIllegalArgumentExceptionIfFileDoesNotExists() { - MiNiFiPropertiesLoader miNiFiPropertiesLoader = new MiNiFiPropertiesLoader(""); - assertThrows(IllegalArgumentException.class, () -> miNiFiPropertiesLoader.load(new File(NON_EXISTING_FILE_PATH))); - } - - @Test - void shouldThrowIllegalArgumentExceptionIfTheConfigFileContainsDuplicatedKeysWithDifferentValues() { - MiNiFiPropertiesLoader miNiFiPropertiesLoader = new MiNiFiPropertiesLoader(""); - - assertThrows(IllegalArgumentException.class, () -> miNiFiPropertiesLoader.load(getFile(DUPLICATED_ITEMS_FILE_PATH))); - } - - @Test - void shouldReturnPropertiesIfConfigFileDoesNotContainProtectedProperties() { - MiNiFiPropertiesLoader miNiFiPropertiesLoader = new MiNiFiPropertiesLoader(""); - - NiFiProperties niFiProperties = miNiFiPropertiesLoader.load(getFile(UNPROTECTED_ITEMS_FILE_PATH)); - - assertEquals(UNPROTECTED_PROPERTIES, - niFiProperties.getPropertyKeys().stream().filter(UNPROTECTED_PROPERTIES::containsKey).collect(Collectors.toMap(Function.identity(), niFiProperties::getProperty))); - } - - @Test - void shouldReturnUnProtectedProperties() { - MiNiFiPropertiesLoader miNiFiPropertiesLoader = new MiNiFiPropertiesLoader(PROTECTION_KEY); - - NiFiProperties niFiProperties = miNiFiPropertiesLoader.load(getUrl(PROTECTED_ITEMS_FILE_PATH).getPath()); - - assertEquals(UNPROTECTED_PROPERTIES, - niFiProperties.getPropertyKeys().stream().filter(UNPROTECTED_PROPERTIES::containsKey).collect(Collectors.toMap(Function.identity(), niFiProperties::getProperty))); - } - - private File getFile(String propertiesFilePath) { - URL resource = getUrl(propertiesFilePath); - return new File(resource.getPath()); - } - - private static URL getUrl(String propertiesFilePath) { - URL resource = BootstrapPropertiesLoaderTest.class.getResource(propertiesFilePath); - assertNotNull(resource); - return resource; - } -} \ No newline at end of file diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/bootstrap_duplicated_items.conf b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/bootstrap_duplicated_items.conf deleted file mode 100644 index dd742bafdabd..000000000000 --- a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/bootstrap_duplicated_items.conf +++ /dev/null @@ -1,18 +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. - -# property file that contains the same key with different values -property1=test -property1=test2 \ No newline at end of file diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/bootstrap_protected.conf b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/bootstrap_protected.conf deleted file mode 100644 index 86966e899963..000000000000 --- a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/bootstrap_protected.conf +++ /dev/null @@ -1,22 +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. - -# property file that contains the protected properties and a sensitive key to decrypt it -nifi.minifi.security.keystorePasswd=noBD32A0ANcz/BHv||nhtyNhlFgNNZcVhgxEOg2xUZ5UAihgyBit1drQ== -nifi.minifi.security.keystorePasswd.protected=aes/gcm/256 -nifi.minifi.sensitive.props.key=JUMeAtpD1Q7CiXHt||BppiPMoWXxkKBl5mYsxP5vkVabsXZyLu2lxjyv9LMHc6RJEE9g== -nifi.minifi.sensitive.props.key.protected=aes/gcm/256 - -minifi.bootstrap.sensitive.key=00714ae7a77b24cde1d36bd19472777e0d4ab02c38913b7f9bf41f3963147b4f diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/bootstrap_protected_without_sensitive_key.conf b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/bootstrap_protected_without_sensitive_key.conf deleted file mode 100644 index bcc8fe9d8a2b..000000000000 --- a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/bootstrap_protected_without_sensitive_key.conf +++ /dev/null @@ -1,20 +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. - -# property file that contains the protected properties but without minifi.bootstrap.sensitive.key -nifi.minifi.security.keystorePasswd=noBD32A0ANcz/BHv||nhtyNhlFgNNZcVhgxEOg2xUZ5UAihgyBit1drQ== -nifi.minifi.security.keystorePasswd.protected=aes/gcm/256 -nifi.minifi.sensitive.props.key=JUMeAtpD1Q7CiXHt||BppiPMoWXxkKBl5mYsxP5vkVabsXZyLu2lxjyv9LMHc6RJEE9g== -nifi.minifi.sensitive.props.key.protected=aes/gcm/256 diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/bootstrap_unprotected.conf b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/bootstrap_unprotected.conf deleted file mode 100644 index e08d4790a5c4..000000000000 --- a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/bootstrap_unprotected.conf +++ /dev/null @@ -1,18 +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. - -# property file that contains the unprotected properties -nifi.minifi.security.keystorePasswd=testPassword -nifi.minifi.sensitive.props.key=testSensitivePropsKey \ No newline at end of file diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/minifi_duplicated.properties b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/minifi_duplicated.properties deleted file mode 100644 index 285d126c1def..000000000000 --- a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/minifi_duplicated.properties +++ /dev/null @@ -1,20 +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.security.keystorePasswd=s+jNt0t608+F0uq9||PWPtOCr5fmItmL8ZsgpheQxkkJJzXWqrNvqdCL/gcGE2cy1NTgGDhI1apuacNHjj -nifi.security.keystorePasswd=123 -nifi.security.keystorePasswd.protected=aes/gcm/256 -nifi.security.keyPasswd=JUMeAtpD1Q7CiXHt||BppiPMoWXxkKBl5mYsxP5vkVabsXZyLu2lxjyv9LMHc6RJEE9g== -nifi.security.keyPasswd.protected=aes/gcm/256 \ No newline at end of file diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/minifi_protected.properties b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/minifi_protected.properties deleted file mode 100644 index 85319171cf80..000000000000 --- a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/minifi_protected.properties +++ /dev/null @@ -1,19 +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.security.keystorePasswd=noBD32A0ANcz/BHv||nhtyNhlFgNNZcVhgxEOg2xUZ5UAihgyBit1drQ== -nifi.security.keystorePasswd.protected=aes/gcm/256 -nifi.security.keyPasswd=JUMeAtpD1Q7CiXHt||BppiPMoWXxkKBl5mYsxP5vkVabsXZyLu2lxjyv9LMHc6RJEE9g== -nifi.security.keyPasswd.protected=aes/gcm/256 \ No newline at end of file diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/minifi_unprotected.properties b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/minifi_unprotected.properties deleted file mode 100644 index 06d04d3f31a6..000000000000 --- a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/minifi_unprotected.properties +++ /dev/null @@ -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.security.keystorePasswd=testPassword -nifi.security.keyPasswd=testSensitivePropsKey \ No newline at end of file diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-runtime/src/main/java/org/apache/nifi/minifi/MiNiFi.java b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-runtime/src/main/java/org/apache/nifi/minifi/MiNiFi.java index 8c0821348b43..76419a366651 100644 --- a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-runtime/src/main/java/org/apache/nifi/minifi/MiNiFi.java +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-runtime/src/main/java/org/apache/nifi/minifi/MiNiFi.java @@ -16,7 +16,6 @@ */ package org.apache.nifi.minifi; -import static org.apache.nifi.minifi.commons.utils.SensitivePropertyUtils.getFormattedKey; import static org.apache.nifi.minifi.util.BootstrapClassLoaderUtils.createBootstrapClassLoader; import java.io.File; @@ -239,14 +238,13 @@ protected static NiFiProperties getValidatedMiNifiProperties() { private static NiFiProperties initializeProperties(ClassLoader boostrapLoader) { ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); - String key = getFormattedKey(); Thread.currentThread().setContextClassLoader(boostrapLoader); try { Class propsLoaderClass = Class.forName("org.apache.nifi.minifi.properties.MiNiFiPropertiesLoader", true, boostrapLoader); - Constructor constructor = propsLoaderClass.getDeclaredConstructor(String.class); - Object loaderInstance = constructor.newInstance(key); + Constructor constructor = propsLoaderClass.getConstructor(); + Object loaderInstance = constructor.newInstance(); Method getMethod = propsLoaderClass.getMethod("get"); NiFiProperties properties = (NiFiProperties) getMethod.invoke(loaderInstance); logger.info("Application Properties loaded [{}]", properties.size()); diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/pom.xml b/minifi/minifi-nar-bundles/minifi-framework-bundle/pom.xml index cc6fda3dc001..fffe2da4c04e 100644 --- a/minifi/minifi-nar-bundles/minifi-framework-bundle/pom.xml +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/pom.xml @@ -79,16 +79,6 @@ limitations under the License. 2.0.0-SNAPSHOT test - - org.apache.nifi - nifi-property-protection-loader - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-cipher - 2.0.0-SNAPSHOT - \ No newline at end of file diff --git a/minifi/minifi-toolkit/minifi-toolkit-assembly/README.md b/minifi/minifi-toolkit/minifi-toolkit-assembly/README.md index 0b0b0444d3a0..c6651d313ed2 100644 --- a/minifi/minifi-toolkit/minifi-toolkit-assembly/README.md +++ b/minifi/minifi-toolkit/minifi-toolkit-assembly/README.md @@ -61,102 +61,6 @@ After downloading the binary and extracting it, to run the MiNiFi Toolkit Conver ## Note It's not guaranteed in all circumstances that the migration will result in a correct flow. For example if a processor's configuration has changed between version, the conversion tool won't be aware of this, and will use the deprecated property names. You will need to fix such issues manually. -# Encrypting Sensitive Properties in bootstrap.conf - -## MiNiFi Encrypt-Config Tool -The encrypt-config command line tool (invoked in minifi-toolkit as ./bin/encrypt-config.sh or bin\encrypt-config.bat) reads from a bootstrap.conf file with plaintext sensitive configuration values and encrypts each value using a random encryption key. It replaces the plain values with the protected value in the same file, or writes to a new bootstrap.conf file if specified. Additionally it can be used to encrypt the unencrypted sensitive properties (if any) in the flow.json.raw. For using this functionality `nifi.minifi.sensitive.props.key` and `nifi.minifi.sensitive.props.algorithm` has to be provided in bootstrap.conf. - -The supported encryption algorithm utilized is AES/GCM 256-bit. - -### Usage -To show help: - -``` -./bin/encrypt-config.sh -h -``` - -The following are the available options: -* -b, --bootstrapConf Path to file containing Bootstrap Configuration [bootstrap.conf] -* -B, --outputBootstrapConf Path to output file for Bootstrap Configuration [bootstrap.conf] with root key configured -* -x, --encryptRawFlowJsonOnly Process Raw Flow Configuration [flow.json.raw] sensitive property values without modifying other configuration files -* -f, --rawFlowJson Path to file containing Raw Flow Configuration [flow.json.raw] that will be updated unless the output argument is provided -* -g, --outputRawFlowJson ath to output file for Raw Flow Configuration [flow.json.raw] with property protection applied -* -h, --help Show help message and exit. - -### Example 1 -As an example of how the tool works with the following existing values in the bootstrap.conf file: -``` -nifi.sensitive.props.key=thisIsABadSensitiveKeyPassword -nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM_256 -nifi.sensitive.props.additional.keys= - -nifi.security.keystore=/path/to/keystore.jks -nifi.security.keystoreType=JKS -nifi.security.keystorePasswd=thisIsABadKeystorePassword -nifi.security.keyPasswd=thisIsABadKeyPassword -nifi.security.truststore= -nifi.security.truststoreType= -nifi.security.truststorePasswd= -c2.security.truststore.location= -c2.security.truststore.password=thisIsABadTruststorePassword -c2.security.truststore.type=JKS -c2.security.keystore.location= -c2.security.keystore.password=thisIsABadKeystorePassword -c2.security.keystore.type=JKS -``` -Enter the following arguments when using the tool: -``` -encrypt-config.sh \ --b bootstrap.conf \ -``` -As a result, the bootstrap.conf file is overwritten with protected properties and sibling encryption identifiers (aes/gcm/256, the currently supported algorithm): -``` -nifi.sensitive.props.key=4OjkrFywZb7BlGz4||Tm9pg0jV4TltvVKeiMlm9zBsqmtmYUA2QkzcLKQpspyggtQuhNAkAla5s2695A== -nifi.sensitive.props.key.protected=aes/gcm/256 -nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM_256 -nifi.sensitive.props.additional.keys= - -nifi.security.keystore=/path/to/keystore.jks -nifi.security.keystoreType=JKS -nifi.security.keystorePasswd=iXDmDCadoNJ3VotZ||WvOGbrii4Gk0vr3b6mDstZg+NE0BPZUPk6LVqQlf2Sx3G5XFbUbUYAUz -nifi.security.keystorePasswd.protected=aes/gcm/256 -nifi.security.keyPasswd=199uUUgpPqB4Fuoo||KckbW7iu+HZf1r4KSMQAFn8NLJK+CnUuayqPsTsdM0Wxou1BHg== -nifi.security.keyPasswd.protected=aes/gcm/256 -nifi.security.truststore= -nifi.security.truststoreType= -nifi.security.truststorePasswd= -c2.security.truststore.location= -c2.security.truststore.password=0pHpp+l/WHsDM/sm||fXBvDAQ1BXvNQ8b4EHKa1GspsLx+UD+2EDhph0HbsdmgpVhEv4qj0q5TDo0= -c2.security.truststore.password.protected=aes/gcm/256 -c2.security.truststore.type=JKS -c2.security.keystore.location= -c2.security.keystore.password=j+80L7++RNDf9INQ||RX/QkdVFwRos6Y4XJ8YSUWoI3W5Wx50dyw7HrAA84719SvfxA9eUSDEA -c2.security.keystore.password.protected=aes/gcm/256 -c2.security.keystore.type=JKS -``` - -Additionally, the bootstrap.conf file is updated with the encryption key as follows: -``` -minifi.bootstrap.sensitive.key=c92623e798be949379d0d18f432a57f1b74732141be321cb4af9ed94aa0ae8ac -``` - -Sensitive configuration values are encrypted by the tool by default, however you can encrypt any additional properties, if desired. To encrypt additional properties, specify them as comma-separated values in the minifi.sensitive.props.additional.keys property. - -If the bootstrap.conf file already has valid protected values, those property values are not modified by the tool. - -### Example 2 -An example to encrypt non encrypted sensitive properties in flow.json.raw -``` -nifi.sensitive.props.key=sensitivePropsKey -nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM_256 -``` -Enter the following arguments when using the tool: -``` -encrypt-config.sh -x -f flow.json.raw -``` -As a result, the flow.json.raw file is overwritten with encrypted sensitive properties -The algorithm uses the property descriptors in the flow.json.raw to determine if a property is sensitive or not. If that information is missing, no properties will be encrypted even if it is defined sensitive in the agent manifest. - ## Getting Help If you have questions, you can reach out to our mailing list: dev@nifi.apache.org ([archive](https://mail-archives.apache.org/mod_mbox/nifi-dev)). diff --git a/minifi/minifi-toolkit/minifi-toolkit-assembly/pom.xml b/minifi/minifi-toolkit/minifi-toolkit-assembly/pom.xml index 1a8c3a386dbf..17ba4461f6a3 100644 --- a/minifi/minifi-toolkit/minifi-toolkit-assembly/pom.xml +++ b/minifi/minifi-toolkit/minifi-toolkit-assembly/pom.xml @@ -62,11 +62,6 @@ limitations under the License. minifi-toolkit-configuration 2.0.0-SNAPSHOT - - org.apache.nifi.minifi - minifi-toolkit-encrypt-config - 2.0.0-SNAPSHOT - org.slf4j slf4j-api diff --git a/minifi/minifi-toolkit/minifi-toolkit-assembly/src/main/resources/bin/encrypt-config.bat b/minifi/minifi-toolkit/minifi-toolkit-assembly/src/main/resources/bin/encrypt-config.bat deleted file mode 100644 index 589d5a96902e..000000000000 --- a/minifi/minifi-toolkit/minifi-toolkit-assembly/src/main/resources/bin/encrypt-config.bat +++ /dev/null @@ -1,41 +0,0 @@ -@echo off -rem -rem Licensed to the Apache Software Foundation (ASF) under one or more -rem contributor license agreements. See the NOTICE file distributed with -rem this work for additional information regarding copyright ownership. -rem The ASF licenses this file to You under the Apache License, Version 2.0 -rem (the "License"); you may not use this file except in compliance with -rem the License. You may obtain a copy of the License at -rem -rem http://www.apache.org/licenses/LICENSE-2.0 -rem -rem Unless required by applicable law or agreed to in writing, software -rem distributed under the License is distributed on an "AS IS" BASIS, -rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -rem See the License for the specific language governing permissions and -rem limitations under the License. -rem - -rem Use JAVA_HOME if it's set; otherwise, just use java - -if "%JAVA_HOME%" == "" goto noJavaHome -if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome -set JAVA_EXE=%JAVA_HOME%\bin\java.exe -goto startConfig - -:noJavaHome -echo The JAVA_HOME environment variable is not defined correctly. -echo Instead the PATH will be used to find the java executable. -echo. -set JAVA_EXE=java -goto startConfig - -:startConfig -set LIB_DIR=%~dp0..\classpath;%~dp0..\lib - -if "%JAVA_OPTS%" == "" set JAVA_OPTS=-Xms128m -Xmx256m - -SET JAVA_PARAMS=-cp %LIB_DIR%\* %JAVA_OPTS% org.apache.nifi.minifi.toolkit.config.EncryptConfigCommand - -cmd.exe /C ""%JAVA_EXE%" %JAVA_PARAMS% %* "" - diff --git a/minifi/minifi-toolkit/minifi-toolkit-assembly/src/main/resources/bin/encrypt-config.sh b/minifi/minifi-toolkit/minifi-toolkit-assembly/src/main/resources/bin/encrypt-config.sh deleted file mode 100644 index 4aa5e13707ce..000000000000 --- a/minifi/minifi-toolkit/minifi-toolkit-assembly/src/main/resources/bin/encrypt-config.sh +++ /dev/null @@ -1,119 +0,0 @@ -#!/bin/sh -# -# 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. -# -# - -# Script structure inspired from Apache Karaf and other Apache projects with similar startup approaches - -SCRIPT_DIR=$(dirname "$0") -SCRIPT_NAME=$(basename "$0") -MINIFI_TOOLKIT_HOME=$(cd "${SCRIPT_DIR}" && cd .. && pwd) -PROGNAME=$(basename "$0") - - -warn() { - echo "${PROGNAME}: $*" -} - -die() { - warn "$*" - exit 1 -} - -detectOS() { - # OS specific support (must be 'true' or 'false'). - cygwin=false; - aix=false; - os400=false; - darwin=false; - case "$(uname)" in - CYGWIN*) - cygwin=true - ;; - AIX*) - aix=true - ;; - OS400*) - os400=true - ;; - Darwin) - darwin=true - ;; - esac - # For AIX, set an environment variable - if ${aix}; then - export LDR_CNTRL=MAXDATA=0xB0000000@DSA - echo ${LDR_CNTRL} - fi -} - -locateJava() { - # Setup the Java Virtual Machine - if $cygwin ; then - [ -n "${JAVA}" ] && JAVA=$(cygpath --unix "${JAVA}") - [ -n "${JAVA_HOME}" ] && JAVA_HOME=$(cygpath --unix "${JAVA_HOME}") - fi - - if [ "x${JAVA}" = "x" ] && [ -r /etc/gentoo-release ] ; then - JAVA_HOME=$(java-config --jre-home) - fi - if [ "x${JAVA}" = "x" ]; then - if [ "x${JAVA_HOME}" != "x" ]; then - if [ ! -d "${JAVA_HOME}" ]; then - die "JAVA_HOME is not valid: ${JAVA_HOME}" - fi - JAVA="${JAVA_HOME}/bin/java" - else - warn "JAVA_HOME not set; results may vary" - JAVA=$(type java) - JAVA=$(expr "${JAVA}" : '.* \(/.*\)$') - if [ "x${JAVA}" = "x" ]; then - die "java command not found" - fi - fi - fi -} - -init() { - # Determine if there is special OS handling we must perform - detectOS - - # Locate the Java VM to execute - locateJava -} - -run() { - LIBS="${MINIFI_TOOLKIT_HOME}/lib/*" - - sudo_cmd_prefix="" - if $cygwin; then - MINIFI_TOOLKIT_HOME=$(cygpath --path --windows "${MINIFI_TOOLKIT_HOME}") - CLASSPATH="$MINIFI_TOOLKIT_HOME/classpath;$(cygpath --path --windows "${LIBS}")" - else - CLASSPATH="$MINIFI_TOOLKIT_HOME/classpath:${LIBS}" - fi - - export JAVA_HOME="$JAVA_HOME" - export MINIFI_TOOLKIT_HOME="$MINIFI_TOOLKIT_HOME" - - umask 0077 - exec "${JAVA}" -cp "${CLASSPATH}" ${JAVA_OPTS:--Xms128m -Xmx256m} org.apache.nifi.minifi.toolkit.config.EncryptConfigCommand "$@" -} - - -init -run "$@" diff --git a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/pom.xml b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/pom.xml deleted file mode 100644 index d4fce1b908ca..000000000000 --- a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/pom.xml +++ /dev/null @@ -1,97 +0,0 @@ - - - - - org.apache.nifi.minifi - minifi-toolkit - 2.0.0-SNAPSHOT - - 4.0.0 - - minifi-toolkit-encrypt-config - Tool to encrypt sensitive configuration values - - - info.picocli - picocli - 4.7.6 - - - org.apache.nifi - nifi-property-protection-api - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-framework-core-api - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-encryptor - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-loader - 2.0.0-SNAPSHOT - - - org.apache.commons - commons-lang3 - - - org.apache.nifi - c2-protocol-component-api - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-utils - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-cipher - 2.0.0-SNAPSHOT - - - org.apache.nifi.minifi - minifi-properties-loader - 2.0.0-SNAPSHOT - - - org.apache.nifi.minifi - minifi-commons-api - 2.0.0-SNAPSHOT - - - org.slf4j - slf4j-api - - - org.apache.nifi.minifi - minifi-commons-framework - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-framework-core - - - - - diff --git a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/EncryptConfigCommand.java b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/EncryptConfigCommand.java deleted file mode 100644 index 9e9942ac3340..000000000000 --- a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/EncryptConfigCommand.java +++ /dev/null @@ -1,42 +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.minifi.toolkit.config; - -import org.apache.nifi.minifi.toolkit.config.command.MiNiFiEncryptConfig; -import picocli.CommandLine; - -/** - * Encrypt Config Command launcher for Command Line implementation - */ -public class EncryptConfigCommand { - - /** - * Main command method launches Picocli Command Line implementation of Encrypt Config - * - * @param arguments Command line arguments - */ - public static void main(String[] arguments) { - CommandLine commandLine = new CommandLine(new MiNiFiEncryptConfig()); - if (arguments.length == 0) { - commandLine.usage(System.out); - } else { - int status = commandLine.execute(arguments); - System.exit(status); - } - } - -} diff --git a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/command/MiNiFiEncryptConfig.java b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/command/MiNiFiEncryptConfig.java deleted file mode 100644 index ebeb3ecd71e6..000000000000 --- a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/command/MiNiFiEncryptConfig.java +++ /dev/null @@ -1,222 +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.minifi.toolkit.config.command; - -import static java.nio.file.Files.readAllBytes; -import static java.nio.file.Files.write; -import static java.util.Optional.ofNullable; -import static org.apache.commons.lang3.StringUtils.isAnyBlank; -import static org.apache.nifi.minifi.commons.api.MiNiFiProperties.NIFI_MINIFI_SENSITIVE_PROPS_ALGORITHM; -import static org.apache.nifi.minifi.commons.api.MiNiFiProperties.NIFI_MINIFI_SENSITIVE_PROPS_KEY; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import java.security.SecureRandom; -import java.util.HashSet; -import java.util.HexFormat; -import java.util.Set; -import org.apache.nifi.controller.flow.VersionedDataflow; -import org.apache.nifi.encrypt.PropertyEncryptorBuilder; -import org.apache.nifi.minifi.commons.service.FlowPropertyEncryptor; -import org.apache.nifi.minifi.commons.service.FlowSerDeService; -import org.apache.nifi.minifi.commons.service.StandardFlowPropertyEncryptor; -import org.apache.nifi.minifi.commons.service.StandardFlowSerDeService; -import org.apache.nifi.minifi.properties.BootstrapProperties; -import org.apache.nifi.minifi.properties.BootstrapPropertiesLoader; -import org.apache.nifi.minifi.properties.ProtectedBootstrapProperties; -import org.apache.nifi.minifi.toolkit.config.transformer.ApplicationPropertiesFileTransformer; -import org.apache.nifi.minifi.toolkit.config.transformer.BootstrapConfigurationFileTransformer; -import org.apache.nifi.minifi.toolkit.config.transformer.FileTransformer; -import org.apache.nifi.properties.AesGcmSensitivePropertyProvider; -import org.apache.nifi.properties.SensitivePropertyProvider; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import picocli.CommandLine.Command; -import picocli.CommandLine.Option; - -/** - * Encrypt Configuration for MiNiFi - */ -@Command( - name = "encrypt-config", - sortOptions = false, - mixinStandardHelpOptions = true, - usageHelpWidth = 160, - separator = " ", - version = { - "Java ${java.version} (${java.vendor} ${java.vm.name} ${java.vm.version})" - }, - descriptionHeading = "Description: ", - description = { - "encrypt-config supports protection of sensitive values in Apache MiNiFi" - } -) -public class MiNiFiEncryptConfig implements Runnable { - - static final String BOOTSTRAP_ROOT_KEY_PROPERTY = "minifi.bootstrap.sensitive.key"; - - private static final String WORKING_FILE_NAME_FORMAT = "%s.%d.working"; - private static final int KEY_LENGTH = 32; - - @Option( - names = {"-b", "--bootstrapConf"}, - description = "Path to file containing Bootstrap Configuration [bootstrap.conf] for optional root key and property protection scheme settings" - ) - Path bootstrapConfPath; - - @Option( - names = {"-B", "--outputBootstrapConf"}, - description = "Path to output file for Bootstrap Configuration [bootstrap.conf] with root key configured" - ) - Path outputBootstrapConf; - - @Option( - names = {"-x", "--encryptRawFlowJsonOnly"}, - description = "Process Raw Flow Configuration [flow.json.raw] sensitive property values without modifying other configuration files" - ) - boolean flowConfigurationRequested; - - @Option( - names = {"-f", "--rawFlowJson"}, - description = "Path to file containing Raw Flow Configuration [flow.json.raw] that will be updated unless the output argument is provided" - ) - Path flowConfigurationPath; - - @Option( - names = {"-g", "--outputRawFlowJson"}, - description = "Path to output file for Raw Flow Configuration [flow.json.raw] with property protection applied" - ) - Path outputFlowConfigurationPath; - - protected final Logger logger = LoggerFactory.getLogger(getClass()); - - @Override - public void run() { - BootstrapProperties unprotectedProperties = BootstrapPropertiesLoader.load(bootstrapConfPath.toFile()); - processBootstrapConf(unprotectedProperties); - processFlowConfiguration(unprotectedProperties); - } - - /** - * Process bootstrap.conf writing new Root Key to specified Root Key Property when bootstrap.conf is specified - */ - protected void processBootstrapConf(BootstrapProperties unprotectedProperties) { - if (flowConfigurationRequested) { - logger.info("Bootstrap Configuration [bootstrap.conf] not modified based on provided arguments"); - return; - } - - logger.info("Started processing Bootstrap Configuration [{}]", bootstrapConfPath); - - String newRootKey = getRootKey(); - - Set sensitivePropertyNames = new HashSet<>((new ProtectedBootstrapProperties(unprotectedProperties)).getSensitivePropertyKeys()); - FileTransformer fileTransformer2 = new ApplicationPropertiesFileTransformer(unprotectedProperties, getInputSensitivePropertyProvider(newRootKey), sensitivePropertyNames); - runFileTransformer(fileTransformer2, bootstrapConfPath, outputBootstrapConf); - - FileTransformer fileTransformer = new BootstrapConfigurationFileTransformer(BOOTSTRAP_ROOT_KEY_PROPERTY, newRootKey); - runFileTransformer(fileTransformer, ofNullable(outputBootstrapConf).orElse(bootstrapConfPath), outputBootstrapConf); - logger.info("Completed processing Bootstrap Configuration [{}]", bootstrapConfPath); - } - - private String getRootKey() { - SecureRandom secureRandom = new SecureRandom(); - byte[] sensitivePropertiesKeyBinary = new byte[KEY_LENGTH]; - secureRandom.nextBytes(sensitivePropertiesKeyBinary); - return HexFormat.of().formatHex(sensitivePropertiesKeyBinary); - } - - /** - * Run File Transformer using working path based on output path - * - * @param fileTransformer File Transformer to be invoked - * @param inputPath Input path of file to be transformed - * @param outputPath Output path for transformed file that defaults to the input path when not specified - */ - protected void runFileTransformer(FileTransformer fileTransformer, Path inputPath, Path outputPath) { - Path configuredOutputPath = outputPath == null ? inputPath : outputPath; - Path workingPath = getWorkingPath(configuredOutputPath); - try { - fileTransformer.transform(inputPath, workingPath); - Files.move(workingPath, configuredOutputPath, StandardCopyOption.REPLACE_EXISTING); - } catch (IOException e) { - String message = String.format("Processing Configuration [%s] failed", inputPath); - throw new UncheckedIOException(message, e); - } - } - - - /** - * Get Input Sensitive Property Provider for decrypting previous values - * - * @return Input Sensitive Property Provider - */ - protected SensitivePropertyProvider getInputSensitivePropertyProvider(String keyHex) { - return new AesGcmSensitivePropertyProvider(keyHex); - } - - private Path getWorkingPath(Path resourcePath) { - Path fileName = resourcePath.getFileName(); - String workingFileName = String.format(WORKING_FILE_NAME_FORMAT, fileName, System.currentTimeMillis()); - return resourcePath.resolveSibling(workingFileName); - } - - private void processFlowConfiguration(BootstrapProperties unprotectedProperties) { - if (flowConfigurationPath == null) { - logger.info("Flow Configuration not specified"); - return; - } - String sensitivePropertiesKey = unprotectedProperties.getProperty(NIFI_MINIFI_SENSITIVE_PROPS_KEY.getKey()); - String sensitivePropertiesAlgorithm = unprotectedProperties.getProperty(NIFI_MINIFI_SENSITIVE_PROPS_ALGORITHM.getKey()); - if (isAnyBlank(sensitivePropertiesKey, sensitivePropertiesAlgorithm)) { - logger.info("Sensitive Properties Key or Sensitive Properties Algorithm is not provided"); - return; - } - - logger.info("Started processing Flow Configuration [{}]", flowConfigurationPath); - - byte[] flowAsBytes; - try { - flowAsBytes = readAllBytes(flowConfigurationPath); - } catch (IOException e) { - logger.error("Unable to load Flow Configuration [{}]", flowConfigurationPath); - return; - } - - FlowSerDeService flowSerDeService = StandardFlowSerDeService.defaultInstance(); - FlowPropertyEncryptor flowPropertyEncryptor = new StandardFlowPropertyEncryptor( - new PropertyEncryptorBuilder(sensitivePropertiesKey).setAlgorithm(sensitivePropertiesAlgorithm).build(), null); - - VersionedDataflow flow = flowSerDeService.deserialize(flowAsBytes); - VersionedDataflow encryptedFlow = flowPropertyEncryptor.encryptSensitiveProperties(flow); - byte[] encryptedFlowAsBytes = flowSerDeService.serialize(encryptedFlow); - - Path targetPath = ofNullable(outputFlowConfigurationPath).orElse(flowConfigurationPath); - try { - write(targetPath, encryptedFlowAsBytes); - } catch (IOException e) { - logger.error("Unable to write Flow Configuration [{}]", targetPath); - return; - } - - logger.info("Completed processing Flow Configuration [{}]", flowConfigurationPath); - } -} diff --git a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/transformer/ApplicationPropertiesFileTransformer.java b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/transformer/ApplicationPropertiesFileTransformer.java deleted file mode 100644 index 5cdc8668dd86..000000000000 --- a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/transformer/ApplicationPropertiesFileTransformer.java +++ /dev/null @@ -1,152 +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.minifi.toolkit.config.transformer; - -import static org.apache.nifi.properties.ApplicationPropertiesProtector.PROTECTED_KEY_SUFFIX; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Objects; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import org.apache.nifi.properties.ApplicationProperties; -import org.apache.nifi.properties.ApplicationPropertiesProtector; -import org.apache.nifi.properties.ProtectedPropertyContext; -import org.apache.nifi.properties.SensitivePropertyProvider; - -/** - * File Transformer supporting transformation of Application Properties with sensitive property values - */ -public class ApplicationPropertiesFileTransformer implements FileTransformer { - - private static final Pattern PROPERTY_VALUE_PATTERN = Pattern.compile("^([^#!][^=]+?)\\s*=\\s?(.+)"); - - private static final int NAME_GROUP = 1; - - private static final int VALUE_GROUP = 2; - - private static final char PROPERTY_VALUE_SEPARATOR = '='; - - private final ApplicationProperties applicationProperties; - - private final SensitivePropertyProvider outputSensitivePropertyProvider; - - private final Set sensitivePropertyNames; - - /** - * Application Properties File Transformer uses provided Application Properties as the source of protected values - * - * @param applicationProperties Application Properties containing decrypted source property values - * @param outputSensitivePropertyProvider Sensitive Property Provider encrypts specified sensitive property values - * @param sensitivePropertyNames Sensitive Property Names marked for encryption - */ - public ApplicationPropertiesFileTransformer( - ApplicationProperties applicationProperties, - SensitivePropertyProvider outputSensitivePropertyProvider, - Set sensitivePropertyNames - ) { - this.applicationProperties = Objects.requireNonNull(applicationProperties, "Application Properties required"); - this.outputSensitivePropertyProvider = Objects.requireNonNull(outputSensitivePropertyProvider, "Output Property Provider required"); - this.sensitivePropertyNames = Objects.requireNonNull(sensitivePropertyNames, "Sensitive Property Names required"); - } - - /** - * Transform input application properties using configured Sensitive Property Provider and write output properties - * - * @param inputPath Input file path to be transformed containing source application properties - * @param outputPath Output file path for protected application properties - * @throws IOException Thrown on transformation failures - */ - @Override - public void transform(Path inputPath, Path outputPath) throws IOException { - Objects.requireNonNull(inputPath, "Input path required"); - Objects.requireNonNull(outputPath, "Output path required"); - - try (BufferedReader reader = Files.newBufferedReader(inputPath); - BufferedWriter writer = Files.newBufferedWriter(outputPath)) { - transform(reader, writer); - } - } - - private void transform(BufferedReader reader, BufferedWriter writer) throws IOException { - String line = reader.readLine(); - while (line != null) { - Matcher matcher = PROPERTY_VALUE_PATTERN.matcher(line); - String nextLine = null; - if (matcher.matches()) { - nextLine = processPropertyLine(reader, writer, matcher, line); - } else { - writeNonSensitiveLine(writer, line); - } - - line = nextLine == null ? reader.readLine() : nextLine; - } - } - - private String processPropertyLine(BufferedReader reader, BufferedWriter writer, Matcher matcher, String line) throws IOException { - String actualPropertyName = matcher.group(NAME_GROUP); - String actualPropertyValue = matcher.group(VALUE_GROUP); - String nextLine = null; - - if (!actualPropertyName.endsWith(PROTECTED_KEY_SUFFIX)) { - nextLine = reader.readLine(); - if (sensitivePropertyNames.contains(actualPropertyName) || isNextPropertyProtected(actualPropertyName, nextLine)) { - String applicationProperty = applicationProperties.getProperty(actualPropertyName, actualPropertyValue); - writeProtectedProperty(writer, actualPropertyName, applicationProperty); - } else { - writeNonSensitiveLine(writer, line); - } - } - return nextLine; - } - - private void writeNonSensitiveLine(BufferedWriter writer, String line) throws IOException { - writer.write(line); - writer.newLine(); - } - - private boolean isNextPropertyProtected(String actualPropertyName, String nextLine) { - if (nextLine != null) { - Matcher nextLineMatcher = PROPERTY_VALUE_PATTERN.matcher(nextLine); - if (nextLineMatcher.matches()) { - String protectedActualPropertyName = ApplicationPropertiesProtector.getProtectionKey(actualPropertyName); - String nextName = nextLineMatcher.group(NAME_GROUP); - return protectedActualPropertyName.equals(nextName); - } - } - return false; - } - - private void writeProtectedProperty(BufferedWriter writer, String name, String value) throws IOException { - ProtectedPropertyContext propertyContext = ProtectedPropertyContext.defaultContext(name); - String protectedValue = outputSensitivePropertyProvider.protect(value, propertyContext); - - writer.write(name); - writer.write(PROPERTY_VALUE_SEPARATOR); - writeNonSensitiveLine(writer, protectedValue); - - String protectedName = ApplicationPropertiesProtector.getProtectionKey(name); - writer.write(protectedName); - writer.write(PROPERTY_VALUE_SEPARATOR); - String protectionIdentifierKey = outputSensitivePropertyProvider.getIdentifierKey(); - writeNonSensitiveLine(writer, protectionIdentifierKey); - } -} diff --git a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/transformer/BootstrapConfigurationFileTransformer.java b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/transformer/BootstrapConfigurationFileTransformer.java deleted file mode 100644 index 8325c1ef70ef..000000000000 --- a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/transformer/BootstrapConfigurationFileTransformer.java +++ /dev/null @@ -1,108 +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.minifi.toolkit.config.transformer; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Objects; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * File Transformer supporting Bootstrap Configuration with updated Root Key - */ -public class BootstrapConfigurationFileTransformer implements FileTransformer { - - private static final Pattern PROPERTY_VALUE_PATTERN = Pattern.compile("^([^#!][^=]+?)\\s*=.*"); - - private static final int NAME_GROUP = 1; - - private static final char PROPERTY_VALUE_SEPARATOR = '='; - - private final String rootKeyPropertyName; - - private final String rootKey; - - /** - * Bootstrap Configuration File Transformer writes provided Root Key to output files - * - * @param rootKeyPropertyName Root Key property name to be written - * @param rootKey Root Key to be written - */ - public BootstrapConfigurationFileTransformer(String rootKeyPropertyName, String rootKey) { - this.rootKeyPropertyName = Objects.requireNonNull(rootKeyPropertyName, "Root Key Property Name required"); - this.rootKey = Objects.requireNonNull(rootKey, "Root Key required"); - } - - /** - * Transform input configuration and write Root Key to output location - * - * @param inputPath Input file path to be transformed containing Bootstrap Configuration - * @param outputPath Output file path for updated configuration - * @throws IOException Thrown on transformation failures - */ - @Override - public void transform(Path inputPath, Path outputPath) throws IOException { - Objects.requireNonNull(inputPath, "Input path required"); - Objects.requireNonNull(outputPath, "Output path required"); - - try (BufferedReader reader = Files.newBufferedReader(inputPath); - BufferedWriter writer = Files.newBufferedWriter(outputPath)) { - transform(reader, writer); - } - } - - private void transform(BufferedReader reader, BufferedWriter writer) throws IOException { - boolean rootKeyPropertyNotFound = true; - - String line = reader.readLine(); - while (line != null) { - Matcher matcher = PROPERTY_VALUE_PATTERN.matcher(line); - if (matcher.matches()) { - String name = matcher.group(NAME_GROUP); - - if (rootKeyPropertyName.equals(name)) { - writeRootKey(writer); - rootKeyPropertyNotFound = false; - } else { - writer.write(line); - writer.newLine(); - } - } else { - writer.write(line); - writer.newLine(); - } - - line = reader.readLine(); - } - - if (rootKeyPropertyNotFound) { - writer.newLine(); - writeRootKey(writer); - } - } - - private void writeRootKey(BufferedWriter writer) throws IOException { - writer.write(rootKeyPropertyName); - writer.write(PROPERTY_VALUE_SEPARATOR); - writer.write(rootKey); - writer.newLine(); - } -} diff --git a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/transformer/FileTransformer.java b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/transformer/FileTransformer.java deleted file mode 100644 index ecc05a43b649..000000000000 --- a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/transformer/FileTransformer.java +++ /dev/null @@ -1,34 +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.minifi.toolkit.config.transformer; - -import java.io.IOException; -import java.nio.file.Path; - -/** - * Abstraction for transforming Files - */ -public interface FileTransformer { - /** - * Transform input file and write contents to output file path - * - * @param inputPath Input file path to be transformed - * @param outputPath Output file path - * @throws IOException Thrown on input or output processing failures - */ - void transform(Path inputPath, Path outputPath) throws IOException; -} diff --git a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/minifi/toolkit/config/transformer/ApplicationPropertiesFileTransformerTest.java b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/minifi/toolkit/config/transformer/ApplicationPropertiesFileTransformerTest.java deleted file mode 100644 index 11bf6b01066a..000000000000 --- a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/minifi/toolkit/config/transformer/ApplicationPropertiesFileTransformerTest.java +++ /dev/null @@ -1,99 +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.minifi.toolkit.config.transformer; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.when; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Map; -import java.util.Objects; -import java.util.Properties; -import java.util.Set; -import org.apache.nifi.properties.ApplicationProperties; -import org.apache.nifi.properties.SensitivePropertyProvider; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.api.io.TempDir; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -class ApplicationPropertiesFileTransformerTest { - - private static final String UNPROTECTED_BOOTSTRAP_CONF = "/transformer/unprotected.conf"; - private static final String PROTECTED_BOOTSTRAP_PROPERTIES = "/transformer/protected.conf"; - private static final String PROPERTIES_TRANSFORMED = "transformed.conf"; - private static final String SENSITIVE_PROPERTY_NAME_1 = "property1"; - private static final String SENSITIVE_PROPERTY_NAME_2 = "property2"; - private static final String SENSITIVE_PROPERTY_NAME_3 = "property3"; - private static final String PROVIDER_IDENTIFIER_KEY = "mocked-provider"; - private static final String UNPROTECTED = "UNPROTECTED"; - private static final String ENCRYPTED = "ENCRYPTED"; - - private static final Set SENSITIVE_PROPERTY_NAMES = Set.of(SENSITIVE_PROPERTY_NAME_1, SENSITIVE_PROPERTY_NAME_2, SENSITIVE_PROPERTY_NAME_3); - - @TempDir - private Path tempDir; - - @Mock - private SensitivePropertyProvider sensitivePropertyProvider; - - @Test - void shouldTransformProperties() throws URISyntaxException, IOException { - Path propertiesPath = getResourcePath(UNPROTECTED_BOOTSTRAP_CONF); - - Path tempPropertiesPath = tempDir.resolve(propertiesPath.getFileName()); - Files.copy(propertiesPath, tempPropertiesPath); - - Path outputPropertiesPath = tempDir.resolve(PROPERTIES_TRANSFORMED); - ApplicationProperties applicationProperties = new ApplicationProperties(Map.of(SENSITIVE_PROPERTY_NAME_3, UNPROTECTED)); - FileTransformer transformer = new ApplicationPropertiesFileTransformer(applicationProperties, sensitivePropertyProvider, SENSITIVE_PROPERTY_NAMES); - - when(sensitivePropertyProvider.getIdentifierKey()).thenReturn(PROVIDER_IDENTIFIER_KEY); - when(sensitivePropertyProvider.protect(eq(UNPROTECTED), any())).thenReturn(ENCRYPTED); - - transformer.transform(tempPropertiesPath, outputPropertiesPath); - - Properties expectedProperties = loadProperties(getResourcePath(PROTECTED_BOOTSTRAP_PROPERTIES)); - Properties resultProperties = loadProperties(outputPropertiesPath); - - assertEquals(expectedProperties, resultProperties); - } - - private Properties loadProperties(Path resourcePath) throws IOException { - Properties properties = new Properties(); - try (InputStream propertiesStream = Files.newInputStream(resourcePath)) { - properties.load(propertiesStream); - } - return properties; - } - - private Path getResourcePath(String resource) throws URISyntaxException { - final URL resourceUrl = Objects.requireNonNull(getClass().getResource(resource), String.format("Resource [%s] not found", resource)); - return Paths.get(resourceUrl.toURI()); - } -} \ No newline at end of file diff --git a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/minifi/toolkit/config/transformer/BootstrapConfigurationFileTransformerTest.java b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/minifi/toolkit/config/transformer/BootstrapConfigurationFileTransformerTest.java deleted file mode 100644 index 7a40921208e9..000000000000 --- a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/minifi/toolkit/config/transformer/BootstrapConfigurationFileTransformerTest.java +++ /dev/null @@ -1,74 +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.minifi.toolkit.config.transformer; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Objects; -import java.util.Properties; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.api.io.TempDir; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -class BootstrapConfigurationFileTransformerTest { - private static final String BOOTSTRAP_ROOT_KEY_PROPERTY = "minifi.bootstrap.sensitive.key"; - private static final String MOCK_KEY = "mockKey"; - private static final String BOOTSTRAP_CONF_FILE_WITHOUT_KEY = "/transformer/bootstrap_without_key.conf"; - private static final String BOOTSTRAP_CONF_TRANSFORMED = "transformed.conf"; - - @TempDir - private Path tempDir; - - @Test - void shouldWriteRootPropertyKeyIfItIsNotPresent() throws URISyntaxException, IOException { - Path propertiesPath = getResourcePath(BOOTSTRAP_CONF_FILE_WITHOUT_KEY); - - Path tempPropertiesPath = tempDir.resolve(propertiesPath.getFileName()); - Files.copy(propertiesPath, tempPropertiesPath); - - Path outputPropertiesPath = tempDir.resolve(BOOTSTRAP_CONF_TRANSFORMED); - - BootstrapConfigurationFileTransformer transformer = new BootstrapConfigurationFileTransformer(BOOTSTRAP_ROOT_KEY_PROPERTY, MOCK_KEY); - transformer.transform(tempPropertiesPath, outputPropertiesPath); - - Properties properties = loadProperties(outputPropertiesPath); - assertEquals(MOCK_KEY, properties.get(BOOTSTRAP_ROOT_KEY_PROPERTY)); - } - - private Properties loadProperties(Path resourcePath) throws IOException { - Properties properties = new Properties(); - try (InputStream propertiesStream = Files.newInputStream(resourcePath)) { - properties.load(propertiesStream); - } - return properties; - } - - private Path getResourcePath(String resource) throws URISyntaxException { - final URL resourceUrl = Objects.requireNonNull(getClass().getResource(resource), String.format("Resource [%s] not found", resource)); - return Paths.get(resourceUrl.toURI()); - } -} \ No newline at end of file diff --git a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/resources/transformer/bootstrap_without_key.conf b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/resources/transformer/bootstrap_without_key.conf deleted file mode 100644 index ae1e83eeb3d4..000000000000 --- a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/resources/transformer/bootstrap_without_key.conf +++ /dev/null @@ -1,14 +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. diff --git a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/resources/transformer/protected.conf b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/resources/transformer/protected.conf deleted file mode 100644 index 573f76b514ab..000000000000 --- a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/resources/transformer/protected.conf +++ /dev/null @@ -1,22 +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. - -property1=ENCRYPTED -property1.protected=mocked-provider -property2=ENCRYPTED -property2.protected=mocked-provider -nonsensitive.property=value -property3=ENCRYPTED -property3.protected=mocked-provider \ No newline at end of file diff --git a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/resources/transformer/unprotected.conf b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/resources/transformer/unprotected.conf deleted file mode 100644 index 5efa9a484d0f..000000000000 --- a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/resources/transformer/unprotected.conf +++ /dev/null @@ -1,20 +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. - -property1=UNPROTECTED -property2=UNPROTECTED -nonsensitive.property=value -property3=ENCRYPTED -property3.protected=mocked-provider \ No newline at end of file diff --git a/minifi/minifi-toolkit/pom.xml b/minifi/minifi-toolkit/pom.xml index 26a73e13c476..2840d9fd20b9 100644 --- a/minifi/minifi-toolkit/pom.xml +++ b/minifi/minifi-toolkit/pom.xml @@ -28,7 +28,6 @@ limitations under the License. minifi-toolkit-schema minifi-toolkit-configuration minifi-toolkit-assembly - minifi-toolkit-encrypt-config diff --git a/nifi-assembly/pom.xml b/nifi-assembly/pom.xml index e06bf2055994..87747410f3f1 100644 --- a/nifi-assembly/pom.xml +++ b/nifi-assembly/pom.xml @@ -186,16 +186,6 @@ language governing permissions and limitations under the License. --> nifi-bootstrap 2.0.0-SNAPSHOT - - org.apache.nifi - nifi-property-protection-api - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-factory - 2.0.0-SNAPSHOT - org.apache.nifi nifi-resources diff --git a/nifi-assembly/src/main/assembly/common.xml b/nifi-assembly/src/main/assembly/common.xml index 8f1240641549..be02ce32cadf 100644 --- a/nifi-assembly/src/main/assembly/common.xml +++ b/nifi-assembly/src/main/assembly/common.xml @@ -51,19 +51,6 @@ - - - runtime - false - lib/properties - 0770 - 0664 - true - - *:nifi-property-protection-factory - - - runtime diff --git a/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/RunNiFi.java b/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/RunNiFi.java index 50b4f6b2fe5c..89d0693e1082 100644 --- a/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/RunNiFi.java +++ b/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/RunNiFi.java @@ -25,7 +25,6 @@ import org.slf4j.LoggerFactory; import java.io.BufferedReader; -import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; @@ -42,15 +41,11 @@ import java.net.InetSocketAddress; import java.net.Socket; import java.nio.charset.StandardCharsets; -import java.nio.file.FileAlreadyExistsException; -import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; -import java.nio.file.attribute.FileAttribute; import java.nio.file.attribute.PosixFilePermission; -import java.nio.file.attribute.PosixFilePermissions; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -102,7 +97,6 @@ public class RunNiFi { public static final String NIFI_PID_FILE_NAME = "nifi.pid"; public static final String NIFI_STATUS_FILE_NAME = "nifi.status"; public static final String NIFI_LOCK_FILE_NAME = "nifi.lock"; - public static final String NIFI_BOOTSTRAP_SENSITIVE_KEY = "nifi.bootstrap.sensitive.key"; public static final String NIFI_BOOTSTRAP_LISTEN_PORT_PROP = "nifi.bootstrap.listen.port"; @@ -1179,11 +1173,6 @@ public boolean accept(final File dir, final String filename) { cmd.add("-Dapp=NiFi"); cmd.add("-Dorg.apache.nifi.bootstrap.config.log.dir=" + nifiLogDir); cmd.add("org.apache.nifi.NiFi"); - if (isSensitiveKeyPresent(props)) { - Path sensitiveKeyFile = createSensitiveKeyFile(confDir); - writeSensitiveKeyFile(props, sensitiveKeyFile); - cmd.add("-K " + sensitiveKeyFile.toFile().getAbsolutePath()); - } builder.command(cmd); @@ -1264,11 +1253,6 @@ public boolean accept(final File dir, final String filename) { setNiFiStarted(false); } - if (isSensitiveKeyPresent(props)) { - Path sensitiveKeyFile = createSensitiveKeyFile(confDir); - writeSensitiveKeyFile(props, sensitiveKeyFile); - } - defaultLogger.warn("Apache NiFi appears to have died. Restarting..."); secretKey = null; process = builder.start(); @@ -1328,50 +1312,6 @@ private String getPlatformDetails(final String minimumHeapSize, final String max return details.toString(); } - private void writeSensitiveKeyFile(Map props, Path sensitiveKeyFile) throws IOException { - BufferedWriter sensitiveKeyWriter = Files.newBufferedWriter(sensitiveKeyFile, StandardCharsets.UTF_8); - sensitiveKeyWriter.write(props.get(NIFI_BOOTSTRAP_SENSITIVE_KEY)); - sensitiveKeyWriter.close(); - } - - private Path createSensitiveKeyFile(File confDir) { - Path sensitiveKeyFile = Paths.get(confDir + "/sensitive.key"); - - final boolean isPosixSupported = FileSystems.getDefault().supportedFileAttributeViews().contains("posix"); - try { - if (isPosixSupported) { - // Initially create file with the empty permission set (so nobody can get a file descriptor on it): - Set perms = new HashSet(); - FileAttribute> attr = PosixFilePermissions.asFileAttribute(perms); - sensitiveKeyFile = Files.createFile(sensitiveKeyFile, attr); - - // Then, once created, add owner-only rights: - perms.add(PosixFilePermission.OWNER_WRITE); - perms.add(PosixFilePermission.OWNER_READ); - attr = PosixFilePermissions.asFileAttribute(perms); - Files.setPosixFilePermissions(sensitiveKeyFile, perms); - } else { - // If Posix is not supported (e.g. Windows) then create the key file without permission settings. - cmdLogger.info("Current file system does not support Posix, using default permission settings."); - sensitiveKeyFile = Files.createFile(sensitiveKeyFile); - } - - } catch (final FileAlreadyExistsException faee) { - cmdLogger.error("The sensitive.key file {} already exists. That shouldn't have been. Aborting.", sensitiveKeyFile); - System.exit(1); - } catch (final Exception e) { - cmdLogger.error("Other failure relating to setting permissions on {}. " - + "(so that only the owner can read it). " - + "This is fatal to the bootstrap process for security reasons. Exception was: {}", sensitiveKeyFile, e); - System.exit(1); - } - return sensitiveKeyFile; - } - - private boolean isSensitiveKeyPresent(Map props) { - return props.containsKey(NIFI_BOOTSTRAP_SENSITIVE_KEY) && !props.get(NIFI_BOOTSTRAP_SENSITIVE_KEY).isBlank(); - } - private void handleLogging(final Process process) { final Set> existingFutures = loggingFutures; if (existingFutures != null) { diff --git a/nifi-code-coverage/pom.xml b/nifi-code-coverage/pom.xml index eb10d436d7e6..3aacf818ccc0 100644 --- a/nifi-code-coverage/pom.xml +++ b/nifi-code-coverage/pom.xml @@ -302,51 +302,6 @@ nifi-property-encryptor 2.0.0-SNAPSHOT - - org.apache.nifi - nifi-property-protection-api - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-aws - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-azure - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-cipher - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-factory - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-gcp - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-hashicorp - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-loader - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-shared - 2.0.0-SNAPSHOT - org.apache.nifi nifi-property-utils @@ -1784,11 +1739,6 @@ nifi-toolkit-cli 2.0.0-SNAPSHOT - - org.apache.nifi - nifi-toolkit-encrypt-config - 2.0.0-SNAPSHOT - diff --git a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiBootstrapUtils.java b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiBootstrapUtils.java index 13605786cb17..eb0c44f97e92 100644 --- a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiBootstrapUtils.java +++ b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiBootstrapUtils.java @@ -27,17 +27,6 @@ public class NiFiBootstrapUtils { private static final AbstractBootstrapPropertiesLoader BOOTSTRAP_PROPERTIES_LOADER = new NiFiBootstrapPropertiesLoader(); - /** - * Returns the key (if any) used to encrypt sensitive properties, extracted from - * {@code $NIFI_HOME/conf/bootstrap.conf}. - * - * @return the key in hexadecimal format - * @throws IOException if the file is not readable - */ - public static String extractKeyFromBootstrapFile() throws IOException { - return BOOTSTRAP_PROPERTIES_LOADER.extractKeyFromBootstrapFile(); - } - /** * Loads the default bootstrap.conf file into a BootstrapProperties object. * @return The default bootstrap.conf as a BootstrapProperties object @@ -57,19 +46,6 @@ public static BootstrapProperties loadBootstrapProperties(final String bootstrap return BOOTSTRAP_PROPERTIES_LOADER.loadBootstrapProperties(bootstrapPath); } - /** - * Returns the key (if any) used to encrypt sensitive properties, extracted from - * {@code $NIFI_HOME/conf/bootstrap.conf}. - * - * @param bootstrapPath the path to the bootstrap file (if null, returns the sensitive key - * found in $NIFI_HOME/conf/bootstrap.conf) - * @return the key in hexadecimal format - * @throws IOException if the file is not readable - */ - public static String extractKeyFromBootstrapFile(final String bootstrapPath) throws IOException { - return BOOTSTRAP_PROPERTIES_LOADER.extractKeyFromBootstrapFile(bootstrapPath); - } - /** * Returns the default file path to {@code $NIFI_HOME/conf/nifi.properties}. If the system * property nifi.properties.file.path is not set, it will be set to the relative conf/nifi.properties diff --git a/nifi-commons/nifi-property-protection-api/pom.xml b/nifi-commons/nifi-property-protection-api/pom.xml deleted file mode 100644 index f63e4faca5c3..000000000000 --- a/nifi-commons/nifi-property-protection-api/pom.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - 4.0.0 - - org.apache.nifi - nifi-commons - 2.0.0-SNAPSHOT - - nifi-property-protection-api - - - org.apache.nifi - nifi-property-utils - 2.0.0-SNAPSHOT - - - diff --git a/nifi-commons/nifi-property-protection-api/src/main/java/org/apache/nifi/properties/SensitivePropertyProtectionException.java b/nifi-commons/nifi-property-protection-api/src/main/java/org/apache/nifi/properties/SensitivePropertyProtectionException.java deleted file mode 100644 index e82c4a9d9441..000000000000 --- a/nifi-commons/nifi-property-protection-api/src/main/java/org/apache/nifi/properties/SensitivePropertyProtectionException.java +++ /dev/null @@ -1,41 +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.properties; - -/** - * Sensitive Property Protection Exception indicating runtime failures - */ -public class SensitivePropertyProtectionException extends RuntimeException { - /** - * Sensitive Property Protection Exception constructor with message and without associated cause - * - * @param message Message describing failure condition - */ - public SensitivePropertyProtectionException(final String message) { - super(message); - } - - /** - * Sensitive Property Protection Exception constructor with message and associated cause - * - * @param message Message describing failure condition - * @param cause Throwable containing associated cause of failure condition - */ - public SensitivePropertyProtectionException(final String message, final Throwable cause) { - super(message, cause); - } -} diff --git a/nifi-commons/nifi-property-protection-api/src/main/java/org/apache/nifi/properties/SensitivePropertyProtector.java b/nifi-commons/nifi-property-protection-api/src/main/java/org/apache/nifi/properties/SensitivePropertyProtector.java deleted file mode 100644 index add7c941bc5c..000000000000 --- a/nifi-commons/nifi-property-protection-api/src/main/java/org/apache/nifi/properties/SensitivePropertyProtector.java +++ /dev/null @@ -1,130 +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.properties; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * Encapsulates methods needed to protect application properties. - * @param The ProtectedProperties type - * @param The ApplicationProperties type - */ -public interface SensitivePropertyProtector, U extends ApplicationProperties> { - /** - * Returns the number of properties, excluding protection scheme properties. - *

- * Example: - *

- * key: E(value, key) - * key.protected: aes/gcm/256 - * key2: value2 - *

- * would return size 2 - * - * @return the count of real properties - */ - int size(); - - /** - * Retrieves all known property keys. - * - * @return all known property keys - */ - Set getPropertyKeys(); - - /** - * Returns the complete set of property keys, including any protection keys (i.e. 'x.y.z.protected'). - * - * @return the set of property keys - */ - Set getPropertyKeysIncludingProtectionSchemes(); - - /** - * Returns a list of the keys identifying "sensitive" properties. There is a default list, - * and additional keys can be provided in the {@code nifi.sensitive.props.additional.keys} property in the ApplicationProperties. - * - * @return the list of sensitive property keys - */ - List getSensitivePropertyKeys(); - - /** - * Returns a list of the keys identifying "sensitive" properties. There is a default list, - * and additional keys can be provided in the {@code nifi.sensitive.props.additional.keys} property in the ApplicationProperties. - * - * @return the list of sensitive property keys - */ - List getPopulatedSensitivePropertyKeys(); - - /** - * Returns true if any sensitive keys are protected. - * - * @return true if any key is protected; false otherwise - */ - boolean hasProtectedKeys(); - - /** - * Returns a Map of the keys identifying "sensitive" properties that are currently protected and the "protection" key for each. - * This may or may not include all properties marked as sensitive. - * - * @return the Map of protected property keys and the protection identifier for each - */ - Map getProtectedPropertyKeys(); - - /** - * Returns true if the property identified by this key is considered sensitive in this instance of {@code ApplicationProperties}. - * Some properties are sensitive by default, while others can be specified by - * {@link ProtectedProperties#getAdditionalSensitivePropertiesKeys()}. - * - * @param key the key - * @return true if it is sensitive - */ - boolean isPropertySensitive(String key); - - /** - * Returns the unprotected {@link ApplicationProperties} instance. If none of the properties - * loaded are marked as protected, it will simply pass through the internal instance. - * If any are protected, it will drop the protection scheme keys and translate each - * protected value (encrypted, HSM-retrieved, etc.) into the raw value and store it - * under the original key. - *

- * If any property fails to unprotect, it will save that key and continue. After - * attempting all properties, it will throw an exception containing all failed - * properties. This is necessary because the order is not enforced, so all failed - * properties should be gathered together. - * - * @return the ApplicationProperties instance with all raw values - * @throws SensitivePropertyProtectionException if there is a problem unprotecting one or more keys - */ - boolean isPropertyProtected(String key); - - /** - * Returns the unprotected ApplicationProperties. - * @return The unprotected properties - * @throws SensitivePropertyProtectionException if there is a problem unprotecting one or more keys - */ - U getUnprotectedProperties() throws SensitivePropertyProtectionException; - - /** - * Registers a new {@link SensitivePropertyProvider}. This method will throw a {@link UnsupportedOperationException} - * if a provider is already registered for the protection scheme. - * - * @param sensitivePropertyProvider the provider - */ - void addSensitivePropertyProvider(SensitivePropertyProvider sensitivePropertyProvider); -} diff --git a/nifi-commons/nifi-property-protection-api/src/main/java/org/apache/nifi/properties/SensitivePropertyProvider.java b/nifi-commons/nifi-property-protection-api/src/main/java/org/apache/nifi/properties/SensitivePropertyProvider.java deleted file mode 100644 index 2b57fc49fc6b..000000000000 --- a/nifi-commons/nifi-property-protection-api/src/main/java/org/apache/nifi/properties/SensitivePropertyProvider.java +++ /dev/null @@ -1,61 +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.properties; - -/** - * Sensitive Property Provider abstracts persistence and retrieval of properties that require additional protection - */ -public interface SensitivePropertyProvider { - /** - * Returns the key used to identify the provider implementation in {@code nifi.properties}. - * - * @return the key to persist in the sibling property - */ - String getIdentifierKey(); - - /** - * Returns whether this SensitivePropertyProvider is supported with the current system - * configuration. - * @return Whether this SensitivePropertyProvider is supported - */ - boolean isSupported(); - - /** - * Returns the "protected" form of this value. This is a form which can safely be persisted in the {@code nifi.properties} file without compromising the value. - * An encryption-based provider would return a cipher text, while a remote-lookup provider could return a unique ID to retrieve the secured value. - * - * @param unprotectedValue the sensitive value - * @param context The context of the value - * @return the value to persist in the {@code nifi.properties} file - */ - String protect(String unprotectedValue, ProtectedPropertyContext context) throws SensitivePropertyProtectionException; - - /** - * Returns the "unprotected" form of this value. This is the raw sensitive value which is used by the application logic. - * An encryption-based provider would decrypt a cipher text and return the plaintext, while a remote-lookup provider could retrieve the secured value. - * - * @param protectedValue the protected value read from the {@code nifi.properties} file - * @param context The context of the value - * @return the raw value to be used by the application - */ - String unprotect(String protectedValue, ProtectedPropertyContext context) throws SensitivePropertyProtectionException; - - /** - * Cleans up resources that may have been allocated/used by an SPP implementation - */ - void cleanUp(); -} diff --git a/nifi-commons/nifi-property-protection-api/src/main/java/org/apache/nifi/properties/SensitivePropertyProviderFactory.java b/nifi-commons/nifi-property-protection-api/src/main/java/org/apache/nifi/properties/SensitivePropertyProviderFactory.java deleted file mode 100644 index 75bbee2a0f0e..000000000000 --- a/nifi-commons/nifi-property-protection-api/src/main/java/org/apache/nifi/properties/SensitivePropertyProviderFactory.java +++ /dev/null @@ -1,54 +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.properties; - -import org.apache.nifi.properties.scheme.ProtectionScheme; - -import java.util.Collection; - -/** - * Sensitive Property Provider Factory abstracts instantiation of supported providers - */ -public interface SensitivePropertyProviderFactory { - /** - * Get Provider for specified Protection Strategy - * - * @param protectionScheme Protection Strategy requested - * @return Property Provider implementation - */ - SensitivePropertyProvider getProvider(ProtectionScheme protectionScheme); - - /** - * Get Supported Property Providers - * - * @return Collection of supported provider implementations - */ - Collection getSupportedProviders(); - - /** - * Returns a ProtectedPropertyContext with the given property name. The ProtectedPropertyContext's - * contextName will be the name found in a matching context mapping from bootstrap.conf, or 'default' if - * no matching mapping was found. - * - * @param groupIdentifier The identifier of a group that contains the configuration property. The definition - * of a group depends on the type of configuration file. - * @param propertyName A property name - * @return The property context, using any mappings configured in bootstrap.conf to match against the - * provided group identifier (or the default context if none match). - */ - ProtectedPropertyContext getPropertyContext(String groupIdentifier, String propertyName); -} diff --git a/nifi-commons/nifi-property-protection-api/src/main/java/org/apache/nifi/properties/scheme/ProtectionScheme.java b/nifi-commons/nifi-property-protection-api/src/main/java/org/apache/nifi/properties/scheme/ProtectionScheme.java deleted file mode 100644 index cb703821fe66..000000000000 --- a/nifi-commons/nifi-property-protection-api/src/main/java/org/apache/nifi/properties/scheme/ProtectionScheme.java +++ /dev/null @@ -1,29 +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.properties.scheme; - -/** - * Definition of Protection Scheme - */ -public interface ProtectionScheme { - /** - * Get path of the protection scheme definition - * - * @return Protection scheme path - */ - String getPath(); -} diff --git a/nifi-commons/nifi-property-protection-api/src/main/java/org/apache/nifi/properties/scheme/ProtectionSchemeResolver.java b/nifi-commons/nifi-property-protection-api/src/main/java/org/apache/nifi/properties/scheme/ProtectionSchemeResolver.java deleted file mode 100644 index adb780b1d22a..000000000000 --- a/nifi-commons/nifi-property-protection-api/src/main/java/org/apache/nifi/properties/scheme/ProtectionSchemeResolver.java +++ /dev/null @@ -1,30 +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.properties.scheme; - -/** - * Protection Scheme Resolver abstracts resolution of Protection Scheme references from string arguments - */ -public interface ProtectionSchemeResolver { - /** - * Get Protection Scheme - * - * @param scheme Scheme name required - * @return Protection Scheme - */ - ProtectionScheme getProtectionScheme(String scheme); -} diff --git a/nifi-commons/nifi-property-protection-api/src/main/java/org/apache/nifi/properties/scheme/StandardProtectionScheme.java b/nifi-commons/nifi-property-protection-api/src/main/java/org/apache/nifi/properties/scheme/StandardProtectionScheme.java deleted file mode 100644 index c0ce8d930fe9..000000000000 --- a/nifi-commons/nifi-property-protection-api/src/main/java/org/apache/nifi/properties/scheme/StandardProtectionScheme.java +++ /dev/null @@ -1,35 +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.properties.scheme; - -import java.util.Objects; - -/** - * Standard implementation of Protection Scheme with configurable parameters - */ -public class StandardProtectionScheme implements ProtectionScheme { - private String path; - - public StandardProtectionScheme(final String path) { - this.path = Objects.requireNonNull(path, "Path required"); - } - - @Override - public String getPath() { - return path; - } -} diff --git a/nifi-commons/nifi-property-protection-aws/pom.xml b/nifi-commons/nifi-property-protection-aws/pom.xml deleted file mode 100644 index b722bba5eebb..000000000000 --- a/nifi-commons/nifi-property-protection-aws/pom.xml +++ /dev/null @@ -1,101 +0,0 @@ - - - - 4.0.0 - - org.apache.nifi - nifi-commons - 2.0.0-SNAPSHOT - - nifi-property-protection-aws - - - org.slf4j - slf4j-api - - - org.apache.nifi - nifi-property-utils - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-api - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-shared - 2.0.0-SNAPSHOT - - - org.apache.commons - commons-lang3 - - - com.fasterxml.jackson.core - jackson-databind - - - com.fasterxml.jackson.core - jackson-core - - - software.amazon.awssdk - regions - - - software.amazon.awssdk - auth - - - software.amazon.awssdk - kms - - - software.amazon.awssdk - aws-core - - - software.amazon.awssdk - sdk-core - - - software.amazon.awssdk - netty-nio-client - - - software.amazon.awssdk - apache-client - - - - - software.amazon.awssdk - secretsmanager - - - software.amazon.awssdk - netty-nio-client - - - software.amazon.awssdk - apache-client - - - - - diff --git a/nifi-commons/nifi-property-protection-aws/src/main/java/org/apache/nifi/properties/AwsKmsSensitivePropertyProvider.java b/nifi-commons/nifi-property-protection-aws/src/main/java/org/apache/nifi/properties/AwsKmsSensitivePropertyProvider.java deleted file mode 100644 index 80a34f336d46..000000000000 --- a/nifi-commons/nifi-property-protection-aws/src/main/java/org/apache/nifi/properties/AwsKmsSensitivePropertyProvider.java +++ /dev/null @@ -1,128 +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.properties; - -import software.amazon.awssdk.core.SdkBytes; -import software.amazon.awssdk.services.kms.KmsClient; -import software.amazon.awssdk.services.kms.model.DecryptRequest; -import software.amazon.awssdk.services.kms.model.DecryptResponse; -import software.amazon.awssdk.services.kms.model.DescribeKeyRequest; -import software.amazon.awssdk.services.kms.model.DescribeKeyResponse; -import software.amazon.awssdk.services.kms.model.EncryptRequest; -import software.amazon.awssdk.services.kms.model.EncryptResponse; -import software.amazon.awssdk.services.kms.model.KeyMetadata; - -import java.util.Properties; - -/** - * Amazon Web Services Key Management Service Sensitive Property Provider - */ -public class AwsKmsSensitivePropertyProvider extends ClientBasedEncodedSensitivePropertyProvider { - protected static final String KEY_ID_PROPERTY = "aws.kms.key.id"; - - private static final String IDENTIFIER_KEY = "aws/kms"; - - AwsKmsSensitivePropertyProvider(final KmsClient kmsClient, final Properties properties) throws SensitivePropertyProtectionException { - super(kmsClient, properties); - } - - @Override - public String getIdentifierKey() { - return IDENTIFIER_KEY; - } - - /** - * Close KMS Client when configured - */ - @Override - public void cleanUp() { - final KmsClient kmsClient = getClient(); - if (kmsClient == null) { - logger.debug("AWS KMS Client not configured"); - } else { - kmsClient.close(); - } - } - - /** - * Validate Client and Key Identifier status when client is configured - * - * @param kmsClient KMS Client - */ - @Override - protected void validate(final KmsClient kmsClient) { - if (kmsClient == null) { - logger.debug("AWS KMS Client not configured"); - } else { - final String keyId = getKeyId(); - try { - final DescribeKeyRequest describeKeyRequest = DescribeKeyRequest.builder() - .keyId(keyId) - .build(); - final DescribeKeyResponse describeKeyResponse = kmsClient.describeKey(describeKeyRequest); - final KeyMetadata keyMetadata = describeKeyResponse.keyMetadata(); - if (keyMetadata.enabled()) { - logger.info("AWS KMS Key [{}] Enabled", keyId); - } else { - throw new SensitivePropertyProtectionException(String.format("AWS KMS Key [%s] Disabled", keyId)); - } - } catch (final RuntimeException e) { - throw new SensitivePropertyProtectionException(String.format("AWS KMS Key [%s] Validation Failed", keyId), e); - } - } - } - - /** - * Get encrypted bytes - * - * @param bytes Unprotected bytes - * @return Encrypted bytes - */ - @Override - protected byte[] getEncrypted(final byte[] bytes) { - final SdkBytes plainBytes = SdkBytes.fromByteArray(bytes); - final EncryptRequest encryptRequest = EncryptRequest.builder() - .keyId(getKeyId()) - .plaintext(plainBytes) - .build(); - final EncryptResponse response = getClient().encrypt(encryptRequest); - final SdkBytes encryptedData = response.ciphertextBlob(); - return encryptedData.asByteArray(); - } - - /** - * Get decrypted bytes - * - * @param bytes Encrypted bytes - * @return Decrypted bytes - */ - @Override - protected byte[] getDecrypted(final byte[] bytes) { - final SdkBytes cipherBytes = SdkBytes.fromByteArray(bytes); - final DecryptRequest decryptRequest = DecryptRequest.builder() - .ciphertextBlob(cipherBytes) - .keyId(getKeyId()) - .build(); - final DecryptResponse response = getClient().decrypt(decryptRequest); - final SdkBytes decryptedData = response.plaintext(); - return decryptedData.asByteArray(); - } - - private String getKeyId() { - return getProperties().getProperty(KEY_ID_PROPERTY); - } -} diff --git a/nifi-commons/nifi-property-protection-aws/src/main/java/org/apache/nifi/properties/AwsSecretsManagerSensitivePropertyProvider.java b/nifi-commons/nifi-property-protection-aws/src/main/java/org/apache/nifi/properties/AwsSecretsManagerSensitivePropertyProvider.java deleted file mode 100644 index cfd3cc5b825c..000000000000 --- a/nifi-commons/nifi-property-protection-aws/src/main/java/org/apache/nifi/properties/AwsSecretsManagerSensitivePropertyProvider.java +++ /dev/null @@ -1,161 +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.properties; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient; -import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueResponse; -import software.amazon.awssdk.services.secretsmanager.model.ResourceNotFoundException; -import software.amazon.awssdk.services.secretsmanager.model.SecretsManagerException; - -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -/** - * Amazon Web Services Secrets Manager implementation of Sensitive Property Provider - */ -public class AwsSecretsManagerSensitivePropertyProvider implements SensitivePropertyProvider { - private static final String IDENTIFIER_KEY = "aws/secretsmanager"; - - private final SecretsManagerClient client; - private final ObjectMapper objectMapper; - - private final ReadWriteLock rwLock = new ReentrantReadWriteLock(); - private final Lock readLock = rwLock.readLock(); - private final Lock writeLock = rwLock.writeLock(); - - AwsSecretsManagerSensitivePropertyProvider(final SecretsManagerClient client) { - this.client = client; - this.objectMapper = new ObjectMapper(); - } - - @Override - public String getIdentifierKey() { - return IDENTIFIER_KEY; - } - - @Override - public boolean isSupported() { - return client != null; - } - - @Override - public String protect(final String unprotectedValue, final ProtectedPropertyContext context) - throws SensitivePropertyProtectionException { - Objects.requireNonNull(context, "Property context must be provided"); - Objects.requireNonNull(unprotectedValue, "Property value must be provided"); - - if (client == null) { - throw new SensitivePropertyProtectionException("AWS Secrets Manager Provider Not Configured"); - } - - try { - writeLock.lock(); - final String secretName = context.getContextName(); - final Optional secretKeyValuesOptional = getSecretKeyValues(context); - final ObjectNode secretObject = secretKeyValuesOptional.orElse(objectMapper.createObjectNode()); - - secretObject.put(context.getPropertyName(), unprotectedValue); - final String secretString = objectMapper.writeValueAsString(secretObject); - - if (secretKeyValuesOptional.isPresent()) { - client.putSecretValue(builder -> builder.secretId(secretName).secretString(secretString)); - } else { - client.createSecret(builder -> builder.name(secretName).secretString(secretString)); - } - return context.getContextKey(); - } catch (final SecretsManagerException | JsonProcessingException e) { - throw new SensitivePropertyProtectionException(String.format("AWS Secrets Manager Secret Could Not Be Stored for [%s]", context), e); - } finally { - writeLock.unlock(); - } - } - - @Override - public String unprotect(final String protectedValue, final ProtectedPropertyContext context) - throws SensitivePropertyProtectionException { - Objects.requireNonNull(context, "Property context must be provided"); - - if (client == null) { - throw new SensitivePropertyProtectionException("AWS Secrets Manager Provider Not Configured"); - } - try { - readLock.lock(); - - String propertyValue = null; - final Optional secretKeyValuesOptional = getSecretKeyValues(context); - if (secretKeyValuesOptional.isPresent()) { - final ObjectNode secretKeyValues = secretKeyValuesOptional.get(); - final String propertyName = context.getPropertyName(); - if (secretKeyValues.has(propertyName)) { - propertyValue = secretKeyValues.get(propertyName).textValue(); - } - } - if (propertyValue == null) { - throw new SensitivePropertyProtectionException( - String.format("AWS Secret Name [%s] Property Name [%s] not found", context.getContextName(), context.getPropertyName())); - } - - return propertyValue; - } finally { - readLock.unlock(); - } - } - - /** - * Returns the optional parsed JSON from the matching secret, or empty if the secret does not exist. - * @param context The property context - * @return The optional parsed JSON, or empty if the secret does not exist - */ - private Optional getSecretKeyValues(final ProtectedPropertyContext context) { - try { - final GetSecretValueResponse response = client.getSecretValue(builder -> builder.secretId(context.getContextName())); - - if (response.secretString() == null) { - throw new SensitivePropertyProtectionException(String.format("AWS Secret Name [%s] string value not found", - context.getContextKey())); - } - final JsonNode responseNode = objectMapper.readTree(response.secretString()); - if (!(responseNode instanceof ObjectNode)) { - throw new SensitivePropertyProtectionException(String.format("AWS Secrets Manager Secret [%s] JSON parsing failed", - context.getContextKey())); - } - return Optional.of((ObjectNode) responseNode); - } catch (final ResourceNotFoundException e) { - return Optional.empty(); - } catch (final SecretsManagerException e) { - throw new SensitivePropertyProtectionException(String.format("AWS Secrets Manager Secret [%s] retrieval failed", - context.getContextKey()), e); - } catch (final JsonProcessingException e) { - throw new SensitivePropertyProtectionException(String.format("AWS Secrets Manager Secret [%s] JSON parsing failed", - context.getContextKey()), e); - } - } - - @Override - public void cleanUp() { - if (client != null) { - client.close(); - } - } -} diff --git a/nifi-commons/nifi-property-protection-aws/src/main/java/org/apache/nifi/properties/configuration/AbstractAwsClientProvider.java b/nifi-commons/nifi-property-protection-aws/src/main/java/org/apache/nifi/properties/configuration/AbstractAwsClientProvider.java deleted file mode 100644 index 9b002b60e8a5..000000000000 --- a/nifi-commons/nifi-property-protection-aws/src/main/java/org/apache/nifi/properties/configuration/AbstractAwsClientProvider.java +++ /dev/null @@ -1,89 +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.properties.configuration; - -import org.apache.commons.lang3.StringUtils; -import org.apache.nifi.properties.BootstrapProperties; -import org.apache.nifi.properties.SensitivePropertyProtectionException; -import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; -import software.amazon.awssdk.auth.credentials.AwsCredentials; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; -import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; -import software.amazon.awssdk.core.SdkClient; - -import java.util.Properties; - -/** - * Amazon Web Services Service Client Provider base class - */ -public abstract class AbstractAwsClientProvider extends BootstrapPropertiesClientProvider { - private static final String ACCESS_KEY_PROPS_NAME = "aws.access.key.id"; - - private static final String SECRET_KEY_PROPS_NAME = "aws.secret.access.key"; - - private static final String REGION_KEY_PROPS_NAME = "aws.region"; - - public AbstractAwsClientProvider() { - super(BootstrapProperties.BootstrapPropertyKey.AWS_SENSITIVE_PROPERTY_PROVIDER_CONF); - } - - /** - * Get Configured Client using either Client Properties or AWS Default Credentials Provider - * - * @param clientProperties Client Properties - * @return KMS Client - */ - @Override - protected T getConfiguredClient(final Properties clientProperties) { - final String accessKey = clientProperties.getProperty(ACCESS_KEY_PROPS_NAME); - final String secretKey = clientProperties.getProperty(SECRET_KEY_PROPS_NAME); - final String region = clientProperties.getProperty(REGION_KEY_PROPS_NAME); - - if (StringUtils.isNoneBlank(accessKey, secretKey, region)) { - logger.debug("AWS Credentials Location: Client Properties"); - try { - final AwsBasicCredentials credentials = AwsBasicCredentials.create(accessKey, secretKey); - return createClient(credentials, region); - } catch (final RuntimeException e) { - throw new SensitivePropertyProtectionException("AWS Client Builder Failed using Client Properties", e); - } - } else { - logger.debug("AWS Credentials Location: Default Credentials Provider"); - try { - final DefaultCredentialsProvider credentialsProvider = DefaultCredentialsProvider.builder().build(); - return createDefaultClient(credentialsProvider); - } catch (final RuntimeException e) { - throw new SensitivePropertyProtectionException("AWS Client Builder Failed using Default Credentials Provider", e); - } - } - } - - /** - * Create a client with the given credentials and region. - * @param credentials AWS credentials - * @param region AWS region - * @return The created client - */ - protected abstract T createClient(AwsCredentials credentials, String region); - - /** - * Create a default client with the given credentials provider. - * @param credentialsProvider AWS credentials provider - * @return The created client - */ - protected abstract T createDefaultClient(AwsCredentialsProvider credentialsProvider); -} diff --git a/nifi-commons/nifi-property-protection-aws/src/main/java/org/apache/nifi/properties/configuration/AwsKmsClientProvider.java b/nifi-commons/nifi-property-protection-aws/src/main/java/org/apache/nifi/properties/configuration/AwsKmsClientProvider.java deleted file mode 100644 index d501735acae0..000000000000 --- a/nifi-commons/nifi-property-protection-aws/src/main/java/org/apache/nifi/properties/configuration/AwsKmsClientProvider.java +++ /dev/null @@ -1,52 +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.properties.configuration; - -import software.amazon.awssdk.auth.credentials.AwsCredentials; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; -import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; -import software.amazon.awssdk.regions.Region; -import software.amazon.awssdk.services.kms.KmsClient; - -import java.util.Collections; -import java.util.Set; - -/** - * Amazon Web Services Key Management Service Client Provider - */ -public class AwsKmsClientProvider extends AbstractAwsClientProvider { - - protected static final String KEY_ID_PROPERTY = "aws.kms.key.id"; - - @Override - protected KmsClient createClient(final AwsCredentials credentials, final String region) { - return KmsClient.builder() - .credentialsProvider(StaticCredentialsProvider.create(credentials)) - .region(Region.of(region)) - .build(); - } - - @Override - protected KmsClient createDefaultClient(final AwsCredentialsProvider credentialsProvider) { - return KmsClient.builder().credentialsProvider(credentialsProvider).build(); - } - - @Override - protected Set getRequiredPropertyNames() { - return Collections.singleton(KEY_ID_PROPERTY); - } -} diff --git a/nifi-commons/nifi-property-protection-aws/src/main/java/org/apache/nifi/properties/configuration/AwsSecretsManagerClientProvider.java b/nifi-commons/nifi-property-protection-aws/src/main/java/org/apache/nifi/properties/configuration/AwsSecretsManagerClientProvider.java deleted file mode 100644 index d0863ddfda58..000000000000 --- a/nifi-commons/nifi-property-protection-aws/src/main/java/org/apache/nifi/properties/configuration/AwsSecretsManagerClientProvider.java +++ /dev/null @@ -1,50 +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.properties.configuration; - -import software.amazon.awssdk.auth.credentials.AwsCredentials; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; -import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; -import software.amazon.awssdk.regions.Region; -import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient; - -import java.util.Collections; -import java.util.Set; - -/** - * Amazon Web Services Secrets Manager Client Provider - */ -public class AwsSecretsManagerClientProvider extends AbstractAwsClientProvider { - - @Override - protected SecretsManagerClient createClient(final AwsCredentials credentials, final String region) { - return SecretsManagerClient.builder() - .credentialsProvider(StaticCredentialsProvider.create(credentials)) - .region(Region.of(region)) - .build(); - } - - @Override - protected SecretsManagerClient createDefaultClient(final AwsCredentialsProvider credentialsProvider) { - return SecretsManagerClient.builder().credentialsProvider(credentialsProvider).build(); - } - - @Override - protected Set getRequiredPropertyNames() { - return Collections.emptySet(); - } -} diff --git a/nifi-commons/nifi-property-protection-aws/src/test/java/org/apache/nifi/properties/AwsKmsSensitivePropertyProviderTest.java b/nifi-commons/nifi-property-protection-aws/src/test/java/org/apache/nifi/properties/AwsKmsSensitivePropertyProviderTest.java deleted file mode 100644 index be747c6e93ca..000000000000 --- a/nifi-commons/nifi-property-protection-aws/src/test/java/org/apache/nifi/properties/AwsKmsSensitivePropertyProviderTest.java +++ /dev/null @@ -1,127 +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.properties; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.core.SdkBytes; -import software.amazon.awssdk.services.kms.KmsClient; -import software.amazon.awssdk.services.kms.model.DecryptRequest; -import software.amazon.awssdk.services.kms.model.DecryptResponse; -import software.amazon.awssdk.services.kms.model.DescribeKeyRequest; -import software.amazon.awssdk.services.kms.model.DescribeKeyResponse; -import software.amazon.awssdk.services.kms.model.EncryptRequest; -import software.amazon.awssdk.services.kms.model.EncryptResponse; -import software.amazon.awssdk.services.kms.model.KeyMetadata; - -import java.nio.charset.StandardCharsets; -import java.util.Base64; -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; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.ArgumentMatchers.any; - -@ExtendWith(MockitoExtension.class) -public class AwsKmsSensitivePropertyProviderTest { - private static final String PROPERTY_NAME = String.class.getSimpleName(); - - private static final String PROPERTY = String.class.getName(); - - private static final String ENCRYPTED_PROPERTY = Integer.class.getName(); - - private static final byte[] ENCRYPTED_BYTES = ENCRYPTED_PROPERTY.getBytes(StandardCharsets.UTF_8); - - private static final String PROTECTED_PROPERTY = Base64.getEncoder().withoutPadding().encodeToString(ENCRYPTED_BYTES); - - private static final String KEY_ID = AwsKmsSensitivePropertyProvider.class.getSimpleName(); - - private static final Properties PROPERTIES = new Properties(); - - private static final String IDENTIFIER_KEY = "aws/kms"; - - static { - PROPERTIES.setProperty(AwsKmsSensitivePropertyProvider.KEY_ID_PROPERTY, KEY_ID); - } - - @Mock - private KmsClient kmsClient; - - private AwsKmsSensitivePropertyProvider provider; - - @BeforeEach - public void setProvider() { - final KeyMetadata keyMetadata = KeyMetadata.builder().enabled(true).build(); - final DescribeKeyResponse describeKeyResponse = DescribeKeyResponse.builder().keyMetadata(keyMetadata).build(); - when(kmsClient.describeKey(any(DescribeKeyRequest.class))).thenReturn(describeKeyResponse); - - provider = new AwsKmsSensitivePropertyProvider(kmsClient, PROPERTIES); - } - - @Test - public void testValidateClientNull() { - final AwsKmsSensitivePropertyProvider provider = new AwsKmsSensitivePropertyProvider(null, PROPERTIES); - assertNotNull(provider); - } - - @Test - public void testValidateKeyDisabled() { - final KeyMetadata keyMetadata = KeyMetadata.builder().enabled(false).build(); - final DescribeKeyResponse describeKeyResponse = DescribeKeyResponse.builder().keyMetadata(keyMetadata).build(); - when(kmsClient.describeKey(any(DescribeKeyRequest.class))).thenReturn(describeKeyResponse); - - assertThrows(SensitivePropertyProtectionException.class, () -> new AwsKmsSensitivePropertyProvider(kmsClient, PROPERTIES)); - } - - @Test - public void testCleanUp() { - provider.cleanUp(); - verify(kmsClient).close(); - } - - @Test - public void testProtect() { - final SdkBytes blob = SdkBytes.fromUtf8String(ENCRYPTED_PROPERTY); - final EncryptResponse encryptResponse = EncryptResponse.builder().ciphertextBlob(blob).build(); - when(kmsClient.encrypt(any(EncryptRequest.class))).thenReturn(encryptResponse); - - final String protectedProperty = provider.protect(PROPERTY, ProtectedPropertyContext.defaultContext(PROPERTY_NAME)); - assertEquals(PROTECTED_PROPERTY, protectedProperty); - } - - @Test - public void testUnprotect() { - final SdkBytes blob = SdkBytes.fromUtf8String(PROPERTY); - final DecryptResponse decryptResponse = DecryptResponse.builder().plaintext(blob).build(); - when(kmsClient.decrypt(any(DecryptRequest.class))).thenReturn(decryptResponse); - - final String property = provider.unprotect(PROTECTED_PROPERTY, ProtectedPropertyContext.defaultContext(PROPERTY_NAME)); - assertEquals(PROPERTY, property); - } - - @Test - public void testGetIdentifierKey() { - final String identifierKey = provider.getIdentifierKey(); - assertEquals(IDENTIFIER_KEY, identifierKey); - } -} diff --git a/nifi-commons/nifi-property-protection-aws/src/test/java/org/apache/nifi/properties/AwsSecretsManagerSensitivePropertyProviderTest.java b/nifi-commons/nifi-property-protection-aws/src/test/java/org/apache/nifi/properties/AwsSecretsManagerSensitivePropertyProviderTest.java deleted file mode 100644 index 09f85e63e65b..000000000000 --- a/nifi-commons/nifi-property-protection-aws/src/test/java/org/apache/nifi/properties/AwsSecretsManagerSensitivePropertyProviderTest.java +++ /dev/null @@ -1,125 +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.properties; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import software.amazon.awssdk.core.SdkBytes; -import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient; -import software.amazon.awssdk.services.secretsmanager.model.CreateSecretResponse; -import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueResponse; -import software.amazon.awssdk.services.secretsmanager.model.PutSecretValueResponse; -import software.amazon.awssdk.services.secretsmanager.model.ResourceNotFoundException; - -import java.nio.charset.Charset; -import java.util.function.Consumer; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -@ExtendWith(MockitoExtension.class) -public class AwsSecretsManagerSensitivePropertyProviderTest { - private static final String PROPERTY_NAME = "propertyName"; - private static final String PROPERTY_VALUE = "propertyValue"; - - private static final String SECRET_STRING = String.format("{ \"%s\": \"%s\" }", PROPERTY_NAME, PROPERTY_VALUE); - - private static final String IDENTIFIER_KEY = "aws/secretsmanager"; - - @Mock - private SecretsManagerClient secretsManagerClient; - - private AwsSecretsManagerSensitivePropertyProvider provider; - - @BeforeEach - public void setProvider() { - provider = new AwsSecretsManagerSensitivePropertyProvider(secretsManagerClient); - } - - @Test - public void testValidateClientNull() { - final AwsSecretsManagerSensitivePropertyProvider provider = new AwsSecretsManagerSensitivePropertyProvider(null); - assertNotNull(provider); - } - - @Test - public void testValidateKeyNoSecretString() { - final GetSecretValueResponse getSecretValueResponse = GetSecretValueResponse.builder() - .secretBinary(SdkBytes.fromString("binary", Charset.defaultCharset())).build(); - when(secretsManagerClient.getSecretValue(any(Consumer.class))).thenReturn(getSecretValueResponse); - - assertThrows(SensitivePropertyProtectionException.class, () -> - provider.unprotect("anyValue", ProtectedPropertyContext.defaultContext(PROPERTY_NAME))); - } - - @Test - public void testCleanUp() { - provider.cleanUp(); - verify(secretsManagerClient).close(); - } - - @Test - public void testProtectCreateSecret() { - final String secretName = ProtectedPropertyContext.defaultContext(PROPERTY_NAME).getContextKey(); - - when(secretsManagerClient.getSecretValue(any(Consumer.class))).thenThrow(ResourceNotFoundException.builder().message("Not found").build()); - - final CreateSecretResponse createSecretResponse = CreateSecretResponse.builder() - .name(secretName).build(); - when(secretsManagerClient.createSecret(any(Consumer.class))).thenReturn(createSecretResponse); - - final String protectedProperty = provider.protect(PROPERTY_VALUE, ProtectedPropertyContext.defaultContext(PROPERTY_NAME)); - assertEquals(secretName, protectedProperty); - } - - @Test - public void testProtectExistingSecret() { - final String secretName = ProtectedPropertyContext.defaultContext(PROPERTY_NAME).getContextKey(); - final GetSecretValueResponse getSecretValueResponse = GetSecretValueResponse.builder().secretString(SECRET_STRING).build(); - when(secretsManagerClient.getSecretValue(any(Consumer.class))).thenReturn(getSecretValueResponse); - - final PutSecretValueResponse putSecretValueResponse = PutSecretValueResponse.builder() - .name(secretName).build(); - when(secretsManagerClient.putSecretValue(any(Consumer.class))).thenReturn(putSecretValueResponse); - - final String protectedProperty = provider.protect(PROPERTY_VALUE, ProtectedPropertyContext.defaultContext(PROPERTY_NAME)); - assertEquals(secretName, protectedProperty); - } - - @Test - public void testUnprotect() { - final GetSecretValueResponse getSecretValueResponse = GetSecretValueResponse.builder().secretString(SECRET_STRING).build(); - when(secretsManagerClient.getSecretValue(any(Consumer.class))).thenReturn(getSecretValueResponse); - - final String property = provider.unprotect("anyValue", ProtectedPropertyContext.defaultContext(PROPERTY_NAME)); - assertEquals(PROPERTY_VALUE, property); - } - - - @Test - public void testGetIdentifierKey() { - final String identifierKey = provider.getIdentifierKey(); - assertEquals(IDENTIFIER_KEY, identifierKey); - } -} diff --git a/nifi-commons/nifi-property-protection-azure/pom.xml b/nifi-commons/nifi-property-protection-azure/pom.xml deleted file mode 100644 index 96f939853c89..000000000000 --- a/nifi-commons/nifi-property-protection-azure/pom.xml +++ /dev/null @@ -1,104 +0,0 @@ - - - - 4.0.0 - - org.apache.nifi - nifi-commons - 2.0.0-SNAPSHOT - - nifi-property-protection-azure - - - - com.azure - azure-sdk-bom - 1.2.24 - import - pom - - - - - - org.slf4j - slf4j-api - - - org.apache.nifi - nifi-property-protection-api - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-utils - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-shared - 2.0.0-SNAPSHOT - - - com.azure - azure-core - - - com.azure - azure-security-keyvault-secrets - - - com.azure - azure-core-http-netty - - - io.netty - netty-tcnative-boringssl-static - - - - - com.azure - azure-security-keyvault-keys - - - com.azure - azure-core-http-netty - - - io.netty - netty-tcnative-boringssl-static - - - - - com.azure - azure-identity - - - com.azure - azure-core-http-netty - - - - - - com.microsoft.azure - msal4j - 1.15.1 - - - diff --git a/nifi-commons/nifi-property-protection-azure/src/main/java/org/apache/nifi/properties/AzureKeyVaultKeySensitivePropertyProvider.java b/nifi-commons/nifi-property-protection-azure/src/main/java/org/apache/nifi/properties/AzureKeyVaultKeySensitivePropertyProvider.java deleted file mode 100644 index 1d60b2a48319..000000000000 --- a/nifi-commons/nifi-property-protection-azure/src/main/java/org/apache/nifi/properties/AzureKeyVaultKeySensitivePropertyProvider.java +++ /dev/null @@ -1,110 +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.properties; - -import com.azure.security.keyvault.keys.models.KeyVaultKey; -import com.azure.security.keyvault.keys.cryptography.CryptographyClient; -import com.azure.security.keyvault.keys.cryptography.models.DecryptResult; -import com.azure.security.keyvault.keys.cryptography.models.EncryptResult; -import com.azure.security.keyvault.keys.cryptography.models.EncryptionAlgorithm; -import com.azure.security.keyvault.keys.models.KeyOperation; -import com.azure.security.keyvault.keys.models.KeyProperties; - -import java.util.Arrays; -import java.util.List; -import java.util.Properties; - -/** - * Microsoft Azure Key Vault Key Sensitive Property Provider using Cryptography Client for encryption operations - */ -public class AzureKeyVaultKeySensitivePropertyProvider extends ClientBasedEncodedSensitivePropertyProvider { - protected static final String ENCRYPTION_ALGORITHM_PROPERTY = "azure.keyvault.encryption.algorithm"; - - protected static final List REQUIRED_OPERATIONS = Arrays.asList(KeyOperation.DECRYPT, KeyOperation.ENCRYPT); - - private static final String IDENTIFIER_KEY = "azure/keyvault/key"; - - private EncryptionAlgorithm encryptionAlgorithm; - - AzureKeyVaultKeySensitivePropertyProvider(final CryptographyClient cryptographyClient, final Properties properties) { - super(cryptographyClient, properties); - } - - @Override - public String getIdentifierKey() { - return IDENTIFIER_KEY; - } - - /** - * Validate Client and Key Operations with Encryption Algorithm when configured - * - * @param cryptographyClient Cryptography Client - */ - @Override - protected void validate(final CryptographyClient cryptographyClient) { - if (cryptographyClient == null) { - logger.debug("Azure Cryptography Client not configured"); - } else { - try { - final KeyVaultKey keyVaultKey = cryptographyClient.getKey(); - final String id = keyVaultKey.getId(); - final KeyProperties keyProperties = keyVaultKey.getProperties(); - if (keyProperties.isEnabled()) { - final List keyOperations = keyVaultKey.getKeyOperations(); - if (keyOperations.containsAll(REQUIRED_OPERATIONS)) { - logger.info("Azure Key Vault Key [{}] Validated", id); - } else { - throw new SensitivePropertyProtectionException(String.format("Azure Key Vault Key [%s] Missing Operations %s", id, REQUIRED_OPERATIONS)); - } - } else { - throw new SensitivePropertyProtectionException(String.format("Azure Key Vault Key [%s] Disabled", id)); - } - } catch (final RuntimeException e) { - throw new SensitivePropertyProtectionException("Azure Key Vault Key Validation Failed", e); - } - final String algorithm = getProperties().getProperty(ENCRYPTION_ALGORITHM_PROPERTY); - if (algorithm == null || algorithm.isEmpty()) { - throw new SensitivePropertyProtectionException("Azure Key Vault Key Algorithm not configured"); - } - encryptionAlgorithm = EncryptionAlgorithm.fromString(algorithm); - } - } - - /** - * Get encrypted bytes - * - * @param bytes Unprotected bytes - * @return Encrypted bytes - */ - @Override - protected byte[] getEncrypted(final byte[] bytes) { - final EncryptResult encryptResult = getClient().encrypt(encryptionAlgorithm, bytes); - return encryptResult.getCipherText(); - } - - /** - * Get decrypted bytes - * - * @param bytes Encrypted bytes - * @return Decrypted bytes - */ - @Override - protected byte[] getDecrypted(final byte[] bytes) { - final DecryptResult decryptResult = getClient().decrypt(encryptionAlgorithm, bytes); - return decryptResult.getPlainText(); - } -} diff --git a/nifi-commons/nifi-property-protection-azure/src/main/java/org/apache/nifi/properties/AzureKeyVaultSecretSensitivePropertyProvider.java b/nifi-commons/nifi-property-protection-azure/src/main/java/org/apache/nifi/properties/AzureKeyVaultSecretSensitivePropertyProvider.java deleted file mode 100644 index e2cbfc70f719..000000000000 --- a/nifi-commons/nifi-property-protection-azure/src/main/java/org/apache/nifi/properties/AzureKeyVaultSecretSensitivePropertyProvider.java +++ /dev/null @@ -1,117 +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.properties; - -import com.azure.core.exception.ResourceNotFoundException; -import com.azure.security.keyvault.secrets.SecretClient; -import com.azure.security.keyvault.secrets.models.KeyVaultSecret; - -import java.util.Objects; - -/** - * Microsoft Azure Key Vault Secret implementation of Sensitive Property Provider for externalized storage of properties - */ -public class AzureKeyVaultSecretSensitivePropertyProvider implements SensitivePropertyProvider { - private static final String FORWARD_SLASH = "/"; - - private static final String PERIOD = "\\."; - - private static final String DASH = "-"; - - private static final String IDENTIFIER_KEY = "azure/keyvault/secret"; - - private SecretClient secretClient; - - AzureKeyVaultSecretSensitivePropertyProvider(final SecretClient secretClient) { - this.secretClient = secretClient; - } - - /** - * Get Identifier key using Protection Scheme - * - * @return Identifier key - */ - @Override - public String getIdentifierKey() { - return IDENTIFIER_KEY; - } - - /** - * Is Provider supported returns status based on configuration of Secret Client - * - * @return Supported status - */ - @Override - public boolean isSupported() { - return secretClient != null; - } - - /** - * Protect value stores a Secret in Azure Key Vault using the Property Context Key as the Secret Name - * - * @param unprotectedValue Value to be stored - * @param context Property Context containing Context Key used to store Secret - * @return Key Vault Secret Identifier - * @throws SensitivePropertyProtectionException Thrown when storing Secret failed - */ - @Override - public String protect(final String unprotectedValue, final ProtectedPropertyContext context) throws SensitivePropertyProtectionException { - Objects.requireNonNull(unprotectedValue, "Value required"); - final String secretName = getSecretName(context); - try { - final KeyVaultSecret keyVaultSecret = secretClient.setSecret(secretName, unprotectedValue); - return keyVaultSecret.getId(); - } catch (final RuntimeException e) { - throw new SensitivePropertyProtectionException(String.format("Set Secret [%s] failed", secretName), e); - } - } - - /** - * Unprotect value retrieves a Secret from Azure Key Vault using Property Context Key - * - * @param protectedValue Key Vault Secret Identifier is not used - * @param context Property Context containing Context Key used to retrieve Secret - * @return Secret Value - * @throws SensitivePropertyProtectionException Thrown when Secret not found or retrieval failed - */ - @Override - public String unprotect(final String protectedValue, final ProtectedPropertyContext context) throws SensitivePropertyProtectionException { - final String secretName = getSecretName(context); - try { - final KeyVaultSecret keyVaultSecret = secretClient.getSecret(secretName); - return keyVaultSecret.getValue(); - } catch (final ResourceNotFoundException e) { - throw new SensitivePropertyProtectionException(String.format("Secret [%s] not found", secretName), e); - } catch (final RuntimeException e) { - throw new SensitivePropertyProtectionException(String.format("Secret [%s] request failed", secretName), e); - } - } - - /** - * Clean up not implemented - */ - @Override - public void cleanUp() { - - } - - private String getSecretName(final ProtectedPropertyContext context) { - final String contextKey = Objects.requireNonNull(context, "Context required").getContextKey(); - // Replace forward slash and period with dash since Azure Key Vault Secret Names do not support certain characters - return contextKey.replaceAll(FORWARD_SLASH, DASH).replaceAll(PERIOD, DASH); - } -} diff --git a/nifi-commons/nifi-property-protection-azure/src/main/java/org/apache/nifi/properties/configuration/AzureClientProvider.java b/nifi-commons/nifi-property-protection-azure/src/main/java/org/apache/nifi/properties/configuration/AzureClientProvider.java deleted file mode 100644 index bc48e45bbe97..000000000000 --- a/nifi-commons/nifi-property-protection-azure/src/main/java/org/apache/nifi/properties/configuration/AzureClientProvider.java +++ /dev/null @@ -1,39 +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.properties.configuration; - -import com.azure.core.credential.TokenCredential; -import com.azure.identity.DefaultAzureCredentialBuilder; -import org.apache.nifi.properties.BootstrapProperties; - -/** - * Abstract Microsoft Azure Client Provider - */ -public abstract class AzureClientProvider extends BootstrapPropertiesClientProvider { - public AzureClientProvider() { - super(BootstrapProperties.BootstrapPropertyKey.AZURE_KEYVAULT_SENSITIVE_PROPERTY_PROVIDER_CONF); - } - - /** - * Get Default Azure Token Credential using Default Credentials Builder for environment variables and system properties - * - * @return Token Credential - */ - protected TokenCredential getDefaultTokenCredential() { - return new DefaultAzureCredentialBuilder().build(); - } -} diff --git a/nifi-commons/nifi-property-protection-azure/src/main/java/org/apache/nifi/properties/configuration/AzureCryptographyClientProvider.java b/nifi-commons/nifi-property-protection-azure/src/main/java/org/apache/nifi/properties/configuration/AzureCryptographyClientProvider.java deleted file mode 100644 index adf974ee2a19..000000000000 --- a/nifi-commons/nifi-property-protection-azure/src/main/java/org/apache/nifi/properties/configuration/AzureCryptographyClientProvider.java +++ /dev/null @@ -1,66 +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.properties.configuration; - -import com.azure.security.keyvault.keys.cryptography.CryptographyClient; -import com.azure.security.keyvault.keys.cryptography.CryptographyClientBuilder; -import org.apache.nifi.properties.SensitivePropertyProtectionException; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Properties; -import java.util.Set; - -/** - * Microsoft Azure Cryptography Client Provider - */ -public class AzureCryptographyClientProvider extends AzureClientProvider { - protected static final String KEY_ID_PROPERTY = "azure.keyvault.key.id"; - - private static final Set REQUIRED_PROPERTY_NAMES = new HashSet<>(Collections.singletonList(KEY_ID_PROPERTY)); - - /** - * Get Configured Client using Default Azure Credentials Builder and configured Key Identifier - * - * @param clientProperties Client Properties - * @return Cryptography Client - */ - @Override - protected CryptographyClient getConfiguredClient(final Properties clientProperties) { - final String keyIdentifier = clientProperties.getProperty(KEY_ID_PROPERTY); - logger.debug("Azure Cryptography Client with Key Identifier [{}]", keyIdentifier); - - try { - return new CryptographyClientBuilder() - .credential(getDefaultTokenCredential()) - .keyIdentifier(keyIdentifier) - .buildClient(); - } catch (final RuntimeException e) { - throw new SensitivePropertyProtectionException("Azure Cryptography Builder Client Failed using Default Credentials", e); - } - } - - /** - * Get required property names for Azure Cryptography Client - * - * @return Required client property names - */ - @Override - protected Set getRequiredPropertyNames() { - return REQUIRED_PROPERTY_NAMES; - } -} diff --git a/nifi-commons/nifi-property-protection-azure/src/main/java/org/apache/nifi/properties/configuration/AzureSecretClientProvider.java b/nifi-commons/nifi-property-protection-azure/src/main/java/org/apache/nifi/properties/configuration/AzureSecretClientProvider.java deleted file mode 100644 index 65432fa6c5eb..000000000000 --- a/nifi-commons/nifi-property-protection-azure/src/main/java/org/apache/nifi/properties/configuration/AzureSecretClientProvider.java +++ /dev/null @@ -1,69 +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.properties.configuration; - -import com.azure.core.credential.TokenCredential; -import com.azure.identity.DefaultAzureCredentialBuilder; -import com.azure.security.keyvault.secrets.SecretClient; -import com.azure.security.keyvault.secrets.SecretClientBuilder; -import org.apache.nifi.properties.SensitivePropertyProtectionException; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Properties; -import java.util.Set; - -/** - * Microsoft Azure Secret Client Provider - */ -public class AzureSecretClientProvider extends AzureClientProvider { - protected static final String URI_PROPERTY = "azure.keyvault.uri"; - - private static final Set REQUIRED_PROPERTY_NAMES = new HashSet<>(Collections.singletonList(URI_PROPERTY)); - - /** - * Get Secret Client using Default Azure Credentials Builder and default configuration from environment variables - * - * @param clientProperties Client Properties - * @return Secret Client - */ - @Override - protected SecretClient getConfiguredClient(final Properties clientProperties) { - final String uri = clientProperties.getProperty(URI_PROPERTY); - logger.debug("Azure Secret Client with URI [{}]", uri); - - try { - final TokenCredential credential = new DefaultAzureCredentialBuilder().build(); - return new SecretClientBuilder() - .credential(credential) - .vaultUrl(uri) - .buildClient(); - } catch (final RuntimeException e) { - throw new SensitivePropertyProtectionException("Azure Secret Builder Client Failed using Default Credentials", e); - } - } - - /** - * Get required property names for Azure Secret Client - * - * @return Required client property names - */ - @Override - protected Set getRequiredPropertyNames() { - return REQUIRED_PROPERTY_NAMES; - } -} diff --git a/nifi-commons/nifi-property-protection-azure/src/test/java/org/apache/nifi/properties/AzureKeyVaultKeySensitivePropertyProviderTest.java b/nifi-commons/nifi-property-protection-azure/src/test/java/org/apache/nifi/properties/AzureKeyVaultKeySensitivePropertyProviderTest.java deleted file mode 100644 index 539a90e31de3..000000000000 --- a/nifi-commons/nifi-property-protection-azure/src/test/java/org/apache/nifi/properties/AzureKeyVaultKeySensitivePropertyProviderTest.java +++ /dev/null @@ -1,118 +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.properties; - -import com.azure.security.keyvault.keys.cryptography.CryptographyClient; -import com.azure.security.keyvault.keys.cryptography.models.DecryptResult; -import com.azure.security.keyvault.keys.cryptography.models.EncryptResult; -import com.azure.security.keyvault.keys.cryptography.models.EncryptionAlgorithm; -import com.azure.security.keyvault.keys.models.KeyProperties; -import com.azure.security.keyvault.keys.models.KeyVaultKey; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.nio.charset.StandardCharsets; -import java.util.Base64; -import java.util.Properties; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.when; - -@ExtendWith(MockitoExtension.class) -public class AzureKeyVaultKeySensitivePropertyProviderTest { - private static final String PROPERTY_NAME = String.class.getSimpleName(); - - private static final String PROPERTY = String.class.getName(); - - private static final byte[] PROPERTY_BYTES = PROPERTY.getBytes(StandardCharsets.UTF_8); - - private static final String ENCRYPTED_PROPERTY = Integer.class.getName(); - - private static final byte[] ENCRYPTED_BYTES = ENCRYPTED_PROPERTY.getBytes(StandardCharsets.UTF_8); - - private static final String PROTECTED_PROPERTY = Base64.getEncoder().withoutPadding().encodeToString(ENCRYPTED_BYTES); - - private static final String ID = KeyVaultKey.class.getSimpleName(); - - private static final Properties PROPERTIES = new Properties(); - - private static final EncryptionAlgorithm ALGORITHM = EncryptionAlgorithm.A256GCM; - - private static final String IDENTIFIER_KEY = "azure/keyvault/key"; - - static { - PROPERTIES.setProperty(AzureKeyVaultKeySensitivePropertyProvider.ENCRYPTION_ALGORITHM_PROPERTY, ALGORITHM.toString()); - } - - @Mock - private CryptographyClient cryptographyClient; - - @Mock - private KeyVaultKey keyVaultKey; - - @Mock - private KeyProperties keyProperties; - - private AzureKeyVaultKeySensitivePropertyProvider provider; - - @BeforeEach - public void setProvider() { - when(keyProperties.isEnabled()).thenReturn(true); - when(keyVaultKey.getId()).thenReturn(ID); - when(keyVaultKey.getProperties()).thenReturn(keyProperties); - when(keyVaultKey.getKeyOperations()).thenReturn(AzureKeyVaultKeySensitivePropertyProvider.REQUIRED_OPERATIONS); - when(cryptographyClient.getKey()).thenReturn(keyVaultKey); - - provider = new AzureKeyVaultKeySensitivePropertyProvider(cryptographyClient, PROPERTIES); - } - - @Test - public void testValidateClientNull() { - final AzureKeyVaultKeySensitivePropertyProvider provider = new AzureKeyVaultKeySensitivePropertyProvider(null, PROPERTIES); - assertNotNull(provider); - } - - @Test - public void testProtect() { - final EncryptResult encryptResult = new EncryptResult(ENCRYPTED_BYTES, ALGORITHM, ID); - when(cryptographyClient.encrypt(eq(ALGORITHM), any(byte[].class))).thenReturn(encryptResult); - - final String protectedProperty = provider.protect(PROPERTY, ProtectedPropertyContext.defaultContext(PROPERTY_NAME)); - assertEquals(PROTECTED_PROPERTY, protectedProperty); - } - - @Test - public void testUnprotect() { - final DecryptResult decryptResult = new DecryptResult(PROPERTY_BYTES, ALGORITHM, ID); - when(cryptographyClient.decrypt(eq(ALGORITHM), any(byte[].class))).thenReturn(decryptResult); - - final String property = provider.unprotect(PROTECTED_PROPERTY, ProtectedPropertyContext.defaultContext(PROPERTY_NAME)); - assertEquals(PROPERTY, property); - } - - @Test - public void testGetIdentifierKey() { - final String identifierKey = provider.getIdentifierKey(); - assertEquals(IDENTIFIER_KEY, identifierKey); - } -} diff --git a/nifi-commons/nifi-property-protection-azure/src/test/java/org/apache/nifi/properties/AzureKeyVaultSecretSensitivePropertyProviderTest.java b/nifi-commons/nifi-property-protection-azure/src/test/java/org/apache/nifi/properties/AzureKeyVaultSecretSensitivePropertyProviderTest.java deleted file mode 100644 index 399d2fb262af..000000000000 --- a/nifi-commons/nifi-property-protection-azure/src/test/java/org/apache/nifi/properties/AzureKeyVaultSecretSensitivePropertyProviderTest.java +++ /dev/null @@ -1,116 +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.properties; - -import com.azure.core.exception.AzureException; -import com.azure.core.exception.ResourceNotFoundException; -import com.azure.core.http.HttpResponse; -import com.azure.security.keyvault.secrets.SecretClient; -import com.azure.security.keyvault.secrets.models.KeyVaultSecret; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.when; - -@ExtendWith(MockitoExtension.class) -public class AzureKeyVaultSecretSensitivePropertyProviderTest { - private static final String PROPERTY_NAME = "property.name"; - - private static final String SECRET_NAME = "default-property-name"; - - private static final String PROPERTY = String.class.getName(); - - private static final String PROTECTED_PROPERTY = KeyVaultSecret.class.getSimpleName(); - - private static final String ID = KeyVaultSecret.class.getName(); - - private static final String IDENTIFIER_KEY = "azure/keyvault/secret"; - - @Mock - private SecretClient secretClient; - - @Mock - private KeyVaultSecret keyVaultSecret; - - @Mock - private HttpResponse httpResponse; - - private AzureKeyVaultSecretSensitivePropertyProvider provider; - - @BeforeEach - public void setProvider() { - provider = new AzureKeyVaultSecretSensitivePropertyProvider(secretClient); - } - - @Test - public void testClientNull() { - final AzureKeyVaultSecretSensitivePropertyProvider provider = new AzureKeyVaultSecretSensitivePropertyProvider(null); - assertNotNull(provider); - assertFalse(provider.isSupported()); - } - - @Test - public void testProtect() { - when(secretClient.setSecret(eq(SECRET_NAME), eq(PROPERTY))).thenReturn(keyVaultSecret); - when(keyVaultSecret.getId()).thenReturn(ID); - - final ProtectedPropertyContext context = ProtectedPropertyContext.defaultContext(PROPERTY_NAME); - final String protectedProperty = provider.protect(PROPERTY, context); - assertEquals(ID, protectedProperty); - } - - @Test - public void testProtectException() { - final ProtectedPropertyContext context = ProtectedPropertyContext.defaultContext(PROPERTY_NAME); - final String secretName = context.getContextKey(); - when(secretClient.setSecret(eq(secretName), eq(PROPERTY))).thenThrow(new AzureException()); - - assertThrows(SensitivePropertyProtectionException.class, () -> provider.protect(PROPERTY, context)); - } - - @Test - public void testUnprotect() { - when(secretClient.getSecret(eq(SECRET_NAME))).thenReturn(keyVaultSecret); - when(keyVaultSecret.getValue()).thenReturn(PROPERTY); - - final ProtectedPropertyContext context = ProtectedPropertyContext.defaultContext(PROPERTY_NAME); - final String property = provider.unprotect(PROTECTED_PROPERTY, context); - assertEquals(PROPERTY, property); - } - - @Test - public void testUnprotectResourceNotFoundException() { - when(secretClient.getSecret(eq(SECRET_NAME))).thenThrow(new ResourceNotFoundException(SECRET_NAME, httpResponse)); - - final ProtectedPropertyContext context = ProtectedPropertyContext.defaultContext(PROPERTY_NAME); - assertThrows(SensitivePropertyProtectionException.class, () -> provider.unprotect(PROTECTED_PROPERTY, context)); - } - - @Test - public void testGetIdentifierKey() { - final String identifierKey = provider.getIdentifierKey(); - assertEquals(IDENTIFIER_KEY, identifierKey); - } -} diff --git a/nifi-commons/nifi-property-protection-azure/src/test/java/org/apache/nifi/properties/configuration/AzureCryptographyClientProviderTest.java b/nifi-commons/nifi-property-protection-azure/src/test/java/org/apache/nifi/properties/configuration/AzureCryptographyClientProviderTest.java deleted file mode 100644 index 92ac1b9f11a1..000000000000 --- a/nifi-commons/nifi-property-protection-azure/src/test/java/org/apache/nifi/properties/configuration/AzureCryptographyClientProviderTest.java +++ /dev/null @@ -1,44 +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.properties.configuration; - -import com.azure.security.keyvault.keys.cryptography.CryptographyClient; -import org.junit.jupiter.api.Test; - -import java.util.Optional; -import java.util.Properties; - -import static org.junit.jupiter.api.Assertions.assertFalse; - -public class AzureCryptographyClientProviderTest { - - @Test - public void testClientPropertiesNull() { - final AzureCryptographyClientProvider provider = new AzureCryptographyClientProvider(); - final Optional optionalClient = provider.getClient(null); - assertFalse(optionalClient.isPresent()); - } - - @Test - public void testClientPropertiesKeyIdBlank() { - final AzureCryptographyClientProvider provider = new AzureCryptographyClientProvider(); - final Properties clientProperties = new Properties(); - clientProperties.setProperty(AzureCryptographyClientProvider.KEY_ID_PROPERTY, ""); - final Optional optionalClient = provider.getClient(clientProperties); - assertFalse(optionalClient.isPresent()); - } -} diff --git a/nifi-commons/nifi-property-protection-azure/src/test/java/org/apache/nifi/properties/configuration/AzureSecretClientProviderTest.java b/nifi-commons/nifi-property-protection-azure/src/test/java/org/apache/nifi/properties/configuration/AzureSecretClientProviderTest.java deleted file mode 100644 index 417b52214041..000000000000 --- a/nifi-commons/nifi-property-protection-azure/src/test/java/org/apache/nifi/properties/configuration/AzureSecretClientProviderTest.java +++ /dev/null @@ -1,44 +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.properties.configuration; - -import com.azure.security.keyvault.secrets.SecretClient; -import org.junit.jupiter.api.Test; - -import java.util.Optional; -import java.util.Properties; - -import static org.junit.jupiter.api.Assertions.assertFalse; - -public class AzureSecretClientProviderTest { - - @Test - public void testClientPropertiesNull() { - final AzureSecretClientProvider provider = new AzureSecretClientProvider(); - final Optional optionalClient = provider.getClient(null); - assertFalse(optionalClient.isPresent()); - } - - @Test - public void testClientPropertiesUriBlank() { - final AzureSecretClientProvider provider = new AzureSecretClientProvider(); - final Properties clientProperties = new Properties(); - clientProperties.setProperty(AzureSecretClientProvider.URI_PROPERTY, ""); - final Optional optionalClient = provider.getClient(clientProperties); - assertFalse(optionalClient.isPresent()); - } -} diff --git a/nifi-commons/nifi-property-protection-cipher/pom.xml b/nifi-commons/nifi-property-protection-cipher/pom.xml deleted file mode 100644 index 1a0aa6ce2528..000000000000 --- a/nifi-commons/nifi-property-protection-cipher/pom.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - 4.0.0 - - org.apache.nifi - nifi-commons - 2.0.0-SNAPSHOT - - nifi-property-protection-cipher - - - org.apache.nifi - nifi-property-protection-api - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-utils - 2.0.0-SNAPSHOT - - - commons-codec - commons-codec - - - diff --git a/nifi-commons/nifi-property-protection-cipher/src/main/java/org/apache/nifi/properties/AesGcmSensitivePropertyProvider.java b/nifi-commons/nifi-property-protection-cipher/src/main/java/org/apache/nifi/properties/AesGcmSensitivePropertyProvider.java deleted file mode 100644 index 70f94486b9b0..000000000000 --- a/nifi-commons/nifi-property-protection-cipher/src/main/java/org/apache/nifi/properties/AesGcmSensitivePropertyProvider.java +++ /dev/null @@ -1,200 +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.properties; - -import org.apache.commons.codec.DecoderException; -import org.apache.commons.codec.binary.Hex; - -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.SecretKey; -import javax.crypto.spec.GCMParameterSpec; -import javax.crypto.spec.SecretKeySpec; -import java.nio.charset.StandardCharsets; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.util.Arrays; -import java.util.Base64; -import java.util.List; -import java.util.Objects; - -/** - * Sensitive Property Provider implementation using AES-GCM with configurable key sizes - */ -public class AesGcmSensitivePropertyProvider implements SensitivePropertyProvider { - private static final String ALGORITHM = "AES/GCM/NoPadding"; - private static final String SECRET_KEY_ALGORITHM = "AES"; - private static final String DELIMITER = "||"; // "|" is not a valid Base64 character, so ensured not to be present in cipher text - private static final int IV_LENGTH = 12; - private static final int TAG_LENGTH = 128; - private static final int MIN_CIPHER_TEXT_LENGTH = IV_LENGTH * 4 / 3 + DELIMITER.length() + 1; - private static final List VALID_KEY_LENGTHS = Arrays.asList(128, 192, 256); - - private static final String IDENTIFIER_KEY_FORMAT = "aes/gcm/%d"; - private static final int BITS_PER_BYTE = 8; - - private static final Base64.Encoder BASE_64_ENCODER = Base64.getEncoder(); - private static final Base64.Decoder BASE_64_DECODER = Base64.getDecoder(); - - private final SecureRandom secureRandom; - private final Cipher cipher; - private final SecretKey key; - private final String identifierKey; - - public AesGcmSensitivePropertyProvider(final String keyHex) { - byte[] keyBytes = validateKey(keyHex); - - secureRandom = new SecureRandom(); - try { - cipher = Cipher.getInstance(ALGORITHM); - key = new SecretKeySpec(keyBytes, SECRET_KEY_ALGORITHM); - - final int keySize = keyBytes.length * BITS_PER_BYTE; - identifierKey = String.format(IDENTIFIER_KEY_FORMAT, keySize); - } catch (final NoSuchAlgorithmException | NoSuchPaddingException e) { - throw new SensitivePropertyProtectionException(String.format("Cipher [%s] initialization failed", ALGORITHM), e); - } - } - - @Override - public boolean isSupported() { - return true; - } - - /** - * Returns the key used to identify the provider implementation in {@code nifi.properties}. - * - * @return the key to persist in the sibling property - */ - @Override - public String getIdentifierKey() { - return identifierKey; - } - - /** - * Returns the encrypted cipher text. - * - * @param unprotectedValue the sensitive value - * @param context The property context, unused in this provider - * @return the value to persist in the {@code nifi.properties} file - * @throws SensitivePropertyProtectionException if there is an exception encrypting the value - */ - @Override - public String protect(final String unprotectedValue, final ProtectedPropertyContext context) throws SensitivePropertyProtectionException { - Objects.requireNonNull(unprotectedValue, "Value required"); - - final byte[] iv = generateIV(); - try { - cipher.init(Cipher.ENCRYPT_MODE, this.key, new GCMParameterSpec(TAG_LENGTH, iv)); - - byte[] plainBytes = unprotectedValue.getBytes(StandardCharsets.UTF_8); - byte[] cipherBytes = cipher.doFinal(plainBytes); - return BASE_64_ENCODER.encodeToString(iv) + DELIMITER + BASE_64_ENCODER.encodeToString(cipherBytes); - } catch (final BadPaddingException | IllegalBlockSizeException | InvalidAlgorithmParameterException | InvalidKeyException e) { - throw new SensitivePropertyProtectionException("AES-GCM encryption failed", e); - } - } - - /** - * Returns the decrypted plaintext. - * - * @param protectedValue the cipher text read from the {@code nifi.properties} file - * @param context The property context, unused in this provider - * @return the raw value to be used by the application - * @throws SensitivePropertyProtectionException if there is an error decrypting the cipher text - */ - @Override - public String unprotect(final String protectedValue, final ProtectedPropertyContext context) throws SensitivePropertyProtectionException { - if (protectedValue == null || protectedValue.trim().length() < MIN_CIPHER_TEXT_LENGTH) { - throw new IllegalArgumentException("Cannot decrypt a cipher text shorter than " + MIN_CIPHER_TEXT_LENGTH + " chars"); - } - - if (!protectedValue.contains(DELIMITER)) { - throw new IllegalArgumentException("The cipher text does not contain the delimiter " + DELIMITER + " -- it should be of the form Base64(IV) || Base64(cipherText)"); - } - final String trimmedProtectedValue = protectedValue.trim(); - - final String armoredIV = trimmedProtectedValue.substring(0, trimmedProtectedValue.indexOf(DELIMITER)); - final byte[] iv = BASE_64_DECODER.decode(armoredIV); - if (iv.length < IV_LENGTH) { - throw new IllegalArgumentException(String.format("The IV (%s bytes) must be at least %s bytes", iv.length, IV_LENGTH)); - } - - final String encodedCipherBytes = trimmedProtectedValue.substring(trimmedProtectedValue.indexOf(DELIMITER) + 2); - - try { - final byte[] cipherBytes = BASE_64_DECODER.decode(encodedCipherBytes); - - cipher.init(Cipher.DECRYPT_MODE, this.key, new GCMParameterSpec(TAG_LENGTH, iv)); - final byte[] plainBytes = cipher.doFinal(cipherBytes); - return new String(plainBytes, StandardCharsets.UTF_8); - } catch (final BadPaddingException | IllegalBlockSizeException | InvalidAlgorithmParameterException | InvalidKeyException e) { - throw new SensitivePropertyProtectionException("AES-GCM decryption failed", e); - } - } - - /** - * No cleanup necessary - */ - @Override - public void cleanUp() { } - - private byte[] generateIV() { - final byte[] iv = new byte[IV_LENGTH]; - secureRandom.nextBytes(iv); - return iv; - } - - private byte[] validateKey(String keyHex) { - if (keyHex == null || keyHex.isEmpty()) { - throw new SensitivePropertyProtectionException("AES Key not provided"); - } - keyHex = formatHexKey(keyHex); - if (!isHexKeyValid(keyHex)) { - throw new SensitivePropertyProtectionException("AES Key not hexadecimal"); - } - final byte[] key; - try { - key = Hex.decodeHex(keyHex); - } catch (final DecoderException e) { - throw new SensitivePropertyProtectionException("AES Key Hexadecimal decoding failed", e); - } - final int keyLengthBits = key.length * BITS_PER_BYTE; - if (!VALID_KEY_LENGTHS.contains(keyLengthBits)) { - throw new SensitivePropertyProtectionException(String.format("AES Key length not valid [%d]", keyLengthBits)); - } - return key; - } - - private static String formatHexKey(String input) { - if (input == null || input.isEmpty()) { - return ""; - } - return input.replaceAll("[^0-9a-fA-F]", "").toLowerCase(); - } - - private static boolean isHexKeyValid(String key) { - if (key == null || key.isEmpty()) { - return false; - } - return key.matches("^[0-9a-fA-F]*$"); - } -} diff --git a/nifi-commons/nifi-property-protection-cipher/src/test/java/org/apache/nifi/properties/AesGcmSensitivePropertyProviderTest.java b/nifi-commons/nifi-property-protection-cipher/src/test/java/org/apache/nifi/properties/AesGcmSensitivePropertyProviderTest.java deleted file mode 100644 index 5e01fc2be029..000000000000 --- a/nifi-commons/nifi-property-protection-cipher/src/test/java/org/apache/nifi/properties/AesGcmSensitivePropertyProviderTest.java +++ /dev/null @@ -1,109 +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.properties; - -import org.junit.jupiter.api.Test; - -import java.util.Base64; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class AesGcmSensitivePropertyProviderTest { - private static final String HEXADECIMAL_KEY_32 = "12345678"; - - private static final String HEXADECIMAL_KEY_128 = "12345678123456788765432187654321"; - - private static final String HEXADECIMAL_KEY_256 = "1234567812345678876543218765432112345678123456788765432187654321"; - - private static final String AES_GCM_128 = "aes/gcm/128"; - - private static final String AES_GCM_256 = "aes/gcm/256"; - - private static final ProtectedPropertyContext PROPERTY_CONTEXT = ProtectedPropertyContext.defaultContext("propertyName"); - - private static final String PROPERTY_VALUE = "propertyValue"; - - private static final String DELIMITER = "||"; - - private static final String DELIMITER_PATTERN = "\\|\\|"; - - private static final int DELIMITED_ELEMENTS = 2; - - private static final int INITIALIZATION_VECTOR_LENGTH = 12; - - @Test - public void testInvalidKeyLength() { - assertThrows(SensitivePropertyProtectionException.class, () -> new AesGcmSensitivePropertyProvider(HEXADECIMAL_KEY_32)); - } - - @Test - public void testIsSupported() { - final AesGcmSensitivePropertyProvider provider = new AesGcmSensitivePropertyProvider(HEXADECIMAL_KEY_128); - assertTrue(provider.isSupported()); - } - - @Test - public void testGetIdentifierKeyAesGcm128() { - final AesGcmSensitivePropertyProvider provider = new AesGcmSensitivePropertyProvider(HEXADECIMAL_KEY_128); - final String identifierKey = provider.getIdentifierKey(); - assertEquals(AES_GCM_128, identifierKey); - } - - @Test - public void testGetIdentifierKeyAesGcm256() { - final AesGcmSensitivePropertyProvider provider = new AesGcmSensitivePropertyProvider(HEXADECIMAL_KEY_256); - final String identifierKey = provider.getIdentifierKey(); - assertEquals(AES_GCM_256, identifierKey); - } - - @Test - public void testProtectUnprotectSuccess() { - final AesGcmSensitivePropertyProvider provider = new AesGcmSensitivePropertyProvider(HEXADECIMAL_KEY_128); - - final String protectedPropertyValue = provider.protect(PROPERTY_VALUE, PROPERTY_CONTEXT); - final String unprotectedPropertyValue = provider.unprotect(protectedPropertyValue, PROPERTY_CONTEXT); - - assertEquals(PROPERTY_VALUE, unprotectedPropertyValue); - assertTrue(protectedPropertyValue.contains(DELIMITER)); - - final String[] elements = protectedPropertyValue.split(DELIMITER_PATTERN); - assertEquals(DELIMITED_ELEMENTS, elements.length); - - final String initializationVectorEncoded = elements[0]; - final byte[] initializationVector = Base64.getDecoder().decode(initializationVectorEncoded); - assertEquals(INITIALIZATION_VECTOR_LENGTH, initializationVector.length); - } - - @Test - public void testProtectUnprotectDifferentKeyFailed() { - final AesGcmSensitivePropertyProvider provider = new AesGcmSensitivePropertyProvider(HEXADECIMAL_KEY_128); - - final String protectedPropertyValue = provider.protect(PROPERTY_VALUE, PROPERTY_CONTEXT); - - final AesGcmSensitivePropertyProvider secondProvider = new AesGcmSensitivePropertyProvider(HEXADECIMAL_KEY_256); - assertThrows(SensitivePropertyProtectionException.class, () -> secondProvider.unprotect(protectedPropertyValue, PROPERTY_CONTEXT)); - } - - @Test - public void testUnprotectMinLengthRequired() { - final AesGcmSensitivePropertyProvider provider = new AesGcmSensitivePropertyProvider(HEXADECIMAL_KEY_128); - - assertThrows(IllegalArgumentException.class, () -> provider.unprotect(HEXADECIMAL_KEY_32, PROPERTY_CONTEXT)); - } -} diff --git a/nifi-commons/nifi-property-protection-factory/pom.xml b/nifi-commons/nifi-property-protection-factory/pom.xml deleted file mode 100644 index 8f8f853ade50..000000000000 --- a/nifi-commons/nifi-property-protection-factory/pom.xml +++ /dev/null @@ -1,157 +0,0 @@ - - - - 4.0.0 - - org.apache.nifi - nifi-commons - 2.0.0-SNAPSHOT - - nifi-property-protection-factory - - - - com.azure - azure-sdk-bom - 1.2.24 - import - pom - - - com.google.cloud - libraries-bom - ${gcp.sdk.version} - pom - import - - - - - - org.slf4j - slf4j-api - - - org.apache.nifi - nifi-property-protection-api - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-utils - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-shared - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-aws - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-azure - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-cipher - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-gcp - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-hashicorp - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-properties - - - com.azure - azure-core-http-okhttp - - - com.google.cloud - google-cloud-kms - - - commons-logging - commons-logging - - - - - com.azure - azure-security-keyvault-secrets - - - com.azure - azure-core-http-netty - - - io.netty - netty-tcnative-boringssl-static - - - - - com.azure - azure-security-keyvault-keys - - - com.azure - azure-core-http-netty - - - io.netty - netty-tcnative-boringssl-static - - - - - software.amazon.awssdk - kms - - - software.amazon.awssdk - secretsmanager - - - software.amazon.awssdk - netty-nio-client - - - software.amazon.awssdk - apache-client - - - - - commons-io - commons-io - test - - - diff --git a/nifi-commons/nifi-property-protection-factory/src/main/java/org/apache/nifi/properties/StandardSensitivePropertyProviderFactory.java b/nifi-commons/nifi-property-protection-factory/src/main/java/org/apache/nifi/properties/StandardSensitivePropertyProviderFactory.java deleted file mode 100644 index feedb8e5d99d..000000000000 --- a/nifi-commons/nifi-property-protection-factory/src/main/java/org/apache/nifi/properties/StandardSensitivePropertyProviderFactory.java +++ /dev/null @@ -1,243 +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.properties; - -import com.azure.security.keyvault.keys.cryptography.CryptographyClient; -import com.azure.security.keyvault.secrets.SecretClient; -import com.google.cloud.kms.v1.KeyManagementServiceClient; - -import org.apache.nifi.properties.BootstrapProperties.BootstrapPropertyKey; -import org.apache.nifi.properties.configuration.AwsKmsClientProvider; -import org.apache.nifi.properties.configuration.AwsSecretsManagerClientProvider; -import org.apache.nifi.properties.configuration.AzureCryptographyClientProvider; -import org.apache.nifi.properties.configuration.AzureSecretClientProvider; -import org.apache.nifi.properties.configuration.ClientProvider; -import org.apache.nifi.properties.configuration.GoogleKeyManagementServiceClientProvider; -import org.apache.nifi.properties.scheme.ProtectionScheme; -import org.apache.nifi.util.NiFiBootstrapUtils; -import org.apache.nifi.util.StringUtils; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import software.amazon.awssdk.services.kms.KmsClient; -import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Properties; -import java.util.function.Supplier; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -/** - * Standard implementation of Sensitive Property Provider Factory with custom initialization for each provider - */ -public class StandardSensitivePropertyProviderFactory implements SensitivePropertyProviderFactory { - private static final Logger logger = LoggerFactory.getLogger(StandardSensitivePropertyProviderFactory.class); - - private static final List> PROVIDER_CLASSES = Arrays.asList( - AesGcmSensitivePropertyProvider.class, - AwsKmsSensitivePropertyProvider.class, - AwsSecretsManagerSensitivePropertyProvider.class, - AzureKeyVaultKeySensitivePropertyProvider.class, - AzureKeyVaultSecretSensitivePropertyProvider.class, - GcpKmsSensitivePropertyProvider.class, - HashiCorpVaultKeyValueSensitivePropertyProvider.class, - HashiCorpVaultTransitSensitivePropertyProvider.class - ); - - private Optional keyHex; - private final Supplier bootstrapPropertiesSupplier; - private final Map, SensitivePropertyProvider> providers; - private Map customPropertyContextMap; - - /** - * Factory default constructor to support java.util.ServiceLoader - */ - public StandardSensitivePropertyProviderFactory() { - this(null, null); - } - - public void setKeyHex(final String hexadecimalKey) { - this.keyHex = Optional.ofNullable(hexadecimalKey); - } - - /** - * Creates a StandardSensitivePropertyProviderFactory using the default bootstrap.conf location and - * the keyHex extracted from this bootstrap.conf. - */ - public static SensitivePropertyProviderFactory withDefaults() { - return withKeyAndBootstrapSupplier(null, null); - } - - /** - * Creates a StandardSensitivePropertyProviderFactory using only the provided secret key hex. The default - * bootstrap.conf will be used for any providers that may require it, but the provided keyHex will be used instead - * of the one from the default bootstrap.conf. - * @param keyHex The secret key hex for encrypting properties - * @return A StandardSensitivePropertyProviderFactory - */ - public static SensitivePropertyProviderFactory withKey(final String keyHex) { - return new StandardSensitivePropertyProviderFactory(keyHex, null); - } - - /** - * Creates a new StandardSensitivePropertyProviderFactory using a separate keyHex and provided bootstrap.conf. - * The provided keyHex will be used instead of the one from the bootstrap.conf. - * @param keyHex The secret key hex for encrypting properties - * @param bootstrapPropertiesSupplier A supplier for the BootstrapProperties that represent bootstrap.conf. - * If the supplier returns null, the default bootstrap.conf will be used instead. - * @return A StandardSensitivePropertyProviderFactory - */ - public static SensitivePropertyProviderFactory withKeyAndBootstrapSupplier(final String keyHex, - final Supplier bootstrapPropertiesSupplier) { - return new StandardSensitivePropertyProviderFactory(keyHex, bootstrapPropertiesSupplier); - } - - private StandardSensitivePropertyProviderFactory(final String keyHex, final Supplier bootstrapPropertiesSupplier) { - this.keyHex = Optional.ofNullable(keyHex); - this.bootstrapPropertiesSupplier = bootstrapPropertiesSupplier == null ? () -> null : bootstrapPropertiesSupplier; - this.providers = new HashMap<>(); - this.customPropertyContextMap = null; - } - - /** - * Get Provider where Protection Scheme path starts with a prefix mapped to the Provider Class - * - * @param protectionScheme Protection Scheme requested - * @return Sensitive Property Provider - * @throws SensitivePropertyProtectionException Thrown when provider path not found for requested scheme - */ - @Override - public SensitivePropertyProvider getProvider(final ProtectionScheme protectionScheme) throws SensitivePropertyProtectionException { - final String path = Objects.requireNonNull(protectionScheme, "Protection Scheme required").getPath(); - final Collection supportedProviders = getSupportedProviders(); - return supportedProviders.stream() - .filter(provider -> provider.getIdentifierKey().startsWith(path)) - .findFirst() - .orElseThrow(() -> new SensitivePropertyProtectionException(String.format("Protection Scheme [%s] not found", path))); - } - - /** - * Get Supported Sensitive Property Providers instantiates providers as needed and checks supported status - * - * @return Supported Sensitive Property Providers - */ - @Override - public Collection getSupportedProviders() { - return PROVIDER_CLASSES - .stream() - .map(this::getProvider) - .filter(SensitivePropertyProvider::isSupported) - .collect(Collectors.toList()); - } - - @Override - public ProtectedPropertyContext getPropertyContext(final String groupIdentifier, final String propertyName) { - if (customPropertyContextMap == null) { - populateCustomPropertyContextMap(); - } - final String contextName = customPropertyContextMap.entrySet().stream() - .filter(entry -> entry.getValue().matcher(groupIdentifier).find()) - .map(Map.Entry::getKey) - .findFirst() - .orElse(null); - return ProtectedPropertyContext.contextFor(propertyName, contextName); - } - - private void populateCustomPropertyContextMap() { - final BootstrapProperties bootstrapProperties = getBootstrapProperties(); - customPropertyContextMap = new HashMap<>(); - final String contextMappingKeyPrefix = BootstrapPropertyKey.CONTEXT_MAPPING_PREFIX.getKey(); - bootstrapProperties.getPropertyKeys().stream() - .filter(k -> k.contains(contextMappingKeyPrefix)) - .forEach(k -> customPropertyContextMap.put(StringUtils.substringAfter(k, contextMappingKeyPrefix), Pattern.compile(bootstrapProperties.getProperty(k)))); - } - - private String getKeyHex() { - return keyHex.orElseGet(() -> getBootstrapProperties().getProperty(BootstrapPropertyKey.SENSITIVE_KEY) - .orElseThrow(() -> new SensitivePropertyProtectionException("Could not read root key from bootstrap.conf"))); - } - - private BootstrapProperties getBootstrapProperties() { - return Optional.ofNullable(bootstrapPropertiesSupplier.get()).orElseGet(() -> { - try { - return NiFiBootstrapUtils.loadBootstrapProperties(); - } catch (final IOException e) { - logger.debug("Bootstrap Properties loading failed", e); - return BootstrapProperties.EMPTY; - } - }); - } - - private Properties getClientProperties(final ClientProvider clientProvider) { - final Optional clientProperties = clientProvider.getClientProperties(getBootstrapProperties()); - return clientProperties.orElse(null); - } - - private SensitivePropertyProvider getProvider(final Class providerClass) throws SensitivePropertyProtectionException { - SensitivePropertyProvider provider = providers.get(providerClass); - if (provider == null) { - if (AesGcmSensitivePropertyProvider.class.equals(providerClass)) { - final String hexadecimalKey = getKeyHex(); - provider = new AesGcmSensitivePropertyProvider(hexadecimalKey); - } else if (AwsKmsSensitivePropertyProvider.class.equals(providerClass)) { - final AwsKmsClientProvider clientProvider = new AwsKmsClientProvider(); - final Properties clientProperties = getClientProperties(clientProvider); - final Optional kmsClient = clientProvider.getClient(clientProperties); - provider = new AwsKmsSensitivePropertyProvider(kmsClient.orElse(null), clientProperties); - } else if (AwsSecretsManagerSensitivePropertyProvider.class.equals(providerClass)) { - final AwsSecretsManagerClientProvider clientProvider = new AwsSecretsManagerClientProvider(); - final Properties clientProperties = getClientProperties(clientProvider); - final Optional secretsManagerClient = clientProvider.getClient(clientProperties); - provider = new AwsSecretsManagerSensitivePropertyProvider(secretsManagerClient.orElse(null)); - } else if (AzureKeyVaultKeySensitivePropertyProvider.class.equals(providerClass)) { - final AzureCryptographyClientProvider clientProvider = new AzureCryptographyClientProvider(); - final Properties clientProperties = getClientProperties(clientProvider); - final Optional cryptographyClient = clientProvider.getClient(clientProperties); - provider = new AzureKeyVaultKeySensitivePropertyProvider(cryptographyClient.orElse(null), clientProperties); - } else if (AzureKeyVaultSecretSensitivePropertyProvider.class.equals(providerClass)) { - final AzureSecretClientProvider clientProvider = new AzureSecretClientProvider(); - final Properties clientProperties = getClientProperties(clientProvider); - final Optional secretClient = clientProvider.getClient(clientProperties); - provider = new AzureKeyVaultSecretSensitivePropertyProvider(secretClient.orElse(null)); - } else if (GcpKmsSensitivePropertyProvider.class.equals(providerClass)) { - final GoogleKeyManagementServiceClientProvider clientProvider = new GoogleKeyManagementServiceClientProvider(); - final Properties clientProperties = getClientProperties(clientProvider); - final Optional keyManagementServiceClient = clientProvider.getClient(clientProperties); - provider = new GcpKmsSensitivePropertyProvider(keyManagementServiceClient.orElse(null), clientProperties); - } else if (HashiCorpVaultKeyValueSensitivePropertyProvider.class.equals(providerClass)) { - provider = new HashiCorpVaultKeyValueSensitivePropertyProvider(getBootstrapProperties()); - } else if (HashiCorpVaultTransitSensitivePropertyProvider.class.equals(providerClass)) { - provider = new HashiCorpVaultTransitSensitivePropertyProvider(getBootstrapProperties()); - } - } - - if (provider == null) { - throw new UnsupportedOperationException(String.format("Provider class not supported [%s]", providerClass)); - } - - providers.put(providerClass, provider); - return provider; - } -} diff --git a/nifi-commons/nifi-property-protection-factory/src/main/java/org/apache/nifi/properties/scheme/PropertyProtectionScheme.java b/nifi-commons/nifi-property-protection-factory/src/main/java/org/apache/nifi/properties/scheme/PropertyProtectionScheme.java deleted file mode 100644 index 51764e1ac596..000000000000 --- a/nifi-commons/nifi-property-protection-factory/src/main/java/org/apache/nifi/properties/scheme/PropertyProtectionScheme.java +++ /dev/null @@ -1,49 +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.properties.scheme; - -/** - * Property Protection Schemes supported as arguments for encryption commands should not have direct references - */ -enum PropertyProtectionScheme implements ProtectionScheme { - AES_GCM("aes/gcm"), - - AWS_SECRETSMANAGER("aws/secretsmanager"), - - AWS_KMS("aws/kms"), - - AZURE_KEYVAULT_KEY("azure/keyvault/key"), - - AZURE_KEYVAULT_SECRET("azure/keyvault/secret"), - - GCP_KMS("gcp/kms"), - - HASHICORP_VAULT_KV("hashicorp/vault/kv"), - - HASHICORP_VAULT_TRANSIT("hashicorp/vault/transit"); - - PropertyProtectionScheme(final String path) { - this.path = path; - } - - private final String path; - - @Override - public String getPath() { - return path; - } -} diff --git a/nifi-commons/nifi-property-protection-factory/src/main/java/org/apache/nifi/properties/scheme/StandardProtectionSchemeResolver.java b/nifi-commons/nifi-property-protection-factory/src/main/java/org/apache/nifi/properties/scheme/StandardProtectionSchemeResolver.java deleted file mode 100644 index 44557963e435..000000000000 --- a/nifi-commons/nifi-property-protection-factory/src/main/java/org/apache/nifi/properties/scheme/StandardProtectionSchemeResolver.java +++ /dev/null @@ -1,52 +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.properties.scheme; - -import org.apache.nifi.properties.SensitivePropertyProtectionException; - -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; - -/** - * Standard implementation of Protection Scheme Resolver using Property Protection Scheme enumeration - */ -public class StandardProtectionSchemeResolver implements ProtectionSchemeResolver { - /** - * Get Protection Scheme based on scheme matching one the supported Protection Property Scheme enumerated values - * - * @param scheme Scheme name required - * @return Protection Scheme - */ - @Override - public ProtectionScheme getProtectionScheme(final String scheme) { - Objects.requireNonNull(scheme, "Scheme required"); - return Arrays.stream(PropertyProtectionScheme.values()) - .filter(propertyProtectionScheme -> - propertyProtectionScheme.name().equals(scheme) || scheme.startsWith(propertyProtectionScheme.getPath()) - ) - .findFirst() - .orElseThrow(() -> new SensitivePropertyProtectionException(String.format("Protection Scheme [%s] not supported", scheme))); - } - - public List getSupportedProtectionSchemes() { - return Arrays.stream(PropertyProtectionScheme.values()) - .map(PropertyProtectionScheme::name) - .collect(Collectors.toList()); - } -} diff --git a/nifi-commons/nifi-property-protection-factory/src/main/resources/META-INF/services/org.apache.nifi.properties.SensitivePropertyProviderFactory b/nifi-commons/nifi-property-protection-factory/src/main/resources/META-INF/services/org.apache.nifi.properties.SensitivePropertyProviderFactory deleted file mode 100644 index f318d70c1596..000000000000 --- a/nifi-commons/nifi-property-protection-factory/src/main/resources/META-INF/services/org.apache.nifi.properties.SensitivePropertyProviderFactory +++ /dev/null @@ -1,15 +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. -org.apache.nifi.properties.StandardSensitivePropertyProviderFactory diff --git a/nifi-commons/nifi-property-protection-factory/src/main/resources/META-INF/services/org.apache.nifi.properties.scheme.ProtectionSchemeResolver b/nifi-commons/nifi-property-protection-factory/src/main/resources/META-INF/services/org.apache.nifi.properties.scheme.ProtectionSchemeResolver deleted file mode 100644 index 28d1fcc31c1c..000000000000 --- a/nifi-commons/nifi-property-protection-factory/src/main/resources/META-INF/services/org.apache.nifi.properties.scheme.ProtectionSchemeResolver +++ /dev/null @@ -1,15 +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. -org.apache.nifi.properties.scheme.StandardProtectionSchemeResolver diff --git a/nifi-commons/nifi-property-protection-factory/src/test/java/org/apache/nifi/properties/StandardSensitivePropertyProviderFactoryTest.java b/nifi-commons/nifi-property-protection-factory/src/test/java/org/apache/nifi/properties/StandardSensitivePropertyProviderFactoryTest.java deleted file mode 100644 index a17cd432bd06..000000000000 --- a/nifi-commons/nifi-property-protection-factory/src/test/java/org/apache/nifi/properties/StandardSensitivePropertyProviderFactoryTest.java +++ /dev/null @@ -1,206 +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.properties; - -import org.apache.commons.io.FilenameUtils; -import org.apache.nifi.properties.scheme.ProtectionScheme; -import org.apache.nifi.properties.scheme.StandardProtectionScheme; -import org.apache.nifi.util.NiFiProperties; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import java.util.Collection; -import java.util.Properties; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class StandardSensitivePropertyProviderFactoryTest { - - private SensitivePropertyProviderFactory factory; - - private static final String BOOTSTRAP_KEY_HEX = "0123456789ABCDEFFEDCBA9876543210"; - - private static final ProtectionScheme AES_GCM = new StandardProtectionScheme("aes/gcm"); - private static final ProtectionScheme AES_GCM_128 = new StandardProtectionScheme("aes/gcm/128"); - private static final ProtectionScheme HASHICORP_VAULT_TRANSIT = new StandardProtectionScheme("hashicorp/vault/transit/testing"); - private static final ProtectionScheme HASHICORP_VAULT_KV = new StandardProtectionScheme("hashicorp/vault/kv/testing"); - - private static Path tempConfDir; - private static Path bootstrapConf; - private static Path hashicorpVaultBootstrapConf; - private static Path nifiProperties; - private static Path azureKeyVaultConf; - private static String defaultBootstrapContents; - - @BeforeAll - public static void initOnce() throws IOException { - tempConfDir = Files.createTempDirectory("conf"); - bootstrapConf = Files.createTempFile("bootstrap", ".conf").toAbsolutePath(); - azureKeyVaultConf = Files.createTempFile("bootstrap-azure-keyvault", ".conf").toAbsolutePath(); - hashicorpVaultBootstrapConf = Files.createTempFile("bootstrap-hashicorp-vault", ".conf").toAbsolutePath(); - - nifiProperties = Files.createTempFile("nifi", ".properties").toAbsolutePath(); - - nifiProperties = Files.move(nifiProperties, tempConfDir.resolve("nifi.properties")); - - defaultBootstrapContents = String.format("%s=%s\n%s=%s\n%s=%s", - "nifi.bootstrap.sensitive.key", BOOTSTRAP_KEY_HEX, - "nifi.bootstrap.protection.azure.keyvault.conf", FilenameUtils.separatorsToUnix(azureKeyVaultConf.toString()), - "nifi.bootstrap.protection.hashicorp.vault.conf", FilenameUtils.separatorsToUnix(hashicorpVaultBootstrapConf.toString())); - bootstrapConf = writeDefaultBootstrapConf(); - System.setProperty(NiFiProperties.PROPERTIES_FILE_PATH, FilenameUtils.separatorsToUnix(nifiProperties.toString())); - } - - @AfterAll - public static void tearDownOnce() throws IOException { - Files.deleteIfExists(bootstrapConf); - Files.deleteIfExists(azureKeyVaultConf); - Files.deleteIfExists(hashicorpVaultBootstrapConf); - Files.deleteIfExists(nifiProperties); - Files.deleteIfExists(tempConfDir); - System.clearProperty(NiFiProperties.PROPERTIES_FILE_PATH); - } - - @BeforeEach - public void setFactory() { - factory = StandardSensitivePropertyProviderFactory.withDefaults(); - } - - @Test - public void testGetPropertyContextNotConfigured() { - assertEquals("default/prop", factory.getPropertyContext("ldap-provider", "prop").getContextKey()); - } - - @Test - public void testGetPropertyContext() throws IOException { - writeBootstrapConf(defaultBootstrapContents + "\n" + - "nifi.bootstrap.protection.context.mapping.ldap=ldap-.*"); - try { - assertEquals("ldap/prop", factory.getPropertyContext("ldap-provider", "prop").getContextKey()); - assertEquals("ldap/prop", factory.getPropertyContext("ldap-user-group-provider", "prop").getContextKey()); - } finally { - writeDefaultBootstrapConf(); - } - } - - @Test - public void testGetSupportedProviders() { - final Collection providers = factory.getSupportedProviders(); - assertFalse(providers.isEmpty()); - - final boolean aesProviderFound = providers.stream() - .anyMatch(provider -> provider instanceof AesGcmSensitivePropertyProvider); - assertTrue(aesProviderFound); - } - - @Test - public void testAzureKeyVaultSecret() throws IOException { - final Properties properties = new Properties(); - properties.put("azure.keyvault.uri", "https://testing.vault.azure.net"); - configureAzureKeyVault(properties); - - final SensitivePropertyProvider provider = factory.getProvider(new StandardProtectionScheme("azure/keyvault/secret")); - assertTrue(provider.isSupported()); - assertEquals(AzureKeyVaultSecretSensitivePropertyProvider.class, provider.getClass()); - } - - @Test - public void testHashiCorpVaultKeyVaultSupported() throws IOException { - final Properties properties = new Properties(); - properties.put("vault.kv.path", "testing"); - properties.put("vault.uri", "http://localhost:8200"); - properties.put("vault.token", "test-token"); - configureHashicorpVault(properties); - - final SensitivePropertyProvider provider = factory.getProvider(HASHICORP_VAULT_KV); - assertTrue(provider.isSupported()); - assertEquals(HashiCorpVaultKeyValueSensitivePropertyProvider.class, provider.getClass()); - } - - @Test - public void testHashiCorpVaultTransitSupported() throws IOException { - final Properties properties = new Properties(); - properties.put("vault.transit.path", "testing"); - properties.put("vault.uri", "http://localhost:8200"); - properties.put("vault.token", "test-token"); - configureHashicorpVault(properties); - - final SensitivePropertyProvider provider = factory.getProvider(HASHICORP_VAULT_TRANSIT); - assertTrue(provider.isSupported()); - assertEquals(HashiCorpVaultTransitSensitivePropertyProvider.class, provider.getClass()); - } - - @Test - public void testHashiCorpVaultTransitExceptionWhenMissingProperties() throws IOException { - final Properties properties = new Properties(); - properties.put("vault.uri", "http://localhost:8200"); - configureHashicorpVault(properties); - - assertThrows(SensitivePropertyProtectionException.class, () -> factory.getProvider(HASHICORP_VAULT_TRANSIT)); - } - - @Test - public void testAesGcmWithoutKeySizeSupported() { - final SensitivePropertyProvider provider = factory.getProvider(AES_GCM); - assertEquals(AesGcmSensitivePropertyProvider.class, provider.getClass()); - assertTrue(provider.isSupported()); - } - - @Test - public void testAesGcm128Supported() { - final SensitivePropertyProvider provider = factory.getProvider(AES_GCM_128); - assertEquals(AesGcmSensitivePropertyProvider.class, provider.getClass()); - assertTrue(provider.isSupported()); - } - - - private static Path writeDefaultBootstrapConf() throws IOException { - return writeBootstrapConf(defaultBootstrapContents); - } - - private static Path writeBootstrapConf(final String contents) throws IOException { - final Path tempBootstrapConf = Files.createTempFile("bootstrap", ".conf").toAbsolutePath(); - final Path bootstrapConf = Files.move(tempBootstrapConf, tempConfDir.resolve("bootstrap.conf"), StandardCopyOption.REPLACE_EXISTING); - - Files.write(bootstrapConf, contents.getBytes(StandardCharsets.UTF_8)); - return bootstrapConf; - } - - private void configureHashicorpVault(final Properties properties) throws IOException { - try (OutputStream out = new FileOutputStream(hashicorpVaultBootstrapConf.toFile())) { - properties.store(out, hashicorpVaultBootstrapConf.toString()); - } - } - - private void configureAzureKeyVault(final Properties properties) throws IOException { - try (OutputStream out = new FileOutputStream(azureKeyVaultConf.toFile())) { - properties.store(out, azureKeyVaultConf.toString()); - } - } -} diff --git a/nifi-commons/nifi-property-protection-factory/src/test/java/org/apache/nifi/properties/scheme/StandardProtectionSchemeResolverTest.java b/nifi-commons/nifi-property-protection-factory/src/test/java/org/apache/nifi/properties/scheme/StandardProtectionSchemeResolverTest.java deleted file mode 100644 index c8893b2231ee..000000000000 --- a/nifi-commons/nifi-property-protection-factory/src/test/java/org/apache/nifi/properties/scheme/StandardProtectionSchemeResolverTest.java +++ /dev/null @@ -1,63 +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.properties.scheme; - -import org.apache.nifi.properties.SensitivePropertyProtectionException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class StandardProtectionSchemeResolverTest { - private static final String AES_GCM = "AES_GCM"; - - private static final String AES_GCM_PATH = "aes/gcm"; - - private static final String AES_GCM_256_PATH = "aes/gcm/256"; - - private static final String UNKNOWN = "UNKNOWN"; - - private StandardProtectionSchemeResolver resolver; - - @BeforeEach - public void setResolver() { - resolver = new StandardProtectionSchemeResolver(); - } - - @Test - public void getProtectionSchemeAesGcmFound() { - final ProtectionScheme protectionScheme = resolver.getProtectionScheme(AES_GCM); - assertNotNull(protectionScheme); - assertEquals(AES_GCM_PATH, protectionScheme.getPath()); - } - - @Test - public void getProtectionSchemeAesGcm256Found() { - final ProtectionScheme protectionScheme = resolver.getProtectionScheme(AES_GCM_256_PATH); - assertNotNull(protectionScheme); - assertEquals(AES_GCM_PATH, protectionScheme.getPath()); - } - - @Test - public void getProtectionSchemeUnknownNotFound() { - final SensitivePropertyProtectionException exception = assertThrows(SensitivePropertyProtectionException.class, () -> resolver.getProtectionScheme(UNKNOWN)); - assertTrue(exception.getMessage().contains(UNKNOWN)); - } -} diff --git a/nifi-commons/nifi-property-protection-gcp/pom.xml b/nifi-commons/nifi-property-protection-gcp/pom.xml deleted file mode 100644 index fd9d73190345..000000000000 --- a/nifi-commons/nifi-property-protection-gcp/pom.xml +++ /dev/null @@ -1,92 +0,0 @@ - - - - 4.0.0 - - org.apache.nifi - nifi-commons - 2.0.0-SNAPSHOT - - nifi-property-protection-gcp - - - - com.google.cloud - libraries-bom - ${gcp.sdk.version} - pom - import - - - - - - org.slf4j - slf4j-api - - - org.apache.nifi - nifi-property-protection-api - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-utils - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-shared - 2.0.0-SNAPSHOT - - - org.apache.commons - commons-lang3 - - - com.google.api - api-common - - - com.google.api - gax - - - com.google.protobuf - protobuf-java - - - com.google.api.grpc - proto-google-cloud-kms-v1 - - - - com.google.guava - guava - ${guava.version} - - - com.google.cloud - google-cloud-kms - - - commons-logging - commons-logging - - - - - diff --git a/nifi-commons/nifi-property-protection-gcp/src/main/java/org/apache/nifi/properties/GcpKmsSensitivePropertyProvider.java b/nifi-commons/nifi-property-protection-gcp/src/main/java/org/apache/nifi/properties/GcpKmsSensitivePropertyProvider.java deleted file mode 100644 index af76dc848135..000000000000 --- a/nifi-commons/nifi-property-protection-gcp/src/main/java/org/apache/nifi/properties/GcpKmsSensitivePropertyProvider.java +++ /dev/null @@ -1,122 +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.properties; - -import com.google.api.gax.rpc.ApiException; -import com.google.cloud.kms.v1.CryptoKey; -import com.google.cloud.kms.v1.CryptoKeyName; -import com.google.cloud.kms.v1.CryptoKeyVersion; -import com.google.cloud.kms.v1.DecryptResponse; -import com.google.cloud.kms.v1.EncryptResponse; -import com.google.cloud.kms.v1.KeyManagementServiceClient; -import com.google.protobuf.ByteString; -import org.apache.commons.lang3.StringUtils; - -import java.util.Properties; - -/** - * Google Cloud Platform Key Management Service Sensitive Property Provider - */ -public class GcpKmsSensitivePropertyProvider extends ClientBasedEncodedSensitivePropertyProvider { - protected static final String PROJECT_PROPERTY = "gcp.kms.project"; - protected static final String LOCATION_PROPERTY = "gcp.kms.location"; - protected static final String KEYRING_PROPERTY = "gcp.kms.keyring"; - protected static final String KEY_PROPERTY = "gcp.kms.key"; - - private static final String SCHEME_BASE_PATH = "gcp/kms"; - - private CryptoKeyName cryptoKeyName; - - GcpKmsSensitivePropertyProvider(final KeyManagementServiceClient keyManagementServiceClient, final Properties properties) { - super(keyManagementServiceClient, properties); - } - - @Override - public String getIdentifierKey() { - return SCHEME_BASE_PATH; - } - - /** - * Close Client when configured - */ - @Override - public void cleanUp() { - final KeyManagementServiceClient keyManagementServiceClient = getClient(); - if (keyManagementServiceClient == null) { - logger.debug("GCP KMS Client not configured"); - } else { - keyManagementServiceClient.close(); - } - } - - /** - * Validate Client and Key Operations with Encryption Algorithm when configured - * - * @param keyManagementServiceClient Key Management Service Client - */ - @Override - protected void validate(final KeyManagementServiceClient keyManagementServiceClient) { - if (keyManagementServiceClient == null) { - logger.debug("GCP KMS Client not configured"); - } else { - final String project = getProperties().getProperty(PROJECT_PROPERTY); - final String location = getProperties().getProperty(LOCATION_PROPERTY); - final String keyring = getProperties().getProperty(KEYRING_PROPERTY); - final String key = getProperties().getProperty(KEY_PROPERTY); - if (StringUtils.isNoneBlank(project, location, keyring, key)) { - cryptoKeyName = CryptoKeyName.of(project, location, keyring, key); - try { - final CryptoKey cryptoKey = keyManagementServiceClient.getCryptoKey(cryptoKeyName); - final CryptoKeyVersion cryptoKeyVersion = cryptoKey.getPrimary(); - if (CryptoKeyVersion.CryptoKeyVersionState.ENABLED == cryptoKeyVersion.getState()) { - logger.info("GCP KMS Crypto Key [{}] Validated", cryptoKeyName); - } else { - throw new SensitivePropertyProtectionException(String.format("GCP KMS Crypto Key [%s] Disabled", cryptoKeyName)); - } - } catch (final ApiException e) { - throw new SensitivePropertyProtectionException(String.format("GCP KMS Crypto Key [%s] Validation Failed", cryptoKeyName), e); - } - } else { - throw new SensitivePropertyProtectionException("GCP KMS Missing Required Properties"); - } - } - } - - /** - * Get encrypted bytes - * - * @param bytes Unprotected bytes - * @return Encrypted bytes - */ - @Override - protected byte[] getEncrypted(final byte[] bytes) { - final EncryptResponse encryptResponse = getClient().encrypt(cryptoKeyName, ByteString.copyFrom(bytes)); - return encryptResponse.getCiphertext().toByteArray(); - } - - /** - * Get decrypted bytes - * - * @param bytes Encrypted bytes - * @return Decrypted bytes - */ - @Override - protected byte[] getDecrypted(final byte[] bytes) { - final DecryptResponse decryptResponse = getClient().decrypt(cryptoKeyName, ByteString.copyFrom(bytes)); - return decryptResponse.getPlaintext().toByteArray(); - } -} diff --git a/nifi-commons/nifi-property-protection-gcp/src/main/java/org/apache/nifi/properties/configuration/GoogleKeyManagementServiceClientProvider.java b/nifi-commons/nifi-property-protection-gcp/src/main/java/org/apache/nifi/properties/configuration/GoogleKeyManagementServiceClientProvider.java deleted file mode 100644 index 2bb707d09d12..000000000000 --- a/nifi-commons/nifi-property-protection-gcp/src/main/java/org/apache/nifi/properties/configuration/GoogleKeyManagementServiceClientProvider.java +++ /dev/null @@ -1,56 +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.properties.configuration; - -import com.google.cloud.kms.v1.KeyManagementServiceClient; - -import org.apache.nifi.properties.BootstrapProperties; -import org.apache.nifi.properties.SensitivePropertyProtectionException; - -import java.io.IOException; -import java.util.Collections; -import java.util.Properties; -import java.util.Set; - -/** - * Google Key Management Service Client Provider - */ -public class GoogleKeyManagementServiceClientProvider extends BootstrapPropertiesClientProvider { - public GoogleKeyManagementServiceClientProvider() { - super(BootstrapProperties.BootstrapPropertyKey.GCP_KMS_SENSITIVE_PROPERTY_PROVIDER_CONF); - } - - /** - * Get Configured Client using default Key Management Service Client settings - * - * @param clientProperties Client Properties - * @return Key Management Service Client - */ - @Override - protected KeyManagementServiceClient getConfiguredClient(final Properties clientProperties) { - try { - return KeyManagementServiceClient.create(); - } catch (final IOException e) { - throw new SensitivePropertyProtectionException("Google Key Management Service Create Failed", e); - } - } - - @Override - protected Set getRequiredPropertyNames() { - return Collections.emptySet(); - } -} diff --git a/nifi-commons/nifi-property-protection-hashicorp/pom.xml b/nifi-commons/nifi-property-protection-hashicorp/pom.xml deleted file mode 100644 index d4f2198c6383..000000000000 --- a/nifi-commons/nifi-property-protection-hashicorp/pom.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - 4.0.0 - - org.apache.nifi - nifi-commons - 2.0.0-SNAPSHOT - - nifi-property-protection-hashicorp - - - org.apache.nifi - nifi-property-protection-api - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-utils - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-hashicorp-vault-api - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-hashicorp-vault - 2.0.0-SNAPSHOT - - - org.springframework - spring-core - - - diff --git a/nifi-commons/nifi-property-protection-hashicorp/src/main/java/org/apache/nifi/properties/AbstractHashiCorpVaultSensitivePropertyProvider.java b/nifi-commons/nifi-property-protection-hashicorp/src/main/java/org/apache/nifi/properties/AbstractHashiCorpVaultSensitivePropertyProvider.java deleted file mode 100644 index 6ccb457ee1a0..000000000000 --- a/nifi-commons/nifi-property-protection-hashicorp/src/main/java/org/apache/nifi/properties/AbstractHashiCorpVaultSensitivePropertyProvider.java +++ /dev/null @@ -1,124 +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.properties; - -import org.apache.nifi.properties.BootstrapProperties.BootstrapPropertyKey; -import org.apache.nifi.vault.hashicorp.HashiCorpVaultCommunicationService; -import org.apache.nifi.vault.hashicorp.StandardHashiCorpVaultCommunicationService; -import org.apache.nifi.vault.hashicorp.config.HashiCorpVaultConfiguration; -import org.apache.nifi.vault.hashicorp.config.HashiCorpVaultConfiguration.VaultConfigurationKey; -import org.springframework.core.env.PropertySource; - -import java.io.IOException; -import java.nio.file.Paths; - -public abstract class AbstractHashiCorpVaultSensitivePropertyProvider implements SensitivePropertyProvider { - private static final String VAULT_PREFIX = "vault"; - - private final String path; - private final HashiCorpVaultCommunicationService vaultCommunicationService; - private final BootstrapProperties vaultBootstrapProperties; - - AbstractHashiCorpVaultSensitivePropertyProvider(final BootstrapProperties bootstrapProperties) { - final String vaultBootstrapConfFilename = bootstrapProperties - .getProperty(BootstrapPropertyKey.HASHICORP_VAULT_SENSITIVE_PROPERTY_PROVIDER_CONF).orElse(null); - vaultBootstrapProperties = getVaultBootstrapProperties(vaultBootstrapConfFilename); - path = getSecretsEnginePath(vaultBootstrapProperties); - if (hasRequiredVaultProperties()) { - try { - vaultCommunicationService = new StandardHashiCorpVaultCommunicationService(getVaultPropertySource(vaultBootstrapConfFilename)); - } catch (final IOException e) { - throw new SensitivePropertyProtectionException("Error configuring HashiCorpVaultCommunicationService", e); - } - } else { - vaultCommunicationService = null; - } - } - - /** - * Return the configured Secrets Engine path for this sensitive property provider. - * @param vaultBootstrapProperties The Properties from the file located at bootstrap.protection.hashicorp.vault.conf - * @return The Secrets Engine path - */ - protected abstract String getSecretsEnginePath(final BootstrapProperties vaultBootstrapProperties); - - private static BootstrapProperties getVaultBootstrapProperties(final String vaultBootstrapConfFilename) { - final BootstrapProperties vaultBootstrapProperties; - if (vaultBootstrapConfFilename != null) { - try { - vaultBootstrapProperties = AbstractBootstrapPropertiesLoader.loadBootstrapProperties( - Paths.get(vaultBootstrapConfFilename), VAULT_PREFIX); - } catch (final IOException e) { - throw new SensitivePropertyProtectionException("Could not load " + vaultBootstrapConfFilename, e); - } - } else { - vaultBootstrapProperties = null; - } - return vaultBootstrapProperties; - } - - private PropertySource getVaultPropertySource(final String vaultBootstrapConfFilename) throws IOException { - return HashiCorpVaultConfiguration.createPropertiesFileSource(vaultBootstrapConfFilename); - } - - /** - * Returns the Secrets Engine path. - * @return The Secrets Engine path - */ - protected String getPath() { - return path; - } - - protected HashiCorpVaultCommunicationService getVaultCommunicationService() { - if (vaultCommunicationService == null) { - throw new SensitivePropertyProtectionException("Vault Protection Scheme missing required properties"); - } - return vaultCommunicationService; - } - - @Override - public boolean isSupported() { - return hasRequiredVaultProperties(); - } - - private boolean hasRequiredVaultProperties() { - return vaultBootstrapProperties != null - && (vaultBootstrapProperties.getProperty(VaultConfigurationKey.URI.getKey()) != null) - && hasRequiredSecretsEngineProperties(vaultBootstrapProperties); - } - - /** - * Return true if the relevant Secrets Engine-specific properties are configured. - * @param vaultBootstrapProperties The Vault-specific bootstrap properties - * @return true if the relevant Secrets Engine-specific properties are configured - */ - protected boolean hasRequiredSecretsEngineProperties(final BootstrapProperties vaultBootstrapProperties) { - return getSecretsEnginePath(vaultBootstrapProperties) != null; - } - - /** - * No cleanup necessary - */ - @Override - public void cleanUp() { } - - protected void requireNotBlank(final String value) { - if (value == null || value.isEmpty()) { - throw new IllegalArgumentException("Property value is null or empty"); - } - } -} diff --git a/nifi-commons/nifi-property-protection-hashicorp/src/main/java/org/apache/nifi/properties/HashiCorpVaultKeyValueSensitivePropertyProvider.java b/nifi-commons/nifi-property-protection-hashicorp/src/main/java/org/apache/nifi/properties/HashiCorpVaultKeyValueSensitivePropertyProvider.java deleted file mode 100644 index f846490e3eaf..000000000000 --- a/nifi-commons/nifi-property-protection-hashicorp/src/main/java/org/apache/nifi/properties/HashiCorpVaultKeyValueSensitivePropertyProvider.java +++ /dev/null @@ -1,80 +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.properties; - -import java.util.Objects; - -/** - * Uses the HashiCorp Vault Key/Value version 1 Secrets Engine to store sensitive values. - */ -public class HashiCorpVaultKeyValueSensitivePropertyProvider extends AbstractHashiCorpVaultSensitivePropertyProvider { - - private static final String KEY_VALUE_PATH = "vault.kv.path"; - - private static final String IDENTIFIER_KEY_FORMAT = "hashicorp/vault/kv/%s"; - - HashiCorpVaultKeyValueSensitivePropertyProvider(final BootstrapProperties bootstrapProperties) { - super(bootstrapProperties); - } - - @Override - protected String getSecretsEnginePath(final BootstrapProperties vaultBootstrapProperties) { - if (vaultBootstrapProperties == null) { - return null; - } - return vaultBootstrapProperties.getProperty(KEY_VALUE_PATH); - } - - @Override - public String getIdentifierKey() { - return String.format(IDENTIFIER_KEY_FORMAT, getPath()); - } - - /** - * Stores the sensitive value in Vault and returns a description of the secret. - * - * @param unprotectedValue the sensitive value - * @param context The property context, unused in this provider - * @return the value to persist in the {@code nifi.properties} file - * @throws SensitivePropertyProtectionException if there is an exception writing the secret - */ - @Override - public String protect(final String unprotectedValue, final ProtectedPropertyContext context) throws SensitivePropertyProtectionException { - requireNotBlank(unprotectedValue); - Objects.requireNonNull(context, "Context is required to protect a value"); - - getVaultCommunicationService().writeKeyValueSecret(getPath(), context.getContextKey(), unprotectedValue); - return String.format("%s/%s", getPath(), context.getContextKey()); - } - - /** - * Returns the secret value, as read from Vault. - * - * @param protectedValue The value read from {@code nifi.properties} file. Ignored in this provider. - * @param context The property context, from which the Vault secret name is pulled - * @return the raw value to be used by the application - * @throws SensitivePropertyProtectionException if there is an error retrieving the secret - */ - @Override - public String unprotect(final String protectedValue, final ProtectedPropertyContext context) throws SensitivePropertyProtectionException { - Objects.requireNonNull(context, "Context is required to unprotect a value"); - - return getVaultCommunicationService().readKeyValueSecret(getPath(), context.getContextKey()) - .orElseThrow(() -> new SensitivePropertyProtectionException(String - .format("Secret [%s] not found in Vault Key/Value engine at [%s]", context.getContextKey(), getPath()))); - } -} diff --git a/nifi-commons/nifi-property-protection-hashicorp/src/main/java/org/apache/nifi/properties/HashiCorpVaultTransitSensitivePropertyProvider.java b/nifi-commons/nifi-property-protection-hashicorp/src/main/java/org/apache/nifi/properties/HashiCorpVaultTransitSensitivePropertyProvider.java deleted file mode 100644 index 9b8cc4b98fea..000000000000 --- a/nifi-commons/nifi-property-protection-hashicorp/src/main/java/org/apache/nifi/properties/HashiCorpVaultTransitSensitivePropertyProvider.java +++ /dev/null @@ -1,75 +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.properties; - -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; - -/** - * Uses the HashiCorp Vault Transit Secrets Engine to encrypt sensitive values at rest. - */ -public class HashiCorpVaultTransitSensitivePropertyProvider extends AbstractHashiCorpVaultSensitivePropertyProvider { - private static final Charset PROPERTY_CHARSET = StandardCharsets.UTF_8; - private static final String TRANSIT_PATH = "vault.transit.path"; - - private static final String IDENTIFIER_KEY_FORMAT = "hashicorp/vault/transit/%s"; - - HashiCorpVaultTransitSensitivePropertyProvider(final BootstrapProperties bootstrapProperties) { - super(bootstrapProperties); - } - - @Override - protected String getSecretsEnginePath(final BootstrapProperties vaultBootstrapProperties) { - if (vaultBootstrapProperties == null) { - return null; - } - return vaultBootstrapProperties.getProperty(TRANSIT_PATH); - } - - @Override - public String getIdentifierKey() { - return String.format(IDENTIFIER_KEY_FORMAT, getPath()); - } - - /** - * Returns the encrypted cipher text. - * - * @param unprotectedValue the sensitive value - * @param context The property context, unused in this provider - * @return the value to persist in the {@code nifi.properties} file - * @throws SensitivePropertyProtectionException if there is an exception encrypting the value - */ - @Override - public String protect(final String unprotectedValue, final ProtectedPropertyContext context) throws SensitivePropertyProtectionException { - requireNotBlank(unprotectedValue); - return getVaultCommunicationService().encrypt(getPath(), unprotectedValue.getBytes(PROPERTY_CHARSET)); - } - - /** - * Returns the decrypted plaintext. - * - * @param protectedValue the cipher text read from the {@code nifi.properties} file - * @param context The property context, unused in this provider - * @return the raw value to be used by the application - * @throws SensitivePropertyProtectionException if there is an error decrypting the cipher text - */ - @Override - public String unprotect(final String protectedValue, final ProtectedPropertyContext context) throws SensitivePropertyProtectionException { - requireNotBlank(protectedValue); - return new String(getVaultCommunicationService().decrypt(getPath(), protectedValue), PROPERTY_CHARSET); - } -} diff --git a/nifi-commons/nifi-property-protection-hashicorp/src/test/java/org/apache/nifi/properties/HashiCorpVaultKeyValueSensitivePropertyProviderTest.java b/nifi-commons/nifi-property-protection-hashicorp/src/test/java/org/apache/nifi/properties/HashiCorpVaultKeyValueSensitivePropertyProviderTest.java deleted file mode 100644 index d421de8d7bc0..000000000000 --- a/nifi-commons/nifi-property-protection-hashicorp/src/test/java/org/apache/nifi/properties/HashiCorpVaultKeyValueSensitivePropertyProviderTest.java +++ /dev/null @@ -1,55 +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.properties; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.util.Optional; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.mockito.Mockito.when; -import static org.mockito.ArgumentMatchers.eq; - -@ExtendWith(MockitoExtension.class) -public class HashiCorpVaultKeyValueSensitivePropertyProviderTest { - private static final String IDENTIFIER_KEY = "hashicorp/vault/kv/null"; - - @Mock - private BootstrapProperties bootstrapProperties; - - @Test - public void testGetIdentifierKeyPropertiesNotFound() { - when(bootstrapProperties.getProperty(eq(BootstrapProperties.BootstrapPropertyKey.HASHICORP_VAULT_SENSITIVE_PROPERTY_PROVIDER_CONF))).thenReturn(Optional.empty()); - final HashiCorpVaultKeyValueSensitivePropertyProvider provider = new HashiCorpVaultKeyValueSensitivePropertyProvider(bootstrapProperties); - - final String identifierKey = provider.getIdentifierKey(); - - assertEquals(IDENTIFIER_KEY, identifierKey); - } - - @Test - public void testIsSupportedPropertiesNotFound() { - when(bootstrapProperties.getProperty(eq(BootstrapProperties.BootstrapPropertyKey.HASHICORP_VAULT_SENSITIVE_PROPERTY_PROVIDER_CONF))).thenReturn(Optional.empty()); - final HashiCorpVaultKeyValueSensitivePropertyProvider provider = new HashiCorpVaultKeyValueSensitivePropertyProvider(bootstrapProperties); - - assertFalse(provider.isSupported()); - } -} diff --git a/nifi-commons/nifi-property-protection-hashicorp/src/test/java/org/apache/nifi/properties/HashiCorpVaultTransitSensitivePropertyProviderTest.java b/nifi-commons/nifi-property-protection-hashicorp/src/test/java/org/apache/nifi/properties/HashiCorpVaultTransitSensitivePropertyProviderTest.java deleted file mode 100644 index c4460462566a..000000000000 --- a/nifi-commons/nifi-property-protection-hashicorp/src/test/java/org/apache/nifi/properties/HashiCorpVaultTransitSensitivePropertyProviderTest.java +++ /dev/null @@ -1,55 +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.properties; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.util.Optional; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.when; - -@ExtendWith(MockitoExtension.class) -public class HashiCorpVaultTransitSensitivePropertyProviderTest { - private static final String IDENTIFIER_KEY = "hashicorp/vault/transit/null"; - - @Mock - private BootstrapProperties bootstrapProperties; - - @Test - public void testGetIdentifierKeyPropertiesNotFound() { - when(bootstrapProperties.getProperty(eq(BootstrapProperties.BootstrapPropertyKey.HASHICORP_VAULT_SENSITIVE_PROPERTY_PROVIDER_CONF))).thenReturn(Optional.empty()); - final HashiCorpVaultTransitSensitivePropertyProvider provider = new HashiCorpVaultTransitSensitivePropertyProvider(bootstrapProperties); - - final String identifierKey = provider.getIdentifierKey(); - - assertEquals(IDENTIFIER_KEY, identifierKey); - } - - @Test - public void testIsSupportedPropertiesNotFound() { - when(bootstrapProperties.getProperty(eq(BootstrapProperties.BootstrapPropertyKey.HASHICORP_VAULT_SENSITIVE_PROPERTY_PROVIDER_CONF))).thenReturn(Optional.empty()); - final HashiCorpVaultTransitSensitivePropertyProvider provider = new HashiCorpVaultTransitSensitivePropertyProvider(bootstrapProperties); - - assertFalse(provider.isSupported()); - } -} diff --git a/nifi-commons/nifi-property-protection-loader/pom.xml b/nifi-commons/nifi-property-protection-loader/pom.xml deleted file mode 100644 index 8a9659178596..000000000000 --- a/nifi-commons/nifi-property-protection-loader/pom.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - 4.0.0 - - org.apache.nifi - nifi-commons - 2.0.0-SNAPSHOT - - nifi-property-protection-loader - - - org.slf4j - slf4j-api - - - org.apache.nifi - nifi-property-utils - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-api - 2.0.0-SNAPSHOT - - - diff --git a/nifi-commons/nifi-property-protection-loader/src/main/java/org/apache/nifi/properties/ApplicationPropertiesProtector.java b/nifi-commons/nifi-property-protection-loader/src/main/java/org/apache/nifi/properties/ApplicationPropertiesProtector.java deleted file mode 100644 index d485c2e978ee..000000000000 --- a/nifi-commons/nifi-property-protection-loader/src/main/java/org/apache/nifi/properties/ApplicationPropertiesProtector.java +++ /dev/null @@ -1,303 +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.properties; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Properties; -import java.util.Set; -import java.util.stream.Collectors; - -import static java.util.Arrays.asList; - -/** - * Class performing unprotection activities before returning a clean - * implementation of {@link ApplicationProperties}. - * This encapsulates the sensitive property access logic from external consumers - * of {@code ApplicationProperties}. - * - * @param The type of protected application properties - * @param The type of standard application properties that backs the protected application properties - */ -public class ApplicationPropertiesProtector, U extends ApplicationProperties> - implements SensitivePropertyProtector { - public static final String PROTECTED_KEY_SUFFIX = ".protected"; - - private static final Logger logger = LoggerFactory.getLogger(ApplicationPropertiesProtector.class); - - private final T protectedProperties; - - private final Map localProviderCache = new HashMap<>(); - - /** - * Creates an instance containing the provided {@link ProtectedProperties}. - * - * @param protectedProperties the ProtectedProperties to contain - */ - public ApplicationPropertiesProtector(final T protectedProperties) { - this.protectedProperties = protectedProperties; - logger.debug("Loaded {} properties (including {} protection schemes) into {}", getPropertyKeysIncludingProtectionSchemes().size(), - getProtectedPropertyKeys().size(), this.getClass().getName()); - } - - /** - * Returns the sibling property key which specifies the protection scheme for this key. - *

- * Example: - *

- * nifi.sensitive.key=ABCXYZ - * nifi.sensitive.key.protected=aes/gcm/256 - *

- * nifi.sensitive.key -> nifi.sensitive.key.protected - * - * @param key the key identifying the sensitive property - * @return the key identifying the protection scheme for the sensitive property - */ - public static String getProtectionKey(final String key) { - if (key == null || key.isEmpty()) { - throw new IllegalArgumentException("Cannot find protection key for null key"); - } - - return key + PROTECTED_KEY_SUFFIX; - } - - /** - * Retrieves all known property keys. - * - * @return all known property keys - */ - @Override - public Set getPropertyKeys() { - Set filteredKeys = getPropertyKeysIncludingProtectionSchemes(); - filteredKeys.removeIf(p -> p.endsWith(PROTECTED_KEY_SUFFIX)); - return filteredKeys; - } - - @Override - public int size() { - return getPropertyKeys().size(); - } - - @Override - public Set getPropertyKeysIncludingProtectionSchemes() { - return protectedProperties.getApplicationProperties().getPropertyKeys(); - } - - /** - * Splits a single string containing multiple property keys into a List. Delimited by ',' or ';' and ignores leading and trailing whitespace around delimiter. - * - * @param multipleProperties a single String containing multiple properties, i.e. "nifi.property.1; nifi.property.2, nifi.property.3" - * @return a List containing the split and trimmed properties - */ - private static List splitMultipleProperties(final String multipleProperties) { - if (multipleProperties == null || multipleProperties.trim().isEmpty()) { - return new ArrayList<>(0); - } else { - List properties = new ArrayList<>(asList(multipleProperties.split("\\s*[,;]\\s*"))); - for (int i = 0; i < properties.size(); i++) { - properties.set(i, properties.get(i).trim()); - } - return properties; - } - } - - private String getProperty(final String key) { - return protectedProperties.getApplicationProperties().getProperty(key); - } - - private String getAdditionalSensitivePropertiesKeys() { - return getProperty(protectedProperties.getAdditionalSensitivePropertiesKeysName()); - } - - private String getAdditionalSensitivePropertiesKeysName() { - return protectedProperties.getAdditionalSensitivePropertiesKeysName(); - } - - @Override - public List getSensitivePropertyKeys() { - final String additionalPropertiesString = getAdditionalSensitivePropertiesKeys(); - final String additionalPropertiesKeyName = protectedProperties.getAdditionalSensitivePropertiesKeysName(); - if (additionalPropertiesString == null || additionalPropertiesString.trim().isEmpty()) { - return protectedProperties.getDefaultSensitiveProperties(); - } else { - List additionalProperties = splitMultipleProperties(additionalPropertiesString); - /* Remove this key if it was accidentally provided as a sensitive key - * because we cannot protect it and read from it - */ - if (additionalProperties.contains(additionalPropertiesKeyName)) { - logger.warn("The key '{}' contains itself. This is poor practice and should be removed", additionalPropertiesKeyName); - additionalProperties.remove(additionalPropertiesKeyName); - } - additionalProperties.addAll(protectedProperties.getDefaultSensitiveProperties()); - return additionalProperties; - } - } - - @Override - public List getPopulatedSensitivePropertyKeys() { - List allSensitiveKeys = getSensitivePropertyKeys(); - return allSensitiveKeys.stream().filter(k -> isNotBlank(getProperty(k))).collect(Collectors.toList()); - } - - @Override - public boolean hasProtectedKeys() { - final List sensitiveKeys = getSensitivePropertyKeys(); - for (String k : sensitiveKeys) { - if (isPropertyProtected(k)) { - return true; - } - } - return false; - } - - @Override - public Map getProtectedPropertyKeys() { - final List sensitiveKeys = getSensitivePropertyKeys(); - - final Map traditionalProtectedProperties = new HashMap<>(); - for (final String key : sensitiveKeys) { - final String protection = getProperty(getProtectionKey(key)); - if (isNotBlank(protection) && isNotBlank(getProperty(key))) { - traditionalProtectedProperties.put(key, protection); - } - } - - return traditionalProtectedProperties; - } - - @Override - public boolean isPropertySensitive(final String key) { - // If the explicit check for ADDITIONAL_SENSITIVE_PROPERTIES_KEY is not here, this will loop infinitely - return key != null && !key.equals(getAdditionalSensitivePropertiesKeysName()) && getSensitivePropertyKeys().contains(key.trim()); - } - - /** - * Returns true if the property identified by this key is considered protected in this instance of {@code NiFiProperties}. - * The property value is protected if the key is sensitive and the sibling key of key.protected is present. - * - * @param key the key - * @return true if it is currently marked as protected - * @see ApplicationPropertiesProtector#getSensitivePropertyKeys() - */ - @Override - public boolean isPropertyProtected(final String key) { - return key != null && isPropertySensitive(key) && isNotBlank(getProperty(getProtectionKey(key))); - } - - @Override - public U getUnprotectedProperties() throws SensitivePropertyProtectionException { - if (hasProtectedKeys()) { - logger.debug("Protected Properties [{}] Sensitive Properties [{}]", - getProtectedPropertyKeys().size(), - getSensitivePropertyKeys().size()); - - final Properties rawProperties = new Properties(); - - final Set failedKeys = new HashSet<>(); - - for (final String key : getPropertyKeys()) { - /* Three kinds of keys - * 1. protection schemes -- skip - * 2. protected keys -- unprotect and copy - * 3. normal keys -- copy over - */ - if (key.endsWith(PROTECTED_KEY_SUFFIX)) { - // Do nothing - } else if (isPropertyProtected(key)) { - try { - rawProperties.setProperty(key, unprotectValue(key, getProperty(key))); - } catch (final SensitivePropertyProtectionException e) { - logger.warn("Failed to unprotect '{}'", key, e); - failedKeys.add(key); - } - } else { - rawProperties.setProperty(key, getProperty(key)); - } - } - - if (!failedKeys.isEmpty()) { - final String failed = failedKeys.size() == 1 ? failedKeys.iterator().next() : String.join(", ", failedKeys); - throw new SensitivePropertyProtectionException(String.format("Failed unprotected properties: %s", failed)); - } - - return protectedProperties.createApplicationProperties(rawProperties); - } else { - logger.debug("No protected properties"); - return protectedProperties.getApplicationProperties(); - } - } - - @Override - public void addSensitivePropertyProvider(final SensitivePropertyProvider sensitivePropertyProvider) { - Objects.requireNonNull(sensitivePropertyProvider, "Provider required"); - - final String identifierKey = sensitivePropertyProvider.getIdentifierKey(); - if (localProviderCache.containsKey(identifierKey)) { - throw new UnsupportedOperationException(String.format("Sensitive Property Provider Identifier [%s] override not supported", identifierKey)); - } - - localProviderCache.put(identifierKey, sensitivePropertyProvider); - } - - @Override - public String toString() { - return String.format("%s Properties [%d]", getClass().getSimpleName(), getPropertyKeys().size()); - } - - /** - * If the value is protected, unprotects it and returns it. If not, returns the original value. - * - * @param key the retrieved property key - * @param retrievedValue the retrieved property value - * @return the unprotected value - */ - private String unprotectValue(final String key, final String retrievedValue) { - // Checks if the key is sensitive and marked as protected - if (isPropertyProtected(key)) { - final String protectionSchemePath = getProperty(getProtectionKey(key)); - - try { - final SensitivePropertyProvider provider = findProvider(protectionSchemePath); - return provider.unprotect(retrievedValue, ProtectedPropertyContext.defaultContext(key)); - } catch (final RuntimeException e) { - throw new SensitivePropertyProtectionException(String.format("Property [%s] unprotect failed", key), e); - } - } - return retrievedValue; - } - - private SensitivePropertyProvider findProvider(final String protectionSchemePath) { - Objects.requireNonNull(protectionSchemePath, "Protection Scheme Path required"); - return localProviderCache.entrySet() - .stream() - .filter(entry -> protectionSchemePath.startsWith(entry.getKey())) - .findFirst() - .map(Map.Entry::getValue) - .orElseThrow(() -> new UnsupportedOperationException(String.format("Protection Scheme Path [%s] Provider not found", protectionSchemePath))); - } - - private boolean isNotBlank(final String string) { - return string != null && string.length() > 0; - } -} diff --git a/nifi-commons/nifi-property-protection-loader/src/main/java/org/apache/nifi/property/protection/loader/PropertyProtectionURLClassLoader.java b/nifi-commons/nifi-property-protection-loader/src/main/java/org/apache/nifi/property/protection/loader/PropertyProtectionURLClassLoader.java deleted file mode 100644 index 93a838121296..000000000000 --- a/nifi-commons/nifi-property-protection-loader/src/main/java/org/apache/nifi/property/protection/loader/PropertyProtectionURLClassLoader.java +++ /dev/null @@ -1,65 +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.property.protection.loader; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.stream.Stream; - -/** - * Property Protection URL Class Loader uses the Current Thread Class Loader as the parent and loads libraries from a standard directory - */ -public class PropertyProtectionURLClassLoader extends URLClassLoader { - private static final String STANDARD_DIRECTORY = "lib/properties"; - - private static final Logger logger = LoggerFactory.getLogger(PropertyProtectionURLClassLoader.class); - - public PropertyProtectionURLClassLoader(final ClassLoader parentClassLoader) { - super(getPropertyProtectionUrls(), parentClassLoader); - } - - private static URL[] getPropertyProtectionUrls() { - final Path standardDirectory = Paths.get(STANDARD_DIRECTORY); - if (Files.exists(standardDirectory)) { - try (final Stream files = Files.list(standardDirectory)) { - return files.map(Path::toUri) - .map(uri -> { - try { - return uri.toURL(); - } catch (final MalformedURLException e) { - throw new UncheckedIOException(String.format("Processing Property Protection libraries failed [%s]", standardDirectory), e); - } - }) - .toArray(URL[]::new); - } catch (final IOException e) { - throw new UncheckedIOException(String.format("Loading Property Protection libraries failed [%s]", standardDirectory), e); - } - } else { - logger.warn("Property Protection libraries directory [{}] not found", standardDirectory); - return new URL[0]; - } - } -} diff --git a/nifi-commons/nifi-property-protection-loader/src/main/java/org/apache/nifi/property/protection/loader/PropertyProviderFactoryLoader.java b/nifi-commons/nifi-property-protection-loader/src/main/java/org/apache/nifi/property/protection/loader/PropertyProviderFactoryLoader.java deleted file mode 100644 index 2505d9a98b8f..000000000000 --- a/nifi-commons/nifi-property-protection-loader/src/main/java/org/apache/nifi/property/protection/loader/PropertyProviderFactoryLoader.java +++ /dev/null @@ -1,45 +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.property.protection.loader; - -import org.apache.nifi.properties.SensitivePropertyProtectionException; -import org.apache.nifi.properties.SensitivePropertyProviderFactory; - -import java.util.Iterator; -import java.util.ServiceLoader; - -/** - * Loader for Sensitive Property Provider Factory - */ -public class PropertyProviderFactoryLoader { - /** - * Get Sensitive Property Provider Factory using ServiceLoader to find available implementations from META-INF directories - * - * @return Sensitive Property Provider Factory - * @throws SensitivePropertyProtectionException Thrown when no implementations found - */ - public SensitivePropertyProviderFactory getPropertyProviderFactory() { - final ServiceLoader serviceLoader = ServiceLoader.load(SensitivePropertyProviderFactory.class); - final Iterator factories = serviceLoader.iterator(); - - if (factories.hasNext()) { - return factories.next(); - } else { - throw new SensitivePropertyProtectionException(String.format("No implementations found [%s]", SensitivePropertyProviderFactory.class.getName())); - } - } -} diff --git a/nifi-commons/nifi-property-protection-loader/src/main/java/org/apache/nifi/property/protection/loader/ProtectionSchemeResolverLoader.java b/nifi-commons/nifi-property-protection-loader/src/main/java/org/apache/nifi/property/protection/loader/ProtectionSchemeResolverLoader.java deleted file mode 100644 index 5608299e25ca..000000000000 --- a/nifi-commons/nifi-property-protection-loader/src/main/java/org/apache/nifi/property/protection/loader/ProtectionSchemeResolverLoader.java +++ /dev/null @@ -1,45 +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.property.protection.loader; - -import org.apache.nifi.properties.SensitivePropertyProtectionException; -import org.apache.nifi.properties.scheme.ProtectionSchemeResolver; - -import java.util.Iterator; -import java.util.ServiceLoader; - -/** - * Loader for Protection Scheme Resolver - */ -public class ProtectionSchemeResolverLoader { - /** - * Get Protection Scheme Resolver using ServiceLoader to find available implementations from META-INF directories - * - * @return Protection Scheme Resolver - * @throws SensitivePropertyProtectionException Thrown when no implementations found - */ - public ProtectionSchemeResolver getProtectionSchemeResolver() { - final ServiceLoader serviceLoader = ServiceLoader.load(ProtectionSchemeResolver.class); - final Iterator factories = serviceLoader.iterator(); - - if (factories.hasNext()) { - return factories.next(); - } else { - throw new SensitivePropertyProtectionException(String.format("No implementations found [%s]", ProtectionSchemeResolver.class.getName())); - } - } -} diff --git a/nifi-commons/nifi-property-protection-shared/pom.xml b/nifi-commons/nifi-property-protection-shared/pom.xml deleted file mode 100644 index cb9adbc9501b..000000000000 --- a/nifi-commons/nifi-property-protection-shared/pom.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - 4.0.0 - - org.apache.nifi - nifi-commons - 2.0.0-SNAPSHOT - - nifi-property-protection-shared - - - org.slf4j - slf4j-api - - - org.apache.nifi - nifi-property-protection-api - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-utils - 2.0.0-SNAPSHOT - - - diff --git a/nifi-commons/nifi-property-protection-shared/src/main/java/org/apache/nifi/properties/ClientBasedEncodedSensitivePropertyProvider.java b/nifi-commons/nifi-property-protection-shared/src/main/java/org/apache/nifi/properties/ClientBasedEncodedSensitivePropertyProvider.java deleted file mode 100644 index c5753b395e31..000000000000 --- a/nifi-commons/nifi-property-protection-shared/src/main/java/org/apache/nifi/properties/ClientBasedEncodedSensitivePropertyProvider.java +++ /dev/null @@ -1,92 +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.properties; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Properties; - -/** - * Client-Based extension of Encoded Sensitive Property Provider - * - * @param Client Type - */ -public abstract class ClientBasedEncodedSensitivePropertyProvider extends EncodedSensitivePropertyProvider { - protected final Logger logger = LoggerFactory.getLogger(getClass()); - - private final T client; - - private final Properties properties; - - public ClientBasedEncodedSensitivePropertyProvider(final T client, - final Properties properties) { - this.client = client; - this.properties = properties; - validate(client); - } - - /** - * Is Provider supported based on client status - * - * @return Provider supported status - */ - @Override - public boolean isSupported() { - return client != null; - } - - /** - * Clean up resources should be overridden when client requires shutdown - */ - @Override - public void cleanUp() { - logger.debug("Cleanup Started"); - } - - /** - * Get Client Properties - * - * @return Client Properties - */ - protected Properties getProperties() { - return properties; - } - - /** - * Get Client - * - * @return Client can be null when not configured - */ - protected T getClient() { - if (client == null) { - throw new IllegalStateException("Client not configured"); - } - return client; - } - - /** - * Validate Provider and Client configuration - * - * @param configuredClient Configured Client - */ - protected void validate(final T configuredClient) { - if (configuredClient == null) { - logger.debug("Client not configured"); - } - } -} diff --git a/nifi-commons/nifi-property-protection-shared/src/main/java/org/apache/nifi/properties/EncodedSensitivePropertyProvider.java b/nifi-commons/nifi-property-protection-shared/src/main/java/org/apache/nifi/properties/EncodedSensitivePropertyProvider.java deleted file mode 100644 index 1a1a2176f0b3..000000000000 --- a/nifi-commons/nifi-property-protection-shared/src/main/java/org/apache/nifi/properties/EncodedSensitivePropertyProvider.java +++ /dev/null @@ -1,91 +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.properties; - -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.Base64; -import java.util.Objects; - -/** - * Encoded Sensitive Property Provider handles Base64 encoding and decoding of property values - */ -public abstract class EncodedSensitivePropertyProvider implements SensitivePropertyProvider { - private static final Charset VALUE_CHARACTER_SET = StandardCharsets.UTF_8; - - private static final Base64.Encoder ENCODER = Base64.getEncoder().withoutPadding(); - - private static final Base64.Decoder DECODER = Base64.getDecoder(); - - /** - * Protect property value and return Base64-encoded representation of encrypted bytes - * - * @param unprotectedValue Unprotected property value to be encrypted - * @param context Property Context - * @return Base64-encoded representation of encrypted bytes - */ - @Override - public String protect(final String unprotectedValue, final ProtectedPropertyContext context) { - Objects.requireNonNull(unprotectedValue, "Value required"); - Objects.requireNonNull(context, "Context required"); - try { - final byte[] bytes = unprotectedValue.getBytes(VALUE_CHARACTER_SET); - final byte[] encrypted = getEncrypted(bytes); - return ENCODER.encodeToString(encrypted); - } catch (final RuntimeException e) { - final String message = String.format("Property [%s] Encryption Failed", context.getContextKey()); - throw new SensitivePropertyProtectionException(message, e); - } - } - - /** - * Unprotect Base64-encoded representation of encrypted property value and return string - * - * @param protectedValue Base64-encoded representation of encrypted bytes - * @param context Property Context - * @return Decrypted property value string - */ - @Override - public String unprotect(final String protectedValue, final ProtectedPropertyContext context) { - Objects.requireNonNull(protectedValue, "Value required"); - Objects.requireNonNull(context, "Context required"); - try { - final byte[] decoded = DECODER.decode(protectedValue); - final byte[] decrypted = getDecrypted(decoded); - return new String(decrypted, VALUE_CHARACTER_SET); - } catch (final RuntimeException e) { - final String message = String.format("Property [%s] Decryption Failed", context.getContextKey()); - throw new SensitivePropertyProtectionException(message, e); - } - } - - /** - * Get encrypted byte array representation of bytes - * - * @param bytes Unprotected bytes - * @return Encrypted bytes - */ - protected abstract byte[] getEncrypted(byte[] bytes); - - /** - * Get decrypted byte array representation of encrypted bytes - * - * @param bytes Encrypted bytes - * @return Decrypted bytes - */ - protected abstract byte[] getDecrypted(byte[] bytes); -} diff --git a/nifi-commons/nifi-property-protection-shared/src/main/java/org/apache/nifi/properties/configuration/BootstrapPropertiesClientProvider.java b/nifi-commons/nifi-property-protection-shared/src/main/java/org/apache/nifi/properties/configuration/BootstrapPropertiesClientProvider.java deleted file mode 100644 index ac8c82ad1887..000000000000 --- a/nifi-commons/nifi-property-protection-shared/src/main/java/org/apache/nifi/properties/configuration/BootstrapPropertiesClientProvider.java +++ /dev/null @@ -1,113 +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.properties.configuration; - -import org.apache.nifi.properties.BootstrapProperties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.io.InputStream; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Objects; -import java.util.Optional; -import java.util.Properties; -import java.util.Set; - -/** - * Shared Client Provider for reading Client Properties from file referenced in configured Bootstrap Property Key - * - * @param Client Type - */ -public abstract class BootstrapPropertiesClientProvider implements ClientProvider { - protected final Logger logger = LoggerFactory.getLogger(getClass()); - - private final BootstrapProperties.BootstrapPropertyKey bootstrapPropertyKey; - - public BootstrapPropertiesClientProvider(final BootstrapProperties.BootstrapPropertyKey bootstrapPropertyKey) { - this.bootstrapPropertyKey = Objects.requireNonNull(bootstrapPropertyKey, "Bootstrap Property Key required"); - } - - /** - * Get Client using Client Properties - * - * @param clientProperties Client Properties can be null - * @return Configured Client or empty when Client Properties object is null - */ - @Override - public Optional getClient(final Properties clientProperties) { - return isMissingProperties(clientProperties) ? Optional.empty() : Optional.of(getConfiguredClient(clientProperties)); - } - - /** - * Get Client Properties from file referenced in Bootstrap Properties - * - * @param bootstrapProperties Bootstrap Properties - * @return Client Properties or empty when not configured - */ - @Override - public Optional getClientProperties(final BootstrapProperties bootstrapProperties) { - Objects.requireNonNull(bootstrapProperties, "Bootstrap Properties required"); - final String clientBootstrapPropertiesPath = bootstrapProperties.getProperty(bootstrapPropertyKey).orElse(null); - if (clientBootstrapPropertiesPath == null || clientBootstrapPropertiesPath.isEmpty()) { - logger.debug("Client Properties [{}] not configured", bootstrapPropertyKey); - return Optional.empty(); - } else { - final Path propertiesPath = Paths.get(clientBootstrapPropertiesPath); - if (Files.exists(propertiesPath)) { - try { - final Properties clientProperties = new Properties(); - try (final InputStream inputStream = Files.newInputStream(propertiesPath)) { - clientProperties.load(inputStream); - } - return Optional.of(clientProperties); - } catch (final IOException e) { - final String message = String.format("Loading Client Properties Failed [%s]", propertiesPath); - throw new UncheckedIOException(message, e); - } - } else { - logger.debug("Client Properties [{}] Path [{}] not found", bootstrapPropertyKey, propertiesPath); - return Optional.empty(); - } - } - } - - /** - * Get Configured Client using Client Properties - * - * @param clientProperties Client Properties - * @return Configured Client - */ - protected abstract T getConfiguredClient(final Properties clientProperties); - - /** - * Get Property Names required for initializing client in order to perform initial validation - * - * @return Set of required client property names - */ - protected abstract Set getRequiredPropertyNames(); - - private boolean isMissingProperties(final Properties clientProperties) { - return clientProperties == null || getRequiredPropertyNames().stream().anyMatch(propertyName -> { - final String property = clientProperties.getProperty(propertyName); - return property == null || property.isEmpty(); - }); - } -} diff --git a/nifi-commons/nifi-property-protection-shared/src/main/java/org/apache/nifi/properties/configuration/ClientProvider.java b/nifi-commons/nifi-property-protection-shared/src/main/java/org/apache/nifi/properties/configuration/ClientProvider.java deleted file mode 100644 index cee6a9c5448f..000000000000 --- a/nifi-commons/nifi-property-protection-shared/src/main/java/org/apache/nifi/properties/configuration/ClientProvider.java +++ /dev/null @@ -1,45 +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.properties.configuration; - -import org.apache.nifi.properties.BootstrapProperties; - -import java.util.Optional; -import java.util.Properties; - -/** - * Client Provider responsible for reading Client Properties and instantiating client services - * - * @param Client Type - */ -public interface ClientProvider { - /** - * Get Client Properties from Bootstrap Properties - * - * @param bootstrapProperties Bootstrap Properties - * @return Client Properties or empty when not configured - */ - Optional getClientProperties(BootstrapProperties bootstrapProperties); - - /** - * Get Client using Client Properties - * - * @param properties Client Properties - * @return Client or empty when not configured - */ - Optional getClient(Properties properties); -} diff --git a/nifi-commons/nifi-property-utils/src/main/java/org/apache/nifi/properties/AbstractBootstrapPropertiesLoader.java b/nifi-commons/nifi-property-utils/src/main/java/org/apache/nifi/properties/AbstractBootstrapPropertiesLoader.java index aa699e7bf294..2684870a8630 100644 --- a/nifi-commons/nifi-property-utils/src/main/java/org/apache/nifi/properties/AbstractBootstrapPropertiesLoader.java +++ b/nifi-commons/nifi-property-utils/src/main/java/org/apache/nifi/properties/AbstractBootstrapPropertiesLoader.java @@ -16,7 +16,6 @@ */ package org.apache.nifi.properties; -import org.apache.nifi.properties.BootstrapProperties.BootstrapPropertyKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -58,17 +57,6 @@ public abstract class AbstractBootstrapPropertiesLoader { */ protected abstract String getApplicationPropertiesFilePathSystemProperty(); - /** - * Returns the key (if any) used to encrypt sensitive properties, extracted from - * {@code $APPLICATION_HOME/conf/bootstrap.conf}. - * - * @return the key in hexadecimal format - * @throws IOException if the file is not readable - */ - public String extractKeyFromBootstrapFile() throws IOException { - return extractKeyFromBootstrapFile(null); - } - /** * Loads the bootstrap.conf file into a BootstrapProperties object. * @param bootstrapPath the path to the bootstrap file @@ -100,24 +88,6 @@ public static BootstrapProperties loadBootstrapProperties(final Path bootstrapPa } } - /** - * Returns the key (if any) used to encrypt sensitive properties, extracted from - * {@code $APPLICATION_HOME/conf/bootstrap.conf}. - * - * @param bootstrapPath the path to the bootstrap file (if null, returns the sensitive key - * found in $APPLICATION_HOME/conf/bootstrap.conf) - * @return the key in hexadecimal format - * @throws IOException if the file is not readable - */ - public String extractKeyFromBootstrapFile(final String bootstrapPath) throws IOException { - final BootstrapProperties bootstrapProperties = loadBootstrapProperties(bootstrapPath); - - return bootstrapProperties.getProperty(BootstrapPropertyKey.SENSITIVE_KEY).orElseGet(() -> { - logger.warn("No encryption key present in the bootstrap.conf file at {}", bootstrapProperties.getConfigFilePath()); - return ""; - }); - } - /** * Returns the file for bootstrap.conf. * diff --git a/nifi-commons/nifi-property-utils/src/main/java/org/apache/nifi/properties/BootstrapProperties.java b/nifi-commons/nifi-property-utils/src/main/java/org/apache/nifi/properties/BootstrapProperties.java index 9b440680d07b..1d97287dbea3 100644 --- a/nifi-commons/nifi-property-utils/src/main/java/org/apache/nifi/properties/BootstrapProperties.java +++ b/nifi-commons/nifi-property-utils/src/main/java/org/apache/nifi/properties/BootstrapProperties.java @@ -21,7 +21,6 @@ import java.util.Collections; import java.util.Enumeration; import java.util.Objects; -import java.util.Optional; import java.util.Properties; import java.util.Set; @@ -31,29 +30,6 @@ public class BootstrapProperties extends StandardReadableProperties { private static final String PROPERTY_KEY_FORMAT = "%s.%s"; - public enum BootstrapPropertyKey { - SENSITIVE_KEY("bootstrap.sensitive.key"), - HASHICORP_VAULT_SENSITIVE_PROPERTY_PROVIDER_CONF("bootstrap.protection.hashicorp.vault.conf"), - AWS_SENSITIVE_PROPERTY_PROVIDER_CONF("bootstrap.protection.aws.conf"), - AZURE_KEYVAULT_SENSITIVE_PROPERTY_PROVIDER_CONF("bootstrap.protection.azure.keyvault.conf"), - GCP_KMS_SENSITIVE_PROPERTY_PROVIDER_CONF("bootstrap.protection.gcp.kms.conf"), - CONTEXT_MAPPING_PREFIX("bootstrap.protection.context.mapping."); - - private final String key; - - BootstrapPropertyKey(final String key) { - this.key = key; - } - - /** - * Returns the property key. - * @return The property key - */ - public String getKey() { - return key; - } - } - private final String propertyPrefix; private final Path configFilePath; @@ -65,7 +41,6 @@ public BootstrapProperties(final String propertyPrefix, final Properties propert this.configFilePath = configFilePath; this.filterProperties(properties); - } /** @@ -119,15 +94,6 @@ private String getPropertyKey(final String subKey) { return String.format(PROPERTY_KEY_FORMAT, propertyPrefix, subKey); } - /** - * Returns the optional property value with the given BootstrapPropertyKey. - * @param key A BootstrapPropertyKey, representing properties in bootstrap.conf - * @return The property value - */ - public Optional getProperty(final BootstrapPropertyKey key) { - return Optional.ofNullable(getProperty(getPropertyKey(key.key))); - } - @Override public String toString() { return String.format("Bootstrap properties [%s] with prefix [%s]", configFilePath, propertyPrefix); diff --git a/nifi-commons/pom.xml b/nifi-commons/pom.xml index a8cfaedf8597..f5d62ce280de 100644 --- a/nifi-commons/pom.xml +++ b/nifi-commons/pom.xml @@ -41,15 +41,6 @@ nifi-property-encryptor nifi-property-utils nifi-properties - nifi-property-protection-api - nifi-property-protection-aws - nifi-property-protection-azure - nifi-property-protection-cipher - nifi-property-protection-factory - nifi-property-protection-gcp - nifi-property-protection-hashicorp - nifi-property-protection-loader - nifi-property-protection-shared nifi-record nifi-record-path nifi-repository-encryption diff --git a/nifi-docs/src/main/asciidoc/administration-guide.adoc b/nifi-docs/src/main/asciidoc/administration-guide.adoc index 9addc6b6c5de..2b9b5b9b4659 100644 --- a/nifi-docs/src/main/asciidoc/administration-guide.adoc +++ b/nifi-docs/src/main/asciidoc/administration-guide.adoc @@ -2025,19 +2025,6 @@ empty. NiFi writes the generated value to `nifi.properties` and logs a warning. Clustered installations of NiFi require the same value to be configured on all nodes. -[[encrypt-config_tool]] -== Encrypted Passwords in Configuration Files - -In order to facilitate the secure setup of NiFi, you can use the `encrypt-config` command line utility to encrypt raw configuration values that NiFi decrypts in memory on startup. This extensible protection scheme transparently allows NiFi to use raw values in operation, while protecting them at rest. - -This is a change in behavior; prior to 1.0, all configuration values were stored in plaintext on the file system. POSIX file permissions were recommended to limit unauthorized access to these files. - -If no administrator action is taken, the configuration values remain unencrypted. - -For more information, see the <> section in the link:toolkit-guide.html[NiFi Toolkit Guide]. - -Configuring each Sensitive Property Provider requires including the appropriate file reference property in `bootstrap.conf`. The default `bootstrap.conf` includes commented file reference properties for available providers. - [[hashicorp-vault-providers]] === HashiCorp Vault providers Two encryption providers are currently configurable in the `bootstrap-hashicorp-vault.conf` file: @@ -2240,14 +2227,9 @@ nifi.bootstrap.protection.context.mapping.ldap=ldap-.* This would cause both of the above to be assigned a context of `"ldap/Manager Password"` instead of `"default/Manager Password"`. [[admin-toolkit]] == NiFi Toolkit Administrative Tools -In addition to `encrypt-config`, the NiFi Toolkit also contains command line utilities for administrators to support NiFi maintenance in standalone and clustered environments. These utilities include: +The NiFi Toolkit also contains command line utilities for administrators to support NiFi maintenance in standalone and clustered environments. * CLI -- The `cli` tool enables administrators to interact with NiFi and NiFi Registry instances to automate tasks such as deploying versioned flows and managing process groups and cluster nodes. -* File Manager -- The `file-manager` tool enables administrators to backup, install or restore a NiFi installation from backup. -* Flow Analyzer -- The `flow-analyzer` tool produces a report that helps administrators understand the max amount of data which can be stored in backpressure for a given flow. -* Node Manager -- The `node-manager` tool enables administrators to perform status checks on nodes as well as the ability to connect, disconnect, or remove nodes from the cluster. -* Notify -- The `notify` tool enables administrators to send bulletins to the NiFi UI. -* S2S -- The `s2s` tool enables administrators to send data into or out of NiFi flows over site-to-site. For more information about each utility, see the link:toolkit-guide.html[NiFi Toolkit Guide]. @@ -3027,9 +3009,6 @@ if the service is still running, the Bootstrap will `kill` the process, or termi |`java.arg.N`|Any number of JVM arguments can be passed to the NiFi JVM when the process is started. These arguments are defined by adding properties to _bootstrap.conf_ that begin with `java.arg.`. The rest of the property name is not relevant, other than to differentiate property names, and will be ignored. The default includes properties for minimum and maximum Java Heap size, the garbage collector to use, Java IO temporary directory, etc. -|`nifi.bootstrap.sensitive.key`|The root key (in hexadecimal format) for encrypted sensitive configuration values. When NiFi is started, this root key is used to decrypt sensitive values from the _nifi.properties_ file into memory for later use. - -The Encrypt-Config Tool can be used to specify the root key, encrypt sensitive values in _nifi.properties_ and update _bootstrap.conf_. See the <> for an example. |`nifi.diagnostics.on.shutdown.enabled`|(true or false) This property decides whether to run NiFi diagnostics before shutting down. The default value is `false`. |`nifi.diagnostics.on.shutdown.verbose`|(true or false) This property decides whether to run NiFi diagnostics in verbose mode. The default value is `false`. |`nifi.diagnostics.on.shutdown.directory`|This property specifies the location of the NiFi diagnostics directory. The default value is `./diagnostics`. @@ -3917,7 +3896,6 @@ These properties pertain to various security features in NiFi. Many of these pro |*Property*|*Description* |`nifi.sensitive.props.key`|This is the password used to encrypt any sensitive property values that are configured in processors. By default, it is blank, but the system administrator should provide a value for it. It can be a string of any length, although the recommended minimum length is 10 characters. Be aware that once this password is set and one or more sensitive processor properties have been configured, this password should not be changed. |`nifi.sensitive.props.algorithm`|The algorithm used to encrypt sensitive properties. The default value is `NIFI_PBKDF2_AES_GCM_256`. -|`nifi.sensitive.props.additional.keys`|The comma separated list of properties in _nifi.properties_ to encrypt in addition to the default sensitive properties (see <>). |`nifi.security.autoreload.enabled`|Specifies whether the SSL context factory should be automatically reloaded if updates to the keystore and truststore are detected. By default, it is set to `false`. |`nifi.security.autoreload.interval`|Specifies the interval at which the keystore and truststore are checked for updates. Only applies if `nifi.security.autoreload.enabled` is set to `true`. The default value is `10 secs`. |`nifi.security.keystore`*|The full path and name of the keystore. The default value is `./conf/keystore.p12`. @@ -4331,33 +4309,6 @@ ZooKeeper “Connect String" property should be set to the same external ZooKeep WARNING: Double check all configured properties for typos. -[[sensitive_flow_migration]] -==== Migrating a Flow with Sensitive Properties - -When a value is set for `nifi.sensitive.props.key` in _nifi.properties_, the specified key is used to encrypt sensitive properties in the flow (e.g. password fields in components). If the key needs to change, the Encrypt-Config tool in the NiFi Toolkit can migrate the sensitive properties key and update the _flow.json.gz_. Specifically, Encrypt-Config: - -1. Reads the existing _flow.json.gz_ and decrypts the sensitive values using the current key. -2. Encrypts all the sensitive values with a specified new key. -3. Updates the _nifi.properties_ and _flow.json.gz_ files or creates new versions of them. - -As an example, assume version 1.9.2 is the existing NiFi instance and the sensitive properties key is set to `password`. The goal is to move the 1.9.2 _flow.json.gz_ to a 1.10.0 instance with a new sensitive properties key: `new_password`. Running the following Encrypt-Config command would read in the _flow.json.gz_ and _nifi.properties_ files from 1.9.2 using the original sensitive properties key and write out new versions in 1.10.0 with the sensitive properties encrypted with the new password: - -``` -$ ./nifi-toolkit-1.10.0/bin/encrypt-config.sh -f /path/to/nifi/nifi-1.9.2/conf/flow.json.gz -g /path/to/nifi/nifi-1.10.0/conf/flow.json.gz -s new_password -n /path/to/nifi/nifi-1.9.2/conf/nifi -.properties -o /path/to/nifi/nifi-1.10.0/conf/nifi.properties -x -``` - -where: - -* `-f` specifies the source _flow.json.gz_ (nifi-1.9.2) -* `-g` specifies the destination _flow.json.gz_ (nifi-1.10.0) -* `-s` specifies the new sensitive properties key (`new_password`) -* `-n` specifies the source _nifi.properties_ (nifi-1.9.2) -* `-o` specifies the destination _nifi.properties_ (nifi-1.10.0) -* `-x` tells Encrypt-Config to only process the sensitive properties - -For more information see the <> section in the NiFi Toolkit Guide. - ==== Updating the Sensitive Properties Algorithm The following command can be used to read an existing flow configuration and set a new sensitive properties algorithm in _nifi.properties_: diff --git a/nifi-docs/src/main/asciidoc/toolkit-guide.adoc b/nifi-docs/src/main/asciidoc/toolkit-guide.adoc index 70f0ea8286fa..2e6c39056184 100644 --- a/nifi-docs/src/main/asciidoc/toolkit-guide.adoc +++ b/nifi-docs/src/main/asciidoc/toolkit-guide.adoc @@ -23,7 +23,6 @@ Apache NiFi Team The NiFi Toolkit contains several command line utilities to setup and support NiFi in standalone and clustered environments. The utilities include: * CLI -- The `cli` tool enables administrators to interact with NiFi and NiFi Registry instances to automate tasks such as deploying versioned flows and managing process groups and cluster nodes. -* Encrypt Config -- The `encrypt-config` tool encrypts the sensitive keys in the _nifi.properties_ file to facilitate the setup of a secure NiFi instance. The utilities are executed with scripts found in the `bin` folder of your NiFi Toolkit installation. @@ -429,347 +428,6 @@ commands.add(new MyCommand()); To add a NiFi Registry command, perform the same steps, but extend from `AbstractNiFiRegistryCommand`, and add the command to `NiFiRegistryCommandGroup`. -[[encrypt_config_tool]] -== Encrypt-Config Tool -The `encrypt-config` command line tool (invoked as `./bin/encrypt-config.sh` or `bin\encrypt-config.bat`) reads from a _nifi.properties_ file with plaintext sensitive configuration values, prompts for a root password or raw hexadecimal key, and encrypts each value. It replaces the plain values with the protected value in the same file, or writes to a new _nifi.properties_ file if specified. - -The default encryption algorithm utilized is AES-GCM with 256-bit keys. - -=== Usage -To show help: - - ./bin/encrypt-config.sh -h - -==== NiFi -The following are available options when targeting NiFi: - -* `-h`,`--help` Show usage information (this message) -* `-v`,`--verbose` Sets verbose mode (default false) -* `-n`,`--niFiProperties ` The _nifi.properties_ file containing unprotected config values (will be overwritten unless `-o` is specified) -* `-o`,`--outputNiFiProperties ` The destination _nifi.properties_ file containing protected config values (will not modify input _nifi.properties_) -* `-l`,`--loginIdentityProviders ` The _login-identity-providers.xml_ file containing unprotected config values (will be overwritten unless `-i` is specified) -* `-i`,`--outputLoginIdentityProviders ` The destination _login-identity-providers.xml_ file containing protected config values (will not modify input _login-identity-providers.xml_) -* `-a`,`--authorizers ` The _authorizers.xml_ file containing unprotected config values (will be overwritten unless `-u` is specified) -* `-u`,`--outputAuthorizers ` The destination _authorizers.xml_ file containing protected config values (will not modify input _authorizers.xml_) -* `-f`,`--flowJson ` The _flow.json.gz_ file currently protected with old password (will be overwritten unless `-g` is specified) -* `-g`,`--outputFlowJson ` The destination _flow.json.gz_ file containing protected config values (will not modify input _flow.json.gz_) -* `-b`,`--bootstrapConf ` The bootstrap.conf file to persist root key and to optionally provide any configuration for the protection scheme. -* `-B`,`--outputBootstrapConf ` The destination _bootstrap.conf_ file to persist root key. If specified, the input _bootstrap.conf_ will not be modified. -* `-S`,`--protectionScheme ` Selects the protection scheme for encrypted properties. Valid values are: [<>, <>, <>, <>, <>, <>, <>, <>] (default is AES_GCM) -* `-k`,`--key ` The raw hexadecimal key to use to encrypt the sensitive properties -* `-e`,`--oldKey ` The old raw hexadecimal key to use during key migration -* `-H`,`--oldProtectionScheme ` The old protection scheme to use during encryption migration (see --protectionScheme for possible values). Default is AES_GCM -* `-p`,`--password ` The password from which to derive the key to use to encrypt the sensitive properties -* `-w`,`--oldPassword ` The old password from which to derive the key during migration -* `-r`,`--useRawKey` If provided, the secure console will prompt for the raw key value in hexadecimal form -* `-m`,`--migrate` If provided, the _nifi.properties_ and/or _login-identity-providers.xml_ sensitive properties will be re-encrypted with the new scheme -* `-x`,`--encryptFlowJsonOnly` If provided, the properties in _flow.json.gz_ will be re-encrypted with a new key but the _nifi.properties_ and/or _login-identity-providers.xml_ files will not be modified -* `-s`,`--propsKey ` The password or key to use to encrypt the sensitive processor properties in _flow.json.gz_ -* `-A`,`--newFlowAlgorithm ` The algorithm to use to encrypt the sensitive processor properties in _flow.json.gz_ - -==== NiFi Registry -The following are available options when targeting NiFi Registry using the `--nifiRegistry` flag: - -* `-h`,`--help` Show usage information (this message) -* `-v`,`--verbose` Sets verbose mode (default false) -* `-p`,`--password ` Protect the files using a password-derived key. If an argument is not provided to this flag, interactive mode will be triggered to prompt the user to enter the password. -* `-k`,`--key ` Protect the files using a raw hexadecimal key. If an argument is not provided to this flag, interactive mode will be triggered to prompt the user to enter the key. -* `-S`,`--protectionScheme ` Selects the protection scheme for encrypted properties. Valid values are: [<>, <>, <>, <>, <>, <>, <>, <>] (default is AES_GCM) -* `-w`,`--oldPassword ` If the input files are already protected using a password-derived key, this specifies the old password so that the files can be unprotected before re-protecting. -* `-e`,`--oldKey ` If the input files are already protected using a key, this specifies the raw hexadecimal key so that the files can be unprotected before re-protecting. -* `-H`,`--oldProtectionScheme ` The old protection scheme to use during encryption migration (see --protectionScheme for possible values). Default is AES_GCM. -* `-b`,`--bootstrapConf ` The _bootstrap.conf_ file containing no root key or an existing root key, and any other protection scheme configuration properties. If a new password or key is specified (using -p or -k) and no output _bootstrap.conf_ file is specified, then this file will be overwritten to persist the new master key. -* `-B`,`--outputBootstrapConf ` The destination _bootstrap.conf_ file to persist root key. If specified, the input _bootstrap.conf_ will not be modified. -* `-r`,`--nifiRegistryProperties ` The _nifi-registry.properties_ file containing unprotected config values, overwritten if no output file specified. -* `-R`,`--outputNifiRegistryProperties ` The destination _nifi-registry.properties_ file containing protected config values. -* `-a`,`--authorizersXml ` The _authorizers.xml_ file containing unprotected config values, overwritten if no output file specified. -* `-u`,`--outputAuthorizersXml ` The destination _authorizers.xml_ file containing protected config values. -* `-i`,`--identityProvidersXml ` The _identity-providers.xml_ file containing unprotected config values, overwritten if no output file specified. -* `-I`,`--outputIdentityProvidersXml ` The destination _identity-providers.xml_ file containing protected config values. - -=== Protection Schemes -The protection scheme can be selected during encryption using the `--protectionScheme` flag. During migration, the former protection scheme is specified using the `--oldProtectionScheme` flag. This distinction allows a set of protected configuration files to be migrated not only to a new key, but to a completely different protection scheme. - -==== AES_GCM [[AES_GCM]] -The default protection scheme, `AES-G/CM` simply encrypts sensitive properties and marks their protection as either `aes/gcm/256` or `aes/gcm/256` as appropriate. This protection is all done within NiFi itself. - -==== HASHICORP_VAULT_TRANSIT [[HASHICORP_VAULT_TRANSIT]] -This protection scheme uses https://www.vaultproject.io/docs/secrets/transit[HashiCorp Vault Transit Secrets Engine] to outsource encryption to a configured Vault server. All HashiCorp Vault configuration is stored in the `bootstrap-hashicorp-vault.conf` file, as referenced in the `bootstrap.conf` of a NiFi or NiFi Registry instance. Therefore, when using the HASHICORP_VAULT_TRANSIT protection scheme, the `nifi(.registry)?.bootstrap.protection.hashicorp.vault.conf` property in the `bootstrap.conf` specified using the `-b` flag must be available to the Encrypt Configuration Tool and must be configured as described in the <> section in the link:administration-guide.html[NiFi Administration Guide]. - -==== HASHICORP_VAULT_KV [[HASHICORP_VAULT_KV]] -This protection scheme uses https://www.vaultproject.io/docs/secrets/kv/kv-v1[HashiCorp Vault Key Value Secrets Engine Version 1] to store sensitive values as Vault Secrets. All HashiCorp Vault configuration is stored in the `bootstrap-hashicorp-vault.conf` file, as referenced in the `bootstrap.conf` of a NiFi or NiFi Registry instance. Therefore, when using the HASHICORP_VAULT_KV protection scheme, the `nifi(.registry)?.bootstrap.protection.hashicorp.vault.conf` property in the `bootstrap.conf` specified using the `-b` flag must be available to the Encrypt Configuration Tool and must be configured as described in the <> section in the link:administration-guide.html[NiFi Administration Guide]. - -==== AWS_KMS [[AWS_KMS]] -This protection scheme uses https://aws.amazon.com/kms/[AWS Key Management] Service for encryption and decryption. AWS KMS configuration properties can be stored in the `bootstrap-aws.conf` file, as referenced in the `bootstrap.conf` of NiFi or NiFi Registry. If the configuration properties are not specified in `bootstrap-aws.conf`, then the provider will attempt to use the AWS default credentials provider, which checks standard environment variables and system properties. Therefore, when using the AWS_KMS protection scheme, the `nifi(.registry)?.bootstrap.protection.aws.conf` property in the `bootstrap.conf` specified using the `-b` flag must be available to the Encrypt Configuration Tool and must be configured as described in the <> section in the link:administration-guide.html[NiFi Administration Guide]. - -==== AWS_SECRETSMANAGER [[AWS_SECRETSMANAGER]] -This protection scheme uses https://aws.amazon.com/secrets-manager/[AWS Secrets Manager] Service to store sensitive values as AWS Secrets. AWS Secrets Manager configuration properties can be stored in the `bootstrap-aws.conf` file, as referenced in the `bootstrap.conf` of NiFi or NiFi Registry. If the configuration properties are not specified in `bootstrap-aws.conf`, then the provider will attempt to use the AWS default credentials provider, which checks standard environment variables and system properties. Therefore, when using the AWS_SECRETS_MANAGER protection scheme, the `nifi(.registry)?.bootstrap.protection.aws.conf` property in the `bootstrap.conf` specified using the `-b` flag must be available to the Encrypt Configuration Tool and must be configured as described in the <> section in the link:administration-guide.html[NiFi Administration Guide]. - -==== Microsoft Azure Key Vault Sensitive Property Providers - -Azure Key Vault configuration properties can be stored in the `bootstrap-azure.conf` file, as referenced in the -`bootstrap.conf` of NiFi or NiFi Registry. - -Azure Key Vault providers will use the -https://docs.microsoft.com/en-us/java/api/com.azure.identity.defaultazurecredential[DefaultAzureCredential] -for authentication. -The https://docs.microsoft.com/en-us/java/api/overview/azure/identity-readme#key-concepts[Azure Identity] client library -describes the process for credentials resolution, which leverages environment variables, system properties, and falls -back to -https://docs.microsoft.com/en-us/java/api/overview/azure/identity-readme#managed-identity-support[Managed Identity] -authentication. - -When using Azure Key Vault providers, `bootstrap.conf` must contain the -`nifi.bootstrap.protection.azure.keyvault.conf` property. The `bootstrap.conf` file location must be specified using the -`-b` argument when running the Encrypt Config Tool. - -===== AZURE_KEYVAULT_KEY [[AZURE_KEYVAULT_KEY]] - -This protection scheme uses keys managed by -https://docs.microsoft.com/en-us/azure/key-vault/keys/about-keys[Azure Key Vault Keys] for encryption and decryption. - -See <> in the NiFi System -Administrator's Guide for required properties. - -===== AZURE_KEYVAULT_SECRET [[AZURE_KEYVAULT_SECRET]] - -This protection scheme uses secrets managed by -https://docs.microsoft.com/en-us/azure/key-vault/secrets/about-secrets[Azure Key Vault Secrets] for storing and -retrieving sensitive property values. - -See <> in the NiFi System -Administrator's Guide for required properties. - -==== GCP_KMS [[GCP_KMS]] -This protection scheme uses Google Cloud Key Management Service (https://cloud.google.com/security-key-management[Google Cloud Key Management Service]) for encryption and decryption. Google Cloud KMS configuration properties are to be stored in the `bootstrap-gcp.conf` file, as referenced in the `bootstrap.conf` of NiFi or NiFi Registry. Credentials must be configured as per the following documentation: https://cloud.google.com/kms/docs/reference/libraries[Google Cloud KMS documentation]. Therefore, when using the GCP_KMS protection scheme, the `nifi(.registry)?.bootstrap.protection.gcp.kms.conf` property in the `bootstrap.conf` specified using the `-b` flag must be available to the Encrypt Configuration Tool and must be configured as described in the <> section in the link:administration-guide.html[NiFi Administration Guide]. - -=== Examples - -==== NiFi -As an example of how the tool works, assume that you have installed the tool on a machine supporting 256-bit encryption and with the following existing values in the _nifi.properties_ file: - -[source] ----- -# security properties # -nifi.sensitive.props.key=thisIsABadSensitiveKeyPassword -nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM_256 -nifi.sensitive.props.additional.keys= - -nifi.security.keystore=/path/to/keystore.jks -nifi.security.keystoreType=JKS -nifi.security.keystorePasswd=thisIsABadKeystorePassword -nifi.security.keyPasswd=thisIsABadKeyPassword -nifi.security.truststore= -nifi.security.truststoreType= -nifi.security.truststorePasswd= ----- - -Enter the following arguments when using the tool: - ----- -encrypt-config.sh \ --b bootstrap.conf \ --k 0123456789ABCDEFFEDCBA98765432100123456789ABCDEFFEDCBA9876543210 \ --n nifi.properties ----- - -As a result, the _nifi.properties_ file is overwritten with protected properties and sibling encryption identifiers (`aes/gcm/256`, the currently supported algorithm): - -[source] ----- -# security properties # -nifi.sensitive.props.key=n2z+tTTbHuZ4V4V2||uWhdasyDXD4ZG2lMAes/vqh6u4vaz4xgL4aEbF4Y/dXevqk3ulRcOwf1vc4RDQ== -nifi.sensitive.props.key.protected=aes/gcm/256 -nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM_256 -nifi.sensitive.props.additional.keys= - -nifi.security.keystore=/path/to/keystore.jks -nifi.security.keystoreType=JKS -nifi.security.keystorePasswd=oBjT92hIGRElIGOh||MZ6uYuWNBrOA6usq/Jt3DaD2e4otNirZDytac/w/KFe0HOkrJR03vcbo -nifi.security.keystorePasswd.protected=aes/gcm/256 -nifi.security.keyPasswd=ac/BaE35SL/esLiJ||+ULRvRLYdIDA2VqpE0eQXDEMjaLBMG2kbKOdOwBk/hGebDKlVg== -nifi.security.keyPasswd.protected=aes/gcm/256 -nifi.security.truststore= -nifi.security.truststoreType= -nifi.security.truststorePasswd= ----- - -Additionally, the _bootstrap.conf_ file is updated with the encryption key as follows: - -[source] ----- -# Root key in hexadecimal format for encrypted sensitive configuration values -nifi.bootstrap.sensitive.key=0123456789ABCDEFFEDCBA98765432100123456789ABCDEFFEDCBA9876543210 ----- - -Sensitive configuration values are encrypted by the tool by default, however you can encrypt any additional properties, if desired. To encrypt additional properties, specify them as comma-separated values in the `nifi.sensitive.props.additional.keys` property. - -If the _nifi.properties_ file already has valid protected values, those property values are not modified by the tool. - -When applied to _login-identity-providers.xml_ and _authorizers.xml_, the property elements are updated with an `encryption` attribute: - -Example of protected _login-identity-providers.xml_: - -[source] ----- - - - ldap-provider - org.apache.nifi.ldap.LdapProvider - START_TLS - someuser - q4r7WIgN0MaxdAKM||SGgdCTPGSFEcuH4RraMYEdeyVbOx93abdWTVSWvh1w+klA - - Uah59TWX+Ru5GY5p||B44RT/LJtC08QWA5ehQf01JxIpf0qSJUzug25UwkF5a50g - - ... - ----- - -Example of protected _authorizers.xml_: - -[source] ----- - - - ldap-user-group-provider - org.apache.nifi.ldap.tenants.LdapUserGroupProvider - START_TLS - someuser - q4r7WIgN0MaxdAKM||SGgdCTPGSFEcuH4RraMYEdeyVbOx93abdWTVSWvh1w+klA - - Uah59TWX+Ru5GY5p||B44RT/LJtC08QWA5ehQf01JxIpf0qSJUzug25UwkF5a50g - - ... - ----- - -==== NiFi Registry -As an example of how the tool works, assume that you have installed the tool on a machine supporting 256-bit encryption and with the following existing values in the _nifi-registry.properties_ file: - ----- -# security properties # -nifi.registry.security.keystore=/path/to/keystore.jks -nifi.registry.security.keystoreType=JKS -nifi.registry.security.keystorePasswd=thisIsABadKeystorePassword -nifi.registry.security.keyPasswd=thisIsABadKeyPassword -nifi.registry.security.truststore= -nifi.registry.security.truststoreType= -nifi.registry.security.truststorePasswd= ----- - -Enter the following arguments when using the tool: - ----- -./bin/encrypt-config.sh --nifiRegistry \ --b bootstrap.conf \ --k 0123456789ABCDEFFEDCBA98765432100123456789ABCDEFFEDCBA9876543210 \ --r nifi-registry.properties ----- - -As a result, the _nifi-registry.properties_ file is overwritten with protected properties and sibling encryption identifiers (`aes/gcm/256`, the currently supported algorithm): - ----- -# security properties # -nifi.registry.security.keystore=/path/to/keystore.jks -nifi.registry.security.keystoreType=JKS -nifi.registry.security.keystorePasswd=oBjT92hIGRElIGOh||MZ6uYuWNBrOA6usq/Jt3DaD2e4otNirZDytac/w/KFe0HOkrJR03vcbo -nifi.registry.security.keystorePasswd.protected=aes/gcm/256 -nifi.registry.security.keyPasswd=ac/BaE35SL/esLiJ||+ULRvRLYdIDA2VqpE0eQXDEMjaLBMG2kbKOdOwBk/hGebDKlVg== -nifi.registry.security.keyPasswd.protected=aes/gcm/256 -nifi.registry.security.truststore= -nifi.registry.security.truststoreType= -nifi.registry.security.truststorePasswd= ----- - -When applied to _identity-providers.xml_ or _authorizers.xml_, the property elements are updated with an `encryption` attribute. For example: - ----- - - - ldap-provider - org.apache.nifi.registry.security.ldap.LdapProvider - START_TLS - someuser - q4r7WIgN0MaxdAKM||SGgdCTPGSFEcuH4RraMYEdeyVbOx93abdWTVSWvh1w+klA - /path/to/keystore.jks - Uah59TWX+Ru5GY5p||B44RT/LJtC08QWA5ehQf01JxIpf0qSJUzug25UwkF5a50g - JKS - ... - ----- - -Additionally, the _bootstrap.conf_ file is updated with the encryption key as follows: - ----- -# Root key in hexadecimal format for encrypted sensitive configuration values -nifi.registry.bootstrap.sensitive.key=0123456789ABCDEFFEDCBA98765432100123456789ABCDEFFEDCBA9876543210 ----- - -Sensitive configuration values are encrypted by the tool by default, however you can encrypt any additional properties, if desired. -To encrypt additional properties, specify them as comma-separated values in the `nifi.registry.sensitive.props.additional.keys` property. - - -If the _nifi-registry.properties_ file already has valid protected values and you wish to protect additional values using the -same root key already present in your _bootstrap.conf_, then run the tool without specifying a new key: - ----- -# bootstrap.conf already contains root key property -# nifi-registy.properties has been updated for nifi.registry.sensitive.props.additional.keys=... - -./bin/encrypt-config.sh --nifiRegistry -b bootstrap.conf -r nifi-registry.properties ----- - -[sensitive_property_key_migration] -=== Sensitive Property Key Migration - -In order to change the key used to encrypt the sensitive values, provide the new key or password using the `-k` or `-p` flags as usual, -and provide the existing key or password using `--old-key` or `--old-password` respectively. This will allow the toolkit to decrypt the -existing values and re-encrypt them, and update _bootstrap.conf_ with the new key. Only one of the key or password needs to be specified -for each phase (old vs. new), and any combination is sufficient: - -* old key -> new key -* old key -> new password -* old password -> new key -* old password -> new password - -In order to change the protection scheme (e.g., migrating from AES encryption to Vault encryption), specify the `--protectionScheme` -and `--oldProtectionScheme` in the migration command. - -The following is an example of the commands for protection scheme migration from AES_GCM to AWS_KMS then back. Execute these commands at the `nifi` directory with the `nifi-toolkit` directory as a sibling directory. In addition, make sure to update `bootstrap-aws.conf` with your AWS KMS Key ARN/ID and have your credentials and region configured. - - -This command encrypts nifi.properties with the AES_GCM protection scheme ----- -./../nifi-toolkit-*-SNAPSHOT/bin/encrypt-config.sh \ --b conf/bootstrap.conf \ --n conf/nifi.properties \ --k 0123456789ABCDEFFEDCBA98765432100123456789ABCDEFFEDCBA9876543210 \ --v ----- -This command migrates nifi.properties from using AES_GCM to using AWS_KMS protection scheme ----- -./../nifi-toolkit-*-SNAPSHOT/bin/encrypt-config.sh \ --b conf/bootstrap.conf \ --n conf/nifi.properties \ --S AWS_KMS \ --H AES_GCM \ --e 0123456789ABCDEFFEDCBA98765432100123456789ABCDEFFEDCBA9876543210 \ --m \ --v ----- -This command migrates nifi.properties back from AWS_KMS to AES_GCM protection scheme ----- -./../nifi-toolkit-*-SNAPSHOT/bin/encrypt-config.sh \ --b conf/bootstrap.conf \ --n conf/nifi.properties \ --S AES_GCM \ --k 0123456789ABCDEFFEDCBA98765432100123456789ABCDEFFEDCBA9876543210 \ --H AWS_KMS \ --m \ --v ----- - [export_import_all_flows] === Export All Flows You can use the `export-all-flows` to perform the following tasks: diff --git a/nifi-framework-bundle/nifi-framework-nar-bom/pom.xml b/nifi-framework-bundle/nifi-framework-nar-bom/pom.xml index f5021eb4e088..65e3202b6ab7 100644 --- a/nifi-framework-bundle/nifi-framework-nar-bom/pom.xml +++ b/nifi-framework-bundle/nifi-framework-nar-bom/pom.xml @@ -153,18 +153,6 @@ 2.0.0-SNAPSHOT provided - - org.apache.nifi - nifi-property-protection-api - 2.0.0-SNAPSHOT - provided - - - org.apache.nifi - nifi-property-protection-loader - 2.0.0-SNAPSHOT - provided - org.apache.nifi nifi-properties-loader @@ -320,14 +308,6 @@ org.apache.nifi nifi-property-encryptor - - org.apache.nifi - nifi-property-protection-api - - - org.apache.nifi - nifi-property-protection-loader - org.apache.nifi nifi-properties-loader diff --git a/nifi-framework-bundle/nifi-framework-nar/pom.xml b/nifi-framework-bundle/nifi-framework-nar/pom.xml index c0a66b5c0df9..a9ac2a114e2b 100644 --- a/nifi-framework-bundle/nifi-framework-nar/pom.xml +++ b/nifi-framework-bundle/nifi-framework-nar/pom.xml @@ -130,16 +130,6 @@ nifi-property-encryptor compile - - org.apache.nifi - nifi-property-protection-api - compile - - - org.apache.nifi - nifi-property-protection-loader - compile - org.apache.nifi nifi-properties-loader diff --git a/nifi-framework-bundle/nifi-framework/nifi-authorizer/pom.xml b/nifi-framework-bundle/nifi-framework/nifi-authorizer/pom.xml index 60455dac347e..86d7f312e6d8 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-authorizer/pom.xml +++ b/nifi-framework-bundle/nifi-framework/nifi-authorizer/pom.xml @@ -108,16 +108,6 @@ nifi-nar-utils test - - org.apache.nifi - nifi-property-protection-api - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-loader - 2.0.0-SNAPSHOT - jakarta.xml.bind jakarta.xml.bind-api @@ -134,12 +124,6 @@ 2.0.0-SNAPSHOT test - - org.apache.nifi - nifi-property-protection-factory - 2.0.0-SNAPSHOT - test - org.apache.nifi nifi-python-framework-api diff --git a/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java b/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java index 823573b8e006..1dfa185d6891 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java +++ b/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java @@ -46,14 +46,6 @@ import org.apache.nifi.authorization.generated.Property; import org.apache.nifi.bundle.Bundle; import org.apache.nifi.nar.ExtensionManager; -import org.apache.nifi.properties.ProtectedPropertyContext; -import org.apache.nifi.properties.SensitivePropertyProvider; -import org.apache.nifi.properties.SensitivePropertyProviderFactory; -import org.apache.nifi.properties.scheme.ProtectionScheme; -import org.apache.nifi.properties.scheme.ProtectionSchemeResolver; -import org.apache.nifi.property.protection.loader.PropertyProtectionURLClassLoader; -import org.apache.nifi.property.protection.loader.PropertyProviderFactoryLoader; -import org.apache.nifi.property.protection.loader.ProtectionSchemeResolverLoader; import org.apache.nifi.util.NiFiProperties; import org.apache.nifi.util.file.classloader.ClassLoaderUtils; import org.apache.nifi.xml.processing.ProcessingException; @@ -177,23 +169,12 @@ private void loadProviderProperties(final Authorizers authorizerConfiguration, f final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); try { - final PropertyProtectionURLClassLoader protectionClassLoader = new PropertyProtectionURLClassLoader(contextClassLoader); - Thread.currentThread().setContextClassLoader(protectionClassLoader); - - final ProtectionSchemeResolverLoader resolverLoader = new ProtectionSchemeResolverLoader(); - final ProtectionSchemeResolver protectionSchemeResolver = resolverLoader.getProtectionSchemeResolver(); - - final PropertyProviderFactoryLoader factoryLoader = new PropertyProviderFactoryLoader(); - final SensitivePropertyProviderFactory sensitivePropertyProviderFactory = factoryLoader.getPropertyProviderFactory(); - // configure each user group provider for (final org.apache.nifi.authorization.generated.UserGroupProvider provider : authorizerConfiguration.getUserGroupProvider()) { final UserGroupProvider instance = userGroupProviders.get(provider.getIdentifier()); final AuthorizerConfigurationContext configurationContext = getConfigurationContext( provider.getIdentifier(), - provider.getProperty(), - sensitivePropertyProviderFactory, - protectionSchemeResolver + provider.getProperty() ); instance.onConfigured(configurationContext); } @@ -203,9 +184,7 @@ private void loadProviderProperties(final Authorizers authorizerConfiguration, f final AccessPolicyProvider instance = accessPolicyProviders.get(provider.getIdentifier()); final AuthorizerConfigurationContext configurationContext = getConfigurationContext( provider.getIdentifier(), - provider.getProperty(), - sensitivePropertyProviderFactory, - protectionSchemeResolver + provider.getProperty() ); instance.onConfigured(configurationContext); } @@ -216,18 +195,14 @@ private void loadProviderProperties(final Authorizers authorizerConfiguration, f if (provider.getIdentifier().equals(authorizerIdentifier)) { authorizerConfigurationContext = getConfigurationContext( provider.getIdentifier(), - provider.getProperty(), - sensitivePropertyProviderFactory, - protectionSchemeResolver + provider.getProperty() ); continue; } final Authorizer instance = authorizers.get(provider.getIdentifier()); final AuthorizerConfigurationContext configurationContext = getConfigurationContext( provider.getIdentifier(), - provider.getProperty(), - sensitivePropertyProviderFactory, - protectionSchemeResolver + provider.getProperty() ); instance.onConfigured(configurationContext); } @@ -406,40 +381,17 @@ private Authorizer createAuthorizer(final String identifier, final String author private AuthorizerConfigurationContext getConfigurationContext( final String identifier, - final List properties, - final SensitivePropertyProviderFactory sensitivePropertyProviderFactory, - final ProtectionSchemeResolver protectionSchemeResolver + final List properties ) { final Map authorizerProperties = new HashMap<>(); for (final Property property : properties) { - final String encryption = property.getEncryption(); - - if (StringUtils.isBlank(encryption)) { - authorizerProperties.put(property.getName(), property.getValue()); - } else { - final String propertyDecrypted = getPropertyDecrypted(identifier, property, sensitivePropertyProviderFactory, protectionSchemeResolver); - authorizerProperties.put(property.getName(), propertyDecrypted); - } + authorizerProperties.put(property.getName(), property.getValue()); } return new StandardAuthorizerConfigurationContext(identifier, authorizerProperties); } - private String getPropertyDecrypted( - final String providerIdentifier, - final Property property, - final SensitivePropertyProviderFactory sensitivePropertyProviderFactory, - final ProtectionSchemeResolver protectionSchemeResolver - ) { - final String scheme = property.getEncryption(); - final ProtectionScheme protectionScheme = protectionSchemeResolver.getProtectionScheme(scheme); - final SensitivePropertyProvider propertyProvider = sensitivePropertyProviderFactory.getProvider(protectionScheme); - final ProtectedPropertyContext protectedPropertyContext = sensitivePropertyProviderFactory.getPropertyContext(providerIdentifier, property.getName()); - final String protectedProperty = property.getValue(); - return propertyProvider.unprotect(protectedProperty, protectedPropertyContext); - } - private void performMethodInjection(final Object instance, final Class authorizerClass) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { for (final Method method : authorizerClass.getMethods()) { if (method.isAnnotationPresent(AuthorizerContext.class)) { @@ -527,7 +479,7 @@ public boolean isSingleton() { } @Override - public void destroy() throws Exception { + public void destroy() { List errors = new ArrayList<>(); authorizers.forEach((identifier, object) -> { diff --git a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/resources/nifi-context.xml b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/resources/nifi-context.xml index 10f08251e002..0536b5a55946 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/resources/nifi-context.xml +++ b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/resources/nifi-context.xml @@ -18,8 +18,8 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> - - + + diff --git a/nifi-framework-bundle/nifi-framework/nifi-properties-loader/pom.xml b/nifi-framework-bundle/nifi-framework/nifi-properties-loader/pom.xml index a0405a6d65a9..799d4bbc2ffa 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-properties-loader/pom.xml +++ b/nifi-framework-bundle/nifi-framework/nifi-properties-loader/pom.xml @@ -22,22 +22,4 @@ nifi-properties-loader nifi-properties-loader jar - - - org.apache.nifi - nifi-property-protection-api - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-loader - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-factory - 2.0.0-SNAPSHOT - test - - \ No newline at end of file diff --git a/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/main/java/org/apache/nifi/properties/NiFiPropertiesLoader.java b/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/main/java/org/apache/nifi/properties/NiFiPropertiesLoader.java index 57a9aea69698..570bc01b87e0 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/main/java/org/apache/nifi/properties/NiFiPropertiesLoader.java +++ b/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/main/java/org/apache/nifi/properties/NiFiPropertiesLoader.java @@ -16,8 +16,6 @@ */ package org.apache.nifi.properties; -import org.apache.nifi.property.protection.loader.PropertyProtectionURLClassLoader; -import org.apache.nifi.property.protection.loader.PropertyProviderFactoryLoader; import org.apache.nifi.util.NiFiBootstrapUtils; import org.apache.nifi.util.NiFiProperties; import org.slf4j.Logger; @@ -29,8 +27,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -51,73 +47,24 @@ public class NiFiPropertiesLoader { private static final String MIGRATION_INSTRUCTIONS = "See Admin Guide section [Updating the Sensitive Properties Key]"; private static final String PROPERTIES_KEY_MESSAGE = String.format("Sensitive Properties Key [%s] not found: %s", NiFiProperties.SENSITIVE_PROPS_KEY, MIGRATION_INSTRUCTIONS); - private static final String SET_KEY_METHOD = "setKeyHex"; - private final String defaultPropertiesFilePath = NiFiBootstrapUtils.getDefaultApplicationPropertiesFilePath(); - private NiFiProperties instance; - private String keyHex; - public NiFiPropertiesLoader() { - } + private NiFiProperties instance; - /** - * Returns an instance of the loader configured with the key. - *

- *

- * NOTE: This method is used reflectively by the process which starts NiFi - * so changes to it must be made in conjunction with that mechanism.

- * - * @param keyHex the key used to encrypt any sensitive properties - * @return the configured loader - */ - public static NiFiPropertiesLoader withKey(final String keyHex) { + public static NiFiProperties load() { final NiFiPropertiesLoader loader = new NiFiPropertiesLoader(); - loader.setKeyHex(keyHex); - return loader; - } - - /** - * Sets the hexadecimal key used to unprotect properties encrypted with a - * {@link SensitivePropertyProvider}. If the key has already been set, - * calling this method will throw a {@link RuntimeException}. - * - * @param keyHex the key in hexadecimal format - */ - public void setKeyHex(final String keyHex) { - if (this.keyHex == null || this.keyHex.trim().isEmpty()) { - this.keyHex = keyHex; - } else { - throw new RuntimeException("Cannot overwrite an existing key"); - } + return loader.loadDefault(); } /** - * Returns a {@link NiFiProperties} instance with any encrypted properties - * decrypted using the key from the {@code conf/bootstrap.conf} file. This - * method is exposed to allow Spring factory-method loading at application - * startup. - * - * @return the populated and decrypted NiFiProperties instance - */ - public static NiFiProperties loadDefaultWithKeyFromBootstrap() { - try { - return new NiFiPropertiesLoader().loadDefault(); - } catch (Exception e) { - logger.warn("Encountered an error naively loading the nifi.properties file because one or more properties are protected: {}", e.getLocalizedMessage()); - throw e; - } - } - - /** - * Returns a {@link ProtectedNiFiProperties} instance loaded from the + * Returns properties loaded from the * serialized form in the file. Responsible for actually reading from disk - * and deserializing the properties. Returns a protected instance to allow - * for decryption operations. + * and deserializing the properties. * * @param file the file containing serialized properties - * @return the ProtectedNiFiProperties instance + * @return Application Properties */ - ProtectedNiFiProperties loadProtectedProperties(final File file) { + NiFiProperties loadProperties(final File file) { if (file == null || !file.exists() || !file.canRead()) { throw new IllegalArgumentException(String.format("Application Properties [%s] not found", file)); } @@ -145,45 +92,18 @@ ProtectedNiFiProperties loadProtectedProperties(final File file) { properties.setProperty(key, property.trim()); } - return new ProtectedNiFiProperties(properties); + return new NiFiProperties(properties); } /** * Returns an instance of {@link NiFiProperties} loaded from the provided - * {@link File}. If any properties are protected, will attempt to use the - * appropriate {@link SensitivePropertyProvider} to unprotect them - * transparently. + * {@link File} * * @param file the File containing the serialized properties * @return the NiFiProperties instance */ public NiFiProperties load(final File file) { - final ProtectedNiFiProperties protectedProperties = loadProtectedProperties(file); - final NiFiProperties properties; - - if (protectedProperties.hasProtectedKeys()) { - final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); - - try { - final PropertyProtectionURLClassLoader protectionClassLoader = new PropertyProtectionURLClassLoader(contextClassLoader); - Thread.currentThread().setContextClassLoader(protectionClassLoader); - - final PropertyProviderFactoryLoader factoryLoader = new PropertyProviderFactoryLoader(); - final SensitivePropertyProviderFactory providerFactory = factoryLoader.getPropertyProviderFactory(); - setBootstrapKey(providerFactory); - providerFactory.getSupportedProviders().forEach(protectedProperties::addSensitivePropertyProvider); - - properties = protectedProperties.getUnprotectedProperties(); - - providerFactory.getSupportedProviders().forEach(SensitivePropertyProvider::cleanUp); - } finally { - Thread.currentThread().setContextClassLoader(contextClassLoader); - } - } else { - properties = protectedProperties.getUnprotectedProperties(); - } - - return properties; + return loadProperties(file); } /** @@ -230,13 +150,13 @@ private NiFiProperties getDefaultProperties() { if (isKeyGenerationRequired(defaultProperties)) { if (defaultProperties.isClustered()) { logger.error("Clustered Configuration Found: Shared Sensitive Properties Key [{}] required for cluster nodes", NiFiProperties.SENSITIVE_PROPS_KEY); - throw new SensitivePropertyProtectionException(PROPERTIES_KEY_MESSAGE); + throw new IllegalStateException(PROPERTIES_KEY_MESSAGE); } final File flowConfigurationFile = defaultProperties.getFlowConfigurationFile(); if (flowConfigurationFile.exists()) { logger.error("Flow Configuration [{}] Found: Migration Required for blank Sensitive Properties Key [{}]", flowConfigurationFile, NiFiProperties.SENSITIVE_PROPS_KEY); - throw new SensitivePropertyProtectionException(PROPERTIES_KEY_MESSAGE); + throw new IllegalStateException(PROPERTIES_KEY_MESSAGE); } setSensitivePropertiesKey(); @@ -275,25 +195,6 @@ private static boolean isKeyGenerationRequired(final NiFiProperties properties) return (configuredSensitivePropertiesKey == null || configuredSensitivePropertiesKey.length() == 0); } - private void setBootstrapKey(final SensitivePropertyProviderFactory providerFactory) { - if (keyHex == null) { - logger.debug("Bootstrap Sensitive Key not configured"); - } else { - final Class factoryClass = providerFactory.getClass(); - try { - // Set Bootstrap Key using reflection to preserve ClassLoader isolation - final Method setMethod = factoryClass.getMethod(SET_KEY_METHOD, String.class); - setMethod.invoke(providerFactory, keyHex); - } catch (final NoSuchMethodException e) { - logger.warn("Method [{}] on Class [{}] not found", SET_KEY_METHOD, factoryClass.getName()); - } catch (final IllegalAccessException e) { - logger.warn("Method [{}] on Class [{}] access not allowed", SET_KEY_METHOD, factoryClass.getName()); - } catch (final InvocationTargetException e) { - throw new SensitivePropertyProtectionException("Set Bootstrap Key on Provider Factory failed", e); - } - } - } - private static class DuplicateDetectingProperties extends Properties { // Only need to retain Properties key. This will help prevent possible inadvertent exposure of sensitive Properties value private final Set duplicateKeys = new HashSet<>(); // duplicate key with different values diff --git a/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/main/java/org/apache/nifi/properties/ProtectedNiFiProperties.java b/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/main/java/org/apache/nifi/properties/ProtectedNiFiProperties.java deleted file mode 100644 index 5ff662aa70ab..000000000000 --- a/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/main/java/org/apache/nifi/properties/ProtectedNiFiProperties.java +++ /dev/null @@ -1,228 +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.properties; - -import org.apache.nifi.util.NiFiProperties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; - -import static java.util.Arrays.asList; - -/** - * Decorator class for intermediate phase when {@link NiFiPropertiesLoader} loads the - * raw properties file and performs unprotection activities before returning a clean - * implementation of {@link NiFiProperties}. - * This encapsulates the sensitive property access logic from external consumers - * of {@code NiFiProperties}. - */ -public class ProtectedNiFiProperties extends NiFiProperties implements ProtectedProperties, - SensitivePropertyProtector { - private static final Logger logger = LoggerFactory.getLogger(ProtectedNiFiProperties.class); - - private final SensitivePropertyProtector propertyProtectionDelegate; - - private NiFiProperties applicationProperties; - - // Additional "sensitive" property key - public static final String ADDITIONAL_SENSITIVE_PROPERTIES_KEY = "nifi.sensitive.props.additional.keys"; - - // Default list of "sensitive" property keys - public static final List DEFAULT_SENSITIVE_PROPERTIES = new ArrayList<>(asList( - SECURITY_KEY_PASSWD, - SECURITY_KEYSTORE_PASSWD, - SECURITY_TRUSTSTORE_PASSWD, - SENSITIVE_PROPS_KEY, - REPOSITORY_ENCRYPTION_KEY_PROVIDER_KEYSTORE_PASSWORD, - SECURITY_USER_OIDC_CLIENT_SECRET - )); - - public ProtectedNiFiProperties() { - this(new NiFiProperties()); - } - - /** - * Creates an instance containing the provided {@link NiFiProperties}. - * - * @param props the NiFiProperties to contain - */ - public ProtectedNiFiProperties(final NiFiProperties props) { - this.applicationProperties = props; - this.propertyProtectionDelegate = new ApplicationPropertiesProtector<>(this); - logger.debug("Loaded {} properties (including {} protection schemes) into ProtectedNiFiProperties", getApplicationProperties() - .getPropertyKeys().size(), getProtectedPropertyKeys().size()); - } - - /** - * Creates an instance containing the provided raw {@link Properties}. - * - * @param rawProps the Properties to contain - */ - public ProtectedNiFiProperties(final Properties rawProps) { - this(new NiFiProperties(rawProps)); - } - - @Override - public String getAdditionalSensitivePropertiesKeys() { - return getProperty(getAdditionalSensitivePropertiesKeysName()); - } - - @Override - public String getAdditionalSensitivePropertiesKeysName() { - return ADDITIONAL_SENSITIVE_PROPERTIES_KEY; - } - - @Override - public List getDefaultSensitiveProperties() { - return DEFAULT_SENSITIVE_PROPERTIES; - } - - /** - * Returns the internal representation of the {@link NiFiProperties} -- protected - * or not as determined by the current state. No guarantee is made to the - * protection state of these properties. If the internal reference is null, a new - * {@link NiFiProperties} instance is created. - * - * @return the internal properties - */ - public NiFiProperties getApplicationProperties() { - if (this.applicationProperties == null) { - this.applicationProperties = new NiFiProperties(); - } - - return this.applicationProperties; - } - - @Override - public NiFiProperties createApplicationProperties(final Properties rawProperties) { - return new NiFiProperties(rawProperties); - } - - /** - * Retrieves the property value for the given property key. - * - * @param key the key of property value to lookup - * @return value of property at given key or null if not found - */ - @Override - public String getProperty(String key) { - return getApplicationProperties().getProperty(key); - } - - /** - * Retrieves all known property keys. - * - * @return all known property keys - */ - @Override - public Set getPropertyKeys() { - return propertyProtectionDelegate.getPropertyKeys(); - } - - /** - * Returns the number of properties, excluding protection scheme properties. - *

- * Example: - *

- * key: E(value, key) - * key.protected: aes/gcm/256 - * key2: value2 - *

- * would return size 2 - * - * @return the count of real properties - */ - @Override - public int size() { - return propertyProtectionDelegate.size(); - } - - @Override - public Set getPropertyKeysIncludingProtectionSchemes() { - return propertyProtectionDelegate.getPropertyKeysIncludingProtectionSchemes(); - } - - @Override - public List getSensitivePropertyKeys() { - return propertyProtectionDelegate.getSensitivePropertyKeys(); - } - - @Override - public List getPopulatedSensitivePropertyKeys() { - return propertyProtectionDelegate.getPopulatedSensitivePropertyKeys(); - } - - @Override - public boolean hasProtectedKeys() { - return propertyProtectionDelegate.hasProtectedKeys(); - } - - @Override - public Map getProtectedPropertyKeys() { - return propertyProtectionDelegate.getProtectedPropertyKeys(); - } - - @Override - public boolean isPropertySensitive(final String key) { - return propertyProtectionDelegate.isPropertySensitive(key); - } - - @Override - public boolean isPropertyProtected(final String key) { - return propertyProtectionDelegate.isPropertyProtected(key); - } - - @Override - public NiFiProperties getUnprotectedProperties() throws SensitivePropertyProtectionException { - return propertyProtectionDelegate.getUnprotectedProperties(); - } - - @Override - public void addSensitivePropertyProvider(final SensitivePropertyProvider sensitivePropertyProvider) { - propertyProtectionDelegate.addSensitivePropertyProvider(sensitivePropertyProvider); - } - - /** - * Returns the number of properties that are marked as protected in the provided {@link NiFiProperties} instance without requiring external creation of a {@link ProtectedNiFiProperties} instance. - * - * @param plainProperties the instance to count protected properties - * @return the number of protected properties - */ - public static int countProtectedProperties(final NiFiProperties plainProperties) { - return new ProtectedNiFiProperties(plainProperties).getProtectedPropertyKeys().size(); - } - - /** - * Returns the number of properties that are marked as sensitive in the provided {@link NiFiProperties} instance without requiring external creation of a {@link ProtectedNiFiProperties} instance. - * - * @param plainProperties the instance to count sensitive properties - * @return the number of sensitive properties - */ - public static int countSensitiveProperties(final NiFiProperties plainProperties) { - return new ProtectedNiFiProperties(plainProperties).getSensitivePropertyKeys().size(); - } - - @Override - public String toString() { - return String.format("%s Size [%d]", getClass().getSimpleName(), size()); - } -} diff --git a/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/java/org/apache/nifi/properties/NiFiPropertiesLoaderTest.java b/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/java/org/apache/nifi/properties/NiFiPropertiesLoaderTest.java index 835e1f71296a..a7246ccc7a60 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/java/org/apache/nifi/properties/NiFiPropertiesLoaderTest.java +++ b/nifi-framework-bundle/nifi-framework/nifi-properties-loader/src/test/java/org/apache/nifi/properties/NiFiPropertiesLoaderTest.java @@ -22,7 +22,6 @@ import java.net.URL; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -32,12 +31,8 @@ class NiFiPropertiesLoaderTest { private static final String EMPTY_PATH = "/properties/conf/empty.nifi.properties"; private static final String FLOW_PATH = "/properties/conf/flow.nifi.properties"; - private static final String PROTECTED_PATH = "/properties/conf/protected.nifi.properties"; private static final String DUPLICATE_PROPERTIES_PATH = "/properties/conf/duplicates.nifi.properties"; - private static final String HEXADECIMAL_KEY = "12345678123456788765432187654321"; - private static final String EXPECTED_PASSWORD = "propertyValue"; - @AfterEach void clearSystemProperty() { System.clearProperty(NiFiProperties.PROPERTIES_FILE_PATH); @@ -52,10 +47,11 @@ void testDuplicateProperties() { System.setProperty(NiFiProperties.PROPERTIES_FILE_PATH, path); - final NiFiPropertiesLoader loader = NiFiPropertiesLoader.withKey(String.class.getSimpleName()); + final NiFiPropertiesLoader loader = new NiFiPropertiesLoader(); Exception exception = assertThrows(IllegalArgumentException.class, () -> { final NiFiProperties properties = loader.get(); + assertNotNull(properties); }); String expectedMessage = "Duplicate property keys with different values were detected in the properties file: another.duplicate, nifi.flow.configuration.file"; @@ -89,7 +85,7 @@ void testGetProperties() { } @Test - void testGetPropertiesWithKeyNoEncryptedProperties() { + void testGetPropertiesNoEncryptedProperties() { final URL resource = NiFiPropertiesLoaderTest.class.getResource(FLOW_PATH); assertNotNull(resource); @@ -97,7 +93,7 @@ void testGetPropertiesWithKeyNoEncryptedProperties() { System.setProperty(NiFiProperties.PROPERTIES_FILE_PATH, path); - final NiFiPropertiesLoader loader = NiFiPropertiesLoader.withKey(String.class.getSimpleName()); + final NiFiPropertiesLoader loader = new NiFiPropertiesLoader(); final NiFiProperties properties = loader.get(); @@ -105,36 +101,6 @@ void testGetPropertiesWithKeyNoEncryptedProperties() { assertNotNull(properties.getFlowConfigurationFile()); } - @Test - void testLoadWithKey() { - final NiFiPropertiesLoader loader = NiFiPropertiesLoader.withKey(HEXADECIMAL_KEY); - - final URL resource = NiFiPropertiesLoaderTest.class.getResource(PROTECTED_PATH); - assertNotNull(resource); - final String path = resource.getPath(); - - final NiFiProperties properties = loader.load(path); - - assertNotNull(properties); - - assertNotNull(properties.getFlowConfigurationFile()); - assertEquals(EXPECTED_PASSWORD, properties.getProperty(NiFiProperties.SECURITY_KEYSTORE_PASSWD)); - } - - @Test - void testLoadWithDefaultKeyFromBootstrap() { - final URL resource = NiFiPropertiesLoaderTest.class.getResource(FLOW_PATH); - assertNotNull(resource); - - final String path = resource.getPath(); - - System.setProperty(NiFiProperties.PROPERTIES_FILE_PATH, path); - - final NiFiProperties properties = NiFiPropertiesLoader.loadDefaultWithKeyFromBootstrap(); - - assertNotNull(properties); - } - @Test void testLoadDefaultNotFound() { final NiFiPropertiesLoader loader = new NiFiPropertiesLoader(); diff --git a/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/bootstrap-aws.conf b/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/bootstrap-aws.conf deleted file mode 100644 index f624dec9b1ac..000000000000 --- a/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/bootstrap-aws.conf +++ /dev/null @@ -1,27 +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. -# - -# AWS KMS Key ID is required to be configured for AWS KMS Sensitive Property Provider -aws.kms.key.id= - -# NiFi uses the following properties when authentication to AWS when all values are provided. -# NiFi uses the default AWS credentials provider chain when one or more or the following properties are blank -# AWS SDK documentation describes the default credential retrieval order: -# https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/credentials.html#credentials-chain -aws.access.key.id= -aws.secret.access.key= -aws.region= diff --git a/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/bootstrap-azure.conf b/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/bootstrap-azure.conf deleted file mode 100644 index 49e318eaad9a..000000000000 --- a/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/bootstrap-azure.conf +++ /dev/null @@ -1,24 +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. -# - -# Key Identifier for Azure Key Vault Key Sensitive Property Provider -azure.keyvault.key.id= -# Encryption Algorithm for Azure Key Vault Key Sensitive Property Provider -azure.keyvault.encryption.algorithm= - -# Vault URI for Azure Key Vault Secret Sensitive Property Provider -azure.keyvault.uri= diff --git a/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/bootstrap-gcp.conf b/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/bootstrap-gcp.conf deleted file mode 100644 index 440dad2360e9..000000000000 --- a/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/bootstrap-gcp.conf +++ /dev/null @@ -1,22 +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. -# - -# These GCP KMS settings must all be configured in order to use the GCP KMS Sensitive Property Provider -gcp.kms.project= -gcp.kms.location= -gcp.kms.keyring= -gcp.kms.key= \ No newline at end of file diff --git a/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/bootstrap-hashicorp-vault.conf b/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/bootstrap-hashicorp-vault.conf deleted file mode 100644 index bf6975b962f2..000000000000 --- a/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/bootstrap-hashicorp-vault.conf +++ /dev/null @@ -1,53 +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. -# - -# HTTP or HTTPS URI for HashiCorp Vault is required to enable the Sensitive Properties Provider -vault.uri= - -# Transit Path is required to enable the Sensitive Properties Provider Protection Scheme 'hashicorp/vault/transit/{path}' -vault.transit.path= - -# Key/Value Path is required to enable the Sensitive Properties Provider Protection Scheme 'hashicorp/vault/kv/{path}' -vault.kv.path= -# Key/Value Secrets Engine version may be 1 or 2, and defaults to 1 -# vault.kv.version=1 - -# Token Authentication example properties -# vault.authentication=TOKEN -# vault.token= - -# Optional file supports authentication properties described in the Spring Vault Environment Configuration -# https://docs.spring.io/spring-vault/docs/2.3.x/reference/html/#vault.core.environment-vault-configuration -# -# All authentication properties must be included in bootstrap-hashicorp-vault.conf when this property is not specified. -# Properties in bootstrap-hashicorp-vault.conf take precedence when the same values are defined in both files. -# Token Authentication is the default when the 'vault.authentication' property is not specified. -vault.authentication.properties.file= - -# Optional Timeout properties -vault.connection.timeout=5 secs -vault.read.timeout=15 secs - -# Optional TLS properties -vault.ssl.enabledCipherSuites= -vault.ssl.enabledProtocols= -vault.ssl.key-store= -vault.ssl.key-store-type= -vault.ssl.key-store-password= -vault.ssl.trust-store= -vault.ssl.trust-store-type= -vault.ssl.trust-store-password= diff --git a/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/bootstrap.conf b/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/bootstrap.conf index 7da2c3c259fc..53094181b79b 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/bootstrap.conf +++ b/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/bootstrap.conf @@ -61,22 +61,5 @@ java.arg.securityAuthUseSubjectCredsOnly=-Djavax.security.auth.useSubjectCredsOn # org.apache.jasper.servlet.JasperLoader,org.jvnet.hk2.internal.DelegatingClassLoader,org.apache.nifi.nar.NarClassLoader # End of Java Agent config for native library loading. -# Root key in hexadecimal format for encrypted sensitive configuration values -nifi.bootstrap.sensitive.key= - -# Sensitive Property Provider configuration - -# HashiCorp Vault Sensitive Property Providers -#nifi.bootstrap.protection.hashicorp.vault.conf=./conf/bootstrap-hashicorp-vault.conf - -# AWS Sensitive Property Providers -#nifi.bootstrap.protection.aws.conf=./conf/bootstrap-aws.conf - -# Azure Key Vault Sensitive Property Providers -#nifi.bootstrap.protection.azure.keyvault.conf=./conf/bootstrap-azure.conf - -# GCP KMS Sensitive Property Providers -#nifi.bootstrap.protection.gcp.kms.conf=./conf/bootstrap-gcp.conf - # Port used to listen for communications from NiFi. If this property is missing, empty, or 0, a random ephemeral port is used. nifi.bootstrap.listen.port=0 diff --git a/nifi-framework-bundle/nifi-framework/nifi-runtime/pom.xml b/nifi-framework-bundle/nifi-framework/nifi-runtime/pom.xml index ab7dabd8fff9..14724d10c58a 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-runtime/pom.xml +++ b/nifi-framework-bundle/nifi-framework/nifi-runtime/pom.xml @@ -50,18 +50,6 @@ 2.0.0-SNAPSHOT test - - org.apache.nifi - nifi-property-protection-loader - 2.0.0-SNAPSHOT - test - - - org.apache.nifi - nifi-property-protection-factory - 2.0.0-SNAPSHOT - test - org.apache.commons commons-lang3 diff --git a/nifi-framework-bundle/nifi-framework/nifi-runtime/src/main/java/org/apache/nifi/NiFi.java b/nifi-framework-bundle/nifi-framework/nifi-runtime/src/main/java/org/apache/nifi/NiFi.java index 270d0603d005..d7b6968ab166 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-runtime/src/main/java/org/apache/nifi/NiFi.java +++ b/nifi-framework-bundle/nifi-framework/nifi-runtime/src/main/java/org/apache/nifi/NiFi.java @@ -346,32 +346,18 @@ protected static NiFiProperties convertArgumentsToValidatedNiFiProperties(String } private static NiFiProperties initializeProperties(final String[] args, final ClassLoader boostrapLoader) { - // Try to get key - // If key doesn't exist, instantiate without - // Load properties - // If properties are protected and key missing, throw RuntimeException - final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); - final String key; - try { - key = loadFormattedKey(args); - // The key might be empty or null when it is passed to the loader - } catch (IllegalArgumentException e) { - final String msg = "The bootstrap process did not provide a valid key"; - throw new IllegalArgumentException(msg, e); - } Thread.currentThread().setContextClassLoader(boostrapLoader); try { final Class propsLoaderClass = Class.forName("org.apache.nifi.properties.NiFiPropertiesLoader", true, boostrapLoader); - final Method withKeyMethod = propsLoaderClass.getMethod("withKey", String.class); - final Object loaderInstance = withKeyMethod.invoke(null, key); + final Object loaderInstance = propsLoaderClass.getConstructor().newInstance(); final Method getMethod = propsLoaderClass.getMethod("get"); final NiFiProperties properties = (NiFiProperties) getMethod.invoke(loaderInstance); LOGGER.info("Application Properties loaded [{}]", properties.size()); return properties; - } catch (InvocationTargetException wrappedException) { - final String msg = "There was an issue decrypting protected properties"; + } catch (final InstantiationException | InvocationTargetException wrappedException) { + final String msg = "There was an issue loading properties"; throw new IllegalArgumentException(msg, wrappedException.getCause() == null ? wrappedException : wrappedException.getCause()); } catch (final IllegalAccessException | NoSuchMethodException | ClassNotFoundException reex) { final String msg = "Unable to access properties loader in the expected manner - apparent classpath or build issue"; diff --git a/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/resources/NiFiProperties/conf/bootstrap.conf b/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/resources/NiFiProperties/conf/bootstrap.conf index e743fadac095..7a3a892903a4 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/resources/NiFiProperties/conf/bootstrap.conf +++ b/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/resources/NiFiProperties/conf/bootstrap.conf @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -nifi.bootstrap.sensitive.key=0000000000000000000000000000000000000000000000000000000000000000 + diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml index 0209d3fe2218..8f1f9b2991a4 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml +++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml @@ -140,16 +140,6 @@ nifi-framework-authorization-providers 2.0.0-SNAPSHOT - - org.apache.nifi - nifi-property-protection-api - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-loader - 2.0.0-SNAPSHOT - org.apache.nifi nifi-utils @@ -316,14 +306,6 @@ mockwebserver test - - org.apache.nifi - nifi-property-protection-factory - 2.0.0-SNAPSHOT - test - - - org.apache.nifi nifi-python-framework-api diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/spring/LoginIdentityProviderFactoryBean.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/spring/LoginIdentityProviderFactoryBean.java index f5233bf68fdb..c5ce3935cc66 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/spring/LoginIdentityProviderFactoryBean.java +++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/spring/LoginIdentityProviderFactoryBean.java @@ -49,14 +49,6 @@ import org.apache.nifi.bundle.Bundle; import org.apache.nifi.nar.ExtensionManager; import org.apache.nifi.nar.NarCloseable; -import org.apache.nifi.properties.ProtectedPropertyContext; -import org.apache.nifi.properties.SensitivePropertyProvider; -import org.apache.nifi.properties.SensitivePropertyProviderFactory; -import org.apache.nifi.properties.scheme.ProtectionScheme; -import org.apache.nifi.properties.scheme.ProtectionSchemeResolver; -import org.apache.nifi.property.protection.loader.PropertyProtectionURLClassLoader; -import org.apache.nifi.property.protection.loader.PropertyProviderFactoryLoader; -import org.apache.nifi.property.protection.loader.ProtectionSchemeResolverLoader; import org.apache.nifi.util.NiFiProperties; import org.apache.nifi.xml.processing.stream.StandardXMLStreamReaderProvider; import org.apache.nifi.xml.processing.stream.XMLStreamReaderProvider; @@ -209,64 +201,24 @@ private LoginIdentityProvider createLoginIdentityProvider(final String identifie } private void loadProviderProperties(final LoginIdentityProviders loginIdentityProviderConfiguration) { - final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); - - try { - final PropertyProtectionURLClassLoader protectionClassLoader = new PropertyProtectionURLClassLoader(contextClassLoader); - Thread.currentThread().setContextClassLoader(protectionClassLoader); - - final ProtectionSchemeResolverLoader resolverLoader = new ProtectionSchemeResolverLoader(); - final ProtectionSchemeResolver protectionSchemeResolver = resolverLoader.getProtectionSchemeResolver(); - - final PropertyProviderFactoryLoader factoryLoader = new PropertyProviderFactoryLoader(); - final SensitivePropertyProviderFactory sensitivePropertyProviderFactory = factoryLoader.getPropertyProviderFactory(); - - for (final Provider provider : loginIdentityProviderConfiguration.getProvider()) { - final LoginIdentityProvider instance = loginIdentityProviders.get(provider.getIdentifier()); - final LoginIdentityProviderConfigurationContext configurationContext = getConfigurationContext(provider, sensitivePropertyProviderFactory, protectionSchemeResolver); - instance.onConfigured(configurationContext); - } - } finally { - Thread.currentThread().setContextClassLoader(contextClassLoader); + for (final Provider provider : loginIdentityProviderConfiguration.getProvider()) { + final LoginIdentityProvider instance = loginIdentityProviders.get(provider.getIdentifier()); + final LoginIdentityProviderConfigurationContext configurationContext = getConfigurationContext(provider); + instance.onConfigured(configurationContext); } } - private LoginIdentityProviderConfigurationContext getConfigurationContext( - final Provider provider, - final SensitivePropertyProviderFactory sensitivePropertyProviderFactory, - final ProtectionSchemeResolver protectionSchemeResolver - ) { + private LoginIdentityProviderConfigurationContext getConfigurationContext(final Provider provider) { final String providerIdentifier = provider.getIdentifier(); final Map providerProperties = new HashMap<>(); for (final Property property : provider.getProperty()) { - final String encryption = property.getEncryption(); - - if (StringUtils.isBlank(encryption)) { - providerProperties.put(property.getName(), property.getValue()); - } else { - final String propertyDecrypted = getPropertyDecrypted(providerIdentifier, property, sensitivePropertyProviderFactory, protectionSchemeResolver); - providerProperties.put(property.getName(), propertyDecrypted); - } + providerProperties.put(property.getName(), property.getValue()); } return new StandardLoginIdentityProviderConfigurationContext(providerIdentifier, providerProperties); } - private String getPropertyDecrypted( - final String providerIdentifier, - final Property property, - final SensitivePropertyProviderFactory sensitivePropertyProviderFactory, - final ProtectionSchemeResolver protectionSchemeResolver - ) { - final String scheme = property.getEncryption(); - final ProtectionScheme protectionScheme = protectionSchemeResolver.getProtectionScheme(scheme); - final SensitivePropertyProvider propertyProvider = sensitivePropertyProviderFactory.getProvider(protectionScheme); - final ProtectedPropertyContext protectedPropertyContext = sensitivePropertyProviderFactory.getPropertyContext(providerIdentifier, property.getName()); - final String protectedProperty = property.getValue(); - return propertyProvider.unprotect(protectedProperty, protectedPropertyContext); - } - private void performMethodInjection(final LoginIdentityProvider instance, final Class loginIdentityProviderClass) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { diff --git a/nifi-registry/nifi-registry-assembly/pom.xml b/nifi-registry/nifi-registry-assembly/pom.xml index eeda2d23cec2..69b5055c2595 100644 --- a/nifi-registry/nifi-registry-assembly/pom.xml +++ b/nifi-registry/nifi-registry-assembly/pom.xml @@ -145,7 +145,6 @@ runtime zip - org.apache.nifi.registry nifi-registry-properties-loader diff --git a/nifi-registry/nifi-registry-assembly/src/main/assembly/dependencies.xml b/nifi-registry/nifi-registry-assembly/src/main/assembly/dependencies.xml index 70fcae0f4452..29e2dabe034c 100644 --- a/nifi-registry/nifi-registry-assembly/src/main/assembly/dependencies.xml +++ b/nifi-registry/nifi-registry-assembly/src/main/assembly/dependencies.xml @@ -54,20 +54,6 @@ - - - runtime - false - lib/spp - 0770 - 0664 - true - - *:nifi-registry-properties-loader - software.amazon.awssdk:* - - - runtime @@ -82,7 +68,6 @@ *:nifi-registry-utils *:nifi-registry-docs *:nifi-registry-aws-assembly - *:nifi-registry-properties-loader diff --git a/nifi-registry/nifi-registry-core/nifi-registry-docs/src/main/asciidoc/administration-guide.adoc b/nifi-registry/nifi-registry-core/nifi-registry-docs/src/main/asciidoc/administration-guide.adoc index d4cf51ce8aad..deced57fc712 100644 --- a/nifi-registry/nifi-registry-core/nifi-registry-docs/src/main/asciidoc/administration-guide.adoc +++ b/nifi-registry/nifi-registry-core/nifi-registry-docs/src/main/asciidoc/administration-guide.adoc @@ -949,9 +949,6 @@ Here, we will address the different properties that are made available in the fi |`conf.dir`|The `conf` directory to use for NiFi Registry. By default, this is set to `./conf` |`graceful.shutdown.seconds`|When NiFi Registry is instructed to shutdown, the Bootstrap will wait this number of seconds for the process to shutdown cleanly. At this amount of time, if the service is still running, the Bootstrap will `kill` the process, or terminate it abruptly. By default, this is set to `20`. |`java.arg.N`|Any number of JVM arguments can be passed to the NiFi Registry JVM when the process is started. These arguments are defined by adding properties to _bootstrap.conf_ that begin with `java.arg.`. The rest of the property name is not relevant, other than to different property names, and will be ignored. The default includes properties for minimum and maximum Java Heap size, the garbage collector to use, etc. -|`nifi.registry.bootstrap.sensitive.key`|The root key (in hexadecimal format) for encrypted sensitive configuration values. When NiFi Registry is started, this root key is used to decrypt sensitive values from the _nifi-registry.properties_ file into memory for later use. - -The <> can be used to specify the root key, encrypt sensitive values in _nifi-registry.properties_ and update _bootstrap.conf_. |==== diff --git a/nifi-registry/nifi-registry-core/nifi-registry-framework/pom.xml b/nifi-registry/nifi-registry-core/nifi-registry-framework/pom.xml index b4580e186142..2f005b1282e2 100644 --- a/nifi-registry/nifi-registry-core/nifi-registry-framework/pom.xml +++ b/nifi-registry/nifi-registry-core/nifi-registry-framework/pom.xml @@ -148,10 +148,6 @@ nifi-registry-data-model 2.0.0-SNAPSHOT - - org.apache.nifi - nifi-property-protection-factory - org.apache.nifi.registry nifi-registry-properties @@ -413,11 +409,6 @@ 7.0.0 test - - org.apache.nifi - nifi-property-protection-api - 2.0.0-SNAPSHOT - jakarta.xml.bind jakarta.xml.bind-api diff --git a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authentication/IdentityProviderFactory.java b/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authentication/IdentityProviderFactory.java index e70d25304aa2..09fc6216e299 100644 --- a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authentication/IdentityProviderFactory.java +++ b/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authentication/IdentityProviderFactory.java @@ -33,10 +33,6 @@ import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import org.apache.commons.lang3.StringUtils; -import org.apache.nifi.properties.SensitivePropertyProtectionException; -import org.apache.nifi.properties.SensitivePropertyProvider; -import org.apache.nifi.properties.SensitivePropertyProviderFactory; -import org.apache.nifi.properties.scheme.StandardProtectionScheme; import org.apache.nifi.registry.extension.ExtensionManager; import org.apache.nifi.registry.properties.NiFiRegistryProperties; import org.apache.nifi.registry.security.authentication.annotation.IdentityProviderContext; @@ -50,7 +46,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; -import org.springframework.lang.Nullable; import org.xml.sax.SAXException; @Configuration @@ -69,18 +64,16 @@ private static JAXBContext initializeJaxbContext() { private final NiFiRegistryProperties properties; private final ExtensionManager extensionManager; - private final SensitivePropertyProviderFactory sensitivePropertyProviderFactory; private IdentityProvider identityProvider; private final Map identityProviders = new HashMap<>(); @Autowired public IdentityProviderFactory( final NiFiRegistryProperties properties, - final ExtensionManager extensionManager, - @Nullable final SensitivePropertyProviderFactory sensitivePropertyProviderFactory) { + final ExtensionManager extensionManager + ) { this.properties = properties; this.extensionManager = extensionManager; - this.sensitivePropertyProviderFactory = sensitivePropertyProviderFactory; if (this.properties == null) { throw new IllegalStateException("NiFiRegistryProperties cannot be null"); @@ -190,12 +183,7 @@ private IdentityProviderConfigurationContext loadLoginIdentityProviderConfigurat final Map providerProperties = new HashMap<>(); for (final Property property : provider.getProperty()) { - if (!StringUtils.isBlank(property.getEncryption())) { - String decryptedValue = decryptValue(property.getValue(), property.getEncryption(), property.getName(), provider.getIdentifier()); - providerProperties.put(property.getName(), decryptedValue); - } else { - providerProperties.put(property.getName(), property.getValue()); - } + providerProperties.put(property.getName(), property.getValue()); } return new StandardIdentityProviderConfigurationContext(provider.getIdentifier(), this, providerProperties); @@ -254,20 +242,4 @@ private void performFieldInjection(final IdentityProvider instance, final Class< performFieldInjection(instance, parentClass); } } - - private String decryptValue(final String cipherText, final String encryptionScheme, final String propertyName, final String groupIdentifier) throws SensitivePropertyProtectionException { - if (sensitivePropertyProviderFactory == null) { - throw new SensitivePropertyProtectionException("Sensitive Property Provider Factory dependency was never wired, so protected " + - "properties cannot be decrypted. This usually indicates that a master key for this NiFi Registry was not " + - "detected and configured during the bootstrap startup sequence. Contact the system administrator."); - } - try { - final SensitivePropertyProvider sensitivePropertyProvider = sensitivePropertyProviderFactory.getProvider(new StandardProtectionScheme(encryptionScheme)); - return sensitivePropertyProvider.unprotect(cipherText, sensitivePropertyProviderFactory.getPropertyContext(groupIdentifier, propertyName)); - } catch (final IllegalArgumentException e) { - throw new SensitivePropertyProtectionException(String.format("Identity Provider configuration XML was protected using %s, which is not supported. " + - "Cannot configure this Identity Provider due to failing to decrypt protected configuration properties.", encryptionScheme)); - } - } - } diff --git a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/AuthorizerFactory.java b/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/AuthorizerFactory.java index 6c0c8bc2caa5..4c0f41d60f25 100644 --- a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/AuthorizerFactory.java +++ b/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/AuthorizerFactory.java @@ -42,10 +42,6 @@ import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import org.apache.commons.lang3.StringUtils; -import org.apache.nifi.properties.SensitivePropertyProtectionException; -import org.apache.nifi.properties.SensitivePropertyProvider; -import org.apache.nifi.properties.SensitivePropertyProviderFactory; -import org.apache.nifi.properties.scheme.StandardProtectionScheme; import org.apache.nifi.registry.extension.ExtensionClassLoader; import org.apache.nifi.registry.extension.ExtensionCloseable; import org.apache.nifi.registry.extension.ExtensionManager; @@ -69,7 +65,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.lang.Nullable; import org.springframework.transaction.annotation.Transactional; /** @@ -105,7 +100,6 @@ private static JAXBContext initializeJaxbContext() { private final NiFiRegistryProperties properties; private final ExtensionManager extensionManager; - private final SensitivePropertyProviderFactory sensitivePropertyProviderFactory; private final RegistryService registryService; private final DataSource dataSource; private final IdentityMapper identityMapper; @@ -119,14 +113,12 @@ private static JAXBContext initializeJaxbContext() { public AuthorizerFactory( final NiFiRegistryProperties properties, final ExtensionManager extensionManager, - @Nullable final SensitivePropertyProviderFactory sensitivePropertyProviderFactory, final RegistryService registryService, final DataSource dataSource, final IdentityMapper identityMapper) { this.properties = Objects.requireNonNull(properties); this.extensionManager = Objects.requireNonNull(extensionManager); - this.sensitivePropertyProviderFactory = sensitivePropertyProviderFactory; this.registryService = Objects.requireNonNull(registryService); this.dataSource = Objects.requireNonNull(dataSource); this.identityMapper = Objects.requireNonNull(identityMapper); @@ -316,12 +308,7 @@ private AuthorizerConfigurationContext loadAuthorizerConfiguration(final String final Map authorizerProperties = new HashMap<>(); for (final Prop property : properties) { - if (!StringUtils.isBlank(property.getEncryption())) { - String decryptedValue = decryptValue(property.getValue(), property.getEncryption(), property.getName(), identifier); - authorizerProperties.put(property.getName(), decryptedValue); - } else { - authorizerProperties.put(property.getName(), property.getValue()); - } + authorizerProperties.put(property.getName(), property.getValue()); } return new StandardAuthorizerConfigurationContext(identifier, authorizerProperties); } @@ -500,22 +487,6 @@ private void performFieldInjection(final Object instance, final Class authori } } - private String decryptValue(final String cipherText, final String encryptionScheme, final String propertyName, final String groupIdentifier) throws SensitivePropertyProtectionException { - if (sensitivePropertyProviderFactory == null) { - throw new SensitivePropertyProtectionException("Sensitive Property Provider Factory dependency was never wired, so protected " + - "properties cannot be decrypted. This usually indicates that a master key for this NiFi Registry was not " + - "detected and configured during the bootstrap startup sequence. Contact the system administrator."); - } - try { - final SensitivePropertyProvider sensitivePropertyProvider = sensitivePropertyProviderFactory.getProvider(new StandardProtectionScheme(encryptionScheme)); - return sensitivePropertyProvider.unprotect(cipherText, sensitivePropertyProviderFactory.getPropertyContext(groupIdentifier, propertyName)); - } catch (final IllegalArgumentException e) { - throw new SensitivePropertyProtectionException(String.format("Authorizer configuration XML was protected using %s, which is not supported. " + - "Cannot configure this Authorizer due to failing to decrypt protected configuration properties.", encryptionScheme)); - } - } - - /** * @return a default Authorizer to use when running unsecurely with no authorizer configured */ diff --git a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/crypto/SensitivePropertyProviderFactoryConfiguration.java b/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/crypto/SensitivePropertyProviderFactoryConfiguration.java deleted file mode 100644 index 2e0d23e618c3..000000000000 --- a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/crypto/SensitivePropertyProviderFactoryConfiguration.java +++ /dev/null @@ -1,69 +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.registry.security.crypto; - -import org.apache.nifi.properties.SensitivePropertyProtectionException; -import org.apache.nifi.properties.SensitivePropertyProviderFactory; -import org.apache.nifi.properties.StandardSensitivePropertyProviderFactory; -import org.apache.nifi.registry.properties.util.NiFiRegistryBootstrapUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import java.io.IOException; - -@Configuration -public class SensitivePropertyProviderFactoryConfiguration { - private static final Logger logger = LoggerFactory.getLogger(SensitivePropertyProviderFactoryConfiguration.class); - - @Autowired(required = false) - private CryptoKeyProvider masterKeyProvider; - - /** - * @return a SensitivePropertyProvider initialized with the master key if present, - * or null if the master key is not present. - */ - @Bean - public SensitivePropertyProviderFactory getProvider() { - if (masterKeyProvider == null || masterKeyProvider.isEmpty()) { - // This NiFi Registry was not configured with a master key, so the assumption is - // the optional Spring bean normally provided by this method will never be needed - return null; - } - - try { - // Note, this bean is intentionally NOT a singleton because we want the - // returned provider, which has a copy of the sensitive master key material - // to be reaped when it goes out of scope in order to decrease the time - // key material is held in memory. - return StandardSensitivePropertyProviderFactory - .withKeyAndBootstrapSupplier(masterKeyProvider.getKey(), () -> { - try { - return NiFiRegistryBootstrapUtils.loadBootstrapProperties(); - } catch (IOException e) { - throw new SensitivePropertyProtectionException("Error creating Sensitive Property Provider", e); - } - }); - } catch (final MissingCryptoKeyException e) { - logger.warn("Error creating Sensitive Property Provider", e); - throw new SensitivePropertyProtectionException("Error creating Sensitive Property Provider", e); - } - } - -} diff --git a/nifi-registry/nifi-registry-core/nifi-registry-jetty/src/main/java/org/apache/nifi/registry/jetty/handler/StandardHandlerProvider.java b/nifi-registry/nifi-registry-core/nifi-registry-jetty/src/main/java/org/apache/nifi/registry/jetty/handler/StandardHandlerProvider.java index c41681d995ff..949dbcfbb992 100644 --- a/nifi-registry/nifi-registry-core/nifi-registry-jetty/src/main/java/org/apache/nifi/registry/jetty/handler/StandardHandlerProvider.java +++ b/nifi-registry/nifi-registry-core/nifi-registry-jetty/src/main/java/org/apache/nifi/registry/jetty/handler/StandardHandlerProvider.java @@ -18,7 +18,6 @@ import org.apache.commons.lang3.StringUtils; import org.apache.nifi.registry.properties.NiFiRegistryProperties; -import org.apache.nifi.registry.security.crypto.CryptoKeyProvider; import org.eclipse.jetty.ee10.webapp.MetaInfConfiguration; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.handler.ContextHandlerCollection; @@ -71,8 +70,6 @@ public class StandardHandlerProvider implements HandlerProvider { private static final String PROPERTIES_PARAMETER = "nifi-registry.properties"; - private static final String KEY_PROVIDER_PARAMETER = "nifi-registry.key"; - private static final String RESOURCE_BASE_PARAMETER = "baseResource"; private static final String DIR_ALLOWED_PARAMETER = "dirAllowed"; @@ -83,12 +80,9 @@ public class StandardHandlerProvider implements HandlerProvider { private static final String CONTAINER_JAR_PATTERN = ".*/jetty-jakarta-servlet-api-[^/]*\\.jar$|.*jakarta.servlet.jsp.jstl-[^/]*\\.jar"; - private final CryptoKeyProvider cryptoKeyProvider; - private final String docsDirectory; - public StandardHandlerProvider(final CryptoKeyProvider cryptoKeyProvider, final String docsDirectory) { - this.cryptoKeyProvider = Objects.requireNonNull(cryptoKeyProvider, "Key Provider required"); + public StandardHandlerProvider(final String docsDirectory) { this.docsDirectory = docsDirectory; } @@ -116,7 +110,6 @@ public Handler getHandler(final NiFiRegistryProperties properties) { final ClassLoader apiClassLoader = getApiClassLoader(properties.getDatabaseDriverDirectory()); final WebAppContext apiContext = getWebAppContext(libDirectory, workDirectory, apiClassLoader, API_FILE_PATTERN, API_CONTEXT_PATH); apiContext.setAttribute(PROPERTIES_PARAMETER, properties); - apiContext.setAttribute(KEY_PROVIDER_PARAMETER, cryptoKeyProvider); handlers.addHandler(apiContext); final WebAppContext docsContext = getWebAppContext(libDirectory, workDirectory, ClassLoader.getSystemClassLoader(), DOCS_FILE_PATTERN, DOCS_CONTEXT_PATH); diff --git a/nifi-registry/nifi-registry-core/nifi-registry-jetty/src/test/java/org/apache/nifi/registry/jetty/handler/StandardHandlerProviderTest.java b/nifi-registry/nifi-registry-core/nifi-registry-jetty/src/test/java/org/apache/nifi/registry/jetty/handler/StandardHandlerProviderTest.java index c1ec0e32e0df..26e877c4c950 100644 --- a/nifi-registry/nifi-registry-core/nifi-registry-jetty/src/test/java/org/apache/nifi/registry/jetty/handler/StandardHandlerProviderTest.java +++ b/nifi-registry/nifi-registry-core/nifi-registry-jetty/src/test/java/org/apache/nifi/registry/jetty/handler/StandardHandlerProviderTest.java @@ -17,12 +17,10 @@ package org.apache.nifi.registry.jetty.handler; import org.apache.nifi.registry.properties.NiFiRegistryProperties; -import org.apache.nifi.registry.security.crypto.CryptoKeyProvider; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.io.TempDir; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import java.io.File; @@ -31,15 +29,13 @@ @ExtendWith(MockitoExtension.class) class StandardHandlerProviderTest { - @Mock - private CryptoKeyProvider cryptoKeyProvider; private StandardHandlerProvider provider; @BeforeEach void setProvider(@TempDir final File tempDir) { final String docsDirectory = tempDir.getAbsolutePath(); - provider = new StandardHandlerProvider(cryptoKeyProvider, docsDirectory); + provider = new StandardHandlerProvider(docsDirectory); } @Test diff --git a/nifi-registry/nifi-registry-core/nifi-registry-properties-loader/pom.xml b/nifi-registry/nifi-registry-core/nifi-registry-properties-loader/pom.xml index b86437af482c..c34601edea1a 100644 --- a/nifi-registry/nifi-registry-core/nifi-registry-properties-loader/pom.xml +++ b/nifi-registry/nifi-registry-core/nifi-registry-properties-loader/pom.xml @@ -28,13 +28,5 @@ org.apache.nifi.registry nifi-registry-properties - - org.apache.nifi - nifi-property-protection-factory - - - org.apache.nifi - nifi-property-protection-loader - diff --git a/nifi-registry/nifi-registry-core/nifi-registry-properties-loader/src/main/java/org/apache/nifi/registry/properties/NiFiRegistryPropertiesLoader.java b/nifi-registry/nifi-registry-core/nifi-registry-properties-loader/src/main/java/org/apache/nifi/registry/properties/NiFiRegistryPropertiesLoader.java index f159ebac0e27..e29e79c5c63f 100644 --- a/nifi-registry/nifi-registry-core/nifi-registry-properties-loader/src/main/java/org/apache/nifi/registry/properties/NiFiRegistryPropertiesLoader.java +++ b/nifi-registry/nifi-registry-core/nifi-registry-properties-loader/src/main/java/org/apache/nifi/registry/properties/NiFiRegistryPropertiesLoader.java @@ -16,11 +16,6 @@ */ package org.apache.nifi.registry.properties; -import org.apache.nifi.properties.BootstrapProperties; -import org.apache.nifi.properties.SensitivePropertyProvider; -import org.apache.nifi.properties.SensitivePropertyProviderFactory; -import org.apache.nifi.properties.StandardSensitivePropertyProviderFactory; -import org.apache.nifi.registry.properties.util.NiFiRegistryBootstrapUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,70 +28,15 @@ public class NiFiRegistryPropertiesLoader { private static final Logger logger = LoggerFactory.getLogger(NiFiRegistryPropertiesLoader.class); - private String keyHex; - - // Future enhancement: allow for external registration of new providers - private SensitivePropertyProviderFactory sensitivePropertyProviderFactory; - - /** - * Returns an instance of the loader configured with the key. - *

- *

- * NOTE: This method is used reflectively by the process which starts NiFi - * so changes to it must be made in conjunction with that mechanism.

- * - * @param keyHex the key used to encrypt any sensitive properties - * @return the configured loader - */ - public static NiFiRegistryPropertiesLoader withKey(final String keyHex) { - NiFiRegistryPropertiesLoader loader = new NiFiRegistryPropertiesLoader(); - loader.setKeyHex(keyHex); - return loader; - } - - /** - * Sets the hexadecimal key used to unprotect properties encrypted with - * {@link SensitivePropertyProvider}. If the key has already been set, - * calling this method will throw a {@link RuntimeException}. - * - * @param keyHex the key in hexadecimal format - */ - public void setKeyHex(final String keyHex) { - if (this.keyHex == null || this.keyHex.trim().isEmpty()) { - this.keyHex = keyHex; - } else { - throw new RuntimeException("Cannot overwrite an existing key"); - } - } - - private SensitivePropertyProviderFactory getSensitivePropertyProviderFactory() { - if (sensitivePropertyProviderFactory == null) { - sensitivePropertyProviderFactory = StandardSensitivePropertyProviderFactory - .withKeyAndBootstrapSupplier(keyHex, () -> { - try { - return NiFiRegistryBootstrapUtils.loadBootstrapProperties(); - } catch (IOException e) { - logger.debug("Cannot read bootstrap.conf -- file is missing or not readable. Defaulting to empty bootstrap.conf"); - return BootstrapProperties.EMPTY; - } - }); - } - return sensitivePropertyProviderFactory; - } - /** - * Returns a {@link ProtectedNiFiRegistryProperties} instance loaded from the - * serialized form in the file. Responsible for actually reading from disk - * and deserializing the properties. Returns a protected instance to allow - * for decryption operations. + * Returns an instance of {@link NiFiRegistryProperties} loaded from the provided + * {@link File}. * - * @param file the file containing serialized properties - * @return the ProtectedNiFiProperties instance + * @param file the File containing the serialized properties + * @return the NiFiProperties instance */ - ProtectedNiFiRegistryProperties readProtectedPropertiesFromDisk(File file) { + public NiFiRegistryProperties load(final File file) { if (file == null || !file.exists() || !file.canRead()) { - String path = (file == null ? "missing file" : file.getAbsolutePath()); - logger.error("Cannot read from '{}' -- file is missing or not readable", path); throw new IllegalArgumentException("NiFi Registry properties file missing or unreadable"); } @@ -105,30 +45,10 @@ ProtectedNiFiRegistryProperties readProtectedPropertiesFromDisk(File file) { rawProperties.load(reader); final NiFiRegistryProperties innerProperties = new NiFiRegistryProperties(rawProperties); logger.info("Loaded {} properties from {}", rawProperties.size(), file.getAbsolutePath()); - return new ProtectedNiFiRegistryProperties(innerProperties); + return innerProperties; } catch (final IOException ioe) { - logger.error("Cannot load properties file", ioe); - throw new RuntimeException("Cannot load properties file due to " + ioe.getLocalizedMessage(), ioe); - } - } - - /** - * Returns an instance of {@link NiFiRegistryProperties} loaded from the provided - * {@link File}. If any properties are protected, will attempt to use the appropriate - * {@link SensitivePropertyProvider} to unprotect them transparently. - * - * @param file the File containing the serialized properties - * @return the NiFiProperties instance - */ - public NiFiRegistryProperties load(final File file) { - final ProtectedNiFiRegistryProperties protectedNiFiProperties = readProtectedPropertiesFromDisk(file); - if (protectedNiFiProperties.hasProtectedKeys()) { - getSensitivePropertyProviderFactory() - .getSupportedProviders() - .forEach(protectedNiFiProperties::addSensitivePropertyProvider); + throw new RuntimeException("Failed to load Application Properties", ioe); } - - return protectedNiFiProperties.getUnprotectedProperties(); } /** diff --git a/nifi-registry/nifi-registry-core/nifi-registry-properties-loader/src/main/java/org/apache/nifi/registry/properties/ProtectedNiFiRegistryProperties.java b/nifi-registry/nifi-registry-core/nifi-registry-properties-loader/src/main/java/org/apache/nifi/registry/properties/ProtectedNiFiRegistryProperties.java deleted file mode 100644 index 50f585011c33..000000000000 --- a/nifi-registry/nifi-registry-core/nifi-registry-properties-loader/src/main/java/org/apache/nifi/registry/properties/ProtectedNiFiRegistryProperties.java +++ /dev/null @@ -1,201 +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.registry.properties; - -import org.apache.nifi.properties.ApplicationPropertiesProtector; -import org.apache.nifi.properties.ProtectedProperties; -import org.apache.nifi.properties.SensitivePropertyProtectionException; -import org.apache.nifi.properties.SensitivePropertyProtector; -import org.apache.nifi.properties.SensitivePropertyProvider; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; - -import static java.util.Arrays.asList; - -/** - * Decorator class for intermediate phase when {@link NiFiRegistryPropertiesLoader} loads the - * raw properties file and performs unprotection activities before returning a clean - * implementation of {@link NiFiRegistryProperties}. - * This encapsulates the sensitive property access logic from external consumers - * of {@code NiFiRegistryProperties}. - */ -public class ProtectedNiFiRegistryProperties extends NiFiRegistryProperties implements ProtectedProperties, - SensitivePropertyProtector { - private static final Logger logger = LoggerFactory.getLogger(ProtectedNiFiRegistryProperties.class); - - private SensitivePropertyProtector propertyProtectionDelegate; - - private NiFiRegistryProperties applicationProperties; - - // Additional "sensitive" property key - public static final String ADDITIONAL_SENSITIVE_PROPERTIES_KEY = "nifi.registry.sensitive.props.additional.keys"; - - // Default list of "sensitive" property keys - public static final List DEFAULT_SENSITIVE_PROPERTIES = new ArrayList<>(asList( - NiFiRegistryProperties.SECURITY_KEY_PASSWD, - NiFiRegistryProperties.SECURITY_KEYSTORE_PASSWD, - NiFiRegistryProperties.SECURITY_TRUSTSTORE_PASSWD, - NiFiRegistryProperties.SECURITY_USER_OIDC_CLIENT_SECRET)); - - public ProtectedNiFiRegistryProperties() { - this(new NiFiRegistryProperties()); - } - - /** - * Creates an instance containing the provided {@link NiFiRegistryProperties}. - * - * @param props the NiFiRegistryProperties to contain - */ - public ProtectedNiFiRegistryProperties(final NiFiRegistryProperties props) { - this.applicationProperties = props; - this.propertyProtectionDelegate = new ApplicationPropertiesProtector<>(this); - logger.debug("Loaded {} properties (including {} protection schemes) into ProtectedNiFiRegistryProperties", getApplicationProperties() - .getPropertyKeys().size(), getProtectedPropertyKeys().size()); - } - - @Override - public String getAdditionalSensitivePropertiesKeys() { - return getProperty(getAdditionalSensitivePropertiesKeysName()); - } - - @Override - public String getAdditionalSensitivePropertiesKeysName() { - return ADDITIONAL_SENSITIVE_PROPERTIES_KEY; - } - - @Override - public List getDefaultSensitiveProperties() { - return DEFAULT_SENSITIVE_PROPERTIES; - } - - /** - * Returns the internal representation of the {@link NiFiRegistryProperties} -- protected - * or not as determined by the current state. No guarantee is made to the - * protection state of these properties. If the internal reference is null, a new - * {@link NiFiRegistryProperties} instance is created. - * - * @return the internal properties - */ - @Override - public NiFiRegistryProperties getApplicationProperties() { - if (this.applicationProperties == null) { - this.applicationProperties = new NiFiRegistryProperties(); - } - - return this.applicationProperties; - } - - @Override - public NiFiRegistryProperties createApplicationProperties(final Properties rawProperties) { - return new NiFiRegistryProperties(rawProperties); - } - - /** - * Retrieves the property value for the given property key. - * - * @param key the key of property value to lookup - * @return value of property at given key or null if not found - */ - @Override - public String getProperty(String key) { - return getApplicationProperties().getProperty(key); - } - - /** - * Retrieves all known property keys. - * - * @return all known property keys - */ - @Override - public Set getPropertyKeys() { - return propertyProtectionDelegate.getPropertyKeys(); - } - - /** - * Returns the number of properties, excluding protection scheme properties. - *

- * Example: - *

- * key: E(value, key) - * key.protected: aes/gcm/256 - * key2: value2 - *

- * would return size 2 - * - * @return the count of real properties - */ - @Override - public int size() { - return propertyProtectionDelegate.size(); - } - - @Override - public Set getPropertyKeysIncludingProtectionSchemes() { - return propertyProtectionDelegate.getPropertyKeysIncludingProtectionSchemes(); - } - - @Override - public List getSensitivePropertyKeys() { - return propertyProtectionDelegate.getSensitivePropertyKeys(); - } - - @Override - public List getPopulatedSensitivePropertyKeys() { - return propertyProtectionDelegate.getPopulatedSensitivePropertyKeys(); - } - - @Override - public boolean hasProtectedKeys() { - return propertyProtectionDelegate.hasProtectedKeys(); - } - - @Override - public Map getProtectedPropertyKeys() { - return propertyProtectionDelegate.getProtectedPropertyKeys(); - } - - @Override - public boolean isPropertySensitive(final String key) { - return propertyProtectionDelegate.isPropertySensitive(key); - } - - @Override - public boolean isPropertyProtected(final String key) { - return propertyProtectionDelegate.isPropertyProtected(key); - } - - @Override - public NiFiRegistryProperties getUnprotectedProperties() throws SensitivePropertyProtectionException { - return propertyProtectionDelegate.getUnprotectedProperties(); - } - - @Override - public void addSensitivePropertyProvider(final SensitivePropertyProvider sensitivePropertyProvider) { - propertyProtectionDelegate.addSensitivePropertyProvider(sensitivePropertyProvider); - } - - @Override - public String toString() { - return String.format("%s Size [%d]", getClass().getSimpleName(), size()); - } -} diff --git a/nifi-registry/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/util/NiFiRegistryBootstrapUtils.java b/nifi-registry/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/util/NiFiRegistryBootstrapUtils.java index 8494915ef2e9..7211ae2bac75 100644 --- a/nifi-registry/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/util/NiFiRegistryBootstrapUtils.java +++ b/nifi-registry/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/util/NiFiRegistryBootstrapUtils.java @@ -27,17 +27,6 @@ public class NiFiRegistryBootstrapUtils { private static final AbstractBootstrapPropertiesLoader BOOTSTRAP_PROPERTIES_LOADER = new NiFiRegistryBootstrapPropertiesLoader(); - /** - * Returns the key (if any) used to encrypt sensitive properties, extracted from - * {@code $NIFI_REGISTRY_HOME/conf/bootstrap.conf}. - * - * @return the key in hexadecimal format - * @throws IOException if the file is not readable - */ - public static String extractKeyFromBootstrapFile() throws IOException { - return BOOTSTRAP_PROPERTIES_LOADER.extractKeyFromBootstrapFile(); - } - /** * Loads the default bootstrap.conf file into a BootstrapProperties object. * @return The default bootstrap.conf as a BootstrapProperties object @@ -57,19 +46,6 @@ public static BootstrapProperties loadBootstrapProperties(final String bootstrap return BOOTSTRAP_PROPERTIES_LOADER.loadBootstrapProperties(bootstrapPath); } - /** - * Returns the key (if any) used to encrypt sensitive properties, extracted from - * {@code $NIFI_REGISTRY_HOME/conf/bootstrap.conf}. - * - * @param bootstrapPath the path to the bootstrap file (if null, returns the sensitive key - * found in $NIFI_REGISTRY_HOME/conf/bootstrap.conf) - * @return the key in hexadecimal format - * @throws IOException if the file is not readable - */ - public static String extractKeyFromBootstrapFile(final String bootstrapPath) throws IOException { - return BOOTSTRAP_PROPERTIES_LOADER.extractKeyFromBootstrapFile(bootstrapPath); - } - /** * Returns the default file path to {@code $NIFI_REGISTRY_HOME/conf/nifi-registry.properties}. If the system * property nifi-registry.properties.file.path is not set, it will be set to the relative conf/nifi-registry.properties diff --git a/nifi-registry/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/security/crypto/BootstrapFileCryptoKeyProvider.java b/nifi-registry/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/security/crypto/BootstrapFileCryptoKeyProvider.java deleted file mode 100644 index c277a9c9b10e..000000000000 --- a/nifi-registry/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/security/crypto/BootstrapFileCryptoKeyProvider.java +++ /dev/null @@ -1,82 +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.registry.security.crypto; - -import org.apache.nifi.registry.properties.util.NiFiRegistryBootstrapUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; - -/** - * An implementation of {@link CryptoKeyProvider} that loads the key from disk every time it is needed. - * - * The persistence-backing of the key is in the bootstrap.conf file, which must be provided to the - * constructor of this class. - * - * As key access for sensitive value decryption is only used a few times during server initialization, - * this implementation trades efficiency for security by only keeping the key in memory with an - * in-scope reference for a brief period of time (assuming callers do not maintain an in-scope reference). - * - * @see CryptoKeyProvider - */ -public class BootstrapFileCryptoKeyProvider implements CryptoKeyProvider { - - private static final Logger logger = LoggerFactory.getLogger(BootstrapFileCryptoKeyProvider.class); - - private final String bootstrapFile; - - /** - * Construct a new instance backed by the contents of a bootstrap.conf file. - * - * @param bootstrapFilePath The path to the bootstrap.conf file for this instance of NiFi Registry. - * Must not be null. - */ - public BootstrapFileCryptoKeyProvider(final String bootstrapFilePath) { - if (bootstrapFilePath == null) { - throw new IllegalArgumentException(BootstrapFileCryptoKeyProvider.class.getSimpleName() + " cannot be initialized with null bootstrap file path."); - } - this.bootstrapFile = bootstrapFilePath; - } - - /** - * @return The bootstrap file path that backs this provider instance. - */ - public String getBootstrapFile() { - return bootstrapFile; - } - - @Override - public String getKey() throws MissingCryptoKeyException { - try { - return NiFiRegistryBootstrapUtils.extractKeyFromBootstrapFile(this.bootstrapFile); - } catch (IOException ioe) { - final String errMsg = "Loading the master crypto key from bootstrap file '" + bootstrapFile + "' failed due to IOException."; - logger.warn(errMsg); - throw new MissingCryptoKeyException(errMsg, ioe); - } - - } - - @Override - public String toString() { - return "BootstrapFileCryptoKeyProvider{" + - "bootstrapFile='" + bootstrapFile + '\'' + - '}'; - } - -} diff --git a/nifi-registry/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/security/crypto/CryptoKeyProvider.java b/nifi-registry/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/security/crypto/CryptoKeyProvider.java deleted file mode 100644 index bab8d7c7f426..000000000000 --- a/nifi-registry/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/security/crypto/CryptoKeyProvider.java +++ /dev/null @@ -1,68 +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.registry.security.crypto; - -/** - * A simple interface that wraps a key that can be used for encryption and decryption. - * This allows for more flexibility with the lifecycle of keys and how other classes - * can declare dependencies for keys, by depending on a CryptoKeyProvider that will provided - * at runtime. - */ -public interface CryptoKeyProvider { - - /** - * A string literal that indicates the contents of a key are empty. - * Can also be used in contexts that a null key is undesirable. - */ - String EMPTY_KEY = ""; - - /** - * @return The crypto key known to this CryptoKeyProvider instance in hexadecimal format, or - * {@link #EMPTY_KEY} if the key is empty. - * @throws MissingCryptoKeyException if the key cannot be provided or determined for any reason. - * If the key is known to be empty, {@link #EMPTY_KEY} will be returned and a - * CryptoKeyMissingException will not be thrown - */ - String getKey() throws MissingCryptoKeyException; - - /** - * @return A boolean indicating if the key value held by this CryptoKeyProvider is empty, - * such as 'null' or empty string. - */ - default boolean isEmpty() { - String key; - try { - key = getKey(); - } catch (MissingCryptoKeyException e) { - return true; - } - return EMPTY_KEY.equals(key); - } - - /** - * A string representation of this CryptoKeyProvider instance. - *

- *

- * Note: Implementations of this interface should take care not to leak sensitive - * key material in any strings they emmit, including in the toString implementation. - * - * @return A string representation of this CryptoKeyProvider instance. - */ - @Override - public String toString(); - -} diff --git a/nifi-registry/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/security/crypto/MissingCryptoKeyException.java b/nifi-registry/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/security/crypto/MissingCryptoKeyException.java deleted file mode 100644 index dbc3752c99e5..000000000000 --- a/nifi-registry/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/security/crypto/MissingCryptoKeyException.java +++ /dev/null @@ -1,47 +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.registry.security.crypto; - -/** - * An exception type used by a {@link CryptoKeyProvider} when a request for the key - * cannot be fulfilled for any reason. - * - * @see CryptoKeyProvider - */ -public class MissingCryptoKeyException extends Exception { - - public MissingCryptoKeyException() { - super(); - } - - public MissingCryptoKeyException(String message) { - super(message); - } - - public MissingCryptoKeyException(String message, Throwable cause) { - super(message, cause); - } - - public MissingCryptoKeyException(Throwable cause) { - super(cause); - } - - protected MissingCryptoKeyException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } - -} diff --git a/nifi-registry/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/bootstrap.conf b/nifi-registry/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/bootstrap.conf index 22680b0ceb9a..f10c0fa5cb00 100644 --- a/nifi-registry/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/bootstrap.conf +++ b/nifi-registry/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/bootstrap.conf @@ -48,19 +48,3 @@ java.arg.3=-Xmx512m java.arg.5=-Dsun.net.http.allowRestrictedHeaders=true java.arg.6=-Djava.protocol.handler.pkgs=sun.net.www.protocol -# Master key in hexadecimal format for encrypted sensitive configuration values -nifi.registry.bootstrap.sensitive.key= - -# Sensitive Property Provider configuration - -# HashiCorp Vault Sensitive Property Providers -#nifi.registry.bootstrap.protection.hashicorp.vault.conf=./conf/bootstrap-hashicorp-vault.conf - -# AWS Sensitive Property Providers -#nifi.registry.bootstrap.protection.aws.conf=./conf/bootstrap-aws.conf - -# Azure Key Vault Sensitive Property Providers -#nifi.registry.bootstrap.protection.azure.keyvault.conf=./conf/bootstrap-azure.conf - -# GCP KMS Sensitive Property Providers -#nifi.registry.bootstrap.protection.gcp.kms.conf=./conf/bootstrap-gcp.conf diff --git a/nifi-registry/nifi-registry-core/nifi-registry-runtime/src/main/java/org/apache/nifi/registry/NiFiRegistry.java b/nifi-registry/nifi-registry-core/nifi-registry-runtime/src/main/java/org/apache/nifi/registry/NiFiRegistry.java index a9e3f4c339d5..f001311a48fe 100644 --- a/nifi-registry/nifi-registry-core/nifi-registry-runtime/src/main/java/org/apache/nifi/registry/NiFiRegistry.java +++ b/nifi-registry/nifi-registry-core/nifi-registry-runtime/src/main/java/org/apache/nifi/registry/NiFiRegistry.java @@ -20,9 +20,6 @@ import org.apache.nifi.registry.jetty.handler.HandlerProvider; import org.apache.nifi.registry.jetty.handler.StandardHandlerProvider; import org.apache.nifi.registry.properties.NiFiRegistryProperties; -import org.apache.nifi.registry.security.crypto.BootstrapFileCryptoKeyProvider; -import org.apache.nifi.registry.security.crypto.CryptoKeyProvider; -import org.apache.nifi.registry.security.crypto.MissingCryptoKeyException; import org.apache.nifi.registry.util.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,16 +29,7 @@ import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.TimeUnit; -import java.util.stream.Stream; /** * Main entry point for NiFiRegistry. @@ -57,7 +45,7 @@ public class NiFiRegistry { private final BootstrapListener bootstrapListener; private volatile boolean shutdown = false; - public NiFiRegistry(final NiFiRegistryProperties properties, CryptoKeyProvider masterKeyProvider) throws IOException, IllegalArgumentException { + public NiFiRegistry(final NiFiRegistryProperties properties) throws IOException, IllegalArgumentException { Thread.setDefaultUncaughtExceptionHandler((t, e) -> LOGGER.error("An Unknown Error Occurred in Thread {}", t, e)); @@ -101,7 +89,7 @@ public NiFiRegistry(final NiFiRegistryProperties properties, CryptoKeyProvider m final String docsDirectory = System.getProperty(NiFiRegistryProperties.NIFI_REGISTRY_BOOTSTRAP_DOCS_DIR_PROPERTY, NiFiRegistryProperties.RELATIVE_DOCS_LOCATION); - final HandlerProvider handlerProvider = new StandardHandlerProvider(masterKeyProvider, docsDirectory); + final HandlerProvider handlerProvider = new StandardHandlerProvider(docsDirectory); server = new JettyServer(properties, handlerProvider); if (shutdown) { @@ -144,83 +132,33 @@ protected void shutdownHook() { public static void main(String[] args) { LOGGER.info("Launching NiFi Registry..."); - final CryptoKeyProvider masterKeyProvider; - final NiFiRegistryProperties properties; - final ClassLoader sensitivePropProviderClassLoader; try { - masterKeyProvider = getMasterKeyProvider(); - sensitivePropProviderClassLoader = createSensitivePropertiesProviderClassLoader(); - properties = initializeProperties(masterKeyProvider, sensitivePropProviderClassLoader); - } catch (final IllegalArgumentException iae) { - throw new RuntimeException("Unable to load properties: " + iae, iae); - } - - try { - new NiFiRegistry(properties, masterKeyProvider); + new NiFiRegistry(initializeProperties()); } catch (final Throwable t) { LOGGER.error("Failure to launch NiFi Registry", t); } } - public static CryptoKeyProvider getMasterKeyProvider() { - final String bootstrapConfigFilePath = System.getProperty(NiFiRegistryProperties.NIFI_REGISTRY_BOOTSTRAP_FILE_PATH_PROPERTY, - NiFiRegistryProperties.RELATIVE_BOOTSTRAP_FILE_LOCATION); - CryptoKeyProvider masterKeyProvider = new BootstrapFileCryptoKeyProvider(bootstrapConfigFilePath); - LOGGER.info("Read property protection key from {}", bootstrapConfigFilePath); - return masterKeyProvider; - } - - public static NiFiRegistryProperties initializeProperties(CryptoKeyProvider masterKeyProvider, final ClassLoader sensitivePropertyProviderClassLoader) { - String key = CryptoKeyProvider.EMPTY_KEY; - try { - key = masterKeyProvider.getKey(); - } catch (MissingCryptoKeyException e) { - LOGGER.debug("CryptoKeyProvider provided to initializeProperties method was empty - did not contain a key."); - // Do nothing. The key can be empty when it is passed to the loader as the loader will only use it if any properties are protected. - } - + public static NiFiRegistryProperties initializeProperties() { final String nifiRegistryPropertiesFilePath = System.getProperty(NiFiRegistryProperties.NIFI_REGISTRY_PROPERTIES_FILE_PATH_PROPERTY, NiFiRegistryProperties.RELATIVE_PROPERTIES_FILE_LOCATION); - final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); - Thread.currentThread().setContextClassLoader(sensitivePropertyProviderClassLoader); - try { - final Class propsLoaderClass = Class.forName("org.apache.nifi.registry.properties.NiFiRegistryPropertiesLoader", true, sensitivePropertyProviderClassLoader); - final Method withKeyMethod = propsLoaderClass.getMethod("withKey", String.class); - final Object loaderInstance = withKeyMethod.invoke(null, key); + final Class propsLoaderClass = Class.forName("org.apache.nifi.registry.properties.NiFiRegistryPropertiesLoader"); + final Object loaderInstance = propsLoaderClass.getConstructor().newInstance(); final Method loadMethod = propsLoaderClass.getMethod("load", String.class); final NiFiRegistryProperties properties = (NiFiRegistryProperties) loadMethod.invoke(loaderInstance, nifiRegistryPropertiesFilePath); LOGGER.info("Application Properties loaded [{}]", properties.size()); return properties; - } catch (InvocationTargetException wrappedException) { + } catch (final InstantiationException | InvocationTargetException wrappedException) { final String msg = "There was an issue decrypting protected properties"; throw new IllegalArgumentException(msg, wrappedException.getCause() == null ? wrappedException : wrappedException.getCause()); - } catch (final IllegalAccessException | NoSuchMethodException | ClassNotFoundException reex) { + } catch (final IllegalAccessException | NoSuchMethodException | ClassNotFoundException e) { final String msg = "Unable to access properties loader in the expected manner - apparent classpath or build issue"; - throw new IllegalArgumentException(msg, reex); + throw new IllegalArgumentException(msg, e); } catch (final RuntimeException e) { final String msg = "There was an issue decrypting protected properties"; throw new IllegalArgumentException(msg, e); - } finally { - Thread.currentThread().setContextClassLoader(contextClassLoader); } } - - public static ClassLoader createSensitivePropertiesProviderClassLoader() { - final List urls = new ArrayList<>(); - try (final Stream files = Files.list(Paths.get("lib/spp"))) { - files.forEach(p -> { - try { - urls.add(p.toUri().toURL()); - } catch (final MalformedURLException mef) { - LOGGER.warn("Unable to load bootstrap library [{}]", p.getFileName(), mef); - } - }); - } catch (IOException ioe) { - LOGGER.warn("Unable to access lib/spp to create sensitive property provider classloader", ioe); - } - return new URLClassLoader(urls.toArray(new URL[0]), Thread.currentThread().getContextClassLoader()); - } - } diff --git a/nifi-registry/nifi-registry-core/nifi-registry-web-api/pom.xml b/nifi-registry/nifi-registry-core/nifi-registry-web-api/pom.xml index eef29cec7d88..a4641c73e478 100644 --- a/nifi-registry/nifi-registry-core/nifi-registry-web-api/pom.xml +++ b/nifi-registry/nifi-registry-core/nifi-registry-web-api/pom.xml @@ -288,6 +288,10 @@ org.glassfish.jersey.media jersey-media-multipart + + org.apache.httpcomponents + httpclient + io.jsonwebtoken jjwt diff --git a/nifi-registry/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/NiFiRegistryApiApplication.java b/nifi-registry/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/NiFiRegistryApiApplication.java index 566fe21055f5..14cc33b48c3b 100644 --- a/nifi-registry/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/NiFiRegistryApiApplication.java +++ b/nifi-registry/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/NiFiRegistryApiApplication.java @@ -53,7 +53,6 @@ public class NiFiRegistryApiApplication extends SpringBootServletInitializer { public static final String NIFI_REGISTRY_PROPERTIES_ATTRIBUTE = "nifi-registry.properties"; - public static final String NIFI_REGISTRY_MASTER_KEY_ATTRIBUTE = "nifi-registry.key"; static { // Disable Spring Logging abstraction for Spring Boot 2 and SLF4J 2 diff --git a/nifi-registry/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiRegistryMasterKeyProviderFactory.java b/nifi-registry/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiRegistryMasterKeyProviderFactory.java deleted file mode 100644 index feb439f8a0a2..000000000000 --- a/nifi-registry/nifi-registry-core/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiRegistryMasterKeyProviderFactory.java +++ /dev/null @@ -1,62 +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.registry.web.security; - -import org.apache.nifi.registry.NiFiRegistryApiApplication; -import org.apache.nifi.registry.security.crypto.CryptoKeyProvider; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.context.ServletContextAware; - -import jakarta.servlet.ServletContext; - -@Configuration -public class NiFiRegistryMasterKeyProviderFactory implements ServletContextAware { - - private static final Logger logger = LoggerFactory.getLogger(NiFiRegistryMasterKeyProviderFactory.class); - - private CryptoKeyProvider masterKeyProvider = null; - - @Bean - public CryptoKeyProvider getNiFiRegistryMasterKeyProvider() { - return masterKeyProvider; - } - - @Override - public void setServletContext(ServletContext servletContext) { - Object rawKeyProviderObject = servletContext.getAttribute(NiFiRegistryApiApplication.NIFI_REGISTRY_MASTER_KEY_ATTRIBUTE); - - if (rawKeyProviderObject == null) { - logger.warn("Value of {} was null. {} bean will not be available in Application Context, so any attempt to load protected property values may fail.", - NiFiRegistryApiApplication.NIFI_REGISTRY_MASTER_KEY_ATTRIBUTE, CryptoKeyProvider.class.getSimpleName()); - return; - } - - if (!(rawKeyProviderObject instanceof CryptoKeyProvider)) { - logger.warn("Expected value of {} to be of type {}, but instead got {}. {} bean will NOT be available in Application Context, so any attempt to load protected property values may fail.", - NiFiRegistryApiApplication.NIFI_REGISTRY_MASTER_KEY_ATTRIBUTE, CryptoKeyProvider.class.getName(), - rawKeyProviderObject.getClass().getName(), CryptoKeyProvider.class.getSimpleName()); - return; - } - - logger.info("Updating Application Context with {} bean for obtaining NiFi Registry master key.", CryptoKeyProvider.class.getSimpleName()); - masterKeyProvider = (CryptoKeyProvider) rawKeyProviderObject; - } - -} diff --git a/nifi-registry/nifi-registry-core/nifi-registry-web-api/src/test/resources/conf/secure-ldap/bootstrap.conf b/nifi-registry/nifi-registry-core/nifi-registry-web-api/src/test/resources/conf/secure-ldap/bootstrap.conf index da0079db702c..85e3606b6fe1 100644 --- a/nifi-registry/nifi-registry-core/nifi-registry-web-api/src/test/resources/conf/secure-ldap/bootstrap.conf +++ b/nifi-registry/nifi-registry-core/nifi-registry-web-api/src/test/resources/conf/secure-ldap/bootstrap.conf @@ -54,5 +54,3 @@ java.arg.6=-Djava.protocol.handler.pkgs=sun.net.www.protocol # performance without significant "stop-the-world" delays. #java.arg.10=-XX:+UseG1GC -# Master key in hexadecimal format for encrypted sensitive configuration values -nifi.registry.bootstrap.sensitive.key=0123456789ABCDEFFEDCBA9876543210 diff --git a/nifi-registry/nifi-registry-toolkit/nifi-registry-toolkit-persistence/src/main/java/org/apache/nifi/registry/toolkit/persistence/FlowPersistenceProviderMigrator.java b/nifi-registry/nifi-registry-toolkit/nifi-registry-toolkit-persistence/src/main/java/org/apache/nifi/registry/toolkit/persistence/FlowPersistenceProviderMigrator.java index 8b5bb546e955..99cb9a3f54a2 100644 --- a/nifi-registry/nifi-registry-toolkit/nifi-registry-toolkit-persistence/src/main/java/org/apache/nifi/registry/toolkit/persistence/FlowPersistenceProviderMigrator.java +++ b/nifi-registry/nifi-registry-toolkit/nifi-registry-toolkit-persistence/src/main/java/org/apache/nifi/registry/toolkit/persistence/FlowPersistenceProviderMigrator.java @@ -82,8 +82,7 @@ public static void main(String[] args) { System.exit(PARSE_EXCEPTION); } - NiFiRegistryProperties fromProperties = NiFiRegistry.initializeProperties( - NiFiRegistry.getMasterKeyProvider(), NiFiRegistry.createSensitivePropertiesProviderClassLoader()); + NiFiRegistryProperties fromProperties = NiFiRegistry.initializeProperties(); DataSource dataSource = new DataSourceFactory(fromProperties).getDataSource(); DatabaseMetadataService fromMetadataService = new DatabaseMetadataService(new JdbcTemplate(dataSource)); diff --git a/nifi-registry/pom.xml b/nifi-registry/pom.xml index 45389dd8416a..fe91c8275db1 100644 --- a/nifi-registry/pom.xml +++ b/nifi-registry/pom.xml @@ -126,16 +126,6 @@ nifi-registry-properties-loader 2.0.0-SNAPSHOT - - org.apache.nifi - nifi-property-protection-factory - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-loader - 2.0.0-SNAPSHOT - org.apache.nifi nifi-property-utils diff --git a/nifi-toolkit/nifi-toolkit-assembly/docker/tests/exit-codes.sh b/nifi-toolkit/nifi-toolkit-assembly/docker/tests/exit-codes.sh index 7cc3c28ae3c8..b306d821985e 100755 --- a/nifi-toolkit/nifi-toolkit-assembly/docker/tests/exit-codes.sh +++ b/nifi-toolkit/nifi-toolkit-assembly/docker/tests/exit-codes.sh @@ -26,12 +26,6 @@ docker run --rm "${image_name}" test 0 -eq $? || exit 1 echo -echo "Testing return values on invalid input for all commands:" -echo "encrypt-config" -docker run --rm "${image_name}" encrypt-config invalid 1>/dev/null 2>&1 -test 2 -eq $? || exit 1 -echo - echo "cli" docker run --rm "${image_name}" cli invalid 1>/dev/null 2>&1 test 255 -eq $? || exit 1 diff --git a/nifi-toolkit/nifi-toolkit-assembly/pom.xml b/nifi-toolkit/nifi-toolkit-assembly/pom.xml index bee5cc0e917e..621601583222 100644 --- a/nifi-toolkit/nifi-toolkit-assembly/pom.xml +++ b/nifi-toolkit/nifi-toolkit-assembly/pom.xml @@ -61,11 +61,6 @@ language governing permissions and limitations under the License. --> - - org.apache.nifi - nifi-toolkit-encrypt-config - 2.0.0-SNAPSHOT - org.apache.nifi nifi-toolkit-cli diff --git a/nifi-toolkit/nifi-toolkit-assembly/src/main/resources/bin/encrypt-config.bat b/nifi-toolkit/nifi-toolkit-assembly/src/main/resources/bin/encrypt-config.bat deleted file mode 100644 index ce4cf4f74461..000000000000 --- a/nifi-toolkit/nifi-toolkit-assembly/src/main/resources/bin/encrypt-config.bat +++ /dev/null @@ -1,41 +0,0 @@ -@echo off -rem -rem Licensed to the Apache Software Foundation (ASF) under one or more -rem contributor license agreements. See the NOTICE file distributed with -rem this work for additional information regarding copyright ownership. -rem The ASF licenses this file to You under the Apache License, Version 2.0 -rem (the "License"); you may not use this file except in compliance with -rem the License. You may obtain a copy of the License at -rem -rem http://www.apache.org/licenses/LICENSE-2.0 -rem -rem Unless required by applicable law or agreed to in writing, software -rem distributed under the License is distributed on an "AS IS" BASIS, -rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -rem See the License for the specific language governing permissions and -rem limitations under the License. -rem - -rem Use JAVA_HOME if it's set; otherwise, just use java - -if "%JAVA_HOME%" == "" goto noJavaHome -if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome -set JAVA_EXE=%JAVA_HOME%\bin\java.exe -goto startConfig - -:noJavaHome -echo The JAVA_HOME environment variable is not defined correctly. -echo Instead the PATH will be used to find the java executable. -echo. -set JAVA_EXE=java -goto startConfig - -:startConfig -set LIB_DIR=%~dp0..\classpath;%~dp0..\lib - -if "%JAVA_OPTS%" == "" set JAVA_OPTS=-Xms128m -Xmx256m - -SET JAVA_PARAMS=-cp %LIB_DIR%\* %JAVA_OPTS% org.apache.nifi.toolkit.config.EncryptConfigCommand - -cmd.exe /C ""%JAVA_EXE%" %JAVA_PARAMS% %* "" - diff --git a/nifi-toolkit/nifi-toolkit-assembly/src/main/resources/bin/encrypt-config.sh b/nifi-toolkit/nifi-toolkit-assembly/src/main/resources/bin/encrypt-config.sh deleted file mode 100644 index 9ed273ba18f7..000000000000 --- a/nifi-toolkit/nifi-toolkit-assembly/src/main/resources/bin/encrypt-config.sh +++ /dev/null @@ -1,119 +0,0 @@ -#!/bin/sh -# -# 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. -# -# - -# Script structure inspired from Apache Karaf and other Apache projects with similar startup approaches - -SCRIPT_DIR=$(dirname "$0") -SCRIPT_NAME=$(basename "$0") -NIFI_TOOLKIT_HOME=$(cd "${SCRIPT_DIR}" && cd .. && pwd) -PROGNAME=$(basename "$0") - - -warn() { - echo "${PROGNAME}: $*" -} - -die() { - warn "$*" - exit 1 -} - -detectOS() { - # OS specific support (must be 'true' or 'false'). - cygwin=false; - aix=false; - os400=false; - darwin=false; - case "$(uname)" in - CYGWIN*) - cygwin=true - ;; - AIX*) - aix=true - ;; - OS400*) - os400=true - ;; - Darwin) - darwin=true - ;; - esac - # For AIX, set an environment variable - if ${aix}; then - export LDR_CNTRL=MAXDATA=0xB0000000@DSA - echo ${LDR_CNTRL} - fi -} - -locateJava() { - # Setup the Java Virtual Machine - if $cygwin ; then - [ -n "${JAVA}" ] && JAVA=$(cygpath --unix "${JAVA}") - [ -n "${JAVA_HOME}" ] && JAVA_HOME=$(cygpath --unix "${JAVA_HOME}") - fi - - if [ "x${JAVA}" = "x" ] && [ -r /etc/gentoo-release ] ; then - JAVA_HOME=$(java-config --jre-home) - fi - if [ "x${JAVA}" = "x" ]; then - if [ "x${JAVA_HOME}" != "x" ]; then - if [ ! -d "${JAVA_HOME}" ]; then - die "JAVA_HOME is not valid: ${JAVA_HOME}" - fi - JAVA="${JAVA_HOME}/bin/java" - else - warn "JAVA_HOME not set; results may vary" - JAVA=$(type java) - JAVA=$(expr "${JAVA}" : '.* \(/.*\)$') - if [ "x${JAVA}" = "x" ]; then - die "java command not found" - fi - fi - fi -} - -init() { - # Determine if there is special OS handling we must perform - detectOS - - # Locate the Java VM to execute - locateJava -} - -run() { - LIBS="${NIFI_TOOLKIT_HOME}/lib/*" - - sudo_cmd_prefix="" - if $cygwin; then - NIFI_TOOLKIT_HOME=$(cygpath --path --windows "${NIFI_TOOLKIT_HOME}") - CLASSPATH="$NIFI_TOOLKIT_HOME/classpath;$(cygpath --path --windows "${LIBS}")" - else - CLASSPATH="$NIFI_TOOLKIT_HOME/classpath:${LIBS}" - fi - - export JAVA_HOME="$JAVA_HOME" - export NIFI_TOOLKIT_HOME="$NIFI_TOOLKIT_HOME" - - umask 0077 - exec "${JAVA}" -cp "${CLASSPATH}" ${JAVA_OPTS:--Xms128m -Xmx256m} org.apache.nifi.toolkit.config.EncryptConfigCommand "$@" -} - - -init -run "$@" diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/pom.xml b/nifi-toolkit/nifi-toolkit-encrypt-config/pom.xml deleted file mode 100644 index 1e1d4d421828..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/pom.xml +++ /dev/null @@ -1,92 +0,0 @@ - - - - - org.apache.nifi - nifi-toolkit - 2.0.0-SNAPSHOT - - 4.0.0 - - nifi-toolkit-encrypt-config - Tool to encrypt sensitive configuration values - - - org.apache.nifi - nifi-flow-encryptor - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-properties - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-properties-loader - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-api - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-factory - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-property-protection-loader - 2.0.0-SNAPSHOT - - - org.apache.nifi.registry - nifi-registry-properties - 2.0.0-SNAPSHOT - - - org.apache.nifi.registry - nifi-registry-properties-loader - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-xml-processing - 2.0.0-SNAPSHOT - - - org.apache.nifi - nifi-security-crypto-key - 2.0.0-SNAPSHOT - - - info.picocli - picocli - 4.7.6 - - - org.slf4j - slf4j-api - compile - - - com.fasterxml.jackson.core - jackson-databind - - - diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/EncryptConfigCommand.java b/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/EncryptConfigCommand.java deleted file mode 100644 index 5b489799e40a..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/EncryptConfigCommand.java +++ /dev/null @@ -1,76 +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.toolkit.config; - -import org.apache.nifi.toolkit.config.command.RegistryEncryptConfig; -import org.apache.nifi.toolkit.config.command.StandardEncryptConfig; -import picocli.CommandLine; - -import java.util.Arrays; - -/** - * Encrypt Config Command launcher for Command Line implementation - */ -public class EncryptConfigCommand { - private static final String NIFI_REGISTRY_ARGUMENT = "--nifiRegistry"; - - /** - * Main command method launches Picocli Command Line implementation of Encrypt Config - * - * @param arguments Command line arguments - */ - public static void main(final String[] arguments) { - final Object command; - - final String[] filteredArguments; - if (isRegistryModeRequested(arguments)) { - command = new RegistryEncryptConfig(); - filteredArguments = getFilteredArguments(arguments); - } else { - command = new StandardEncryptConfig(); - filteredArguments = arguments; - } - - final CommandLine commandLine = new CommandLine(command); - if (filteredArguments.length == 0) { - commandLine.usage(System.out); - } else { - final int status = commandLine.execute(filteredArguments); - System.exit(status); - } - } - - private static boolean isRegistryModeRequested(final String[] arguments) { - boolean registryModeRequested = false; - - for (final String argument : arguments) { - if (NIFI_REGISTRY_ARGUMENT.equals(argument)) { - registryModeRequested = true; - break; - } - } - - return registryModeRequested; - } - - private static String[] getFilteredArguments(final String[] arguments) { - return Arrays.stream(arguments) - .filter(argument -> !NIFI_REGISTRY_ARGUMENT.equals(argument)) - .toList() - .toArray(new String[]{}); - } -} diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/command/RegistryEncryptConfig.java b/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/command/RegistryEncryptConfig.java deleted file mode 100644 index bb8205224e5b..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/command/RegistryEncryptConfig.java +++ /dev/null @@ -1,141 +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.toolkit.config.command; - -import org.apache.nifi.properties.ApplicationProperties; -import org.apache.nifi.properties.ApplicationPropertiesProtector; -import org.apache.nifi.properties.SensitivePropertyProvider; -import org.apache.nifi.properties.SensitivePropertyProviderFactory; -import org.apache.nifi.registry.properties.NiFiRegistryProperties; -import org.apache.nifi.registry.properties.NiFiRegistryPropertiesLoader; -import org.apache.nifi.registry.properties.ProtectedNiFiRegistryProperties; -import org.apache.nifi.toolkit.config.transformer.ApplicationPropertiesFileTransformer; -import org.apache.nifi.toolkit.config.transformer.FileTransformer; -import org.apache.nifi.toolkit.config.transformer.XmlFileTransformer; -import picocli.CommandLine.Command; -import picocli.CommandLine.Option; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Collections; -import java.util.Set; - -/** - * Encrypt Config Registry implementation for NiFi Registry configuration files - */ -@Command -public class RegistryEncryptConfig extends SharedEncryptConfig implements Runnable { - - static final String BOOTSTRAP_ROOT_KEY_PROPERTY = "nifi.registry.bootstrap.sensitive.key"; - - @Option( - names = {"-r", "--nifiRegistryProperties"}, - description = "Path to file containing Application Properties [nifi-registry.properties] that will be updated unless the output argument is provided" - ) - Path applicationPropertiesPath; - - @Option( - names = {"-R", "--outputNiFiProperties"}, - description = "Path to output file for Application Properties [nifi-registry.properties] with property protection applied" - ) - Path outputApplicationPropertiesPath; - - @Option( - names = {"-i", "--identityProviders"}, - description = "Path to file containing Identity Providers [identity-providers.xml] configuration that will be updated unless the output argument is provided" - ) - Path identityProvidersPath; - - @Option( - names = {"-I", "--outputIdentityProviders"}, - description = "Path to output file for Identity Providers [identity-providers.xml] with property protection applied" - ) - Path outputIdentityProvidersPath; - - @Override - public void run() { - final ApplicationProperties applicationProperties = loadApplicationProperties(); - - processBootstrapConf(BOOTSTRAP_ROOT_KEY_PROPERTY); - processApplicationProperties(applicationProperties); - processAuthorizers(); - processIdentityProviders(); - } - - private ApplicationProperties loadApplicationProperties() { - final ApplicationProperties applicationProperties; - - if (applicationPropertiesPath == null) { - applicationProperties = new ApplicationProperties(Collections.emptyMap()); - if (verboseModeEnabled) { - logger.info("Application Properties [nifi-registry.properties] not specified"); - } - } else if (Files.notExists(applicationPropertiesPath)) { - throw new IllegalArgumentException(String.format("Application Properties [nifi-registry.properties] not found [%s]", applicationPropertiesPath)); - } else { - final NiFiRegistryPropertiesLoader propertiesLoader = new NiFiRegistryPropertiesLoader(); - - final String inputRootKey = getInputRootKey(); - final String rootKey = inputRootKey == null ? getRootKey() : inputRootKey; - propertiesLoader.setKeyHex(rootKey); - - applicationProperties = propertiesLoader.load(applicationPropertiesPath.toFile()); - } - - return applicationProperties; - } - - private void processApplicationProperties(final ApplicationProperties applicationProperties) { - if (applicationPropertiesPath == null) { - if (verboseModeEnabled) { - logger.info("Application Properties [nifi-registry.properties] not specified"); - } - } else { - logger.info("Started processing Application Properties [{}]", applicationPropertiesPath); - - final SensitivePropertyProviderFactory sensitivePropertyProviderFactory = getSensitivePropertyProviderFactory(); - final SensitivePropertyProvider sensitivePropertyProvider = sensitivePropertyProviderFactory.getProvider(protectionScheme); - final Set sensitivePropertyNames = getSensitivePropertyNames(); - final FileTransformer fileTransformer = new ApplicationPropertiesFileTransformer(applicationProperties, sensitivePropertyProvider, sensitivePropertyNames); - runFileTransformer(fileTransformer, applicationPropertiesPath, outputApplicationPropertiesPath); - - logger.info("Completed processing Application Properties [{}]", applicationPropertiesPath); - } - } - - private void processIdentityProviders() { - if (identityProvidersPath == null) { - if (verboseModeEnabled) { - logger.info("Identity Providers not specified"); - } - } else { - logger.info("Started processing Identity Providers [{}]", identityProvidersPath); - - final SensitivePropertyProvider inputSensitivePropertyProvider = getInputSensitivePropertyProvider(); - final SensitivePropertyProviderFactory sensitivePropertyProviderFactory = getSensitivePropertyProviderFactory(); - final FileTransformer fileTransformer = new XmlFileTransformer(inputSensitivePropertyProvider, sensitivePropertyProviderFactory, protectionScheme); - runFileTransformer(fileTransformer, identityProvidersPath, outputIdentityProvidersPath); - - logger.info("Completed processing Identity Providers [{}]", identityProvidersPath); - } - } - - private Set getSensitivePropertyNames() { - final ApplicationPropertiesProtector protector = new ApplicationPropertiesProtector<>(new ProtectedNiFiRegistryProperties()); - return Set.copyOf(protector.getSensitivePropertyKeys()); - } -} diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/command/SharedEncryptConfig.java b/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/command/SharedEncryptConfig.java deleted file mode 100644 index 5ee44bc1876d..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/command/SharedEncryptConfig.java +++ /dev/null @@ -1,317 +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.toolkit.config.command; - -import org.apache.nifi.properties.BootstrapProperties; -import org.apache.nifi.properties.SensitivePropertyProvider; -import org.apache.nifi.properties.SensitivePropertyProviderFactory; -import org.apache.nifi.properties.StandardSensitivePropertyProviderFactory; -import org.apache.nifi.properties.scheme.ProtectionScheme; -import org.apache.nifi.toolkit.config.command.converter.ProtectionSchemeTypeConverter; -import org.apache.nifi.toolkit.config.crypto.DerivedKeyGenerator; -import org.apache.nifi.toolkit.config.crypto.StandardDerivedKeyGenerator; -import org.apache.nifi.toolkit.config.transformer.BootstrapConfigurationFileTransformer; -import org.apache.nifi.toolkit.config.transformer.FileTransformer; -import org.apache.nifi.toolkit.config.transformer.XmlFileTransformer; -import org.apache.nifi.util.NiFiBootstrapUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import picocli.CommandLine.Command; -import picocli.CommandLine.Option; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import java.util.function.Supplier; - -/** - * Shared Encrypt Configuration for NiFi and NiFi Registry - */ -@Command( - name = "encrypt-config", - sortOptions = false, - mixinStandardHelpOptions = true, - usageHelpWidth = 160, - separator = " ", - version = { - "Java ${java.version} (${java.vendor} ${java.vm.name} ${java.vm.version})" - }, - descriptionHeading = "Description: ", - description = { - "encrypt-config supports protection of sensitive values in Apache NiFi and Apache NiFi Registry", - "", - " --nifiRegistry Targets Apache NiFi Registry configuration files", - "" - } -) -public class SharedEncryptConfig { - - private static final String DEFAULT_PROTECTION_SCHEME = "AES_GCM"; - - private static final String WORKING_FILE_NAME_FORMAT = "%s.%d.working"; - - private static final DerivedKeyGenerator derivedKeyGenerator = new StandardDerivedKeyGenerator(); - - @Option( - names = {"-v", "--verbose"}, - description = "Enable verbose logging for debugging" - ) - boolean verboseModeEnabled; - - @Option( - names = {"-a", "--authorizers"}, - description = "Path to file containing Authorizers [authorizers.xml] configuration that will be updated unless the output argument is provided" - ) - Path authorizersPath; - - @Option( - names = {"-u", "--outputAuthorizers"}, - description = "Path to output file for Authorizers [authorizers.xml] with property protection applied" - ) - Path outputAuthorizersPath; - - @Option( - names = {"-b", "--bootstrapConf"}, - description = "Path to file containing Bootstrap Configuration [bootstrap.conf] for optional root key and property protection scheme settings" - ) - Path bootstrapConfPath; - - @Option( - names = {"-B", "--outputBootstrapConf"}, - description = "Path to output file for Bootstrap Configuration [bootstrap.conf] with root key configured" - ) - Path outputBootstrapConf; - - @Option( - names = {"-S", "--protectionScheme"}, - description = "Protection Scheme for values stored in Application Properties and other configuration files. Default is ${DEFAULT-VALUE}", - defaultValue = DEFAULT_PROTECTION_SCHEME, - converter = ProtectionSchemeTypeConverter.class - ) - ProtectionScheme protectionScheme; - - @Option( - names = {"-H", "--oldProtectionScheme"}, - description = "Previous Protection Scheme for values stored in Application Properties required for migration processing. Default is ${DEFAULT-VALUE}", - defaultValue = DEFAULT_PROTECTION_SCHEME, - converter = ProtectionSchemeTypeConverter.class - ) - ProtectionScheme oldProtectionScheme; - - @Option( - names = {"-k", "--key"}, - description = "Bootstrap hexadecimal root key for encrypting property values in Application Properties and other configuration files", - arity = "0..1", - interactive = true - ) - String key; - - @Option( - names = {"-e", "--oldKey"}, - description = "Previous Bootstrap hexadecimal root key used during migration for encrypting property values in Application Properties", - arity = "0..1", - interactive = true - ) - String oldKey; - - @Option( - names = {"-p", "--password"}, - description = "Bootstrap password from which to derive the root key used to encrypt the sensitive properties in Application Properties", - arity = "0..1", - interactive = true - ) - String password; - - @Option( - names = {"-w", "--oldPassword"}, - description = "Previous Bootstrap password from which to derive the root key during migration for decrypting sensitive properties in Application Properties", - arity = "0..1", - interactive = true - ) - String oldPassword; - - protected final Logger logger = LoggerFactory.getLogger(getClass()); - - /** - * Process bootstrap.conf writing new Root Key to specified Root Key Property when bootstrap.conf is specified - * - * @param rootKeyProperty Root Key Property in bootstrap.conf to be updated - */ - protected void processBootstrapConf(final String rootKeyProperty) { - if (bootstrapConfPath == null) { - if (verboseModeEnabled) { - logger.info("Bootstrap Configuration [bootstrap.conf] not specified"); - } - } else { - final String rootKey = getRootKey(); - if (rootKey == null) { - logger.info("Bootstrap Root Key or Root Password not specified"); - } else { - logger.info("Started processing Bootstrap Configuration [{}]", bootstrapConfPath); - - final FileTransformer fileTransformer = new BootstrapConfigurationFileTransformer(rootKeyProperty, rootKey); - runFileTransformer(fileTransformer, bootstrapConfPath, outputBootstrapConf); - - logger.info("Completed processing Bootstrap Configuration [{}]", bootstrapConfPath); - } - } - } - - /** - * Process authorizers.xml decrypting sensitive values when required and encrypting sensitive values with new settings - */ - protected void processAuthorizers() { - if (authorizersPath == null) { - if (verboseModeEnabled) { - logger.info("Authorizers not specified"); - } - } else { - logger.info("Started processing Authorizers [{}]", authorizersPath); - - final SensitivePropertyProvider inputSensitivePropertyProvider = getInputSensitivePropertyProvider(); - final SensitivePropertyProviderFactory sensitivePropertyProviderFactory = getSensitivePropertyProviderFactory(); - final FileTransformer fileTransformer = new XmlFileTransformer(inputSensitivePropertyProvider, sensitivePropertyProviderFactory, protectionScheme); - runFileTransformer(fileTransformer, authorizersPath, outputAuthorizersPath); - - logger.info("Completed processing Authorizers [{}]", authorizersPath); - } - } - - /** - * Run File Transformer using working path based on output path - * - * @param fileTransformer File Transformer to be invoked - * @param inputPath Input path of file to be transformed - * @param outputPath Output path for transformed file that defaults to the input path when not specified - */ - protected void runFileTransformer(final FileTransformer fileTransformer, final Path inputPath, final Path outputPath) { - final Path configuredOutputPath = outputPath == null ? inputPath : outputPath; - final Path workingPath = getWorkingPath(configuredOutputPath); - try { - fileTransformer.transform(inputPath, workingPath); - Files.move(workingPath, configuredOutputPath, StandardCopyOption.REPLACE_EXISTING); - } catch (final IOException e) { - final String message = String.format("Processing Configuration [%s] failed", inputPath); - throw new UncheckedIOException(message, e); - } - } - - /** - * Get Sensitive Property Provider Factory using provided Root Key or Password for derived Root Key - * - * @return Sensitive Property Provider Factory - */ - protected SensitivePropertyProviderFactory getSensitivePropertyProviderFactory() { - return StandardSensitivePropertyProviderFactory.withKeyAndBootstrapSupplier(getRootKey(), getBootstrapPropertiesSupplier()); - } - - /** - * Get Input Sensitive Property Provider for decrypting previous values - * - * @return Input Sensitive Property Provider - */ - protected SensitivePropertyProvider getInputSensitivePropertyProvider() { - final SensitivePropertyProvider inputSensitivePropertyProvider; - if (oldPassword == null && oldKey == null) { - final SensitivePropertyProviderFactory sensitivePropertyProviderFactory = getSensitivePropertyProviderFactory(); - inputSensitivePropertyProvider = sensitivePropertyProviderFactory.getProvider(protectionScheme); - } else { - final SensitivePropertyProviderFactory sensitivePropertyProviderFactory = getInputSensitivePropertyProviderFactory(); - inputSensitivePropertyProvider = sensitivePropertyProviderFactory.getProvider(oldProtectionScheme); - } - return inputSensitivePropertyProvider; - } - - /** - * Get Bootstrap Root Key provided as hexadecimal encoded key or derived from password - * - * @return Root Key or null when neither Root Key nor Password specified - */ - protected String getRootKey() { - final String rootKey; - - if (key == null) { - if (password == null) { - if (verboseModeEnabled) { - logger.info("Neither Bootstrap Root Key nor Bootstrap Password specified"); - } - rootKey = null; - } else { - if (verboseModeEnabled) { - logger.info("Bootstrap Root Key Derivation started"); - } - rootKey = derivedKeyGenerator.getDerivedKeyEncoded(password.toCharArray()); - } - } else { - rootKey = key; - } - - return rootKey; - } - - /** - * Get Previous Bootstrap Root Key provided as hexadecimal encoded key or derived from password for decrypting previous values - * - * @return Root Key or null when neither Root Key nor Password specified - */ - protected String getInputRootKey() { - final String rootKey; - - if (oldKey == null) { - if (oldPassword == null) { - logger.info("Neither Migration Bootstrap Root Key nor Migration Bootstrap Password specified"); - rootKey = null; - } else { - if (verboseModeEnabled) { - logger.info("Migration Bootstrap Root Key Derivation started"); - } - rootKey = derivedKeyGenerator.getDerivedKeyEncoded(oldPassword.toCharArray()); - } - } else { - rootKey = oldKey; - } - - return rootKey; - } - - private Path getWorkingPath(final Path resourcePath) { - final Path fileName = resourcePath.getFileName(); - final String workingFileName = String.format(WORKING_FILE_NAME_FORMAT, fileName, System.currentTimeMillis()); - return resourcePath.resolveSibling(workingFileName); - } - - private SensitivePropertyProviderFactory getInputSensitivePropertyProviderFactory() { - return StandardSensitivePropertyProviderFactory.withKeyAndBootstrapSupplier(getInputRootKey(), getBootstrapPropertiesSupplier()); - } - - private Supplier getBootstrapPropertiesSupplier() { - return () -> { - if (bootstrapConfPath == null) { - return BootstrapProperties.EMPTY; - } - - try { - return NiFiBootstrapUtils.loadBootstrapProperties(bootstrapConfPath.toString()); - } catch (final IOException e) { - logger.warn("Loading Bootstrap Configuration failed [{}]", bootstrapConfPath, e); - return BootstrapProperties.EMPTY; - } - }; - } -} diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/command/StandardEncryptConfig.java b/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/command/StandardEncryptConfig.java deleted file mode 100644 index ec7fe56255af..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/command/StandardEncryptConfig.java +++ /dev/null @@ -1,250 +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.toolkit.config.command; - -import org.apache.nifi.encrypt.PropertyEncryptor; -import org.apache.nifi.encrypt.PropertyEncryptorBuilder; -import org.apache.nifi.properties.ApplicationProperties; -import org.apache.nifi.properties.ApplicationPropertiesProtector; -import org.apache.nifi.properties.NiFiPropertiesLoader; -import org.apache.nifi.properties.ProtectedNiFiProperties; -import org.apache.nifi.properties.SensitivePropertyProvider; -import org.apache.nifi.properties.SensitivePropertyProviderFactory; -import org.apache.nifi.toolkit.config.transformer.ApplicationPropertiesFileTransformer; -import org.apache.nifi.toolkit.config.transformer.FileTransformer; -import org.apache.nifi.toolkit.config.transformer.FlowConfigurationFileTransformer; -import org.apache.nifi.toolkit.config.transformer.XmlFileTransformer; -import org.apache.nifi.util.NiFiProperties; -import picocli.CommandLine.Command; -import picocli.CommandLine.Option; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Collections; -import java.util.Objects; -import java.util.Set; - -/** - * Encrypt Config Standard implementation for NiFi configuration files - */ -@Command -public class StandardEncryptConfig extends SharedEncryptConfig implements Runnable { - - static final String BOOTSTRAP_ROOT_KEY_PROPERTY = "nifi.bootstrap.sensitive.key"; - - private static final String DEFAULT_PROPERTIES_ALGORITHM = "NIFI_PBKDF2_AES_GCM_256"; - - @Option( - names = {"-m", "--migrate"}, - description = "Migrate configuration files from current protection configuration to new protection configuration" - ) - boolean migrationRequested; - - @Option( - names = {"-x", "--encryptFlowXmlOnly", "--encryptFlowJsonOnly"}, - description = "Process Flow Configuration [flow.json.gz] sensitive property values without modifying other configuration files" - ) - boolean flowConfigurationRequested; - - @Option( - names = {"-n", "--niFiProperties"}, - description = "Path to file containing Application Properties [nifi.properties] that will be updated unless the output argument is provided" - ) - Path applicationPropertiesPath; - - @Option( - names = {"-o", "--outputNiFiProperties"}, - description = "Path to output file for Application Properties [nifi.properties] with property protection applied" - ) - Path outputApplicationPropertiesPath; - - @Option( - names = {"-l", "--loginIdentityProviders"}, - description = "Path to file containing Login Identity Providers [login-identity-providers.xml] configuration that will be updated unless the output argument is provided" - ) - Path loginIdentityProvidersPath; - - @Option( - names = {"-i", "--outputLoginIdentityProviders"}, - description = "Path to output file for Login Identity Providers [login-identity-providers.xml] with property protection applied" - ) - Path outputLoginIdentityProvidersPath; - - @Option( - names = {"-f", "--flowConfiguration", "--flowJson", "--flowXml"}, - description = "Path to file containing Flow Configuration [flow.json.gz] that will be updated unless the output argument is provided" - ) - Path flowConfigurationPath; - - @Option( - names = {"-g", "--outputFlowConfiguration", "--outputFlowJson", "--outputFlowXml"}, - description = "Path to output file for Flow Configuration [flow.json.gz] with property protection applied" - ) - Path outputFlowConfigurationPath; - - @Option( - names = {"-s", "--propsKey"}, - description = "Properties Key [nifi.sensitive.props.key] from which to derive the key used to encrypt the sensitive values in the Flow Configuration", - arity = "0..1", - interactive = true - ) - String sensitivePropertiesKey; - - @Option( - names = {"-A", "--newFlowAlgorithm"}, - description = "Properties Algorithm [nifi.sensitive.props.algorithm] with which to encrypt the sensitive values in the Flow Configuration. Default is ${DEFAULT-VALUE}", - defaultValue = DEFAULT_PROPERTIES_ALGORITHM - ) - String newFlowAlgorithm; - - @Override - public void run() { - final ApplicationProperties applicationProperties = loadApplicationProperties(); - - processBootstrapConf(BOOTSTRAP_ROOT_KEY_PROPERTY); - processApplicationProperties(applicationProperties); - processFlowConfiguration(applicationProperties); - processAuthorizers(); - processLoginIdentityProviders(); - } - - @Override - protected void processBootstrapConf(final String rootKeyProperty) { - if (flowConfigurationRequested) { - logger.info("Bootstrap Configuration [bootstrap.conf] not modified based on provided arguments"); - } else { - super.processBootstrapConf(rootKeyProperty); - } - } - - @Override - protected void processAuthorizers() { - if (flowConfigurationRequested) { - logger.info("Authorizers not modified based on provided arguments"); - } else { - super.processAuthorizers(); - } - } - - private ApplicationProperties loadApplicationProperties() { - final ApplicationProperties applicationProperties; - - if (applicationPropertiesPath == null) { - applicationProperties = new ApplicationProperties(Collections.emptyMap()); - if (verboseModeEnabled) { - logger.info("Application Properties [nifi.properties] not specified"); - } - } else if (Files.notExists(applicationPropertiesPath)) { - throw new IllegalArgumentException(String.format("Application Properties [nifi.properties] not found [%s]", applicationPropertiesPath)); - } else { - final NiFiPropertiesLoader propertiesLoader = new NiFiPropertiesLoader(); - - final String rootKey = migrationRequested ? getInputRootKey() : getRootKey(); - propertiesLoader.setKeyHex(rootKey); - - applicationProperties = propertiesLoader.load(applicationPropertiesPath.toFile()); - } - - return applicationProperties; - } - - private void processApplicationProperties(final ApplicationProperties applicationProperties) { - if (applicationPropertiesPath == null) { - if (verboseModeEnabled) { - logger.info("Application Properties [nifi.properties] not specified"); - } - } else if (flowConfigurationRequested) { - logger.info("Application Properties [nifi.properties] not modified based on provided arguments"); - } else { - logger.info("Started processing Application Properties [{}]", applicationPropertiesPath); - - final SensitivePropertyProviderFactory sensitivePropertyProviderFactory = getSensitivePropertyProviderFactory(); - final SensitivePropertyProvider sensitivePropertyProvider = sensitivePropertyProviderFactory.getProvider(protectionScheme); - final Set sensitivePropertyNames = getSensitivePropertyNames(); - final FileTransformer fileTransformer = new ApplicationPropertiesFileTransformer(applicationProperties, sensitivePropertyProvider, sensitivePropertyNames); - runFileTransformer(fileTransformer, applicationPropertiesPath, outputApplicationPropertiesPath); - - logger.info("Completed processing Application Properties [{}]", applicationPropertiesPath); - } - } - - private void processFlowConfiguration(final ApplicationProperties applicationProperties) { - if (flowConfigurationPath == null) { - if (verboseModeEnabled) { - logger.info("Flow Configuration not specified"); - } - } else { - logger.info("Started processing Flow Configuration [{}]", flowConfigurationPath); - - final PropertyEncryptor inputPropertyEncryptor = getInputPropertyEncryptor(applicationProperties); - final PropertyEncryptor outputPropertyEncryptor = getOutputPropertyEncryptor(applicationProperties); - final FileTransformer fileTransformer = new FlowConfigurationFileTransformer(inputPropertyEncryptor, outputPropertyEncryptor); - runFileTransformer(fileTransformer, flowConfigurationPath, outputFlowConfigurationPath); - - logger.info("Completed processing Flow Configuration [{}]", flowConfigurationPath); - } - } - - private void processLoginIdentityProviders() { - if (loginIdentityProvidersPath == null) { - if (verboseModeEnabled) { - logger.info("Login Identity Providers not specified"); - } - } else if (flowConfigurationRequested) { - logger.info("Login Identity Providers not modified based on provided arguments"); - } else { - logger.info("Started processing Login Identity Providers [{}]", loginIdentityProvidersPath); - - final SensitivePropertyProvider inputSensitivePropertyProvider = getInputSensitivePropertyProvider(); - final SensitivePropertyProviderFactory sensitivePropertyProviderFactory = getSensitivePropertyProviderFactory(); - final FileTransformer fileTransformer = new XmlFileTransformer(inputSensitivePropertyProvider, sensitivePropertyProviderFactory, protectionScheme); - runFileTransformer(fileTransformer, loginIdentityProvidersPath, outputLoginIdentityProvidersPath); - - logger.info("Completed processing Login Identity Providers [{}]", loginIdentityProvidersPath); - } - } - - private PropertyEncryptor getInputPropertyEncryptor(final ApplicationProperties applicationProperties) { - final String applicationSensitivePropertiesKey = applicationProperties.getProperty(NiFiProperties.SENSITIVE_PROPS_KEY); - if (applicationSensitivePropertiesKey == null) { - throw new IllegalArgumentException(String.format("Sensitive Properties Key [%s] not found in Application Properties", NiFiProperties.SENSITIVE_PROPS_KEY)); - } - - final String sensitivePropertiesAlgorithm = applicationProperties.getProperty(NiFiProperties.SENSITIVE_PROPS_ALGORITHM, DEFAULT_PROPERTIES_ALGORITHM); - return new PropertyEncryptorBuilder(applicationSensitivePropertiesKey).setAlgorithm(sensitivePropertiesAlgorithm).build(); - } - - private PropertyEncryptor getOutputPropertyEncryptor(final ApplicationProperties applicationProperties) { - if (sensitivePropertiesKey == null) { - throw new IllegalArgumentException("Sensitive Properties Key not provided"); - } - - final String sensitivePropertiesAlgorithm = applicationProperties.getProperty(NiFiProperties.SENSITIVE_PROPS_ALGORITHM, DEFAULT_PROPERTIES_ALGORITHM); - final String outputPropertiesAlgorithm = Objects.requireNonNullElse(newFlowAlgorithm, sensitivePropertiesAlgorithm); - - if (verboseModeEnabled) { - logger.info("Output Sensitive Properties Algorithm configured [{}]", outputPropertiesAlgorithm); - } - - return new PropertyEncryptorBuilder(sensitivePropertiesKey).setAlgorithm(outputPropertiesAlgorithm).build(); - } - - private Set getSensitivePropertyNames() { - final ApplicationPropertiesProtector protector = new ApplicationPropertiesProtector<>(new ProtectedNiFiProperties()); - return Set.copyOf(protector.getSensitivePropertyKeys()); - } -} diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/command/converter/ProtectionSchemeTypeConverter.java b/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/command/converter/ProtectionSchemeTypeConverter.java deleted file mode 100644 index 4ceb90a85ab7..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/command/converter/ProtectionSchemeTypeConverter.java +++ /dev/null @@ -1,40 +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.toolkit.config.command.converter; - -import org.apache.nifi.properties.scheme.ProtectionScheme; -import org.apache.nifi.properties.scheme.ProtectionSchemeResolver; -import org.apache.nifi.properties.scheme.StandardProtectionSchemeResolver; -import picocli.CommandLine; - -/** - * Argument Type Converter implementation for Property Protection Schemes - */ -public class ProtectionSchemeTypeConverter implements CommandLine.ITypeConverter { - private static final ProtectionSchemeResolver PROTECTION_SCHEME_RESOLVER = new StandardProtectionSchemeResolver(); - - /** - * Convert value to Property Protection Scheme using Resolver based on enumerated name or matching path string - * - * @param value Argument value to be converted - * @return Protection Scheme resolved from argument value provided - */ - @Override - public ProtectionScheme convert(final String value) { - return PROTECTION_SCHEME_RESOLVER.getProtectionScheme(value); - } -} diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/crypto/DerivedKeyGenerator.java b/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/crypto/DerivedKeyGenerator.java deleted file mode 100644 index a92b4bee31d4..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/crypto/DerivedKeyGenerator.java +++ /dev/null @@ -1,30 +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.toolkit.config.crypto; - -/** - * Abstraction for generating an encryption key from a password - */ -public interface DerivedKeyGenerator { - /** - * Get Derived Key based on the provided password and return an encoded representation - * - * @param password Password source for key derivation - * @return Derived key encoded using hexadecimal - */ - String getDerivedKeyEncoded(char[] password); -} diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/crypto/StandardDerivedKeyGenerator.java b/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/crypto/StandardDerivedKeyGenerator.java deleted file mode 100644 index b3adc6287555..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/crypto/StandardDerivedKeyGenerator.java +++ /dev/null @@ -1,58 +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.toolkit.config.crypto; - -import org.apache.nifi.security.crypto.key.DerivedKey; -import org.apache.nifi.security.crypto.key.DerivedKeySpec; -import org.apache.nifi.security.crypto.key.StandardDerivedKeySpec; -import org.apache.nifi.security.crypto.key.scrypt.ScryptDerivedKeyParameterSpec; -import org.apache.nifi.security.crypto.key.scrypt.ScryptDerivedKeyProvider; - -import java.nio.charset.StandardCharsets; -import java.util.HexFormat; -import java.util.Objects; - -/** - * Standard implementation of Derived Key Generator using scrypt with compatible parameters and preset salt for reproducible outputs - */ -public class StandardDerivedKeyGenerator implements DerivedKeyGenerator { - - private static final String SALT = "NIFI_SCRYPT_SALT"; - - private static final ScryptDerivedKeyProvider KEY_PROVIDER = new ScryptDerivedKeyProvider(); - - private static final ScryptDerivedKeyParameterSpec KEY_PARAMETER_SPEC = new ScryptDerivedKeyParameterSpec(65536, 8, 1, SALT.getBytes(StandardCharsets.UTF_8)); - - private static final String KEY_ALGORITHM = "AES"; - - private static final int KEY_LENGTH = 32; - - /** - * Get Derived Key based on the provided password using scrypt and return an encoded representation - * - * @param password Password source for key derivation - * @return Derived key encoded using hexadecimal - */ - @Override - public String getDerivedKeyEncoded(char[] password) { - Objects.requireNonNull(password, "Password required"); - - final DerivedKeySpec derivedKeySpec = new StandardDerivedKeySpec<>(password, KEY_LENGTH, KEY_ALGORITHM, KEY_PARAMETER_SPEC); - final DerivedKey derivedKey = KEY_PROVIDER.getDerivedKey(derivedKeySpec); - return HexFormat.of().formatHex(derivedKey.getEncoded()); - } -} diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/transformer/ApplicationPropertiesFileTransformer.java b/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/transformer/ApplicationPropertiesFileTransformer.java deleted file mode 100644 index 2acfaecf77c3..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/transformer/ApplicationPropertiesFileTransformer.java +++ /dev/null @@ -1,166 +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.toolkit.config.transformer; - -import org.apache.nifi.properties.ApplicationProperties; -import org.apache.nifi.properties.ApplicationPropertiesProtector; -import org.apache.nifi.properties.ProtectedPropertyContext; -import org.apache.nifi.properties.SensitivePropertyProvider; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Objects; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * File Transformer supporting transformation of Application Properties with sensitive property values - */ -public class ApplicationPropertiesFileTransformer implements FileTransformer { - - private static final Pattern PROPERTY_VALUE_PATTERN = Pattern.compile("^([^#!][^=]+?)\\s*=\\s?(.+)"); - - private static final int NAME_GROUP = 1; - - private static final int VALUE_GROUP = 2; - - private static final char PROPERTY_VALUE_SEPARATOR = '='; - - private final ApplicationProperties applicationProperties; - - private final SensitivePropertyProvider outputSensitivePropertyProvider; - - private final Set sensitivePropertyNames; - - /** - * Application Properties File Transformer uses provided Application Properties as the source of protected values - * - * @param applicationProperties Application Properties containing decrypted source property values - * @param outputSensitivePropertyProvider Sensitive Property Provider encrypts specified sensitive property values - * @param sensitivePropertyNames Sensitive Property Names marked for encryption - */ - public ApplicationPropertiesFileTransformer( - final ApplicationProperties applicationProperties, - final SensitivePropertyProvider outputSensitivePropertyProvider, - final Set sensitivePropertyNames - ) { - this.applicationProperties = Objects.requireNonNull(applicationProperties, "Application Properties required"); - this.outputSensitivePropertyProvider = Objects.requireNonNull(outputSensitivePropertyProvider, "Output Property Provider required"); - this.sensitivePropertyNames = Objects.requireNonNull(sensitivePropertyNames, "Sensitive Property Names required"); - } - - /** - * Transform input application properties using configured Sensitive Property Provider and write output properties - * - * @param inputPath Input file path to be transformed containing source application properties - * @param outputPath Output file path for protected application properties - * @throws IOException Thrown on transformation failures - */ - @Override - public void transform(final Path inputPath, final Path outputPath) throws IOException { - Objects.requireNonNull(inputPath, "Input path required"); - Objects.requireNonNull(outputPath, "Output path required"); - - try ( - BufferedReader reader = Files.newBufferedReader(inputPath); - BufferedWriter writer = Files.newBufferedWriter(outputPath) - ) { - transform(reader, writer); - } - } - - private void transform(final BufferedReader reader, final BufferedWriter writer) throws IOException { - String line = reader.readLine(); - while (line != null) { - final Matcher matcher = PROPERTY_VALUE_PATTERN.matcher(line); - if (matcher.matches()) { - final String name = matcher.group(NAME_GROUP); - final String value = matcher.group(VALUE_GROUP); - final String protectedName = ApplicationPropertiesProtector.getProtectionKey(name); - - final String nextLine = reader.readLine(); - if (nextLine == null) { - if (sensitivePropertyNames.contains(name)) { - writeProtectedProperty(writer, name, value); - } else { - writer.write(line); - writer.newLine(); - } - break; - } - - final Matcher nextLineMatcher = PROPERTY_VALUE_PATTERN.matcher(nextLine); - if (nextLineMatcher.matches()) { - final String nextName = nextLineMatcher.group(NAME_GROUP); - final String nextValue = nextLineMatcher.group(VALUE_GROUP); - - if (protectedName.equals(nextName)) { - // Read application property and write protected property - final String applicationProperty = applicationProperties.getProperty(name, value); - writeProtectedProperty(writer, name, applicationProperty); - } else { - if (sensitivePropertyNames.contains(name)) { - writeProtectedProperty(writer, name, value); - } else { - writer.write(line); - writer.newLine(); - } - if (sensitivePropertyNames.contains(nextName)) { - writeProtectedProperty(writer, nextName, nextValue); - } else { - writer.write(nextLine); - writer.newLine(); - } - } - } else if (sensitivePropertyNames.contains(name)) { - writeProtectedProperty(writer, name, value); - } else { - writer.write(line); - writer.newLine(); - writer.write(nextLine); - writer.newLine(); - } - } else { - writer.write(line); - writer.newLine(); - } - - line = reader.readLine(); - } - } - - private void writeProtectedProperty(final BufferedWriter writer, final String name, final String value) throws IOException { - final ProtectedPropertyContext propertyContext = ProtectedPropertyContext.defaultContext(name); - final String protectedValue = outputSensitivePropertyProvider.protect(value, propertyContext); - - writer.write(name); - writer.write(PROPERTY_VALUE_SEPARATOR); - writer.write(protectedValue); - writer.newLine(); - - final String protectedName = ApplicationPropertiesProtector.getProtectionKey(name); - writer.write(protectedName); - writer.write(PROPERTY_VALUE_SEPARATOR); - final String protectionIdentifierKey = outputSensitivePropertyProvider.getIdentifierKey(); - writer.write(protectionIdentifierKey); - writer.newLine(); - } -} diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/transformer/BootstrapConfigurationFileTransformer.java b/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/transformer/BootstrapConfigurationFileTransformer.java deleted file mode 100644 index 30a67a9d1ed3..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/transformer/BootstrapConfigurationFileTransformer.java +++ /dev/null @@ -1,110 +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.toolkit.config.transformer; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Objects; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * File Transformer supporting Bootstrap Configuration with updated Root Key - */ -public class BootstrapConfigurationFileTransformer implements FileTransformer { - - private static final Pattern PROPERTY_VALUE_PATTERN = Pattern.compile("^([^#!][^=]+?)\\s*=.*"); - - private static final int NAME_GROUP = 1; - - private static final char PROPERTY_VALUE_SEPARATOR = '='; - - private final String rootKeyPropertyName; - - private final String rootKey; - - /** - * Bootstrap Configuration File Transformer writes provided Root Key to output files - * - * @param rootKeyPropertyName Root Key property name to be written - * @param rootKey Root Key to be written - */ - public BootstrapConfigurationFileTransformer(final String rootKeyPropertyName, final String rootKey) { - this.rootKeyPropertyName = Objects.requireNonNull(rootKeyPropertyName, "Root Key Property Name required"); - this.rootKey = Objects.requireNonNull(rootKey, "Root Key required"); - } - - /** - * Transform input configuration and write Root Key to output location - * - * @param inputPath Input file path to be transformed containing Bootstrap Configuration - * @param outputPath Output file path for updated configuration - * @throws IOException Thrown on transformation failures - */ - @Override - public void transform(final Path inputPath, final Path outputPath) throws IOException { - Objects.requireNonNull(inputPath, "Input path required"); - Objects.requireNonNull(outputPath, "Output path required"); - - try ( - BufferedReader reader = Files.newBufferedReader(inputPath); - BufferedWriter writer = Files.newBufferedWriter(outputPath) - ) { - transform(reader, writer); - } - } - - private void transform(final BufferedReader reader, final BufferedWriter writer) throws IOException { - boolean rootKeyPropertyNotFound = true; - - String line = reader.readLine(); - while (line != null) { - final Matcher matcher = PROPERTY_VALUE_PATTERN.matcher(line); - if (matcher.matches()) { - final String name = matcher.group(NAME_GROUP); - - if (rootKeyPropertyName.equals(name)) { - writeRootKey(writer); - rootKeyPropertyNotFound = false; - } else { - writer.write(line); - writer.newLine(); - } - } else { - writer.write(line); - writer.newLine(); - } - - line = reader.readLine(); - } - - if (rootKeyPropertyNotFound) { - writer.newLine(); - writeRootKey(writer); - } - } - - private void writeRootKey(final BufferedWriter writer) throws IOException { - writer.write(rootKeyPropertyName); - writer.write(PROPERTY_VALUE_SEPARATOR); - writer.write(rootKey); - writer.newLine(); - } -} diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/transformer/FileTransformer.java b/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/transformer/FileTransformer.java deleted file mode 100644 index 8ddd09a973ef..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/transformer/FileTransformer.java +++ /dev/null @@ -1,34 +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.toolkit.config.transformer; - -import java.io.IOException; -import java.nio.file.Path; - -/** - * Abstraction for transforming Files - */ -public interface FileTransformer { - /** - * Transform input file and write contents to output file path - * - * @param inputPath Input file path to be transformed - * @param outputPath Output file path - * @throws IOException Thrown on input or output processing failures - */ - void transform(Path inputPath, Path outputPath) throws IOException; -} diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/transformer/FlowConfigurationFileTransformer.java b/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/transformer/FlowConfigurationFileTransformer.java deleted file mode 100644 index 369f2585e0cd..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/transformer/FlowConfigurationFileTransformer.java +++ /dev/null @@ -1,65 +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.toolkit.config.transformer; - -import org.apache.nifi.encrypt.PropertyEncryptor; -import org.apache.nifi.flow.encryptor.FlowEncryptor; -import org.apache.nifi.flow.encryptor.JsonFlowEncryptor; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Objects; -import java.util.zip.GZIPInputStream; -import java.util.zip.GZIPOutputStream; - -/** - * File Transformer supporting transformation of Flow Configuration with sensitive property values - */ -public class FlowConfigurationFileTransformer implements FileTransformer { - - private final PropertyEncryptor inputEncryptor; - - private final PropertyEncryptor outputEncryptor; - - /** - * Flow Configuration File Transformer with components required for decrypting input values and encrypting output values - * - * @param inputEncryptor Property Encryptor for decrypting input values - * @param outputEncryptor Property Encryptor for encrypting output values - */ - public FlowConfigurationFileTransformer(final PropertyEncryptor inputEncryptor, final PropertyEncryptor outputEncryptor) { - this.inputEncryptor = Objects.requireNonNull(inputEncryptor, "Input Encryptor required"); - this.outputEncryptor = Objects.requireNonNull(outputEncryptor, "Output Encryptor required"); - } - - @Override - public void transform(final Path inputPath, final Path outputPath) throws IOException { - Objects.requireNonNull(inputPath, "Input path required"); - Objects.requireNonNull(outputPath, "Output path required"); - - try ( - InputStream inputStream = new GZIPInputStream(Files.newInputStream(inputPath)); - OutputStream outputStream = new GZIPOutputStream(Files.newOutputStream(outputPath)) - ) { - final FlowEncryptor flowEncryptor = new JsonFlowEncryptor(); - flowEncryptor.processFlow(inputStream, outputStream, inputEncryptor, outputEncryptor); - } - } -} diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/transformer/XmlFileTransformer.java b/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/transformer/XmlFileTransformer.java deleted file mode 100644 index dbe53393f2ab..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/toolkit/config/transformer/XmlFileTransformer.java +++ /dev/null @@ -1,224 +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.toolkit.config.transformer; - -import org.apache.nifi.properties.ProtectedPropertyContext; -import org.apache.nifi.properties.SensitivePropertyProvider; -import org.apache.nifi.properties.SensitivePropertyProviderFactory; -import org.apache.nifi.properties.scheme.ProtectionScheme; -import org.apache.nifi.xml.processing.stream.StandardXMLEventReaderProvider; -import org.apache.nifi.xml.processing.stream.XMLEventReaderProvider; - -import javax.xml.namespace.QName; -import javax.xml.stream.XMLEventFactory; -import javax.xml.stream.XMLEventReader; -import javax.xml.stream.XMLEventWriter; -import javax.xml.stream.XMLOutputFactory; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.events.Attribute; -import javax.xml.stream.events.Characters; -import javax.xml.stream.events.Namespace; -import javax.xml.stream.events.StartElement; -import javax.xml.stream.events.XMLEvent; -import javax.xml.transform.stream.StreamSource; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.Iterator; -import java.util.Objects; -import java.util.regex.Pattern; - -/** - * File Transformer supporting transformation of XML configuration files containing property elements - */ -public class XmlFileTransformer implements FileTransformer { - private static final Pattern SENSITIVE_PATTERN = Pattern.compile("Password|Secret"); - - private static final QName NAME_ATTRIBUTE = QName.valueOf("name"); - - private static final QName ENCRYPTION_ATTRIBUTE = QName.valueOf("encryption"); - - private static final String IDENTIFIER_ELEMENT_NAME = "identifier"; - - private static final XMLEventReaderProvider readerProvider = new StandardXMLEventReaderProvider(); - - private final XMLEventFactory eventFactory = XMLEventFactory.newFactory(); - - private final SensitivePropertyProvider inputSensitivePropertyProvider; - - private final SensitivePropertyProviderFactory sensitivePropertyProviderFactory; - - private final SensitivePropertyProvider sensitivePropertyProvider; - - /** - * XML File Transformer with Sensitive Property Provider Factory and Protection Scheme applied when writing output files - * - * @param sensitivePropertyProviderFactory Sensitive Property Provider Factory for output files - * @param protectionScheme Protection Scheme for output files - */ - public XmlFileTransformer( - final SensitivePropertyProvider inputSensitivePropertyProvider, - final SensitivePropertyProviderFactory sensitivePropertyProviderFactory, - final ProtectionScheme protectionScheme - ) { - this.inputSensitivePropertyProvider = Objects.requireNonNull(inputSensitivePropertyProvider, "Input Sensitive Property Provider required"); - this.sensitivePropertyProviderFactory = Objects.requireNonNull(sensitivePropertyProviderFactory, "Sensitive Property Provider Factory required"); - this.sensitivePropertyProvider = sensitivePropertyProviderFactory.getProvider(Objects.requireNonNull(protectionScheme, "Protection Scheme required")); - } - - /** - * Read input file using XMLEventReader and write protected values using XMLEventWriter - * - * @param inputPath Input file path to be transformed - * @param outputPath Output file path containing protected values - * @throws IOException Thrown on transformation failures - */ - @Override - public void transform(final Path inputPath, final Path outputPath) throws IOException { - Objects.requireNonNull(inputPath, "Input path required"); - Objects.requireNonNull(outputPath, "Output path required"); - - try ( - InputStream inputStream = Files.newInputStream(inputPath); - OutputStream outputStream = Files.newOutputStream(outputPath) - ) { - final StreamSource streamSource = new StreamSource(inputStream); - final XMLEventReader eventReader = readerProvider.getEventReader(streamSource); - - final XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); - final XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(outputStream); - - try { - transform(eventReader, eventWriter); - } finally { - eventReader.close(); - eventWriter.close(); - } - } catch (final XMLStreamException e) { - final String message = String.format("XML processing failed [%s]", inputPath); - throw new IOException(message, e); - } - } - - /** - * Transform input XML Event Reader to output XML Event Writer - * - * @param eventReader XML Event Reader - * @param eventWriter XML Event Writer - * @throws XMLStreamException Thrown on XML processing failures - */ - protected void transform(final XMLEventReader eventReader, final XMLEventWriter eventWriter) throws XMLStreamException { - String groupIdentifier = null; - - while (eventReader.hasNext()) { - final XMLEvent event = eventReader.nextEvent(); - - if (event.isStartElement()) { - final StartElement startElement = event.asStartElement(); - final QName startElementName = startElement.getName(); - final String startElementLocalPart = startElementName.getLocalPart(); - if (IDENTIFIER_ELEMENT_NAME.equals(startElementLocalPart)) { - final XMLEvent nextEvent = eventReader.nextEvent(); - if (nextEvent.isCharacters()) { - groupIdentifier = nextEvent.asCharacters().getData(); - } - eventWriter.add(startElement); - eventWriter.add(nextEvent); - } else if (isEncryptionRequired(startElement)) { - transformStartElement(eventReader, eventWriter, startElement, groupIdentifier); - } else { - eventWriter.add(event); - } - } else { - eventWriter.add(event); - } - } - } - - private boolean isEncryptionSupported(final String propertyName) { - final boolean encryptionSupported; - - if (propertyName == null || propertyName.isEmpty()) { - encryptionSupported = false; - } else { - encryptionSupported = SENSITIVE_PATTERN.matcher(propertyName).find(); - } - - return encryptionSupported; - } - - private boolean isEncryptionRequired(final StartElement startElement) { - final String name = getNameAttribute(startElement); - return isEncryptionSupported(name); - } - - private void transformStartElement( - final XMLEventReader eventReader, - final XMLEventWriter eventWriter, - final StartElement startElement, - final String groupIdentifier - ) throws XMLStreamException { - final XMLEvent nextEvent = eventReader.nextEvent(); - if (nextEvent.isCharacters()) { - final Attribute nameAttribute = startElement.getAttributeByName(NAME_ATTRIBUTE); - final String propertyName = nameAttribute.getValue(); - final ProtectedPropertyContext propertyContext = sensitivePropertyProviderFactory.getPropertyContext(groupIdentifier, propertyName); - - final StartElement encryptedStartElement = getEncryptedStartElement(startElement); - eventWriter.add(encryptedStartElement); - - final String data = nextEvent.asCharacters().getData(); - final String inputData; - final String encryption = getEncryptionAttribute(startElement); - if (encryption == null) { - inputData = data; - } else { - inputData = inputSensitivePropertyProvider.unprotect(data, propertyContext); - } - - final String protectedProperty = sensitivePropertyProvider.protect(inputData, propertyContext); - final Characters characters = eventFactory.createCharacters(protectedProperty); - eventWriter.add(characters); - } else { - eventWriter.add(startElement); - eventWriter.add(nextEvent); - } - } - - private String getNameAttribute(final StartElement startElement) { - final Attribute attribute = startElement.getAttributeByName(NAME_ATTRIBUTE); - return attribute == null ? null : attribute.getValue(); - } - - private String getEncryptionAttribute(final StartElement startElement) { - final Attribute attribute = startElement.getAttributeByName(ENCRYPTION_ATTRIBUTE); - return attribute == null ? null : attribute.getValue(); - } - - private StartElement getEncryptedStartElement(final StartElement startElement) { - final String name = getNameAttribute(startElement); - final Attribute nameAttribute = eventFactory.createAttribute(NAME_ATTRIBUTE, name); - final Attribute encryptionAttribute = eventFactory.createAttribute(ENCRYPTION_ATTRIBUTE, sensitivePropertyProvider.getIdentifierKey()); - - final Iterator attributes = Arrays.asList(encryptionAttribute, nameAttribute).iterator(); - final Iterator namespaces = startElement.getNamespaces(); - return eventFactory.createStartElement(startElement.getName(), attributes, namespaces); - } -} diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/toolkit/config/command/RegistryEncryptConfigTest.java b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/toolkit/config/command/RegistryEncryptConfigTest.java deleted file mode 100644 index f299b1a750b3..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/toolkit/config/command/RegistryEncryptConfigTest.java +++ /dev/null @@ -1,241 +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.toolkit.config.command; - -import org.apache.nifi.properties.ApplicationPropertiesProtector; -import org.apache.nifi.xml.processing.parsers.DocumentProvider; -import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; -import org.w3c.dom.Document; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import picocli.CommandLine; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.PrintWriter; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Objects; -import java.util.Properties; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -class RegistryEncryptConfigTest { - - private static final String BOOTSTRAP_CONF_RESOURCE = "/command/bootstrap-registry.conf"; - - private static final String APPLICATION_PROPERTIES_RESOURCE = "/command/nifi-registry.properties"; - - private static final String AUTHORIZERS_UNPROTECTED_RESOURCE = "/transformer/authorizers-unprotected.xml"; - - private static final String IDENTITY_PROVIDERS_UNPROTECTED_RESOURCE = "/command/identity-providers-unprotected.xml"; - - private static final String APPLICATION_PROPERTIES_TRANSFORMED = "transformed.nifi.properties"; - - private static final String AUTHORIZERS_TRANSFORMED = "transformed.authorizers.xml"; - - private static final String IDENTITY_PROVIDERS_TRANSFORMED = "transformed.identity-providers.xml"; - - private static final String BOOTSTRAP_CONF_TRANSFORMED = "transformed.bootstrap-registry.conf"; - - private static final String BOOTSTRAP_HEXADECIMAL_KEY = "012345678901234567890123456789012345678901234567890123456789ABCD"; - - private static final String PROTECTED_PROPERTY_NAME = "Random Password"; - - private static final String SENSITIVE_APPLICATION_PROPERTY = "nifi.registry.security.keystorePasswd"; - - private static final String PROTECTED_IDENTIFIER = "aes/gcm/256"; - - @TempDir - private Path tempDir; - - @Test - void testRun() { - final String[] arguments = new String[0]; - - final int status = run(arguments); - assertEquals(CommandLine.ExitCode.OK, status); - } - - @Test - void testHelpRequested() { - final String[] arguments = {"-h"}; - - final int status = run(arguments); - assertEquals(CommandLine.ExitCode.OK, status); - } - - @Test - void testApplicationPropertiesNotFound() { - final Path propertiesPath = tempDir.resolve(APPLICATION_PROPERTIES_TRANSFORMED); - - final String[] arguments = { - "-k", BOOTSTRAP_HEXADECIMAL_KEY, - "-r", propertiesPath.toString() - }; - - final int status = run(arguments); - assertEquals(CommandLine.ExitCode.SOFTWARE, status); - } - - @Test - void testApplicationProperties() throws URISyntaxException, IOException { - final Path propertiesPath = getResourcePath(APPLICATION_PROPERTIES_RESOURCE); - final Path outputPropertiesPath = tempDir.resolve(APPLICATION_PROPERTIES_TRANSFORMED); - - final String[] arguments = { - "-k", BOOTSTRAP_HEXADECIMAL_KEY, - "-r", propertiesPath.toString(), - "-R", outputPropertiesPath.toString() - }; - - final int status = run(arguments); - assertEquals(CommandLine.ExitCode.OK, status); - - assertProtectedPropertyFound(outputPropertiesPath); - } - - @Test - void testApplicationPropertiesWithBootstrapConf() throws URISyntaxException, IOException { - final Path propertiesPath = getResourcePath(APPLICATION_PROPERTIES_RESOURCE); - final Path outputPropertiesPath = tempDir.resolve(APPLICATION_PROPERTIES_TRANSFORMED); - - final Path bootstrapConfPath = getResourcePath(BOOTSTRAP_CONF_RESOURCE); - final Path outputBootstrapConfPath = tempDir.resolve(BOOTSTRAP_CONF_TRANSFORMED); - - final String[] arguments = { - "-k", BOOTSTRAP_HEXADECIMAL_KEY, - "-b", bootstrapConfPath.toString(), - "-B", outputBootstrapConfPath.toString(), - "-r", propertiesPath.toString(), - "-R", outputPropertiesPath.toString() - }; - - final int status = run(arguments); - assertEquals(CommandLine.ExitCode.OK, status); - - assertProtectedPropertyFound(outputPropertiesPath); - assertRootKeyFound(outputBootstrapConfPath); - } - - @Test - void testAuthorizersWithKey() throws URISyntaxException, IOException { - final Path authorizersPath = getResourcePath(AUTHORIZERS_UNPROTECTED_RESOURCE); - final Path outputAuthorizersPath = tempDir.resolve(AUTHORIZERS_TRANSFORMED); - - final String[] arguments = { - "-k", BOOTSTRAP_HEXADECIMAL_KEY, - "-a", authorizersPath.toString(), - "-u", outputAuthorizersPath.toString() - }; - - final int status = run(arguments); - assertEquals(CommandLine.ExitCode.OK, status); - - assertEncryptedPropertyFound(outputAuthorizersPath); - } - - @Test - void testIdentityProvidersWithKey() throws URISyntaxException, IOException { - final Path identityProvidersPath = getResourcePath(IDENTITY_PROVIDERS_UNPROTECTED_RESOURCE); - final Path outputIdentityProvidersPath = tempDir.resolve(IDENTITY_PROVIDERS_TRANSFORMED); - - final String[] arguments = { - "-k", BOOTSTRAP_HEXADECIMAL_KEY, - "-i", identityProvidersPath.toString(), - "-I", outputIdentityProvidersPath.toString() - }; - - final int status = run(arguments); - assertEquals(CommandLine.ExitCode.OK, status); - - assertEncryptedPropertyFound(outputIdentityProvidersPath); - } - - private int run(final String[] arguments) { - final CommandLine commandLine = new CommandLine(new RegistryEncryptConfig()); - final PrintWriter writer = new PrintWriter(new ByteArrayOutputStream()); - commandLine.setOut(writer); - commandLine.setErr(writer); - return commandLine.execute(arguments); - } - - private void assertEncryptedPropertyFound(final Path resourcePath) throws IOException { - try (InputStream inputStream = Files.newInputStream(resourcePath)) { - final DocumentProvider documentProvider = new StandardDocumentProvider(); - final Document document = documentProvider.parse(inputStream); - final NodeList propertyNodes = document.getElementsByTagName("property"); - assertNotEquals(0, propertyNodes.getLength()); - - boolean protectedPropertyFound = false; - - for (int i = 0; i < propertyNodes.getLength(); i++) { - final Node propertyNode = propertyNodes.item(i); - final NamedNodeMap attributes = propertyNode.getAttributes(); - final Node propertyNameAttribute = attributes.getNamedItem("name"); - final String propertyNameValue = propertyNameAttribute.getNodeValue(); - if (PROTECTED_PROPERTY_NAME.equals(propertyNameValue)) { - protectedPropertyFound = true; - final Node encryptionAttribute = attributes.getNamedItem("encryption"); - assertNotNull(encryptionAttribute); - } - } - - assertTrue(protectedPropertyFound, "Protected Property element not found"); - } - } - - private void assertProtectedPropertyFound(final Path outputPropertiesPath) throws IOException { - final Properties outputProperties = loadProperties(outputPropertiesPath); - - assertTrue(outputProperties.containsKey(SENSITIVE_APPLICATION_PROPERTY)); - - final String applicationPropertyProtected = ApplicationPropertiesProtector.getProtectionKey(SENSITIVE_APPLICATION_PROPERTY); - final String protectedIdentifier = outputProperties.getProperty(applicationPropertyProtected); - assertEquals(PROTECTED_IDENTIFIER, protectedIdentifier); - } - - private void assertRootKeyFound(final Path bootstrapConfPath) throws IOException { - final Properties bootstrapConf = loadProperties(bootstrapConfPath); - - final String rootKey = bootstrapConf.getProperty(RegistryEncryptConfig.BOOTSTRAP_ROOT_KEY_PROPERTY); - assertEquals(BOOTSTRAP_HEXADECIMAL_KEY, rootKey); - } - - private Properties loadProperties(final Path resourcePath) throws IOException { - final Properties properties = new Properties(); - try (InputStream propertiesStream = Files.newInputStream(resourcePath)) { - properties.load(propertiesStream); - } - return properties; - } - - private Path getResourcePath(final String resource) throws URISyntaxException { - final URL resourceUrl = Objects.requireNonNull(getClass().getResource(resource), String.format("Resource [%s] not found", resource)); - return Paths.get(resourceUrl.toURI()); - } -} diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/toolkit/config/command/StandardEncryptConfigTest.java b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/toolkit/config/command/StandardEncryptConfigTest.java deleted file mode 100644 index d7dcdef1eab4..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/toolkit/config/command/StandardEncryptConfigTest.java +++ /dev/null @@ -1,390 +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.toolkit.config.command; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.TextNode; -import org.apache.nifi.properties.ApplicationPropertiesProtector; -import org.apache.nifi.xml.processing.parsers.DocumentProvider; -import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; -import org.w3c.dom.Document; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import picocli.CommandLine; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Objects; -import java.util.Properties; -import java.util.zip.GZIPInputStream; -import java.util.zip.GZIPOutputStream; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -class StandardEncryptConfigTest { - - private static final String FLOW_JSON_RESOURCE = "/command/flow.json"; - - private static final String BOOTSTRAP_CONF_RESOURCE = "/command/bootstrap.conf"; - - private static final String APPLICATION_PROPERTIES_RESOURCE = "/command/nifi.properties"; - - private static final String AUTHORIZERS_UNPROTECTED_RESOURCE = "/transformer/authorizers-unprotected.xml"; - - private static final String LOGIN_IDENTITY_PROVIDERS_UNPROTECTED_RESOURCE = "/command/login-identity-providers-unprotected.xml"; - - private static final String LOGIN_IDENTITY_PROVIDERS_PROTECTED_RESOURCE = "/command/login-identity-providers-protected.xml"; - - private static final String APPLICATION_PROPERTIES_TRANSFORMED = "transformed.nifi.properties"; - - private static final String FLOW_JSON_TRANSFORMED = "transformed.flow.json.gz"; - - private static final String AUTHORIZERS_TRANSFORMED = "transformed.authorizers.xml"; - - private static final String LOGIN_IDENTITY_PROVIDERS_TRANSFORMED = "transformed.login-identity-providers.xml"; - - private static final String COMPRESSED_FILE_NAME_FORMAT = "%s.gz"; - - private static final String SENSITIVE_PROPERTIES_KEY = "UNPROTECTED_KEY"; - - private static final String BOOTSTRAP_HEXADECIMAL_KEY = "012345678901234567890123456789012345678901234567890123456789ABCD"; - - private static final String NEW_BOOTSTRAP_HEXADECIMAL_KEY = "ABCD012345678901234567890123456789012345678901234567890123456789"; - - private static final String BOOTSTRAP_PASSWORD = "BOOTSTRAP_UNPROTECTED"; - - private static final String NEW_SENSITIVE_PROPERTIES_ALGORITHM = "NIFI_ARGON2_AES_GCM_256"; - - private static final String SENSITIVE_PROPERTY_NAME = "Sensitive Property"; - - private static final String PROTECTED_PROPERTY_NAME = "Random Password"; - - private static final String SENSITIVE_APPLICATION_PROPERTY = "nifi.sensitive.props.key"; - - private static final String PROTECTED_IDENTIFIER = "aes/gcm/256"; - - private static final String STANDARD_PROTECTION_SCHEME = "AES_GCM"; - - private static final ObjectMapper objectMapper = new ObjectMapper(); - - @TempDir - private Path tempDir; - - @Test - void testRun() { - final String[] arguments = new String[0]; - - final int status = run(arguments); - assertEquals(CommandLine.ExitCode.OK, status); - } - - @Test - void testHelpRequested() { - final String[] arguments = {"-h"}; - - final int status = run(arguments); - assertEquals(CommandLine.ExitCode.OK, status); - } - - @Test - void testApplicationPropertiesNotFound() { - final Path propertiesPath = tempDir.resolve(APPLICATION_PROPERTIES_TRANSFORMED); - - final String[] arguments = { - "-k", BOOTSTRAP_HEXADECIMAL_KEY, - "-n", propertiesPath.toString() - }; - - final int status = run(arguments); - assertEquals(CommandLine.ExitCode.SOFTWARE, status); - } - - @Test - void testApplicationProperties() throws URISyntaxException, IOException { - final Path propertiesPath = getResourcePath(APPLICATION_PROPERTIES_RESOURCE); - final Path outputPropertiesPath = tempDir.resolve(APPLICATION_PROPERTIES_TRANSFORMED); - - final String[] arguments = { - "-k", BOOTSTRAP_HEXADECIMAL_KEY, - "-n", propertiesPath.toString(), - "-o", outputPropertiesPath.toString() - }; - - final int status = run(arguments); - assertEquals(CommandLine.ExitCode.OK, status); - - assertProtectedPropertyFound(outputPropertiesPath); - } - - @Test - void testFlowConfiguration() throws URISyntaxException, IOException { - final Path propertiesPath = getResourcePath(APPLICATION_PROPERTIES_RESOURCE); - final Path flowConfigurationPath = getResourcePathCompressed(); - final Path outputFlowConfigurationPath = tempDir.resolve(FLOW_JSON_TRANSFORMED); - - final String[] arguments = { - "-x", - "-k", BOOTSTRAP_HEXADECIMAL_KEY, - "-s", SENSITIVE_PROPERTIES_KEY, - "-n", propertiesPath.toString(), - "-f", flowConfigurationPath.toString(), - "-g", outputFlowConfigurationPath.toString() - }; - - final int status = run(arguments); - assertEquals(CommandLine.ExitCode.OK, status); - - assertFlowConfigurationTransformed(flowConfigurationPath, outputFlowConfigurationPath); - } - - @Test - void testFlowConfigurationNewPropertiesAlgorithm() throws URISyntaxException, IOException { - final Path propertiesPath = getResourcePath(APPLICATION_PROPERTIES_RESOURCE); - final Path flowConfigurationPath = getResourcePathCompressed(); - final Path outputFlowConfigurationPath = tempDir.resolve(FLOW_JSON_TRANSFORMED); - - final String[] arguments = { - "-x", - "-k", BOOTSTRAP_HEXADECIMAL_KEY, - "-A", NEW_SENSITIVE_PROPERTIES_ALGORITHM, - "-s", SENSITIVE_PROPERTIES_KEY, - "-n", propertiesPath.toString(), - "-f", flowConfigurationPath.toString(), - "-g", outputFlowConfigurationPath.toString() - }; - - final int status = run(arguments); - assertEquals(CommandLine.ExitCode.OK, status); - - assertFlowConfigurationTransformed(flowConfigurationPath, outputFlowConfigurationPath); - } - - @Test - void testFlowConfigurationWithBootstrapConf() throws URISyntaxException, IOException { - final Path propertiesPath = getResourcePath(APPLICATION_PROPERTIES_RESOURCE); - final Path flowConfigurationPath = getResourcePathCompressed(); - final Path outputFlowConfigurationPath = tempDir.resolve(FLOW_JSON_TRANSFORMED); - - final Path inputBootstrapConfPath = getResourcePath(BOOTSTRAP_CONF_RESOURCE); - final Path bootstrapConfPath = tempDir.resolve(inputBootstrapConfPath.getFileName()); - Files.copy(inputBootstrapConfPath, bootstrapConfPath); - - final String[] arguments = { - "-b", bootstrapConfPath.toString(), - "-k", BOOTSTRAP_HEXADECIMAL_KEY, - "-s", SENSITIVE_PROPERTIES_KEY, - "-n", propertiesPath.toString(), - "-f", flowConfigurationPath.toString(), - "-g", outputFlowConfigurationPath.toString() - }; - - final int status = run(arguments); - assertEquals(CommandLine.ExitCode.OK, status); - - assertFlowConfigurationTransformed(flowConfigurationPath, outputFlowConfigurationPath); - assertRootKeyFound(bootstrapConfPath); - } - - @Test - void testAuthorizersWithKey() throws URISyntaxException, IOException { - final Path authorizersPath = getResourcePath(AUTHORIZERS_UNPROTECTED_RESOURCE); - final Path outputAuthorizersPath = tempDir.resolve(AUTHORIZERS_TRANSFORMED); - - final String[] arguments = { - "-k", BOOTSTRAP_HEXADECIMAL_KEY, - "-a", authorizersPath.toString(), - "-u", outputAuthorizersPath.toString() - }; - - final int status = run(arguments); - assertEquals(CommandLine.ExitCode.OK, status); - - assertEncryptedPropertyFound(outputAuthorizersPath); - } - - @Test - void testAuthorizersWithPassword() throws URISyntaxException, IOException { - final Path authorizersPath = getResourcePath(AUTHORIZERS_UNPROTECTED_RESOURCE); - final Path outputAuthorizersPath = tempDir.resolve(AUTHORIZERS_TRANSFORMED); - - final String[] arguments = { - "-p", BOOTSTRAP_PASSWORD, - "-a", authorizersPath.toString(), - "-u", outputAuthorizersPath.toString() - }; - - final int status = run(arguments); - assertEquals(CommandLine.ExitCode.OK, status); - - assertEncryptedPropertyFound(outputAuthorizersPath); - } - - @Test - void testLoginIdentityProvidersWithKey() throws URISyntaxException, IOException { - final Path loginIdentityProvidersPath = getResourcePath(LOGIN_IDENTITY_PROVIDERS_UNPROTECTED_RESOURCE); - final Path outputLoginIdentityProvidersPath = tempDir.resolve(LOGIN_IDENTITY_PROVIDERS_TRANSFORMED); - - final String[] arguments = { - "-k", BOOTSTRAP_HEXADECIMAL_KEY, - "-l", loginIdentityProvidersPath.toString(), - "-i", outputLoginIdentityProvidersPath.toString() - }; - - final int status = run(arguments); - assertEquals(CommandLine.ExitCode.OK, status); - - assertEncryptedPropertyFound(outputLoginIdentityProvidersPath); - } - - @Test - void testLoginIdentityProvidersMigrationWithKey() throws URISyntaxException, IOException { - final Path loginIdentityProvidersPath = getResourcePath(LOGIN_IDENTITY_PROVIDERS_PROTECTED_RESOURCE); - final Path outputLoginIdentityProvidersPath = tempDir.resolve(LOGIN_IDENTITY_PROVIDERS_TRANSFORMED); - - final String[] arguments = { - "-m", - "-e", BOOTSTRAP_HEXADECIMAL_KEY, - "-H", STANDARD_PROTECTION_SCHEME, - "-k", NEW_BOOTSTRAP_HEXADECIMAL_KEY, - "-l", loginIdentityProvidersPath.toString(), - "-i", outputLoginIdentityProvidersPath.toString() - }; - - final int status = run(arguments); - assertEquals(CommandLine.ExitCode.OK, status); - - assertEncryptedPropertyFound(outputLoginIdentityProvidersPath); - } - - private int run(final String[] arguments) { - final CommandLine commandLine = new CommandLine(new StandardEncryptConfig()); - final PrintWriter writer = new PrintWriter(new ByteArrayOutputStream()); - //commandLine.setOut(writer); - commandLine.setErr(writer); - return commandLine.execute(arguments); - } - - private void assertFlowConfigurationTransformed(final Path inputFlowConfigurationPath, final Path outputFlowConfigurationPath) throws IOException { - assertTrue(Files.isReadable(outputFlowConfigurationPath)); - - final String inputSensitiveProperty = assertSensitivePropertyFound(inputFlowConfigurationPath); - final String outputSensitiveProperty = assertSensitivePropertyFound(outputFlowConfigurationPath); - assertNotEquals(inputSensitiveProperty, outputSensitiveProperty); - } - - private String assertSensitivePropertyFound(final Path flowConfigurationPath) throws IOException { - try (InputStream inputStream = new GZIPInputStream(Files.newInputStream(flowConfigurationPath))) { - final JsonNode flowConfiguration = objectMapper.readTree(inputStream); - final JsonNode rootGroup = flowConfiguration.get("rootGroup"); - assertNotNull(rootGroup); - final JsonNode processors = rootGroup.get("processors"); - assertNotNull(processors); - final JsonNode processor = processors.get(0); - assertNotNull(processor); - final JsonNode properties = processor.get("properties"); - assertNotNull(properties); - final JsonNode sensitiveProperty = properties.get(SENSITIVE_PROPERTY_NAME); - assertInstanceOf(TextNode.class, sensitiveProperty); - final TextNode sensitivePropertyValue = (TextNode) sensitiveProperty; - return sensitivePropertyValue.asText(); - } - } - - private void assertEncryptedPropertyFound(final Path resourcePath) throws IOException { - try (InputStream inputStream = Files.newInputStream(resourcePath)) { - final DocumentProvider documentProvider = new StandardDocumentProvider(); - final Document document = documentProvider.parse(inputStream); - final NodeList propertyNodes = document.getElementsByTagName("property"); - assertNotEquals(0, propertyNodes.getLength()); - - boolean protectedPropertyFound = false; - - for (int i = 0; i < propertyNodes.getLength(); i++) { - final Node propertyNode = propertyNodes.item(i); - final NamedNodeMap attributes = propertyNode.getAttributes(); - final Node propertyNameAttribute = attributes.getNamedItem("name"); - final String propertyNameValue = propertyNameAttribute.getNodeValue(); - if (PROTECTED_PROPERTY_NAME.equals(propertyNameValue)) { - protectedPropertyFound = true; - final Node encryptionAttribute = attributes.getNamedItem("encryption"); - assertNotNull(encryptionAttribute); - } - } - - assertTrue(protectedPropertyFound, "Protected Property element not found"); - } - } - - private void assertProtectedPropertyFound(final Path outputPropertiesPath) throws IOException { - final Properties outputProperties = loadProperties(outputPropertiesPath); - - assertTrue(outputProperties.containsKey(SENSITIVE_APPLICATION_PROPERTY)); - - final String applicationPropertyProtected = ApplicationPropertiesProtector.getProtectionKey(SENSITIVE_APPLICATION_PROPERTY); - final String protectedIdentifier = outputProperties.getProperty(applicationPropertyProtected); - assertEquals(PROTECTED_IDENTIFIER, protectedIdentifier); - } - - private void assertRootKeyFound(final Path bootstrapConfPath) throws IOException { - final Properties bootstrapConf = loadProperties(bootstrapConfPath); - - final String rootKey = bootstrapConf.getProperty(StandardEncryptConfig.BOOTSTRAP_ROOT_KEY_PROPERTY); - assertEquals(BOOTSTRAP_HEXADECIMAL_KEY, rootKey); - } - - private Properties loadProperties(final Path resourcePath) throws IOException { - final Properties properties = new Properties(); - try (InputStream propertiesStream = Files.newInputStream(resourcePath)) { - properties.load(propertiesStream); - } - return properties; - } - - private Path getResourcePathCompressed() throws URISyntaxException, IOException { - final Path resourcePath = getResourcePath(FLOW_JSON_RESOURCE); - final byte[] resourceBytes = Files.readAllBytes(resourcePath); - - final String resourceFileName = String.format(COMPRESSED_FILE_NAME_FORMAT, resourcePath.getFileName()); - final Path resourcePathCompressed = tempDir.resolve(resourceFileName); - try (OutputStream outputStream = new GZIPOutputStream(Files.newOutputStream(resourcePathCompressed))) { - outputStream.write(resourceBytes); - } - - return resourcePathCompressed; - } - - private Path getResourcePath(final String resource) throws URISyntaxException { - final URL resourceUrl = Objects.requireNonNull(getClass().getResource(resource), String.format("Resource [%s] not found", resource)); - return Paths.get(resourceUrl.toURI()); - } -} diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/toolkit/config/crypto/StandardDerivedKeyGeneratorTest.java b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/toolkit/config/crypto/StandardDerivedKeyGeneratorTest.java deleted file mode 100644 index 10f9030c71ba..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/toolkit/config/crypto/StandardDerivedKeyGeneratorTest.java +++ /dev/null @@ -1,44 +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.toolkit.config.crypto; - -import org.junit.jupiter.api.Test; - -import java.util.HexFormat; -import java.util.UUID; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -class StandardDerivedKeyGeneratorTest { - - private static final int KEY_LENGTH = 32; - - @Test - void testGetDerivedKeyEncoded() { - final StandardDerivedKeyGenerator generator = new StandardDerivedKeyGenerator(); - - final char[] random = UUID.randomUUID().toString().toCharArray(); - - final String firstDerivedKey = generator.getDerivedKeyEncoded(random); - final String secondDerivedKey = generator.getDerivedKeyEncoded(random); - - assertEquals(firstDerivedKey, secondDerivedKey); - - final byte[] decoded = HexFormat.of().parseHex(firstDerivedKey); - assertEquals(KEY_LENGTH, decoded.length); - } -} diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/toolkit/config/transformer/ApplicationPropertiesFileTransformerTest.java b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/toolkit/config/transformer/ApplicationPropertiesFileTransformerTest.java deleted file mode 100644 index 687575cb6964..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/toolkit/config/transformer/ApplicationPropertiesFileTransformerTest.java +++ /dev/null @@ -1,159 +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.toolkit.config.transformer; - -import org.apache.nifi.properties.ApplicationProperties; -import org.apache.nifi.properties.SensitivePropertyProvider; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.api.io.TempDir; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Collections; -import java.util.Objects; -import java.util.Properties; -import java.util.Set; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.verifyNoInteractions; -import static org.mockito.Mockito.when; - -@ExtendWith(MockitoExtension.class) -class ApplicationPropertiesFileTransformerTest { - private static final String UNPROTECTED_NIFI_PROPERTIES = "/transformer/application-unprotected-nifi.properties"; - - private static final String PROPERTIES_PROTECTED_RESOURCE = "/transformer/application-protected-nifi.properties"; - - private static final String PROPERTIES_NON_SENSITIVE_RESOURCE = "/transformer/application-non-sensitive-nifi.properties"; - - private static final String PROPERTIES_TRANSFORMED = "transformed-nifi.properties"; - - private static final String PROVIDER_IDENTIFIER_KEY = "mocked-provider"; - - private static final String SENSITIVE_PROPERTY_NAME = "nifi.security.keystorePasswd"; - - private static final String SENSITIVE_PROPERTY_NAME_PROTECTED = String.format("%s.protected", SENSITIVE_PROPERTY_NAME); - - private static final Set SENSITIVE_PROPERTY_NAMES = Collections.singleton(SENSITIVE_PROPERTY_NAME); - - private static final String ENCRYPTED = "ENCRYPTED"; - - private static final String UNPROTECTED = "UNPROTECTED"; - - @TempDir - private Path tempDir; - - @Mock - private SensitivePropertyProvider sensitivePropertyProvider; - - @Test - void testTransformUnprotectedProperty() throws URISyntaxException, IOException { - final Path propertiesPath = getResourcePath(UNPROTECTED_NIFI_PROPERTIES); - - final Path tempPropertiesPath = tempDir.resolve(propertiesPath.getFileName()); - Files.copy(propertiesPath, tempPropertiesPath); - - final Path outputPropertiesPath = tempDir.resolve(PROPERTIES_TRANSFORMED); - - final ApplicationProperties applicationProperties = new ApplicationProperties(Collections.emptyMap()); - final FileTransformer transformer = new ApplicationPropertiesFileTransformer(applicationProperties, sensitivePropertyProvider, SENSITIVE_PROPERTY_NAMES); - - when(sensitivePropertyProvider.getIdentifierKey()).thenReturn(PROVIDER_IDENTIFIER_KEY); - when(sensitivePropertyProvider.protect(eq(UNPROTECTED), any())).thenReturn(ENCRYPTED); - - transformer.transform(tempPropertiesPath, outputPropertiesPath); - - assertProtectedPropertyFound(outputPropertiesPath); - } - - @Test - void testTransformProtectedProperty() throws URISyntaxException, IOException { - final Path propertiesPath = getResourcePath(PROPERTIES_PROTECTED_RESOURCE); - - final Path tempPropertiesPath = tempDir.resolve(propertiesPath.getFileName()); - Files.copy(propertiesPath, tempPropertiesPath); - - final Path outputPropertiesPath = tempDir.resolve(PROPERTIES_TRANSFORMED); - - final Properties sourceProperties = new Properties(); - sourceProperties.setProperty(SENSITIVE_PROPERTY_NAME, UNPROTECTED); - final ApplicationProperties applicationProperties = new ApplicationProperties(sourceProperties); - final FileTransformer transformer = new ApplicationPropertiesFileTransformer(applicationProperties, sensitivePropertyProvider, SENSITIVE_PROPERTY_NAMES); - - when(sensitivePropertyProvider.getIdentifierKey()).thenReturn(PROVIDER_IDENTIFIER_KEY); - when(sensitivePropertyProvider.protect(eq(UNPROTECTED), any())).thenReturn(ENCRYPTED); - - transformer.transform(tempPropertiesPath, outputPropertiesPath); - - assertProtectedPropertyFound(outputPropertiesPath); - } - - @Test - void testTransformNonSensitiveProperties() throws URISyntaxException, IOException { - final Path propertiesPath = getResourcePath(PROPERTIES_NON_SENSITIVE_RESOURCE); - - final Path tempPropertiesPath = tempDir.resolve(propertiesPath.getFileName()); - Files.copy(propertiesPath, tempPropertiesPath); - - final Path outputPropertiesPath = tempDir.resolve(PROPERTIES_TRANSFORMED); - - final ApplicationProperties applicationProperties = new ApplicationProperties(Collections.emptyMap()); - final FileTransformer transformer = new ApplicationPropertiesFileTransformer(applicationProperties, sensitivePropertyProvider, SENSITIVE_PROPERTY_NAMES); - - transformer.transform(tempPropertiesPath, outputPropertiesPath); - - verifyNoInteractions(sensitivePropertyProvider); - - final Properties inputProperties = loadProperties(propertiesPath); - final Properties outputProperties = loadProperties(outputPropertiesPath); - - assertEquals(inputProperties, outputProperties); - } - - private void assertProtectedPropertyFound(final Path outputPropertiesPath) throws IOException { - final Properties outputProperties = loadProperties(outputPropertiesPath); - - final String sensitivePropertyValue = outputProperties.getProperty(SENSITIVE_PROPERTY_NAME); - assertEquals(ENCRYPTED, sensitivePropertyValue); - - final String protectedSensitivePropertyValue = outputProperties.getProperty(SENSITIVE_PROPERTY_NAME_PROTECTED); - assertEquals(PROVIDER_IDENTIFIER_KEY, protectedSensitivePropertyValue); - } - - private Properties loadProperties(final Path resourcePath) throws IOException { - final Properties properties = new Properties(); - try (InputStream propertiesStream = Files.newInputStream(resourcePath)) { - properties.load(propertiesStream); - } - return properties; - } - - private Path getResourcePath(final String resource) throws URISyntaxException { - final URL resourceUrl = Objects.requireNonNull(getClass().getResource(resource), String.format("Resource [%s] not found", resource)); - return Paths.get(resourceUrl.toURI()); - } -} diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/toolkit/config/transformer/XmlFileTransformerTest.java b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/toolkit/config/transformer/XmlFileTransformerTest.java deleted file mode 100644 index 0b88556d37f4..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/toolkit/config/transformer/XmlFileTransformerTest.java +++ /dev/null @@ -1,96 +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.toolkit.config.transformer; - -import org.apache.nifi.properties.SensitivePropertyProvider; -import org.apache.nifi.properties.SensitivePropertyProviderFactory; -import org.apache.nifi.properties.scheme.ProtectionScheme; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.api.io.TempDir; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.io.IOException; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Objects; - -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.verifyNoInteractions; -import static org.mockito.Mockito.when; - -@ExtendWith(MockitoExtension.class) -class XmlFileTransformerTest { - private static final String AUTHORIZERS_RESOURCE = "/transformer/authorizers-unprotected.xml"; - - private static final String AUTHORIZERS_TRANSFORMED = "authorizers-transformed.xml"; - - private static final String PROVIDER_IDENTIFIER_KEY = "protected"; - - private static final String ENCRYPTED = "ENCRYPTED"; - - private static final String UNPROTECTED = "UNPROTECTED"; - - @TempDir - private Path tempDir; - - @Mock - private SensitivePropertyProvider inputSensitivePropertyProvider; - - @Mock - private SensitivePropertyProviderFactory sensitivePropertyProviderFactory; - - @Mock - private SensitivePropertyProvider sensitivePropertyProvider; - - @Mock - private ProtectionScheme protectionScheme; - - @Test - void testTransform() throws URISyntaxException, IOException { - final Path authorizersPath = getResourcePath(); - - final Path tempAuthorizersPath = tempDir.resolve(authorizersPath.getFileName()); - Files.copy(authorizersPath, tempAuthorizersPath); - - final Path outputAuthorizesPath = tempDir.resolve(AUTHORIZERS_TRANSFORMED); - - when(sensitivePropertyProviderFactory.getProvider(eq(protectionScheme))).thenReturn(sensitivePropertyProvider); - final XmlFileTransformer transformer = new XmlFileTransformer(inputSensitivePropertyProvider, sensitivePropertyProviderFactory, protectionScheme); - - when(sensitivePropertyProvider.getIdentifierKey()).thenReturn(PROVIDER_IDENTIFIER_KEY); - when(sensitivePropertyProvider.protect(eq(UNPROTECTED), any())).thenReturn(ENCRYPTED); - - transformer.transform(tempAuthorizersPath, outputAuthorizesPath); - - final String outputAuthorizers = Files.readString(outputAuthorizesPath); - assertTrue(outputAuthorizers.contains(ENCRYPTED), "encrypted property not found"); - - verifyNoInteractions(inputSensitivePropertyProvider); - } - - private Path getResourcePath() throws URISyntaxException { - final URL resourceUrl = Objects.requireNonNull(getClass().getResource(AUTHORIZERS_RESOURCE), "Resource not found"); - return Paths.get(resourceUrl.toURI()); - } -} diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/command/bootstrap-registry.conf b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/command/bootstrap-registry.conf deleted file mode 100644 index ee4c54d542cc..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/command/bootstrap-registry.conf +++ /dev/null @@ -1,20 +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. - -# Java command -java=java - -# Bootstrap hexadecimal root key for encrypting sensitive application properties -nifi.registry.bootstrap.sensitive.key= diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/command/bootstrap.conf b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/command/bootstrap.conf deleted file mode 100644 index a2f3223c08d4..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/command/bootstrap.conf +++ /dev/null @@ -1,20 +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. - -# Java command -java=java - -# Bootstrap hexadecimal root key for encrypting sensitive application properties -nifi.bootstrap.sensitive.key= diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/command/flow.json b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/command/flow.json deleted file mode 100644 index 6a6deec2fb10..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/command/flow.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "rootGroup": { - "processors": [ - { - "identifier": "f1c86bb5-7895-3a60-beab-57a2f0766b33", - "instanceIdentifier": "018b1000-69eb-1fbe-df08-68f5b862eab2", - "name": "UpdateConfiguration", - "type": "org.apache.nifi.processors.standad.UpdateConfiguration", - "bundle": { - "group": "org.apache.nifi", - "artifact": "nifi-standard-nar", - "version": "2.0.0-SNAPSHOT" - }, - "properties": { - "Standard Property": "configured", - "Sensitive Property": "enc{24bc2edb43607b07a0e4bb4283ae7fd133d6b4f86eebb1b06b9a4d55773b44df311e091b25d0cb5c82}" - } - } - ] - } -} diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/command/identity-providers-unprotected.xml b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/command/identity-providers-unprotected.xml deleted file mode 100644 index 9db6ba1f5ae3..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/command/identity-providers-unprotected.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - ldap-provider - org.apache.nifi.registry.IdentityProvider - TLS - UNPROTECTED - - - diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/command/login-identity-providers-protected.xml b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/command/login-identity-providers-protected.xml deleted file mode 100644 index b3e92664dc85..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/command/login-identity-providers-protected.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - ldap-provider - org.apache.nifi.LoginIdentityProvider - TLS - 0wnJSmbM0Os53Nfx||PFRSEinMyMgIcg5+Lt5wOPWoeOuTN92YiBwG - - - diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/command/login-identity-providers-unprotected.xml b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/command/login-identity-providers-unprotected.xml deleted file mode 100644 index 9fe6d6c4b413..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/command/login-identity-providers-unprotected.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - ldap-provider - org.apache.nifi.LoginIdentityProvider - TLS - UNPROTECTED - - - diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/command/nifi-registry.properties b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/command/nifi-registry.properties deleted file mode 100644 index 6e26eac84c93..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/command/nifi-registry.properties +++ /dev/null @@ -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.registry.security.keystoreType=PKCS12 -nifi.registry.security.keystorePasswd=UNPROTECTED diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/command/nifi.properties b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/command/nifi.properties deleted file mode 100644 index 7fdac4c5a69c..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/command/nifi.properties +++ /dev/null @@ -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=UNPROTECTED_KEY -nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM_256 diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/transformer/application-non-sensitive-nifi.properties b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/transformer/application-non-sensitive-nifi.properties deleted file mode 100644 index 3769952c8b32..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/transformer/application-non-sensitive-nifi.properties +++ /dev/null @@ -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.web.https.host= -nifi.web.https.port=8443 diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/transformer/application-protected-nifi.properties b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/transformer/application-protected-nifi.properties deleted file mode 100644 index cbf5deefb339..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/transformer/application-protected-nifi.properties +++ /dev/null @@ -1,20 +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.web.https.host= -nifi.web.https.port=8443 - -nifi.security.keystorePasswd=ENCRYPTED -nifi.security.keystorePasswd.protected=mocked-provider diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/transformer/application-unprotected-nifi.properties b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/transformer/application-unprotected-nifi.properties deleted file mode 100644 index 76a5bca4fac5..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/transformer/application-unprotected-nifi.properties +++ /dev/null @@ -1,19 +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.web.https.host= -nifi.web.https.port=8443 - -nifi.security.keystorePasswd=UNPROTECTED diff --git a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/transformer/authorizers-unprotected.xml b/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/transformer/authorizers-unprotected.xml deleted file mode 100644 index df27ff377231..000000000000 --- a/nifi-toolkit/nifi-toolkit-encrypt-config/src/test/resources/transformer/authorizers-unprotected.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - user-group-provider - org.apache.nifi.UserGroupProvider - TLS - UNPROTECTED - - - diff --git a/nifi-toolkit/pom.xml b/nifi-toolkit/pom.xml index 520a98d7ace0..831237572907 100644 --- a/nifi-toolkit/pom.xml +++ b/nifi-toolkit/pom.xml @@ -23,7 +23,6 @@ nifi-toolkit pom - nifi-toolkit-encrypt-config nifi-toolkit-assembly nifi-toolkit-cli nifi-toolkit-api