Repository: nifi-registry
Updated Branches:
  refs/heads/master a3f01faf1 -> 64211451c


http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-runtime/src/main/java/org/apache/nifi/registry/NiFiRegistry.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-runtime/src/main/java/org/apache/nifi/registry/NiFiRegistry.java
 
b/nifi-registry-runtime/src/main/java/org/apache/nifi/registry/NiFiRegistry.java
index 5877b8b..43f8ecf 100644
--- 
a/nifi-registry-runtime/src/main/java/org/apache/nifi/registry/NiFiRegistry.java
+++ 
b/nifi-registry-runtime/src/main/java/org/apache/nifi/registry/NiFiRegistry.java
@@ -18,23 +18,19 @@ package org.apache.nifi.registry;
 
 import org.apache.nifi.registry.jetty.JettyServer;
 import org.apache.nifi.registry.properties.NiFiRegistryProperties;
+import org.apache.nifi.registry.properties.NiFiRegistryPropertiesLoader;
+import 
org.apache.nifi.registry.properties.SensitivePropertyProtectionException;
+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;
 import org.slf4j.bridge.SLF4JBridgeHandler;
 
 import java.io.File;
-import java.io.FileReader;
-import java.io.FileWriter;
 import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Random;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -43,15 +39,17 @@ import java.util.concurrent.TimeUnit;
 public class NiFiRegistry {
 
     private static final Logger LOGGER = 
LoggerFactory.getLogger(NiFiRegistry.class);
-    private static final String KEY_FILE_FLAG = "-K";
 
     public static final String BOOTSTRAP_PORT_PROPERTY = 
"nifi.registry.bootstrap.listen.port";
 
+    public static final String REGISTRY_BOOTSTRAP_FILE_LOCATION = 
"conf/bootstrap.conf";
+    public static final String REGISTRY_PROPERTIES_FILE_LOCATION = 
"conf/nifi-registry.properties";
+
     private final JettyServer server;
     private final BootstrapListener bootstrapListener;
     private volatile boolean shutdown = false;
 
-    public NiFiRegistry(final NiFiRegistryProperties properties)
+    public NiFiRegistry(final NiFiRegistryProperties properties, 
CryptoKeyProvider masterKeyProvider)
             throws ClassNotFoundException, IOException, NoSuchMethodException, 
InstantiationException, IllegalAccessException, IllegalArgumentException, 
InvocationTargetException {
 
         Thread.setDefaultUncaughtExceptionHandler(new 
Thread.UncaughtExceptionHandler() {
@@ -104,7 +102,7 @@ public class NiFiRegistry {
         SLF4JBridgeHandler.install();
 
         final long startTime = System.nanoTime();
-        server = new JettyServer(properties);
+        server = new JettyServer(properties, masterKeyProvider);
 
         if (shutdown) {
             LOGGER.info("NiFi Registry has been shutdown via NiFi Registry 
Bootstrap. Will not start Controller");
@@ -146,111 +144,49 @@ public class NiFiRegistry {
     public static void main(String[] args) {
         LOGGER.info("Launching NiFi Registry...");
 
-        final NiFiRegistryProperties properties = new NiFiRegistryProperties();
-        try (final FileReader reader = new 
FileReader("conf/nifi-registry.properties")) {
-            properties.load(reader);
-        } catch (final IOException ioe) {
-            throw new RuntimeException("Unable to load properties: " + ioe, 
ioe);
+        final CryptoKeyProvider masterKeyProvider;
+        final NiFiRegistryProperties properties;
+        try {
+            masterKeyProvider = new 
BootstrapFileCryptoKeyProvider(REGISTRY_BOOTSTRAP_FILE_LOCATION);
+            LOGGER.info("Read property protection key from {}", 
REGISTRY_BOOTSTRAP_FILE_LOCATION);
+            properties = initializeProperties(masterKeyProvider);
+        } catch (final IllegalArgumentException iae) {
+            throw new RuntimeException("Unable to load properties: " + iae, 
iae);
         }
 
         try {
-            new NiFiRegistry(properties);
+            new NiFiRegistry(properties, masterKeyProvider);
         } catch (final Throwable t) {
             LOGGER.error("Failure to launch NiFi Registry due to " + t, t);
         }
     }
 
-    private static String loadFormattedKey(String[] args) {
-        String key = null;
-        List<String> parsedArgs = parseArgs(args);
-        // Check if args contain protection key
-        if (parsedArgs.contains(KEY_FILE_FLAG)) {
-            key = getKeyFromKeyFileAndPrune(parsedArgs);
-            // Format the key (check hex validity and remove spaces)
-            key = formatHexKey(key);
-        }
-
-        if (null == key) {
-            return "";
-        } else if (!isHexKeyValid(key)) {
-            throw new IllegalArgumentException("The key was not provided in 
valid hex format and of the correct length");
-        } else {
-            return key;
-        }
-    }
+    private static NiFiRegistryProperties 
initializeProperties(CryptoKeyProvider masterKeyProvider) {
 
-    private static String getKeyFromKeyFileAndPrune(List<String> parsedArgs) {
-        String key = null;
-        LOGGER.debug("The bootstrap process provided the " + KEY_FILE_FLAG + " 
flag");
-        int i = parsedArgs.indexOf(KEY_FILE_FLAG);
-        if (parsedArgs.size() <= i + 1) {
-            LOGGER.error("The bootstrap process passed the {} flag without a 
filename", KEY_FILE_FLAG);
-            throw new IllegalArgumentException("The bootstrap process provided 
the " + KEY_FILE_FLAG + " flag but no key");
-        }
+        String key = CryptoKeyProvider.EMPTY_KEY;
         try {
-            String passwordfile_path = parsedArgs.get(i + 1);
-            // Slurp in the contents of the file:
-            byte[] encoded = Files.readAllBytes(Paths.get(passwordfile_path));
-            key = new String(encoded, StandardCharsets.UTF_8);
-            if (0 == key.length())
-                throw new IllegalArgumentException("Key in keyfile " + 
passwordfile_path + " yielded an empty key");
-
-            LOGGER.info("Now overwriting file in "+passwordfile_path);
-
-            // Overwrite the contents of the file (to avoid littering file 
system
-            // unlinked with key material):
-            File password_file = new File(passwordfile_path);
-            FileWriter overwriter = new FileWriter(password_file,false);
-
-            // Construe a random pad:
-            Random r = new Random();
-            StringBuffer sb = new StringBuffer();
-            // Note on correctness: this pad is longer, but equally sufficient.
-            while(sb.length() < encoded.length){
-                sb.append(Integer.toHexString(r.nextInt()));
-            }
-            String pad = sb.toString();
-            LOGGER.info("Overwriting key material with pad: "+pad);
-            overwriter.write(pad);
-            overwriter.close();
-
-            LOGGER.info("Removing/unlinking file: "+passwordfile_path);
-            password_file.delete();
-
-        } catch (IOException e) {
-            LOGGER.error("Caught IOException while retrieving the 
"+KEY_FILE_FLAG+"-passed keyfile; aborting: "+e.toString());
-            System.exit(1);
+            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.
         }
 
-        LOGGER.info("Read property protection key from key file provided by 
bootstrap process");
-        return key;
-    }
-
-    private static List<String> parseArgs(String[] args) {
-        List<String> parsedArgs = new ArrayList<>(Arrays.asList(args));
-        for (int i = 0; i < parsedArgs.size(); i++) {
-            if (parsedArgs.get(i).startsWith(KEY_FILE_FLAG + " ")) {
-                String[] split = parsedArgs.get(i).split(" ", 2);
-                parsedArgs.set(i, split[0]);
-                parsedArgs.add(i + 1, split[1]);
-                break;
+        try {
+            try {
+                // Load properties using key. If properties are protected and 
key missing, throw RuntimeException
+                NiFiRegistryProperties properties = 
NiFiRegistryPropertiesLoader.withKey(key).load(REGISTRY_PROPERTIES_FILE_LOCATION);
+                LOGGER.info("Loaded {} properties", properties.size());
+                return properties;
+            } catch (SensitivePropertyProtectionException e) {
+                final String msg = "There was an issue decrypting protected 
properties";
+                LOGGER.error(msg, e);
+                throw new IllegalArgumentException(msg);
             }
+        } catch (IllegalArgumentException e) {
+            final String msg = "The bootstrap process did not provide a valid 
key and there are protected properties present in the properties file";
+            LOGGER.error(msg, e);
+            throw new IllegalArgumentException(msg);
         }
-        return parsedArgs;
     }
 
-    private static String formatHexKey(String input) {
-        if (input == null || input.trim().isEmpty()) {
-            return "";
-        }
-        return input.replaceAll("[^0-9a-fA-F]", "").toLowerCase();
-    }
-
-    private static boolean isHexKeyValid(String key) {
-        if (key == null || key.trim().isEmpty()) {
-            return false;
-        }
-        // Key length is in "nibbles" (i.e. one hex char = 4 bits)
-        return Arrays.asList(128, 196, 256).contains(key.length() * 4) && 
key.matches("^[0-9a-fA-F]*$");
-    }
 }

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-web-api/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/pom.xml b/nifi-registry-web-api/pom.xml
index 9041a2c..6065de4 100644
--- a/nifi-registry-web-api/pom.xml
+++ b/nifi-registry-web-api/pom.xml
@@ -187,8 +187,8 @@
         </dependency>
         <dependency>
             <groupId>org.apache.nifi.registry</groupId>
-                <artifactId>nifi-registry-security-utils</artifactId>
-                <version>0.0.1-SNAPSHOT</version>
+            <artifactId>nifi-registry-security-utils</artifactId>
+            <version>0.0.1-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>org.apache.commons</groupId>

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/NiFiRegistryApiApplication.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/NiFiRegistryApiApplication.java
 
b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/NiFiRegistryApiApplication.java
index fa96e18..29c6480 100644
--- 
a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/NiFiRegistryApiApplication.java
+++ 
b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/NiFiRegistryApiApplication.java
@@ -35,6 +35,7 @@ import 
org.springframework.boot.web.servlet.support.SpringBootServletInitializer
 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";
 
     public static void main(String[] args) {
         SpringApplication.run(NiFiRegistryApiApplication.class, args);

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiRegistryMasterKeyProviderFactory.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiRegistryMasterKeyProviderFactory.java
 
b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiRegistryMasterKeyProviderFactory.java
new file mode 100644
index 0000000..8026cca
--- /dev/null
+++ 
b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiRegistryMasterKeyProviderFactory.java
@@ -0,0 +1,67 @@
+/*
+ * 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 javax.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;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureLdapIT.java
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureLdapIT.java
 
b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureLdapIT.java
index 556e10b..543ea87 100644
--- 
a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureLdapIT.java
+++ 
b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureLdapIT.java
@@ -25,9 +25,13 @@ import org.apache.nifi.registry.authorization.Permissions;
 import org.apache.nifi.registry.authorization.Tenant;
 import org.apache.nifi.registry.bucket.Bucket;
 import org.apache.nifi.registry.extension.ExtensionManager;
+import org.apache.nifi.registry.properties.AESSensitivePropertyProvider;
 import org.apache.nifi.registry.properties.NiFiRegistryProperties;
+import org.apache.nifi.registry.properties.SensitivePropertyProvider;
 import org.apache.nifi.registry.security.authorization.Authorizer;
 import org.apache.nifi.registry.security.authorization.AuthorizerFactory;
+import org.apache.nifi.registry.security.crypto.BootstrapFileCryptoKeyProvider;
+import org.apache.nifi.registry.security.crypto.CryptoKeyProvider;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -90,13 +94,23 @@ public class SecureLdapIT extends IntegrationTestBase {
         @Primary
         @Bean
         @DependsOn({"directoryServer"}) // Can't load LdapUserGroupProvider 
until the embedded LDAP server, which creates the "directoryServer" bean, is 
running
-        public static Authorizer getAuthorizer(@Autowired 
NiFiRegistryProperties properties, ExtensionManager extensionManager) {
+        public static Authorizer getAuthorizer(@Autowired 
NiFiRegistryProperties properties, ExtensionManager extensionManager) throws 
Exception {
             if (authorizerFactory == null) {
-                authorizerFactory = new AuthorizerFactory(properties, 
extensionManager);
+                authorizerFactory = new AuthorizerFactory(properties, 
extensionManager, sensitivePropertyProvider());
             }
             return authorizerFactory.getAuthorizer();
         }
 
+        @Primary
+        @Bean
+        public static SensitivePropertyProvider sensitivePropertyProvider() 
throws Exception {
+            return new 
AESSensitivePropertyProvider(getNiFiRegistryMasterKeyProvider().getKey());
+        }
+
+        private static CryptoKeyProvider getNiFiRegistryMasterKeyProvider() {
+            return new 
BootstrapFileCryptoKeyProvider("src/test/resources/conf/secure-ldap/bootstrap.conf");
+        }
+
     }
 
     private String adminAuthToken;

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-web-api/src/test/resources/conf/secure-ldap/authorizers.protected.xml
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-api/src/test/resources/conf/secure-ldap/authorizers.protected.xml
 
b/nifi-registry-web-api/src/test/resources/conf/secure-ldap/authorizers.protected.xml
new file mode 100644
index 0000000..44007bd
--- /dev/null
+++ 
b/nifi-registry-web-api/src/test/resources/conf/secure-ldap/authorizers.protected.xml
@@ -0,0 +1,221 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+  ~ 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.
+  -->
+<!--
+    This file lists the userGroupProviders, accessPolicyProviders, and 
authorizers to use when running securely. In order
+    to use a specific authorizer it must be configured here and its identifier 
must be specified in the nifi-registry.properties file.
+    If the authorizer is a managedAuthorizer, it may need to be configured 
with an accessPolicyProvider and an userGroupProvider.
+    This file allows for configuration of them, but they must be configured in 
order:
+
+    ...
+    all userGroupProviders
+    all accessPolicyProviders
+    all Authorizers
+    ...
+-->
+<authorizers>
+
+    <!--
+        The LdapUserGroupProvider will retrieve users and groups from an LDAP 
server. The users and groups
+        are not configurable.
+
+        'Authentication Strategy' - How the connection to the LDAP server is 
authenticated. Possible
+            values are ANONYMOUS, SIMPLE, LDAPS, or START_TLS.
+
+        'Manager DN' - The DN of the manager that is used to bind to the LDAP 
server to search for users.
+        'Manager Password' - The password of the manager that is used to bind 
to the LDAP server to
+            search for users.
+
+        'TLS - Keystore' - Path to the Keystore that is used when connecting 
to LDAP using LDAPS or START_TLS.
+        'TLS - Keystore Password' - Password for the Keystore that is used 
when connecting to LDAP
+            using LDAPS or START_TLS.
+        'TLS - Keystore Type' - Type of the Keystore that is used when 
connecting to LDAP using
+            LDAPS or START_TLS (i.e. JKS or PKCS12).
+        'TLS - Truststore' - Path to the Truststore that is used when 
connecting to LDAP using LDAPS or START_TLS.
+        'TLS - Truststore Password' - Password for the Truststore that is used 
when connecting to
+            LDAP using LDAPS or START_TLS.
+        'TLS - Truststore Type' - Type of the Truststore that is used when 
connecting to LDAP using
+            LDAPS or START_TLS (i.e. JKS or PKCS12).
+        'TLS - Client Auth' - Client authentication policy when connecting to 
LDAP using LDAPS or START_TLS.
+            Possible values are REQUIRED, WANT, NONE.
+        'TLS - Protocol' - Protocol to use when connecting to LDAP using LDAPS 
or START_TLS. (i.e. TLS,
+            TLSv1.1, TLSv1.2, etc).
+        'TLS - Shutdown Gracefully' - Specifies whether the TLS should be shut 
down gracefully
+            before the target context is closed. Defaults to false.
+
+        'Referral Strategy' - Strategy for handling referrals. Possible values 
are FOLLOW, IGNORE, THROW.
+        'Connect Timeout' - Duration of connect timeout. (i.e. 10 secs).
+        'Read Timeout' - Duration of read timeout. (i.e. 10 secs).
+
+        'Url' - Space-separated list of URLs of the LDAP servers (i.e. 
ldap://<hostname>:<port>).
+        'Page Size' - Sets the page size when retrieving users and groups. If 
not specified, no paging is performed.
+        'Sync Interval' - Duration of time between syncing users and groups. 
(i.e. 30 mins).
+
+        'User Search Base' - Base DN for searching for users (i.e. 
ou=users,o=nifi). Required to search users.
+        'User Object Class' - Object class for identifying users (i.e. 
person). Required if searching users.
+        'User Search Scope' - Search scope for searching users (ONE_LEVEL, 
OBJECT, or SUBTREE). Required if searching users.
+        'User Search Filter' - Filter for searching for users against the 
'User Search Base' (i.e. (memberof=cn=team1,ou=groups,o=nifi) ). Optional.
+        'User Identity Attribute' - Attribute to use to extract user identity 
(i.e. cn). Optional. If not set, the entire DN is used.
+        'User Group Name Attribute' - Attribute to use to define group 
membership (i.e. memberof). Optional. If not set
+            group membership will not be calculated through the users. Will 
rely on group membership being defined
+            through 'Group Member Attribute' if set.
+
+        'Group Search Base' - Base DN for searching for groups (i.e. 
ou=groups,o=nifi). Required to search groups.
+        'Group Object Class' - Object class for identifying groups (i.e. 
groupOfNames). Required if searching groups.
+        'Group Search Scope' - Search scope for searching groups (ONE_LEVEL, 
OBJECT, or SUBTREE). Required if searching groups.
+        'Group Search Filter' - Filter for searching for groups against the 
'Group Search Base'. Optional.
+        'Group Name Attribute' - Attribute to use to extract group name (i.e. 
cn). Optional. If not set, the entire DN is used.
+        'Group Member Attribute' - Attribute to use to define group membership 
(i.e. member). Optional. If not set
+            group membership will not be calculated through the groups. Will 
rely on group member being defined
+            through 'User Group Name Attribute' if set.
+
+        NOTE: Any identity mapping rules specified in nifi-registry.properties 
will also be applied to the user identities.
+            Group names are not mapped.
+    -->
+    <userGroupProvider>
+        <identifier>ldap-user-group-provider</identifier>
+        
<class>org.apache.nifi.registry.security.ldap.tenants.LdapUserGroupProvider</class>
+        <property name="Authentication Strategy">SIMPLE</property>
+
+        <property name="Manager 
DN">cn=read-only-admin,dc=example,dc=com</property>
+        <!-- password='password' encrypted with algo='aes/gcm/128' and 
key='0123456789ABCDEFFEDCBA9876543210' -->
+        <property name="Manager Password" 
encryption="aes/gcm/128">oVU8w3uH7yZlKscG||Hu4ZtRgZWKISn3DyGuB50rKL1qGceWZp</property>
+
+        <!--
+        <property name="TLS - Keystore"></property>
+        <property name="TLS - Keystore Password"></property>
+        <property name="TLS - Keystore Type"></property>
+        <property name="TLS - Truststore"></property>
+        <property name="TLS - Truststore Password"></property>
+        <property name="TLS - Truststore Type"></property>
+        <property name="TLS - Client Auth"></property>
+        <property name="TLS - Protocol"></property>
+        <property name="TLS - Shutdown Gracefully"></property>
+        -->
+
+        <property name="Referral Strategy">FOLLOW</property>
+        <property name="Connect Timeout">10 secs</property>
+        <property name="Read Timeout">10 secs</property>
+
+        <property name="Url">ldap://localhost:8389</property>
+        <!--<property name="Page Size"></property>-->
+        <property name="Sync Interval">30 mins</property>
+
+        <property name="User Search Base">dc=example,dc=com</property>
+        <property name="User Object Class">person</property>
+        <property name="User Search Scope">ONE_LEVEL</property>
+        <property name="User Search Filter">(uid=*)</property>
+        <property name="User Identity Attribute">uid</property>
+        <!--<property name="User Group Name Attribute"></property>-->
+
+        <property name="Group Search Base">dc=example,dc=com</property>
+        <property name="Group Object Class">groupOfUniqueNames</property>
+        <property name="Group Search Scope">ONE_LEVEL</property>
+        <property name="Group Search Filter">(ou=*)</property>
+        <property name="Group Name Attribute">ou</property>
+        <property name="Group Member Attribute">uniqueMember</property>
+    </userGroupProvider>
+
+    <!--
+        The CompositeUserGroupProvider will provide support for retrieving 
users and groups from multiple sources.
+
+        - User Group Provider [unique key] - The identifier of user group 
providers to load from. The name of
+            each property must be unique, for example: "User Group Provider 
A", "User Group Provider B",
+            "User Group Provider C" or "User Group Provider 1", "User Group 
Provider 2", "User Group Provider 3"
+
+            NOTE: Any identity mapping rules specified in 
nifi-registry.properties are not applied in this implementation. This behavior
+            would need to be applied by the base implementation.
+    -->
+    <!-- To enable the composite-user-group-provider remove 2 lines. This is 1 
of 2.
+    <userGroupProvider>
+        <identifier>composite-user-group-provider</identifier>
+        <class>org.apache.nifi.authorization.CompositeUserGroupProvider</class>
+        <property name="User Group Provider 1"></property>
+    </userGroupProvider>
+    To enable the composite-user-group-provider remove 2 lines. This is 2 of 
2. -->
+
+    <!--
+        The CompositeConfigurableUserGroupProvider will provide support for 
retrieving users and groups from multiple sources.
+        Additionally, a single configurable user group provider is required. 
Users from the configurable user group provider
+        are configurable, however users loaded from one of the User Group 
Provider [unique key] will not be.
+
+        - Configurable User Group Provider - A configurable user group 
provider.
+
+        - User Group Provider [unique key] - The identifier of user group 
providers to load from. The name of
+            each property must be unique, for example: "User Group Provider 
A", "User Group Provider B",
+            "User Group Provider C" or "User Group Provider 1", "User Group 
Provider 2", "User Group Provider 3"
+
+            NOTE: Any identity mapping rules specified in 
nifi-registry.properties are not applied in this implementation. This behavior
+            would need to be applied by the base implementation.
+    -->
+    <!-- To enable the composite-configurable-user-group-provider remove 2 
lines. This is 1 of 2.
+    <userGroupProvider>
+        <identifier>composite-configurable-user-group-provider</identifier>
+        
<class>org.apache.nifi.authorization.CompositeConfigurableUserGroupProvider</class>
+        <property name="Configurable User Group 
Provider">file-user-group-provider</property>
+        <property name="User Group Provider 1"></property>
+    </userGroupProvider>
+    To enable the composite-configurable-user-group-provider remove 2 lines. 
This is 2 of 2. -->
+
+    <!--
+        The FileAccessPolicyProvider will provide support for managing access 
policies which is backed by a file
+        on the local file system.
+
+        - User Group Provider - The identifier for an User Group Provider 
defined above that will be used to access
+            users and groups for use in the managed access policies.
+
+        - Authorizations File - The file where the FileAccessPolicyProvider 
will store policies.
+
+        - Initial Admin Identity - The identity of an initial admin user that 
will be granted access to the UI and
+            given the ability to create additional users, groups, and 
policies. The value of this property could be
+            a DN when using certificates or LDAP. This property will only be 
used when there
+            are no other policies defined.
+
+            NOTE: Any identity mapping rules specified in 
nifi-registry.properties will also be applied to the initial admin identity,
+            so the value should be the unmapped identity. This identity must 
be found in the configured User Group Provider.
+
+        - NiFi Identity [unique key] - The identity of a NiFi node that will 
have access to this NiFi Registry and will be able
+            to act as a proxy on behalf of a NiFi Registry end user. A 
property should be created for the identity of every NiFi
+            node that needs to access this NiFi Registry.
+
+            NOTE: Any identity mapping rules specified in 
nifi-registry.properties will also be applied to the nifi identities,
+            so the values should be the unmapped identities (i.e. full DN from 
a certificate). This identity must be found
+            in the configured User Group Provider.
+    -->
+    <accessPolicyProvider>
+        <identifier>file-access-policy-provider</identifier>
+        
<class>org.apache.nifi.registry.security.authorization.file.FileAccessPolicyProvider</class>
+        <property name="User Group 
Provider">ldap-user-group-provider</property>
+        <property name="Authorizations 
File">./target/test-classes/conf/secure-ldap/authorizations.xml</property>
+        <property name="Initial Admin Identity">nifiadmin</property>
+    </accessPolicyProvider>
+
+    <!--
+        The StandardManagedAuthorizer. This authorizer implementation must be 
configured with the
+        Access Policy Provider which it will use to access and manage users, 
groups, and policies.
+        These users, groups, and policies will be used to make all access 
decisions during authorization
+        requests.
+
+        - Access Policy Provider - The identifier for an Access Policy 
Provider defined above.
+    -->
+    <authorizer>
+        <identifier>managed-authorizer</identifier>
+        
<class>org.apache.nifi.registry.security.authorization.StandardManagedAuthorizer</class>
+        <property name="Access Policy 
Provider">file-access-policy-provider</property>
+    </authorizer>
+
+</authorizers>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-web-api/src/test/resources/conf/secure-ldap/bootstrap.conf
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-api/src/test/resources/conf/secure-ldap/bootstrap.conf 
b/nifi-registry-web-api/src/test/resources/conf/secure-ldap/bootstrap.conf
new file mode 100644
index 0000000..4bd28ba
--- /dev/null
+++ b/nifi-registry-web-api/src/test/resources/conf/secure-ldap/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=0123456789ABCDEFFEDCBA9876543210

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-web-api/src/test/resources/conf/secure-ldap/identity-providers.protected.xml
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-api/src/test/resources/conf/secure-ldap/identity-providers.protected.xml
 
b/nifi-registry-web-api/src/test/resources/conf/secure-ldap/identity-providers.protected.xml
new file mode 100644
index 0000000..51336e2
--- /dev/null
+++ 
b/nifi-registry-web-api/src/test/resources/conf/secure-ldap/identity-providers.protected.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+  ~ 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.
+  -->
+<!--
+    This file lists the login identity providers to use when running securely. 
In order
+    to use a specific provider it must be configured here and it's identifier
+    must be specified in the nifi-registry.properties file.
+-->
+<identityProviders>
+    <!--
+        Identity Provider for users logging in with username/password against 
an LDAP server.
+        
+        'Authentication Strategy' - How the connection to the LDAP server is 
authenticated. Possible
+            values are ANONYMOUS, SIMPLE, LDAPS, or START_TLS.
+        
+        'Manager DN' - The DN of the manager that is used to bind to the LDAP 
server to search for users.
+        'Manager Password' - The password of the manager that is used to bind 
to the LDAP server to
+            search for users.
+            
+        'TLS - Keystore' - Path to the Keystore that is used when connecting 
to LDAP using LDAPS or START_TLS.
+        'TLS - Keystore Password' - Password for the Keystore that is used 
when connecting to LDAP
+            using LDAPS or START_TLS.
+        'TLS - Keystore Type' - Type of the Keystore that is used when 
connecting to LDAP using
+            LDAPS or START_TLS (i.e. JKS or PKCS12).
+        'TLS - Truststore' - Path to the Truststore that is used when 
connecting to LDAP using LDAPS or START_TLS.
+        'TLS - Truststore Password' - Password for the Truststore that is used 
when connecting to
+            LDAP using LDAPS or START_TLS.
+        'TLS - Truststore Type' - Type of the Truststore that is used when 
connecting to LDAP using
+            LDAPS or START_TLS (i.e. JKS or PKCS12).
+        'TLS - Client Auth' - Client authentication policy when connecting to 
LDAP using LDAPS or START_TLS.
+            Possible values are REQUIRED, WANT, NONE.
+        'TLS - Protocol' - Protocol to use when connecting to LDAP using LDAPS 
or START_TLS. (i.e. TLS,
+            TLSv1.1, TLSv1.2, etc).
+        'TLS - Shutdown Gracefully' - Specifies whether the TLS should be shut 
down gracefully 
+            before the target context is closed. Defaults to false.
+            
+        'Referral Strategy' - Strategy for handling referrals. Possible values 
are FOLLOW, IGNORE, THROW.
+        'Connect Timeout' - Duration of connect timeout. (i.e. 10 secs).
+        'Read Timeout' - Duration of read timeout. (i.e. 10 secs).
+       
+        'Url' - Space-separated list of URLs of the LDAP servers (i.e. 
ldap://<hostname>:<port>).
+        'User Search Base' - Base DN for searching for users (i.e. 
CN=Users,DC=example,DC=com).
+        'User Search Filter' - Filter for searching for users against the 
'User Search Base'.
+            (i.e. sAMAccountName={0}). The user specified name is inserted 
into '{0}'.
+
+        'Identity Strategy' - Strategy to identify users. Possible values are 
USE_DN and USE_USERNAME.
+            The default functionality if this property is missing is USE_DN in 
order to retain
+            backward compatibility. USE_DN will use the full DN of the user 
entry if possible.
+            USE_USERNAME will use the username the user logged in with.
+        'Authentication Expiration' - The duration of how long the user 
authentication is valid
+            for. If the user never logs out, they will be required to log back 
in following
+            this duration.
+    -->
+    <provider>
+        <identifier>ldap-identity-provider</identifier>
+        
<class>org.apache.nifi.registry.security.ldap.LdapIdentityProvider</class>
+        <property name="Authentication Strategy">SIMPLE</property>
+
+        <property name="Manager 
DN">cn=read-only-admin,dc=example,dc=com</property>
+        <!-- password='password' encrypted with algo='aes/gcm/128' and 
key='0123456789ABCDEFFEDCBA9876543210' -->
+        <property name="Manager Password" 
encryption="aes/gcm/128">p43I3jRcK+wPhR3c||oaqMg3YGo2WblTxBJSgI8H9fLMBwQiaM</property>
+        
+        <property name="Referral Strategy">FOLLOW</property>
+        <property name="Connect Timeout">10 secs</property>
+        <property name="Read Timeout">10 secs</property>
+
+        <property name="Url">ldap://localhost:8389</property>
+        <property name="User Search Base">dc=example,dc=com</property>
+        <property name="User Search Filter">(uid={0})</property>
+
+        <property name="Identity Strategy">USE_USERNAME</property>
+        <property name="Authentication Expiration">12 hours</property>
+    </provider>
+
+</identityProviders>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/64211451/nifi-registry-web-api/src/test/resources/conf/secure-ldap/nifi-registry.properties
----------------------------------------------------------------------
diff --git 
a/nifi-registry-web-api/src/test/resources/conf/secure-ldap/nifi-registry.properties
 
b/nifi-registry-web-api/src/test/resources/conf/secure-ldap/nifi-registry.properties
index 40b2916..1b46ac2 100644
--- 
a/nifi-registry-web-api/src/test/resources/conf/secure-ldap/nifi-registry.properties
+++ 
b/nifi-registry-web-api/src/test/resources/conf/secure-ldap/nifi-registry.properties
@@ -23,9 +23,9 @@ nifi.registry.web.https.port=0
 #
 # ** Server KeyStore and TrustStore configuration set in Spring profile 
properties for embedded Jetty **
 #
-nifi.registry.security.authorizers.configuration.file=./target/test-classes/conf/secure-ldap/authorizers.xml
+nifi.registry.security.authorizers.configuration.file=./target/test-classes/conf/secure-ldap/authorizers.protected.xml
 nifi.registry.security.authorizer=managed-authorizer
-nifi.registry.security.identity.providers.configuration.file=./target/test-classes/conf/secure-ldap/identity-providers.xml
+nifi.registry.security.identity.providers.configuration.file=./target/test-classes/conf/secure-ldap/identity-providers.protected.xml
 nifi.registry.security.identity.provider=ldap-identity-provider
 
 # providers properties #

Reply via email to