This is an automated email from the ASF dual-hosted git repository. kdoran pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nifi-registry.git
The following commit(s) were added to refs/heads/master by this push: new ecce44e NIFIREG-217 Adding identity and group transforms ecce44e is described below commit ecce44e587dc9e2b2fa2cbaf4b13702623577fa3 Author: Bryan Bende <bbe...@apache.org> AuthorDate: Thu Feb 7 14:32:08 2019 -0500 NIFIREG-217 Adding identity and group transforms This closses #154. Signed-off-by: Kevin Doran <kdo...@apache.org> --- .../ldap/tenants/LdapUserGroupProvider.java | 4 +- .../ldap/tenants/LdapUserGroupProviderTest.java | 43 +++++++++++ .../properties/NiFiRegistryProperties.java | 4 ++ .../registry/properties/util/IdentityMapping.java | 17 +++++ .../properties/util/IdentityMappingUtil.java | 83 +++++++++++++++++++--- .../main/resources/conf/nifi-registry.properties | 12 ++++ 6 files changed, 153 insertions(+), 10 deletions(-) diff --git a/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/ldap/tenants/LdapUserGroupProvider.java b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/ldap/tenants/LdapUserGroupProvider.java index 984c890..5a892be 100644 --- a/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/ldap/tenants/LdapUserGroupProvider.java +++ b/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/ldap/tenants/LdapUserGroupProvider.java @@ -117,6 +117,7 @@ public class LdapUserGroupProvider implements UserGroupProvider { public static final String PROP_SYNC_INTERVAL = "Sync Interval"; private List<IdentityMapping> identityMappings; + private List<IdentityMapping> groupMappings; private NiFiRegistryProperties properties; private ScheduledExecutorService ldapSync; @@ -350,6 +351,7 @@ public class LdapUserGroupProvider implements UserGroupProvider { // extract the identity mappings from nifi-registry.properties if any are provided identityMappings = Collections.unmodifiableList(IdentityMappingUtil.getIdentityMappings(properties)); + groupMappings = Collections.unmodifiableList(IdentityMappingUtil.getGroupMappings(properties)); // set the base environment is necessary if (!baseEnvironment.isEmpty()) { @@ -704,7 +706,7 @@ public class LdapUserGroupProvider implements UserGroupProvider { } } - return name; + return IdentityMappingUtil.mapIdentity(name, groupMappings); } private String getReferencedGroupValue(final DirContextOperations ctx) { diff --git a/nifi-registry-core/nifi-registry-framework/src/test/java/org/apache/nifi/registry/security/ldap/tenants/LdapUserGroupProviderTest.java b/nifi-registry-core/nifi-registry-framework/src/test/java/org/apache/nifi/registry/security/ldap/tenants/LdapUserGroupProviderTest.java index 9a408b2..94d2031 100644 --- a/nifi-registry-core/nifi-registry-framework/src/test/java/org/apache/nifi/registry/security/ldap/tenants/LdapUserGroupProviderTest.java +++ b/nifi-registry-core/nifi-registry-framework/src/test/java/org/apache/nifi/registry/security/ldap/tenants/LdapUserGroupProviderTest.java @@ -507,6 +507,49 @@ public class LdapUserGroupProviderTest extends AbstractLdapTestUnit { assertNotNull(ldapUserGroupProvider.getUserByIdentity("User 1,ou=users")); } + @Test + public void testUserIdentityMappingWithTransforms() throws Exception { + final Properties props = new Properties(); + props.setProperty("nifi.registry.security.identity.mapping.pattern.dn1", "^cn=(.*?),ou=(.*?),o=(.*?)$"); + props.setProperty("nifi.registry.security.identity.mapping.value.dn1", "$1"); + props.setProperty("nifi.registry.security.identity.mapping.transform.dn1", "UPPER"); + + final NiFiRegistryProperties properties = getNiFiProperties(props); + ldapUserGroupProvider.setNiFiProperties(properties); + + final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(USER_SEARCH_BASE, null); + when(configurationContext.getProperty(PROP_USER_SEARCH_FILTER)).thenReturn(new StandardPropertyValue("(uid=user1)")); + ldapUserGroupProvider.onConfigured(configurationContext); + + assertEquals(1, ldapUserGroupProvider.getUsers().size()); + assertNotNull(ldapUserGroupProvider.getUserByIdentity("USER 1")); + } + + @Test + public void testUserIdentityAndGroupMappingWithTransforms() throws Exception { + final Properties props = new Properties(); + props.setProperty("nifi.registry.security.identity.mapping.pattern.dn1", "^cn=(.*?),ou=(.*?),o=(.*?)$"); + props.setProperty("nifi.registry.security.identity.mapping.value.dn1", "$1"); + props.setProperty("nifi.registry.security.identity.mapping.transform.dn1", "UPPER"); + props.setProperty("nifi.registry.security.group.mapping.pattern.dn1", "^cn=(.*?),ou=(.*?),o=(.*?)$"); + props.setProperty("nifi.registry.security.group.mapping.value.dn1", "$1"); + props.setProperty("nifi.registry.security.group.mapping.transform.dn1", "UPPER"); + + final NiFiRegistryProperties properties = getNiFiProperties(props); + ldapUserGroupProvider.setNiFiProperties(properties); + + final AuthorizerConfigurationContext configurationContext = getBaseConfiguration(USER_SEARCH_BASE, GROUP_SEARCH_BASE); + when(configurationContext.getProperty(PROP_USER_SEARCH_FILTER)).thenReturn(new StandardPropertyValue("(uid=user1)")); + when(configurationContext.getProperty(PROP_GROUP_SEARCH_FILTER)).thenReturn(new StandardPropertyValue("(cn=admins)")); + ldapUserGroupProvider.onConfigured(configurationContext); + + assertEquals(1, ldapUserGroupProvider.getUsers().size()); + assertNotNull(ldapUserGroupProvider.getUserByIdentity("USER 1")); + + assertEquals(1, ldapUserGroupProvider.getGroups().size()); + assertEquals("ADMINS", ldapUserGroupProvider.getGroups().iterator().next().getName()); + } + @Test(expected = SecurityProviderCreationException.class) public void testReferencedGroupAttributeWithoutGroupSearchBase() throws Exception { final AuthorizerConfigurationContext configurationContext = getBaseConfiguration("ou=users-2,o=nifi", null); diff --git a/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/NiFiRegistryProperties.java b/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/NiFiRegistryProperties.java index 89a8e60..aa4d19e 100644 --- a/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/NiFiRegistryProperties.java +++ b/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/NiFiRegistryProperties.java @@ -53,6 +53,10 @@ public class NiFiRegistryProperties extends Properties { public static final String SECURITY_IDENTITY_PROVIDER = "nifi.registry.security.identity.provider"; public static final String SECURITY_IDENTITY_MAPPING_PATTERN_PREFIX = "nifi.registry.security.identity.mapping.pattern."; public static final String SECURITY_IDENTITY_MAPPING_VALUE_PREFIX = "nifi.registry.security.identity.mapping.value."; + public static final String SECURITY_IDENTITY_MAPPING_TRANSFORM_PREFIX = "nifi.registry.security.identity.mapping.transform."; + public static final String SECURITY_GROUP_MAPPING_PATTERN_PREFIX = "nifi.registry.security.group.mapping.pattern."; + public static final String SECURITY_GROUP_MAPPING_VALUE_PREFIX = "nifi.registry.security.group.mapping.value."; + public static final String SECURITY_GROUP_MAPPING_TRANSFORM_PREFIX = "nifi.registry.security.group.mapping.transform."; public static final String EXTENSION_DIR_PREFIX = "nifi.registry.extension.dir."; diff --git a/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/util/IdentityMapping.java b/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/util/IdentityMapping.java index df3bbe6..cedec8b 100644 --- a/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/util/IdentityMapping.java +++ b/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/util/IdentityMapping.java @@ -18,19 +18,33 @@ package org.apache.nifi.registry.properties.util; import java.util.regex.Pattern; +import static org.apache.nifi.registry.properties.util.IdentityMapping.Transform.NONE; + /** * Holder to pass around the key, pattern, and replacement from an identity mapping in NiFiProperties. */ public class IdentityMapping { + public enum Transform { + NONE, + UPPER, + LOWER + } + private final String key; private final Pattern pattern; private final String replacementValue; + private final Transform transform; public IdentityMapping(String key, Pattern pattern, String replacementValue) { + this(key, pattern, replacementValue, NONE); + } + + public IdentityMapping(String key, Pattern pattern, String replacementValue, Transform transform) { this.key = key; this.pattern = pattern; this.replacementValue = replacementValue; + this.transform = transform; } public String getKey() { @@ -45,4 +59,7 @@ public class IdentityMapping { return replacementValue; } + public Transform getTransform() { + return transform; + } } diff --git a/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/util/IdentityMappingUtil.java b/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/util/IdentityMappingUtil.java index 3c9208c..d7c2709 100644 --- a/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/util/IdentityMappingUtil.java +++ b/nifi-registry-core/nifi-registry-properties/src/main/java/org/apache/nifi/registry/properties/util/IdentityMappingUtil.java @@ -17,6 +17,7 @@ package org.apache.nifi.registry.properties.util; import org.apache.commons.lang3.StringUtils; +import org.apache.nifi.registry.properties.util.IdentityMapping.Transform; import org.apache.nifi.registry.properties.NiFiRegistryProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,9 +26,17 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static org.apache.nifi.registry.properties.NiFiRegistryProperties.SECURITY_GROUP_MAPPING_PATTERN_PREFIX; +import static org.apache.nifi.registry.properties.NiFiRegistryProperties.SECURITY_GROUP_MAPPING_TRANSFORM_PREFIX; +import static org.apache.nifi.registry.properties.NiFiRegistryProperties.SECURITY_GROUP_MAPPING_VALUE_PREFIX; +import static org.apache.nifi.registry.properties.NiFiRegistryProperties.SECURITY_IDENTITY_MAPPING_PATTERN_PREFIX; +import static org.apache.nifi.registry.properties.NiFiRegistryProperties.SECURITY_IDENTITY_MAPPING_TRANSFORM_PREFIX; +import static org.apache.nifi.registry.properties.NiFiRegistryProperties.SECURITY_IDENTITY_MAPPING_VALUE_PREFIX; + public class IdentityMappingUtil { private static final Logger LOGGER = LoggerFactory.getLogger(IdentityMappingUtil.class); @@ -40,33 +49,81 @@ public class IdentityMappingUtil { * @return a list of identity mappings */ public static List<IdentityMapping> getIdentityMappings(final NiFiRegistryProperties properties) { + return getMappings( + properties, + SECURITY_IDENTITY_MAPPING_PATTERN_PREFIX, + SECURITY_IDENTITY_MAPPING_VALUE_PREFIX, + SECURITY_IDENTITY_MAPPING_TRANSFORM_PREFIX, + () -> "Identity"); + } + + /** + * Buils the group mappings from NiFiProperties. + * + * @param properties the NiFiProperties instance + * @return a list of group mappings + */ + public static List<IdentityMapping> getGroupMappings(final NiFiRegistryProperties properties) { + return getMappings( + properties, + SECURITY_GROUP_MAPPING_PATTERN_PREFIX, + SECURITY_GROUP_MAPPING_VALUE_PREFIX, + SECURITY_GROUP_MAPPING_TRANSFORM_PREFIX, + () -> "Group"); + } + + /** + * Builds the identity mappings from NiFiRegistryProperties. + * + * @param properties the NiFiRegistryProperties instance + * @return a list of identity mappings + */ + private static List<IdentityMapping> getMappings(final NiFiRegistryProperties properties, final String patternPrefix, + final String valuePrefix, final String transformPrefix, final Supplier<String> getSubject) { final List<IdentityMapping> mappings = new ArrayList<>(); // go through each property for (String propertyName : properties.getPropertyKeys()) { - if (StringUtils.startsWith(propertyName, NiFiRegistryProperties.SECURITY_IDENTITY_MAPPING_PATTERN_PREFIX)) { - final String key = StringUtils.substringAfter(propertyName, NiFiRegistryProperties.SECURITY_IDENTITY_MAPPING_PATTERN_PREFIX); + if (StringUtils.startsWith(propertyName, patternPrefix)) { + final String key = StringUtils.substringAfter(propertyName, patternPrefix); final String identityPattern = properties.getProperty(propertyName); if (StringUtils.isBlank(identityPattern)) { - LOGGER.warn("Identity Mapping property {} was found, but was empty", new Object[]{propertyName}); + LOGGER.warn("{} Mapping property {} was found, but was empty", new Object[] {getSubject.get(), propertyName}); continue; } - final String identityValueProperty = NiFiRegistryProperties.SECURITY_IDENTITY_MAPPING_VALUE_PREFIX + key; + final String identityValueProperty = valuePrefix + key; final String identityValue = properties.getProperty(identityValueProperty); if (StringUtils.isBlank(identityValue)) { - LOGGER.warn("Identity Mapping property {} was found, but corresponding value {} was not found", + LOGGER.warn("{} Mapping property {} was found, but corresponding value {} was not found", new Object[]{propertyName, identityValueProperty}); continue; } - final IdentityMapping identityMapping = new IdentityMapping(key, Pattern.compile(identityPattern), identityValue); + final String identityTransformProperty = transformPrefix + key; + String rawIdentityTransform = properties.getProperty(identityTransformProperty); + + if (StringUtils.isBlank(rawIdentityTransform)) { + LOGGER.debug("{} Mapping property {} was found, but no transform was present. Using NONE.", new Object[] {getSubject.get(), propertyName}); + rawIdentityTransform = IdentityMapping.Transform.NONE.name(); + } + + final Transform identityTransform; + try { + identityTransform = Transform.valueOf(rawIdentityTransform); + } catch (final IllegalArgumentException iae) { + LOGGER.warn("{} Mapping property {} was found, but corresponding transform {} was not valid. Allowed values {}", + new Object[] {getSubject.get(), propertyName, rawIdentityTransform, StringUtils.join(Transform.values(), ", ")}); + continue; + } + + final IdentityMapping identityMapping = new IdentityMapping(key, Pattern.compile(identityPattern), identityValue, identityTransform); mappings.add(identityMapping); - LOGGER.debug("Found Identity Mapping with key = {}, pattern = {}, value = {}", - new Object[] {key, identityPattern, identityValue}); + LOGGER.debug("Found {} Mapping with key = {}, pattern = {}, value = {}, transform = {}", + new Object[] {getSubject.get(), key, identityPattern, identityValue, rawIdentityTransform}); } } @@ -95,7 +152,15 @@ public class IdentityMappingUtil { if (m.matches()) { final String pattern = mapping.getPattern().pattern(); final String replacementValue = escapeLiteralBackReferences(mapping.getReplacementValue(), m.groupCount()); - return identity.replaceAll(pattern, replacementValue); + final String replacement = identity.replaceAll(pattern, replacementValue); + + if (Transform.UPPER.equals(mapping.getTransform())) { + return replacement.toUpperCase(); + } else if (Transform.LOWER.equals(mapping.getTransform())) { + return replacement.toLowerCase(); + } else { + return replacement; + } } } diff --git a/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/nifi-registry.properties b/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/nifi-registry.properties index ce4377f..6d8771f 100644 --- a/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/nifi-registry.properties +++ b/nifi-registry-core/nifi-registry-resources/src/main/resources/conf/nifi-registry.properties @@ -73,8 +73,20 @@ nifi.registry.db.sql.debug=${nifi.registry.db.sql.debug} # # nifi.registry.security.identity.mapping.pattern.dn=^CN=(.*?), OU=(.*?), O=(.*?), L=(.*?), ST=(.*?), C=(.*?)$ # nifi.registry.security.identity.mapping.value.dn=$1@$2 +# nifi.registry.security.identity.mapping.transform.dn=NONE + # nifi.registry.security.identity.mapping.pattern.kerb=^(.*?)/instance@(.*?)$ # nifi.registry.security.identity.mapping.value.kerb=$1@$2 +# nifi.registry.security.identity.mapping.transform.kerb=UPPER + +# Group Mapping Properties # +# These properties allow normalizing group names coming from external sources like LDAP. The following example +# lowercases any group name. +# +# nifi.registry.security.group.mapping.pattern.anygroup=^(.*)$ +# nifi.registry.security.group.mapping.value.anygroup=$1 +# nifi.registry.security.group.mapping.transform.anygroup=LOWER + # kerberos properties # nifi.registry.kerberos.krb5.file=${nifi.registry.kerberos.krb5.file}