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 #
