http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-properties/src/test/groovy/org/apache/nifi/registry/properties/ProtectedNiFiPropertiesGroovyTest.groovy
----------------------------------------------------------------------
diff --git 
a/nifi-registry-properties/src/test/groovy/org/apache/nifi/registry/properties/ProtectedNiFiPropertiesGroovyTest.groovy
 
b/nifi-registry-properties/src/test/groovy/org/apache/nifi/registry/properties/ProtectedNiFiPropertiesGroovyTest.groovy
new file mode 100644
index 0000000..86c7fb4
--- /dev/null
+++ 
b/nifi-registry-properties/src/test/groovy/org/apache/nifi/registry/properties/ProtectedNiFiPropertiesGroovyTest.groovy
@@ -0,0 +1,739 @@
+/*
+ * 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.bouncycastle.jce.provider.BouncyCastleProvider
+import org.junit.After
+import org.junit.AfterClass
+import org.junit.Assume
+import org.junit.Before
+import org.junit.BeforeClass
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+
+import javax.crypto.Cipher
+import java.security.Security
+
+@RunWith(JUnit4.class)
+class ProtectedNiFiPropertiesGroovyTest extends GroovyTestCase {
+    private static final Logger logger = 
LoggerFactory.getLogger(ProtectedNiFiPropertiesGroovyTest.class)
+
+    private static final String KEYSTORE_PASSWORD_KEY = 
NiFiRegistryProperties.SECURITY_KEYSTORE_PASSWD
+    private static final String KEY_PASSWORD_KEY = 
NiFiRegistryProperties.SECURITY_KEY_PASSWD
+    private static final String TRUSTSTORE_PASSWORD_KEY = 
NiFiRegistryProperties.SECURITY_TRUSTSTORE_PASSWD
+
+    private static final def DEFAULT_SENSITIVE_PROPERTIES = [
+            KEYSTORE_PASSWORD_KEY,
+            KEY_PASSWORD_KEY,
+            TRUSTSTORE_PASSWORD_KEY
+    ]
+
+    private static final String KEY_HEX_128 = 
"0123456789ABCDEFFEDCBA9876543210"
+    private static final String KEY_HEX_256 = KEY_HEX_128 * 2
+    private static final String KEY_HEX = Cipher.getMaxAllowedKeyLength("AES") 
< 256 ? KEY_HEX_128 : KEY_HEX_256
+
+    @BeforeClass
+    static void setUpOnce() throws Exception {
+        Security.addProvider(new BouncyCastleProvider())
+
+        logger.metaClass.methodMissing = { String name, args ->
+            logger.info("[${name?.toUpperCase()}] ${(args as List).join(" ")}")
+        }
+    }
+
+    @Before
+    void setUp() throws Exception {
+    }
+
+    @After
+    void tearDown() throws Exception {
+    }
+
+    @AfterClass
+    static void tearDownOnce() {
+    }
+
+    private static ProtectedNiFiRegistryProperties loadFromResourceFile(String 
propertiesFilePath) {
+        return loadFromResourceFile(propertiesFilePath, KEY_HEX)
+    }
+
+    private static ProtectedNiFiRegistryProperties loadFromResourceFile(String 
propertiesFilePath, String keyHex) {
+        File file = fileForResource(propertiesFilePath)
+
+        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")
+        }
+
+        NiFiRegistryProperties properties = new NiFiRegistryProperties()
+        FileReader reader = new FileReader(file)
+
+        try {
+            properties.load(reader)
+            logger.info("Loaded {} properties from {}", properties.size(), 
file.getAbsolutePath())
+
+            ProtectedNiFiRegistryProperties protectedNiFiProperties = new 
ProtectedNiFiRegistryProperties(properties)
+
+            // If it has protected keys, inject the SPP
+            if (protectedNiFiProperties.hasProtectedKeys()) {
+                protectedNiFiProperties.addSensitivePropertyProvider(new 
AESSensitivePropertyProvider(keyHex))
+            }
+
+            return protectedNiFiProperties
+        } catch (final Exception ex) {
+            logger.error("Cannot load properties file due to " + 
ex.getLocalizedMessage())
+            throw new RuntimeException("Cannot load properties file due to "
+                    + ex.getLocalizedMessage(), ex)
+        }
+    }
+
+    private static File fileForResource(String resourcePath) {
+        String filePath
+        try {
+            URL resourceURL = 
ProtectedNiFiPropertiesGroovyTest.class.getResource(resourcePath)
+            if (!resourceURL) {
+                throw new RuntimeException("File ${resourcePath} not found in 
class resources, cannot load.")
+            }
+            filePath = resourceURL.toURI().getPath()
+        } catch (URISyntaxException ex) {
+            throw new RuntimeException("Cannot load resource file due to "
+                    + ex.getLocalizedMessage(), ex)
+        }
+        File file = new File(filePath)
+        return file
+    }
+
+    @Test
+    void testShouldDetectIfPropertyIsSensitive() throws Exception {
+        // Arrange
+        final String INSENSITIVE_PROPERTY_KEY = "nifi.registry.web.http.port"
+        final String SENSITIVE_PROPERTY_KEY = 
"nifi.registry.security.keystorePasswd"
+
+        ProtectedNiFiRegistryProperties properties = 
loadFromResourceFile("/conf/nifi-registry.properties")
+
+        // Act
+        boolean bannerIsSensitive = 
properties.isPropertySensitive(INSENSITIVE_PROPERTY_KEY)
+        logger.info("${INSENSITIVE_PROPERTY_KEY} is ${bannerIsSensitive ? 
"SENSITIVE" : "NOT SENSITIVE"}")
+        boolean passwordIsSensitive = 
properties.isPropertySensitive(SENSITIVE_PROPERTY_KEY)
+        logger.info("${SENSITIVE_PROPERTY_KEY} is ${passwordIsSensitive ? 
"SENSITIVE" : "NOT SENSITIVE"}")
+
+        // Assert
+        assert !bannerIsSensitive
+        assert passwordIsSensitive
+    }
+
+    @Test
+    void testShouldGetDefaultSensitiveProperties() throws Exception {
+        // Arrange
+        logger.info("${DEFAULT_SENSITIVE_PROPERTIES.size()} default sensitive 
properties: ${DEFAULT_SENSITIVE_PROPERTIES.join(", ")}")
+
+        ProtectedNiFiRegistryProperties properties = 
loadFromResourceFile("/conf/nifi-registry.properties")
+
+        // Act
+        List defaultSensitiveProperties = properties.getSensitivePropertyKeys()
+        logger.info("${defaultSensitiveProperties.size()} default sensitive 
properties: ${defaultSensitiveProperties.join(", ")}")
+
+        // Assert
+        assert defaultSensitiveProperties.size() == 
DEFAULT_SENSITIVE_PROPERTIES.size()
+        assert 
defaultSensitiveProperties.containsAll(DEFAULT_SENSITIVE_PROPERTIES)
+    }
+
+    @Test
+    void testShouldGetAdditionalSensitiveProperties() throws Exception {
+        // Arrange
+        def completeSensitiveProperties = DEFAULT_SENSITIVE_PROPERTIES + 
["nifi.registry.web.http.port", "nifi.registry.web.http.host"]
+        logger.info("${completeSensitiveProperties.size()} total sensitive 
properties: ${completeSensitiveProperties.join(", ")}")
+
+        ProtectedNiFiRegistryProperties properties = 
loadFromResourceFile("/conf/nifi-registry.with_additional_sensitive_keys.properties")
+
+        // Act
+        List retrievedSensitiveProperties = 
properties.getSensitivePropertyKeys()
+        logger.info("${retrievedSensitiveProperties.size()} retrieved 
sensitive properties: ${retrievedSensitiveProperties.join(", ")}")
+
+        // Assert
+        assert retrievedSensitiveProperties.size() == 
completeSensitiveProperties.size()
+        assert 
retrievedSensitiveProperties.containsAll(completeSensitiveProperties)
+    }
+
+    @Test
+    void testGetAdditionalSensitivePropertiesShouldNotIncludeSelf() throws 
Exception {
+        // Arrange
+        def completeSensitiveProperties = DEFAULT_SENSITIVE_PROPERTIES + 
["nifi.registry.web.http.port", "nifi.registry.web.http.host"]
+        logger.info("${completeSensitiveProperties.size()} total sensitive 
properties: ${completeSensitiveProperties.join(", ")}")
+
+        ProtectedNiFiRegistryProperties properties = 
loadFromResourceFile("/conf/nifi-registry.with_additional_sensitive_keys.properties")
+
+        // Act
+        List retrievedSensitiveProperties = 
properties.getSensitivePropertyKeys()
+        logger.info("${retrievedSensitiveProperties.size()} retrieved 
sensitive properties: ${retrievedSensitiveProperties.join(", ")}")
+
+        // Assert
+        assert retrievedSensitiveProperties.size() == 
completeSensitiveProperties.size()
+        assert 
retrievedSensitiveProperties.containsAll(completeSensitiveProperties)
+    }
+
+    /**
+     * In the default (no protection enabled) scenario, a call to retrieve a 
sensitive property should return the raw value transparently.
+     * @throws Exception
+     */
+    @Test
+    void testShouldGetUnprotectedValueOfSensitiveProperty() throws Exception {
+        // Arrange
+        final String expectedKeystorePassword = "thisIsABadKeystorePassword"
+
+        ProtectedNiFiRegistryProperties properties = 
loadFromResourceFile("/conf/nifi-registry.with_sensitive_props_unprotected.properties")
+
+        boolean isSensitive = 
properties.isPropertySensitive(KEYSTORE_PASSWORD_KEY)
+        boolean isProtected = 
properties.isPropertyProtected(KEYSTORE_PASSWORD_KEY)
+        logger.info("The property is ${isSensitive ? "sensitive" : "not 
sensitive"} and ${isProtected ? "protected" : "not protected"}")
+
+        // Act
+        String retrievedKeystorePassword = 
properties.getProperty(KEYSTORE_PASSWORD_KEY)
+        logger.info("${KEYSTORE_PASSWORD_KEY}: ${retrievedKeystorePassword}")
+
+        // Assert
+        assert retrievedKeystorePassword == expectedKeystorePassword
+        assert isSensitive
+        assert !isProtected
+    }
+
+    /**
+     * In the default (no protection enabled) scenario, a call to retrieve a 
sensitive property (which is empty) should return the raw value transparently.
+     * @throws Exception
+     */
+    @Test
+    void testShouldGetEmptyUnprotectedValueOfSensitiveProperty() throws 
Exception {
+        // Arrange
+        final String expectedTruststorePassword = ""
+
+        ProtectedNiFiRegistryProperties properties = 
loadFromResourceFile("/conf/nifi-registry.with_sensitive_props_unprotected.properties")
+
+        boolean isSensitive = 
properties.isPropertySensitive(TRUSTSTORE_PASSWORD_KEY)
+        boolean isProtected = 
properties.isPropertyProtected(TRUSTSTORE_PASSWORD_KEY)
+        logger.info("The property is ${isSensitive ? "sensitive" : "not 
sensitive"} and ${isProtected ? "protected" : "not protected"}")
+
+        // Act
+        NiFiRegistryProperties unprotectedProperties = 
properties.getUnprotectedProperties()
+        String retrievedTruststorePassword = 
unprotectedProperties.getProperty(TRUSTSTORE_PASSWORD_KEY)
+        logger.info("${TRUSTSTORE_PASSWORD_KEY}: 
${retrievedTruststorePassword}")
+
+        // Assert
+        assert retrievedTruststorePassword == expectedTruststorePassword
+        assert isSensitive
+        assert !isProtected
+    }
+
+    /**
+     * The new model no longer needs to maintain the protected state -- it is 
used as a wrapper/decorator during load to unprotect the sensitive properties 
and then return an instance of raw properties.
+     *
+     * @throws Exception
+     */
+    @Test
+    void testShouldGetUnprotectedValueOfSensitivePropertyWhenProtected() 
throws Exception {
+        // Arrange
+        final String expectedKeystorePassword = "thisIsABadPassword"
+
+        ProtectedNiFiRegistryProperties properties = 
loadFromResourceFile("/conf/nifi-registry.with_sensitive_props_protected_aes_128.properties",
 KEY_HEX_128)
+
+        boolean isSensitive = 
properties.isPropertySensitive(KEYSTORE_PASSWORD_KEY)
+        boolean isProtected = 
properties.isPropertyProtected(KEYSTORE_PASSWORD_KEY)
+        logger.info("The property is ${isSensitive ? "sensitive" : "not 
sensitive"} and ${isProtected ? "protected" : "not protected"}")
+
+        // Act
+        NiFiRegistryProperties unprotectedProperties = 
properties.getUnprotectedProperties()
+        String retrievedKeystorePassword = 
unprotectedProperties.getProperty(KEYSTORE_PASSWORD_KEY)
+        logger.info("${KEYSTORE_PASSWORD_KEY}: ${retrievedKeystorePassword}")
+
+        // Assert
+        assert retrievedKeystorePassword == expectedKeystorePassword
+        assert isSensitive
+        assert isProtected
+    }
+
+    /**
+     * In the protection enabled scenario, a call to retrieve a sensitive 
property should handle if the property is protected with an unknown protection 
scheme.
+     * @throws Exception
+     */
+    @Test
+    void testGetValueOfSensitivePropertyShouldHandleUnknownProtectionScheme() 
throws Exception {
+        // Arrange
+
+        // Raw properties
+        Properties rawProperties = new Properties()
+        rawProperties.load(new 
FileReader(fileForResource("/conf/nifi-registry.with_sensitive_props_protected_unknown.properties")))
+        final String expectedKeystorePassword = 
rawProperties.getProperty(KEYSTORE_PASSWORD_KEY)
+        logger.info("Raw value for ${KEYSTORE_PASSWORD_KEY}: 
${expectedKeystorePassword}")
+
+        ProtectedNiFiRegistryProperties properties = 
loadFromResourceFile("/conf/nifi-registry.with_sensitive_props_protected_unknown.properties")
+
+        boolean isSensitive = 
properties.isPropertySensitive(KEYSTORE_PASSWORD_KEY)
+        boolean isProtected = 
properties.isPropertyProtected(KEYSTORE_PASSWORD_KEY)
+
+        // While the value is "protected", the scheme is not registered, so 
treat it as raw
+        logger.info("The property is ${isSensitive ? "sensitive" : "not 
sensitive"} and ${isProtected ? "protected" : "not protected"}")
+
+        // Act
+        NiFiRegistryProperties unprotectedProperties = 
properties.getUnprotectedProperties()
+        String retrievedKeystorePassword = 
unprotectedProperties.getProperty(KEYSTORE_PASSWORD_KEY)
+        logger.info("${KEYSTORE_PASSWORD_KEY}: ${retrievedKeystorePassword}")
+
+        // Assert
+        assert retrievedKeystorePassword == expectedKeystorePassword
+        assert isSensitive
+        assert isProtected
+    }
+
+    /**
+     * In the protection enabled scenario, a call to retrieve a sensitive 
property should handle if the property is unable to be unprotected due to a 
malformed value.
+     * @throws Exception
+     */
+    @Test
+    void testGetValueOfSensitivePropertyShouldHandleSingleMalformedValue() 
throws Exception {
+        // Arrange
+        ProtectedNiFiRegistryProperties properties = 
loadFromResourceFile("/conf/nifi-registry.with_sensitive_props_protected_aes_single_malformed.properties",
 KEY_HEX_128)
+        boolean isSensitive = 
properties.isPropertySensitive(KEYSTORE_PASSWORD_KEY)
+        boolean isProtected = 
properties.isPropertyProtected(KEYSTORE_PASSWORD_KEY)
+        logger.info("The property is ${isSensitive ? "sensitive" : "not 
sensitive"} and ${isProtected ? "protected" : "not protected"}")
+
+        // Act
+        def msg = shouldFail(SensitivePropertyProtectionException) {
+            NiFiRegistryProperties unprotectedProperties = 
properties.getUnprotectedProperties()
+            String retrievedKeystorePassword = 
unprotectedProperties.getProperty(KEYSTORE_PASSWORD_KEY)
+            logger.info("${KEYSTORE_PASSWORD_KEY}: 
${retrievedKeystorePassword}")
+        }
+        logger.info(msg)
+
+        // Assert
+        assert msg =~ "Failed to unprotect key ${KEYSTORE_PASSWORD_KEY}"
+        assert isSensitive
+        assert isProtected
+    }
+
+    /**
+     * In the protection enabled scenario, a call to retrieve a sensitive 
property should handle if the property is unable to be unprotected due to a 
malformed value.
+     * @throws Exception
+     */
+    @Test
+    void testGetValueOfSensitivePropertyShouldHandleMultipleMalformedValues() 
throws Exception {
+        // Arrange
+
+        // Raw properties
+        ProtectedNiFiRegistryProperties properties =
+                
loadFromResourceFile("/conf/nifi-registry.with_sensitive_props_protected_aes_multiple_malformed.properties",
 KEY_HEX_128)
+
+        // Iterate over the protected keys and track the ones that fail to 
decrypt
+        SensitivePropertyProvider spp = new 
AESSensitivePropertyProvider(KEY_HEX_128)
+        Set<String> malformedKeys = properties.getProtectedPropertyKeys()
+                .findAll { String key, String scheme -> scheme == 
spp.identifierKey }
+                .keySet()
+                .findAll { String key ->
+            try {
+                spp.unprotect(properties.getProperty(key))
+                return false
+            } catch (SensitivePropertyProtectionException e) {
+                logger.expected("Caught a malformed value for ${key}")
+                return true
+            }
+        }
+
+        logger.expected("Malformed keys: ${malformedKeys.join(", ")}")
+
+        // Act
+        def e = 
groovy.test.GroovyAssert.shouldFail(SensitivePropertyProtectionException) {
+            NiFiRegistryProperties unprotectedProperties = 
properties.getUnprotectedProperties()
+            String retrievedKeystorePassword = 
unprotectedProperties.getProperty(KEYSTORE_PASSWORD_KEY)
+            logger.info("${KEYSTORE_PASSWORD_KEY}: 
${retrievedKeystorePassword}")
+        }
+        logger.expected(e.getMessage())
+
+        // Assert
+        assert e instanceof MultipleSensitivePropertyProtectionException
+        assert e.getMessage() =~ "Failed to unprotect keys"
+        assert e.getFailedKeys() == malformedKeys
+
+    }
+
+    /**
+     * In the protection enabled scenario, a call to retrieve a sensitive 
property should handle if the internal cache of providers is empty.
+     * @throws Exception
+     */
+    @Test
+    void testGetValueOfSensitivePropertyShouldHandleInvalidatedInternalCache() 
throws Exception {
+        // Arrange
+        ProtectedNiFiRegistryProperties properties =
+                
loadFromResourceFile("/conf/nifi-registry.with_sensitive_props_protected_aes_128.properties",
 KEY_HEX_128)
+        final String expectedKeystorePassword = 
properties.getProperty(KEYSTORE_PASSWORD_KEY)
+        logger.info("Read raw value from properties: 
${expectedKeystorePassword}")
+
+        // Overwrite the internal cache
+        properties.localProviderCache = [:]
+
+        boolean isSensitive = 
properties.isPropertySensitive(KEYSTORE_PASSWORD_KEY)
+        boolean isProtected = 
properties.isPropertyProtected(KEYSTORE_PASSWORD_KEY)
+        logger.info("The property is ${isSensitive ? "sensitive" : "not 
sensitive"} and ${isProtected ? "protected" : "not protected"}")
+
+        // Act
+        NiFiRegistryProperties unprotectedProperties = 
properties.getUnprotectedProperties()
+        String retrievedKeystorePassword = 
unprotectedProperties.getProperty(KEYSTORE_PASSWORD_KEY)
+        logger.info("${KEYSTORE_PASSWORD_KEY}: ${retrievedKeystorePassword}")
+
+        // Assert
+        assert retrievedKeystorePassword == expectedKeystorePassword
+        assert isSensitive
+        assert isProtected
+    }
+
+    @Test
+    void testShouldDetectIfPropertyIsProtected() throws Exception {
+        // Arrange
+        final String unprotectedPropertyKey = TRUSTSTORE_PASSWORD_KEY
+        final String protectedPropertyKey = KEYSTORE_PASSWORD_KEY
+
+        ProtectedNiFiRegistryProperties properties =
+                
loadFromResourceFile("/conf/nifi-registry.with_sensitive_props_protected_aes_128.properties",
 KEY_HEX_128)
+
+        // Act
+        boolean unprotectedPasswordIsSensitive = 
properties.isPropertySensitive(unprotectedPropertyKey)
+        boolean unprotectedPasswordIsProtected = 
properties.isPropertyProtected(unprotectedPropertyKey)
+        logger.info("${unprotectedPropertyKey} is 
${unprotectedPasswordIsSensitive ? "SENSITIVE" : "NOT SENSITIVE"}")
+        logger.info("${unprotectedPropertyKey} is 
${unprotectedPasswordIsProtected ? "PROTECTED" : "NOT PROTECTED"}")
+        boolean protectedPasswordIsSensitive = 
properties.isPropertySensitive(protectedPropertyKey)
+        boolean protectedPasswordIsProtected = 
properties.isPropertyProtected(protectedPropertyKey)
+        logger.info("${protectedPropertyKey} is ${protectedPasswordIsSensitive 
? "SENSITIVE" : "NOT SENSITIVE"}")
+        logger.info("${protectedPropertyKey} is ${protectedPasswordIsProtected 
? "PROTECTED" : "NOT PROTECTED"}")
+
+        // Assert
+        assert unprotectedPasswordIsSensitive
+        assert !unprotectedPasswordIsProtected
+
+        assert protectedPasswordIsSensitive
+        assert protectedPasswordIsProtected
+    }
+
+    @Test
+    void testShouldDetectIfPropertyWithEmptyProtectionSchemeIsProtected() 
throws Exception {
+        // Arrange
+        final String unprotectedPropertyKey = KEY_PASSWORD_KEY
+        ProtectedNiFiRegistryProperties properties =
+                
loadFromResourceFile("/conf/nifi-registry.with_sensitive_props_unprotected_extra_line.properties")
+
+        // Act
+        boolean unprotectedPasswordIsSensitive = 
properties.isPropertySensitive(unprotectedPropertyKey)
+        boolean unprotectedPasswordIsProtected = 
properties.isPropertyProtected(unprotectedPropertyKey)
+        logger.info("${unprotectedPropertyKey} is 
${unprotectedPasswordIsSensitive ? "SENSITIVE" : "NOT SENSITIVE"}")
+        logger.info("${unprotectedPropertyKey} is 
${unprotectedPasswordIsProtected ? "PROTECTED" : "NOT PROTECTED"}")
+
+        // Assert
+        assert unprotectedPasswordIsSensitive
+        assert !unprotectedPasswordIsProtected
+    }
+
+    @Test
+    void testShouldGetPercentageOfSensitivePropertiesProtected_0() throws 
Exception {
+        // Arrange
+        ProtectedNiFiRegistryProperties properties = 
loadFromResourceFile("/conf/nifi-registry.properties")
+
+        logger.info("Sensitive property keys: 
${properties.getSensitivePropertyKeys()}")
+        logger.info("Protected property keys: 
${properties.getProtectedPropertyKeys().keySet()}")
+
+        // Act
+        double percentProtected = 
properties.getPercentOfSensitivePropertiesProtected()
+        logger.info("${percentProtected}% 
(${properties.getProtectedPropertyKeys().size()} of 
${properties.getPopulatedSensitivePropertyKeys().size()}) protected")
+
+        // Assert
+        assert percentProtected == 0.0
+    }
+
+    @Test
+    void testShouldGetPercentageOfSensitivePropertiesProtected_75() throws 
Exception {
+        // Arrange
+        ProtectedNiFiRegistryProperties properties =
+                
loadFromResourceFile("/conf/nifi-registry.with_sensitive_props_protected_aes_128.properties",
 KEY_HEX_128)
+
+        logger.info("Sensitive property keys: 
${properties.getSensitivePropertyKeys()}")
+        logger.info("Protected property keys: 
${properties.getProtectedPropertyKeys().keySet()}")
+
+        // Act
+        double percentProtected = 
properties.getPercentOfSensitivePropertiesProtected()
+        logger.info("${percentProtected}% 
(${properties.getProtectedPropertyKeys().size()} of 
${properties.getPopulatedSensitivePropertyKeys().size()}) protected")
+
+        // Assert
+        assert percentProtected == 67.0
+    }
+
+    @Test
+    void testShouldGetPercentageOfSensitivePropertiesProtected_100() throws 
Exception {
+        // Arrange
+        ProtectedNiFiRegistryProperties properties =
+                
loadFromResourceFile("/conf/nifi-registry.with_sensitive_props_fully_protected_aes_128.properties",
 KEY_HEX_128)
+
+        logger.info("Sensitive property keys: 
${properties.getSensitivePropertyKeys()}")
+        logger.info("Protected property keys: 
${properties.getProtectedPropertyKeys().keySet()}")
+
+        // Act
+        double percentProtected = 
properties.getPercentOfSensitivePropertiesProtected()
+        logger.info("${percentProtected}% 
(${properties.getProtectedPropertyKeys().size()} of 
${properties.getPopulatedSensitivePropertyKeys().size()}) protected")
+
+        // Assert
+        assert percentProtected == 100.0
+    }
+
+    @Test
+    void testInstanceWithNoProtectedPropertiesShouldNotLoadSPP() throws 
Exception {
+        // Arrange
+        ProtectedNiFiRegistryProperties properties = 
loadFromResourceFile("/conf/nifi-registry.properties")
+        assert properties.@localProviderCache?.isEmpty()
+
+        logger.info("Has protected properties: 
${properties.hasProtectedKeys()}")
+        assert !properties.hasProtectedKeys()
+
+        // Act
+        Map localCache = properties.@localProviderCache
+        logger.info("Internal cache ${localCache} has ${localCache.size()} 
providers loaded")
+
+        // Assert
+        assert localCache.isEmpty()
+    }
+
+    @Test
+    void testShouldAddSensitivePropertyProvider() throws Exception {
+        // Arrange
+        ProtectedNiFiRegistryProperties properties = new 
ProtectedNiFiRegistryProperties()
+        assert properties.getSensitivePropertyProviders().isEmpty()
+
+        SensitivePropertyProvider mockProvider =
+                [unprotect       : { String input ->
+                    logger.mock("Mock call to #unprotect(${input})")
+                    input.reverse()
+                },
+                 getIdentifierKey: { -> "mockProvider" }] as 
SensitivePropertyProvider
+
+        // Act
+        properties.addSensitivePropertyProvider(mockProvider)
+
+        // Assert
+        assert properties.getSensitivePropertyProviders().size() == 1
+    }
+
+    @Test
+    void testShouldNotAddNullSensitivePropertyProvider() throws Exception {
+        // Arrange
+        ProtectedNiFiRegistryProperties properties = new 
ProtectedNiFiRegistryProperties()
+        assert properties.@localProviderCache?.isEmpty()
+
+        // Act
+        def msg = shouldFail(IllegalArgumentException) {
+            properties.addSensitivePropertyProvider(null)
+        }
+        logger.info(msg)
+
+        // Assert
+        assert properties.getSensitivePropertyProviders().size() == 0
+        assert msg == "Cannot add null SensitivePropertyProvider"
+    }
+
+    @Test
+    void testShouldNotAllowOverwriteOfProvider() throws Exception {
+        // Arrange
+        ProtectedNiFiRegistryProperties properties = new 
ProtectedNiFiRegistryProperties()
+        assert properties.getSensitivePropertyProviders().isEmpty()
+
+        SensitivePropertyProvider mockProvider =
+                [unprotect       : { String input ->
+                    logger.mock("Mock call to 1#unprotect(${input})")
+                    input.reverse()
+                },
+                 getIdentifierKey: { -> "mockProvider" }] as 
SensitivePropertyProvider
+        properties.addSensitivePropertyProvider(mockProvider)
+        assert properties.getSensitivePropertyProviders().size() == 1
+
+        SensitivePropertyProvider mockProvider2 =
+                [unprotect       : { String input ->
+                    logger.mock("Mock call to 2#unprotect(${input})")
+                    input.reverse()
+                },
+                 getIdentifierKey: { -> "mockProvider" }] as 
SensitivePropertyProvider
+
+        // Act
+        def msg = shouldFail(UnsupportedOperationException) {
+            properties.addSensitivePropertyProvider(mockProvider2)
+        }
+        logger.info(msg)
+
+        // Assert
+        assert msg == "Cannot overwrite existing sensitive property provider 
registered for mockProvider"
+        assert properties.getSensitivePropertyProviders().size() == 1
+    }
+
+    @Test
+    void 
testGetUnprotectedPropertiesShouldReturnInternalInstanceWhenNoneProtected() {
+        // Arrange
+        ProtectedNiFiRegistryProperties protectedNiFiProperties = 
loadFromResourceFile("/conf/nifi-registry.properties")
+        logger.info("Loaded ${protectedNiFiProperties.size()} properties from 
conf/nifi.properties")
+
+        int hashCode = 
protectedNiFiProperties.internalNiFiProperties.hashCode()
+        logger.info("Hash code of internal instance: ${hashCode}")
+
+        // Act
+        NiFiRegistryProperties unprotectedNiFiProperties = 
protectedNiFiProperties.getUnprotectedProperties()
+        logger.info("Unprotected ${unprotectedNiFiProperties.size()} 
properties")
+
+        // Assert
+        assert unprotectedNiFiProperties.size() == 
protectedNiFiProperties.size()
+        assert unprotectedNiFiProperties.getPropertyKeys().every {
+            !unprotectedNiFiProperties.getProperty(it).endsWith(".protected")
+        }
+        logger.info("Hash code from returned unprotected instance: 
${unprotectedNiFiProperties.hashCode()}")
+        assert unprotectedNiFiProperties.hashCode() == hashCode
+    }
+
+    @Test
+    void testGetUnprotectedPropertiesShouldDecryptProtectedProperties() {
+        // Arrange
+        ProtectedNiFiRegistryProperties protectedNiFiProperties =
+                
loadFromResourceFile("/conf/nifi-registry.with_sensitive_props_protected_aes_128.properties",
 KEY_HEX_128)
+
+        int protectedPropertyCount = 
protectedNiFiProperties.getProtectedPropertyKeys().size()
+        int protectionSchemeCount = protectedNiFiProperties
+                .getPropertyKeysIncludingProtectionSchemes()
+                .findAll { it.endsWith(".protected") }
+                .size()
+        int expectedUnprotectedPropertyCount = protectedNiFiProperties.size()
+
+        String protectedProps = protectedNiFiProperties
+                .getProtectedPropertyKeys()
+                .collectEntries {
+            [(it.key): protectedNiFiProperties.getProperty(it.key)]
+        }.entrySet()
+                .join("\n")
+
+        logger.info("Detected ${protectedPropertyCount} protected properties 
and ${protectionSchemeCount} protection scheme properties")
+        logger.info("Protected properties: \n${protectedProps}")
+
+        logger.info("Expected unprotected property count: 
${expectedUnprotectedPropertyCount}")
+
+        int hashCode = 
protectedNiFiProperties.internalNiFiProperties.hashCode()
+        logger.info("Hash code of internal instance: ${hashCode}")
+
+        // Act
+        NiFiRegistryProperties unprotectedNiFiProperties = 
protectedNiFiProperties.getUnprotectedProperties()
+        logger.info("Unprotected ${unprotectedNiFiProperties.size()} 
properties")
+
+        // Assert
+        assert unprotectedNiFiProperties.size() == 
expectedUnprotectedPropertyCount
+        assert unprotectedNiFiProperties.getPropertyKeys().every {
+            !unprotectedNiFiProperties.getProperty(it).endsWith(".protected")
+        }
+        logger.info("Hash code from returned unprotected instance: 
${unprotectedNiFiProperties.hashCode()}")
+        assert unprotectedNiFiProperties.hashCode() != hashCode
+    }
+
+    @Test
+    void 
testGetUnprotectedPropertiesShouldDecryptProtectedPropertiesWith256Bit() {
+        // Arrange
+        Assume.assumeTrue("JCE unlimited strength crypto policy must be 
installed for this test", Cipher.getMaxAllowedKeyLength("AES") > 128)
+        ProtectedNiFiRegistryProperties protectedNiFiProperties =
+                
loadFromResourceFile("/conf/nifi-registry.with_sensitive_props_protected_aes_256.properties",
 KEY_HEX_256)
+
+        int protectedPropertyCount = 
protectedNiFiProperties.getProtectedPropertyKeys().size()
+        int protectionSchemeCount = protectedNiFiProperties
+                .getPropertyKeysIncludingProtectionSchemes()
+                .findAll { it.endsWith(".protected") }
+                .size()
+        int expectedUnprotectedPropertyCount = protectedNiFiProperties.size()
+
+        String protectedProps = protectedNiFiProperties
+                .getProtectedPropertyKeys()
+                .collectEntries {
+            [(it.key): protectedNiFiProperties.getProperty(it.key)]
+        }.entrySet()
+                .join("\n")
+
+        logger.info("Detected ${protectedPropertyCount} protected properties 
and ${protectionSchemeCount} protection scheme properties")
+        logger.info("Protected properties: \n${protectedProps}")
+
+        logger.info("Expected unprotected property count: 
${expectedUnprotectedPropertyCount}")
+
+        int hashCode = 
protectedNiFiProperties.internalNiFiProperties.hashCode()
+        logger.info("Hash code of internal instance: ${hashCode}")
+
+        // Act
+        NiFiRegistryProperties unprotectedNiFiProperties = 
protectedNiFiProperties.getUnprotectedProperties()
+        logger.info("Unprotected ${unprotectedNiFiProperties.size()} 
properties")
+
+        // Assert
+        assert unprotectedNiFiProperties.size() == 
expectedUnprotectedPropertyCount
+        assert unprotectedNiFiProperties.getPropertyKeys().every {
+            !unprotectedNiFiProperties.getProperty(it).endsWith(".protected")
+        }
+        logger.info("Hash code from returned unprotected instance: 
${unprotectedNiFiProperties.hashCode()}")
+        assert unprotectedNiFiProperties.hashCode() != hashCode
+    }
+
+    @Test
+    void testShouldCalculateSize() {
+        // Arrange
+        NiFiRegistryProperties rawProperties = [key: "protectedValue", 
"key.protected": "scheme", "key2": "value2"] as NiFiRegistryProperties
+        ProtectedNiFiRegistryProperties protectedNiFiProperties = new 
ProtectedNiFiRegistryProperties(rawProperties)
+        logger.info("Raw properties (${rawProperties.size()}): 
${rawProperties.keySet().join(", ")}")
+
+        // Act
+        int protectedSize = protectedNiFiProperties.size()
+        logger.info("Protected properties (${protectedNiFiProperties.size()}): 
" +
+                
"${protectedNiFiProperties.getPropertyKeysExcludingProtectionSchemes().join(", 
")}")
+
+        // Assert
+        assert protectedSize == rawProperties.size() - 1
+    }
+
+    @Test
+    void testGetPropertyKeysShouldMatchSize() {
+        // Arrange
+        NiFiRegistryProperties rawProperties = [key: "protectedValue", 
"key.protected": "scheme", "key2": "value2"] as NiFiRegistryProperties
+        ProtectedNiFiRegistryProperties protectedNiFiProperties = new 
ProtectedNiFiRegistryProperties(rawProperties)
+        logger.info("Raw properties (${rawProperties.size()}): 
${rawProperties.keySet().join(", ")}")
+
+        // Act
+        def filteredKeys = 
protectedNiFiProperties.getPropertyKeysExcludingProtectionSchemes()
+        logger.info("Protected properties (${protectedNiFiProperties.size()}): 
${filteredKeys.join(", ")}")
+
+        // Assert
+        assert protectedNiFiProperties.size() == rawProperties.size() - 1
+        assert filteredKeys == rawProperties.keySet() - "key.protected"
+    }
+
+    @Test
+    void testShouldGetPropertyKeysIncludingProtectionSchemes() {
+        // Arrange
+        NiFiRegistryProperties rawProperties = [key: "protectedValue", 
"key.protected": "scheme", "key2": "value2"] as NiFiRegistryProperties
+        ProtectedNiFiRegistryProperties protectedNiFiProperties = new 
ProtectedNiFiRegistryProperties(rawProperties)
+        logger.info("Raw properties (${rawProperties.size()}): 
${rawProperties.keySet().join(", ")}")
+
+        // Act
+        def allKeys = 
protectedNiFiProperties.getPropertyKeysIncludingProtectionSchemes()
+        logger.info("Protected properties with schemes (${allKeys.size()}): 
${allKeys.join(", ")}")
+
+        // Assert
+        assert allKeys.size() == rawProperties.size()
+        assert allKeys == rawProperties.keySet()
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-properties/src/test/groovy/org/apache/nifi/security/crypto/CryptoKeyLoaderGroovyTest.groovy
----------------------------------------------------------------------
diff --git 
a/nifi-registry-properties/src/test/groovy/org/apache/nifi/security/crypto/CryptoKeyLoaderGroovyTest.groovy
 
b/nifi-registry-properties/src/test/groovy/org/apache/nifi/security/crypto/CryptoKeyLoaderGroovyTest.groovy
new file mode 100644
index 0000000..4f69682
--- /dev/null
+++ 
b/nifi-registry-properties/src/test/groovy/org/apache/nifi/security/crypto/CryptoKeyLoaderGroovyTest.groovy
@@ -0,0 +1,121 @@
+/*
+ * 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.security.crypto
+
+import org.apache.nifi.registry.security.crypto.CryptoKeyLoader
+import org.apache.nifi.registry.security.crypto.CryptoKeyProvider
+import org.bouncycastle.jce.provider.BouncyCastleProvider
+import org.junit.BeforeClass
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+
+import java.nio.file.Files
+import java.nio.file.attribute.PosixFilePermission
+import java.security.Security
+
+@RunWith(JUnit4.class)
+class CryptoKeyLoaderGroovyTest extends GroovyTestCase {
+
+    private static final Logger logger = 
LoggerFactory.getLogger(CryptoKeyLoaderGroovyTest.class)
+
+    private static final String KEY_HEX_128 = 
"0123456789ABCDEFFEDCBA9876543210"
+    private static final String KEY_HEX_256 = KEY_HEX_128 * 2
+
+    @BeforeClass
+    public static void setUpOnce() throws Exception {
+        Security.addProvider(new BouncyCastleProvider())
+
+        logger.metaClass.methodMissing = { String name, args ->
+            logger.info("[${name?.toUpperCase()}] ${(args as List).join(" ")}")
+        }
+    }
+
+    @Test
+    public void testShouldExtractKeyFromBootstrapFile() throws Exception {
+        // Arrange
+        final String expectedKey = KEY_HEX_256
+
+        // Act
+        String key = 
CryptoKeyLoader.extractKeyFromBootstrapFile("src/test/resources/conf/bootstrap.conf")
+
+        // Assert
+        assert key == expectedKey
+    }
+
+    @Test
+    public void testShouldNotExtractKeyFromBootstrapFileWithoutKeyLine() 
throws Exception {
+        // Arrange
+
+        // Act
+        String key = 
CryptoKeyLoader.extractKeyFromBootstrapFile("src/test/resources/conf/bootstrap.with_missing_key_line.conf")
+
+        // Assert
+        assert key == CryptoKeyProvider.EMPTY_KEY
+    }
+
+    @Test
+    public void testShouldNotExtractKeyFromBootstrapFileWithoutKey() throws 
Exception {
+        // Arrange
+
+        // Act
+        String key = 
CryptoKeyLoader.extractKeyFromBootstrapFile("src/test/resources/conf/bootstrap.with_missing_key.conf")
+
+        // Assert
+        assert key == CryptoKeyProvider.EMPTY_KEY
+    }
+
+    @Test
+    public void testShouldNotExtractKeyFromMissingBootstrapFile() throws 
Exception {
+        // Arrange
+
+        // Act
+        def msg = shouldFail(IOException) {
+            
CryptoKeyLoader.extractKeyFromBootstrapFile("src/test/resources/conf/bootstrap.missing.conf")
+        }
+        logger.info(msg)
+
+        // Assert
+        assert msg == "Cannot read from bootstrap.conf"
+    }
+
+    @Test
+    public void testShouldNotExtractKeyFromUnreadableBootstrapFile() throws 
Exception {
+        // Arrange
+        File unreadableFile = new 
File("src/test/resources/conf/bootstrap.unreadable_file_permissions.conf")
+        Set<PosixFilePermission> originalPermissions = 
Files.getPosixFilePermissions(unreadableFile.toPath())
+        Files.setPosixFilePermissions(unreadableFile.toPath(), [] as Set)
+        try {
+            assert !unreadableFile.canRead()
+
+            // Act
+            def msg = shouldFail(IOException) {
+                
CryptoKeyLoader.extractKeyFromBootstrapFile("src/test/resources/conf/bootstrap.unreadable_file_permissions.conf")
+            }
+            logger.info(msg)
+
+            // Assert
+            assert msg == "Cannot read from bootstrap.conf"
+        } finally {
+            // Clean up to allow for indexing, etc.
+            Files.setPosixFilePermissions(unreadableFile.toPath(), 
originalPermissions)
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-properties/src/test/resources/conf/bootstrap.conf
----------------------------------------------------------------------
diff --git a/nifi-registry-properties/src/test/resources/conf/bootstrap.conf 
b/nifi-registry-properties/src/test/resources/conf/bootstrap.conf
new file mode 100644
index 0000000..4321bca
--- /dev/null
+++ b/nifi-registry-properties/src/test/resources/conf/bootstrap.conf
@@ -0,0 +1,60 @@
+#
+# 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 to use when running nifi-registry
+java=java
+
+# Username to use when running nifi-registry. This value will be ignored on 
Windows.
+run.as=
+
+# Configure where nifi-registry's lib and conf directories live
+lib.dir=./lib
+conf.dir=./conf
+
+# How long to wait after telling nifi-registry to shutdown before explicitly 
killing the Process
+graceful.shutdown.seconds=20
+
+# Disable JSR 199 so that we can use JSP's without running a JDK
+java.arg.1=-Dorg.apache.jasper.compiler.disablejsr199=true
+
+# JVM memory settings
+java.arg.2=-Xms512m
+java.arg.3=-Xmx512m
+
+# Enable Remote Debugging
+#java.arg.debug=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000
+
+java.arg.4=-Djava.net.preferIPv4Stack=true
+
+# allowRestrictedHeaders is required for Cluster/Node communications to work 
properly
+java.arg.5=-Dsun.net.http.allowRestrictedHeaders=true
+java.arg.6=-Djava.protocol.handler.pkgs=sun.net.www.protocol
+
+# Java 7 and below have issues with Code Cache. The following lines allow us 
to run well even with
+# many classes loaded in the JVM.
+#java.arg.7=-XX:ReservedCodeCacheSize=256m
+#java.arg.8=-XX:CodeCacheFlushingMinimumFreeSpace=10m
+#java.arg.9=-XX:+UseCodeCacheFlushing
+#java.arg.11=-XX:PermSize=128M
+#java.arg.12=-XX:MaxPermSize=128M
+
+# The G1GC is still considered experimental but has proven to be very 
advantageous in providing great
+# 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=0123456789ABCDEFFEDCBA98765432100123456789ABCDEFFEDCBA9876543210
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-properties/src/test/resources/conf/bootstrap.unreadable_file_permissions.conf
----------------------------------------------------------------------
diff --git 
a/nifi-registry-properties/src/test/resources/conf/bootstrap.unreadable_file_permissions.conf
 
b/nifi-registry-properties/src/test/resources/conf/bootstrap.unreadable_file_permissions.conf
new file mode 100644
index 0000000..3043635
--- /dev/null
+++ 
b/nifi-registry-properties/src/test/resources/conf/bootstrap.unreadable_file_permissions.conf
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+
+# The POSIX file permissions for this file are emptied (i.e., chmod 000) 
during test and then reverted
+# See 
org.apache.nifi.registry.properties.NiFiRegistryPropertiesLoaderGroovyTest#testShouldNotExtractKeyFromUnreadableBootstrapFile
+
+# Master key in hexadecimal format for encrypted sensitive configuration values
+nifi.registry.bootstrap.sensitive.key=0123456789ABCDEFFEDCBA98765432100123456789ABCDEFFEDCBA9876543210
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-properties/src/test/resources/conf/bootstrap.with_missing_key.conf
----------------------------------------------------------------------
diff --git 
a/nifi-registry-properties/src/test/resources/conf/bootstrap.with_missing_key.conf
 
b/nifi-registry-properties/src/test/resources/conf/bootstrap.with_missing_key.conf
new file mode 100644
index 0000000..7317ab0
--- /dev/null
+++ 
b/nifi-registry-properties/src/test/resources/conf/bootstrap.with_missing_key.conf
@@ -0,0 +1,60 @@
+#
+# 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 to use when running nifi-registry
+java=java
+
+# Username to use when running nifi-registry. This value will be ignored on 
Windows.
+run.as=
+
+# Configure where nifi-registry's lib and conf directories live
+lib.dir=./lib
+conf.dir=./conf
+
+# How long to wait after telling nifi-registry to shutdown before explicitly 
killing the Process
+graceful.shutdown.seconds=20
+
+# Disable JSR 199 so that we can use JSP's without running a JDK
+java.arg.1=-Dorg.apache.jasper.compiler.disablejsr199=true
+
+# JVM memory settings
+java.arg.2=-Xms512m
+java.arg.3=-Xmx512m
+
+# Enable Remote Debugging
+#java.arg.debug=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000
+
+java.arg.4=-Djava.net.preferIPv4Stack=true
+
+# allowRestrictedHeaders is required for Cluster/Node communications to work 
properly
+java.arg.5=-Dsun.net.http.allowRestrictedHeaders=true
+java.arg.6=-Djava.protocol.handler.pkgs=sun.net.www.protocol
+
+# Java 7 and below have issues with Code Cache. The following lines allow us 
to run well even with
+# many classes loaded in the JVM.
+#java.arg.7=-XX:ReservedCodeCacheSize=256m
+#java.arg.8=-XX:CodeCacheFlushingMinimumFreeSpace=10m
+#java.arg.9=-XX:+UseCodeCacheFlushing
+#java.arg.11=-XX:PermSize=128M
+#java.arg.12=-XX:MaxPermSize=128M
+
+# The G1GC is still considered experimental but has proven to be very 
advantageous in providing great
+# 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=
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-properties/src/test/resources/conf/bootstrap.with_missing_key_line.conf
----------------------------------------------------------------------
diff --git 
a/nifi-registry-properties/src/test/resources/conf/bootstrap.with_missing_key_line.conf
 
b/nifi-registry-properties/src/test/resources/conf/bootstrap.with_missing_key_line.conf
new file mode 100644
index 0000000..6ccdaaf
--- /dev/null
+++ 
b/nifi-registry-properties/src/test/resources/conf/bootstrap.with_missing_key_line.conf
@@ -0,0 +1,60 @@
+#
+# 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 to use when running nifi-registry
+java=java
+
+# Username to use when running nifi-registry. This value will be ignored on 
Windows.
+run.as=
+
+# Configure where nifi-registry's lib and conf directories live
+lib.dir=./lib
+conf.dir=./conf
+
+# How long to wait after telling nifi-registry to shutdown before explicitly 
killing the Process
+graceful.shutdown.seconds=20
+
+# Disable JSR 199 so that we can use JSP's without running a JDK
+java.arg.1=-Dorg.apache.jasper.compiler.disablejsr199=true
+
+# JVM memory settings
+java.arg.2=-Xms512m
+java.arg.3=-Xmx512m
+
+# Enable Remote Debugging
+#java.arg.debug=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000
+
+java.arg.4=-Djava.net.preferIPv4Stack=true
+
+# allowRestrictedHeaders is required for Cluster/Node communications to work 
properly
+java.arg.5=-Dsun.net.http.allowRestrictedHeaders=true
+java.arg.6=-Djava.protocol.handler.pkgs=sun.net.www.protocol
+
+# Java 7 and below have issues with Code Cache. The following lines allow us 
to run well even with
+# many classes loaded in the JVM.
+#java.arg.7=-XX:ReservedCodeCacheSize=256m
+#java.arg.8=-XX:CodeCacheFlushingMinimumFreeSpace=10m
+#java.arg.9=-XX:+UseCodeCacheFlushing
+#java.arg.11=-XX:PermSize=128M
+#java.arg.12=-XX:MaxPermSize=128M
+
+# The G1GC is still considered experimental but has proven to be very 
advantageous in providing great
+# 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 is intentionally absent from this file
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-properties/src/test/resources/conf/nifi-registry.properties
----------------------------------------------------------------------
diff --git 
a/nifi-registry-properties/src/test/resources/conf/nifi-registry.properties 
b/nifi-registry-properties/src/test/resources/conf/nifi-registry.properties
new file mode 100644
index 0000000..a7efedb
--- /dev/null
+++ b/nifi-registry-properties/src/test/resources/conf/nifi-registry.properties
@@ -0,0 +1,45 @@
+#
+# 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.
+#
+
+# web properties #
+nifi.registry.web.war.directory=./target/lib
+nifi.registry.web.http.host=
+nifi.registry.web.http.port=8080
+nifi.registry.web.https.host=
+nifi.registry.web.https.port=
+nifi.registry.web.jetty.working.directory=./target/work/jetty
+nifi.registry.web.jetty.threads=1
+
+# security properties #
+nifi.registry.security.keystore=
+nifi.registry.security.keystoreType=
+nifi.registry.security.keystorePasswd=
+nifi.registry.security.keyPasswd=
+nifi.registry.security.truststore=
+nifi.registry.security.truststoreType=
+nifi.registry.security.truststorePasswd=
+nifi.registry.security.needClientAuth=
+nifi.registry.security.authorizers.configuration.file=
+nifi.registry.security.authorizer=
+nifi.registry.security.identity.providers.configuration.file=
+nifi.registry.security.identity.provider=
+
+# kerberos properties
+nifi.registry.kerberos.krb5.file=/path/to/krb5.conf
+nifi.registry.kerberos.spnego.authentication.expiration=12 hours
+nifi.registry.kerberos.spnego.principal=HTTP/localhost@LOCALHOST
+nifi.registry.kerberos.spnego.keytab.location=/path/to/keytab

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_additional_sensitive_keys.properties
----------------------------------------------------------------------
diff --git 
a/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_additional_sensitive_keys.properties
 
b/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_additional_sensitive_keys.properties
new file mode 100644
index 0000000..5afb3dd
--- /dev/null
+++ 
b/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_additional_sensitive_keys.properties
@@ -0,0 +1,55 @@
+#
+# 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.
+#
+
+# web properties #
+nifi.registry.web.war.directory=./target/lib
+nifi.registry.web.http.host=
+nifi.registry.web.http.port=8080
+nifi.registry.web.https.host=
+nifi.registry.web.https.port=
+nifi.registry.web.jetty.working.directory=./target/work/jetty
+nifi.registry.web.jetty.threads=1
+
+# security properties #
+nifi.registry.security.keystore=
+nifi.registry.security.keystoreType=
+nifi.registry.security.keystorePasswd=
+nifi.registry.security.keyPasswd=
+nifi.registry.security.truststore=
+nifi.registry.security.truststoreType=
+nifi.registry.security.truststorePasswd=
+nifi.registry.security.needClientAuth=
+nifi.registry.security.authorizers.configuration.file=
+nifi.registry.security.authorizer=
+nifi.registry.security.identity.providers.configuration.file=
+nifi.registry.security.identity.provider=
+
+# providers properties #
+nifi.registry.providers.configuration.file=
+
+# database properties
+nifi.registry.db.directory=./target/db
+nifi.registry.db.url.append=
+
+# kerberos properties #
+nifi.registry.kerberos.krb5.file=/path/to/krb5.conf
+nifi.registry.kerberos.spnego.authentication.expiration=12 hours
+nifi.registry.kerberos.spnego.principal=HTTP/localhost@LOCALHOST
+nifi.registry.kerberos.spnego.keytab.location=/path/to/keytab
+
+# security properties #
+nifi.registry.sensitive.props.additional.keys=nifi.registry.web.http.port, 
nifi.registry.web.http.host, nifi.registry.sensitive.props.additional.keys

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_fully_protected_aes_128.properties
----------------------------------------------------------------------
diff --git 
a/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_fully_protected_aes_128.properties
 
b/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_fully_protected_aes_128.properties
new file mode 100644
index 0000000..90eb64f
--- /dev/null
+++ 
b/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_fully_protected_aes_128.properties
@@ -0,0 +1,43 @@
+#
+# 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.
+#
+
+# web properties #
+nifi.registry.web.war.directory=./target/lib
+nifi.registry.web.http.host=
+nifi.registry.web.http.port=8080
+nifi.registry.web.https.host=
+nifi.registry.web.https.port=
+nifi.registry.web.jetty.working.directory=./target/work/jetty
+nifi.registry.web.jetty.threads=1
+
+# security properties #
+nifi.registry.security.keystore=/path/to/keystore.jks
+nifi.registry.security.keystoreType=JKS
+nifi.registry.security.keystorePasswd=6WUpex+VZiN05LXu||joWJMuoSzYniEC7IAoingTimlG7+RGk8I2irl/WTlIuMcg
+nifi.registry.security.keystorePasswd.protected=aes/gcm/128
+nifi.registry.security.keyPasswd=6WUpex+VZiN05LXu||joWJMuoSzYniEC7IAoingTimlG7+RGk8I2irl/WTlIuMcg
+nifi.registry.security.keyPasswd.protected=aes/gcm/128
+nifi.registry.security.truststore=
+nifi.registry.security.truststoreType=
+nifi.registry.security.truststorePasswd=
+nifi.registry.security.needClientAuth=
+nifi.registry.security.authorizers.configuration.file=
+nifi.registry.security.authorizer=
+nifi.registry.security.identity.providers.configuration.file=
+nifi.registry.security.identity.provider=
+
+nifi.registry.sensitive.props.additional.keys=

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_protected_aes_128.properties
----------------------------------------------------------------------
diff --git 
a/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_protected_aes_128.properties
 
b/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_protected_aes_128.properties
new file mode 100644
index 0000000..6ecd281
--- /dev/null
+++ 
b/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_protected_aes_128.properties
@@ -0,0 +1,43 @@
+#
+# 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.
+#
+
+# web properties #
+nifi.registry.web.war.directory=./target/lib
+nifi.registry.web.http.host=
+nifi.registry.web.http.port=8080
+nifi.registry.web.https.host=
+nifi.registry.web.https.port=
+nifi.registry.web.jetty.working.directory=./target/work/jetty
+nifi.registry.web.jetty.threads=1
+
+# security properties #
+nifi.registry.security.keystore=/path/to/keystore.jks
+nifi.registry.security.keystoreType=JKS
+nifi.registry.security.keystorePasswd=6WUpex+VZiN05LXu||joWJMuoSzYniEC7IAoingTimlG7+RGk8I2irl/WTlIuMcg
+nifi.registry.security.keystorePasswd.protected=aes/gcm/128
+nifi.registry.security.keyPasswd=6WUpex+VZiN05LXu||joWJMuoSzYniEC7IAoingTimlG7+RGk8I2irl/WTlIuMcg
+nifi.registry.security.keyPasswd.protected=aes/gcm/128
+nifi.registry.security.truststore=
+nifi.registry.security.truststoreType=
+nifi.registry.security.truststorePasswd=
+nifi.registry.security.needClientAuth=
+nifi.registry.security.authorizers.configuration.file=
+nifi.registry.security.authorizer=
+nifi.registry.security.identity.providers.configuration.file=
+nifi.registry.security.identity.provider=
+
+nifi.registry.sensitive.props.additional.keys=nifi.registry.web.http.port

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_protected_aes_128_password.properties
----------------------------------------------------------------------
diff --git 
a/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_protected_aes_128_password.properties
 
b/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_protected_aes_128_password.properties
new file mode 100644
index 0000000..a3b272d
--- /dev/null
+++ 
b/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_protected_aes_128_password.properties
@@ -0,0 +1,43 @@
+#
+# 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.
+#
+
+# web properties #
+nifi.registry.web.war.directory=./target/lib
+nifi.registry.web.http.host=
+nifi.registry.web.http.port=8080
+nifi.registry.web.https.host=
+nifi.registry.web.https.port=
+nifi.registry.web.jetty.working.directory=./target/work/jetty
+nifi.registry.web.jetty.threads=1
+
+# security properties #
+nifi.registry.security.keystore=/path/to/keystore.jks
+nifi.registry.security.keystoreType=JKS
+nifi.registry.security.keystorePasswd=oa6Aaz5tlFprPuKt||IlVgftF2VqvBIambkP5HVDbRoyKzZl8wwKSw4O9tjHTALA
+nifi.registry.security.keystorePasswd.protected=aes/gcm/128
+nifi.registry.security.keyPasswd=oa6Aaz5tlFprPuKt||IlVgftF2VqvBIambkP5HVDbRoyKzZl8wwKSw4O9tjHTALA
+nifi.registry.security.keyPasswd.protected=aes/gcm/128
+nifi.registry.security.truststore=
+nifi.registry.security.truststoreType=
+nifi.registry.security.truststorePasswd=
+nifi.registry.security.needClientAuth=
+nifi.registry.security.authorizers.configuration.file=
+nifi.registry.security.authorizer=
+nifi.registry.security.identity.providers.configuration.file=
+nifi.registry.security.identity.provider=
+
+nifi.registry.sensitive.props.additional.keys=nifi.registry.web.http.port

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_protected_aes_256.properties
----------------------------------------------------------------------
diff --git 
a/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_protected_aes_256.properties
 
b/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_protected_aes_256.properties
new file mode 100644
index 0000000..97aaba0
--- /dev/null
+++ 
b/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_protected_aes_256.properties
@@ -0,0 +1,43 @@
+#
+# 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.
+#
+
+# web properties #
+nifi.registry.web.war.directory=./target/lib
+nifi.registry.web.http.host=
+nifi.registry.web.http.port=8080
+nifi.registry.web.https.host=
+nifi.registry.web.https.port=
+nifi.registry.web.jetty.working.directory=./target/work/jetty
+nifi.registry.web.jetty.threads=1
+
+# 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=
+nifi.registry.security.needClientAuth=
+nifi.registry.security.authorizers.configuration.file=
+nifi.registry.security.authorizer=
+nifi.registry.security.identity.providers.configuration.file=
+nifi.registry.security.identity.provider=
+
+nifi.registry.sensitive.props.additional.keys=nifi.registry.web.http.port

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_protected_aes_multiple_malformed.properties
----------------------------------------------------------------------
diff --git 
a/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_protected_aes_multiple_malformed.properties
 
b/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_protected_aes_multiple_malformed.properties
new file mode 100644
index 0000000..d408df0
--- /dev/null
+++ 
b/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_protected_aes_multiple_malformed.properties
@@ -0,0 +1,43 @@
+#
+# 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.
+#
+
+# web properties #
+nifi.registry.web.war.directory=./target/lib
+nifi.registry.web.http.host=
+nifi.registry.web.http.port=8080
+nifi.registry.web.https.host=
+nifi.registry.web.https.port=
+nifi.registry.web.jetty.working.directory=./target/work/jetty
+nifi.registry.web.jetty.threads=1
+
+# security properties #
+nifi.registry.security.keystore=/path/to/keystore.jks
+nifi.registry.security.keystoreType=JKS
+nifi.registry.security.keystorePasswd=6WUpex+VZiN05LXu||thisIsAnIntentionallyMalformedCipherValue
+nifi.registry.security.keystorePasswd.protected=aes/gcm/128
+nifi.registry.security.keyPasswd=6WUpex+VZiN05LXu||thisIsAnIntentionallyMalformedCipherValue
+nifi.registry.security.keyPasswd.protected=aes/gcm/128
+nifi.registry.security.truststore=
+nifi.registry.security.truststoreType=
+nifi.registry.security.truststorePasswd=
+nifi.registry.security.needClientAuth=
+nifi.registry.security.authorizers.configuration.file=
+nifi.registry.security.authorizer=
+nifi.registry.security.identity.providers.configuration.file=
+nifi.registry.security.identity.provider=
+
+nifi.registry.sensitive.props.additional.keys=

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_protected_aes_single_malformed.properties
----------------------------------------------------------------------
diff --git 
a/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_protected_aes_single_malformed.properties
 
b/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_protected_aes_single_malformed.properties
new file mode 100644
index 0000000..8552f9e
--- /dev/null
+++ 
b/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_protected_aes_single_malformed.properties
@@ -0,0 +1,43 @@
+#
+# 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.
+#
+
+# web properties #
+nifi.registry.web.war.directory=./target/lib
+nifi.registry.web.http.host=
+nifi.registry.web.http.port=8080
+nifi.registry.web.https.host=
+nifi.registry.web.https.port=
+nifi.registry.web.jetty.working.directory=./target/work/jetty
+nifi.registry.web.jetty.threads=1
+
+# security properties #
+nifi.registry.security.keystore=/path/to/keystore.jks
+nifi.registry.security.keystoreType=JKS
+nifi.registry.security.keystorePasswd=6WUpex+VZiN05LXu||thisIsAnIntentionallyMalformedCipherValue
+nifi.registry.security.keystorePasswd.protected=aes/gcm/128
+nifi.registry.security.keyPasswd=6WUpex+VZiN05LXu||joWJMuoSzYniEC7IAoingTimlG7+RGk8I2irl/WTlIuMcg
+nifi.registry.security.keyPasswd.protected=aes/gcm/128
+nifi.registry.security.truststore=
+nifi.registry.security.truststoreType=
+nifi.registry.security.truststorePasswd=
+nifi.registry.security.needClientAuth=
+nifi.registry.security.authorizers.configuration.file=
+nifi.registry.security.authorizer=
+nifi.registry.security.identity.providers.configuration.file=
+nifi.registry.security.identity.provider=
+
+nifi.registry.sensitive.props.additional.keys=

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_protected_unknown.properties
----------------------------------------------------------------------
diff --git 
a/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_protected_unknown.properties
 
b/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_protected_unknown.properties
new file mode 100644
index 0000000..8bd6f4f
--- /dev/null
+++ 
b/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_protected_unknown.properties
@@ -0,0 +1,43 @@
+#
+# 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.
+#
+
+# web properties #
+nifi.registry.web.war.directory=./target/lib
+nifi.registry.web.http.host=
+nifi.registry.web.http.port=8080
+nifi.registry.web.https.host=
+nifi.registry.web.https.port=
+nifi.registry.web.jetty.working.directory=./target/work/jetty
+nifi.registry.web.jetty.threads=1
+
+# 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=unknown
+nifi.registry.security.keyPasswd=ac/BaE35SL/esLiJ||+ULRvRLYdIDA2VqpE0eQXDEMjaLBMG2kbKOdOwBk/hGebDKlVg==
+nifi.registry.security.keyPasswd.protected=unknown
+nifi.registry.security.truststore=
+nifi.registry.security.truststoreType=
+nifi.registry.security.truststorePasswd=
+nifi.registry.security.needClientAuth=
+nifi.registry.security.authorizers.configuration.file=
+nifi.registry.security.authorizer=
+nifi.registry.security.identity.providers.configuration.file=
+nifi.registry.security.identity.provider=
+
+nifi.registry.sensitive.props.additional.keys=nifi.registry.web.http.port, 
nifi.registry.web.http.host

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_unprotected.properties
----------------------------------------------------------------------
diff --git 
a/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_unprotected.properties
 
b/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_unprotected.properties
new file mode 100644
index 0000000..b0f9f40
--- /dev/null
+++ 
b/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_unprotected.properties
@@ -0,0 +1,41 @@
+#
+# 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.
+#
+
+# web properties #
+nifi.registry.web.war.directory=./target/lib
+nifi.registry.web.http.host=
+nifi.registry.web.http.port=8080
+nifi.registry.web.https.host=
+nifi.registry.web.https.port=
+nifi.registry.web.jetty.working.directory=./target/work/jetty
+nifi.registry.web.jetty.threads=1
+
+# 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=
+nifi.registry.security.needClientAuth=
+nifi.registry.security.authorizers.configuration.file=
+nifi.registry.security.authorizer=
+nifi.registry.security.identity.providers.configuration.file=
+nifi.registry.security.identity.provider=
+
+nifi.registry.sensitive.props.additional.keys=nifi.registry.web.http.port, 
nifi.registry.web.http.host

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_unprotected_extra_line.properties
----------------------------------------------------------------------
diff --git 
a/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_unprotected_extra_line.properties
 
b/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_unprotected_extra_line.properties
new file mode 100644
index 0000000..34b80a3
--- /dev/null
+++ 
b/nifi-registry-properties/src/test/resources/conf/nifi-registry.with_sensitive_props_unprotected_extra_line.properties
@@ -0,0 +1,42 @@
+#
+# 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.
+#
+
+# web properties #
+nifi.registry.web.war.directory=./target/lib
+nifi.registry.web.http.host=
+nifi.registry.web.http.port=8080
+nifi.registry.web.https.host=
+nifi.registry.web.https.port=
+nifi.registry.web.jetty.working.directory=./target/work/jetty
+nifi.registry.web.jetty.threads=1
+
+# 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.keyPasswd.protected=
+nifi.registry.security.truststore=
+nifi.registry.security.truststoreType=
+nifi.registry.security.truststorePasswd=
+nifi.registry.security.needClientAuth=
+nifi.registry.security.authorizers.configuration.file=
+nifi.registry.security.authorizer=
+nifi.registry.security.identity.providers.configuration.file=
+nifi.registry.security.identity.provider=
+
+nifi.registry.sensitive.props.additional.keys=nifi.registry.web.http.port, 
nifi.registry.web.http.host

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-resources/src/main/resources/conf/bootstrap.conf
----------------------------------------------------------------------
diff --git a/nifi-registry-resources/src/main/resources/conf/bootstrap.conf 
b/nifi-registry-resources/src/main/resources/conf/bootstrap.conf
index 7abf30c..637eb64 100644
--- a/nifi-registry-resources/src/main/resources/conf/bootstrap.conf
+++ b/nifi-registry-resources/src/main/resources/conf/bootstrap.conf
@@ -43,3 +43,6 @@ java.arg.4=-Djava.net.preferIPv4Stack=true
 # allowRestrictedHeaders is required for Cluster/Node communications to work 
properly
 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=
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-resources/src/main/resources/conf/nifi-registry.properties
----------------------------------------------------------------------
diff --git 
a/nifi-registry-resources/src/main/resources/conf/nifi-registry.properties 
b/nifi-registry-resources/src/main/resources/conf/nifi-registry.properties
index 28577dc..5b6dae2 100644
--- a/nifi-registry-resources/src/main/resources/conf/nifi-registry.properties
+++ b/nifi-registry-resources/src/main/resources/conf/nifi-registry.properties
@@ -36,6 +36,9 @@ 
nifi.registry.security.authorizer=${nifi.registry.security.authorizer}
 
nifi.registry.security.identity.providers.configuration.file=${nifi.registry.security.identity.providers.configuration.file}
 
nifi.registry.security.identity.provider=${nifi.registry.security.identity.provider}
 
+# sensitive property protection properties #
+# nifi.registry.sensitive.props.additional.keys=
+
 # providers properties #
 
nifi.registry.providers.configuration.file=${nifi.registry.providers.configuration.file}
 

Reply via email to