Ranger-684: Added support for Ranger Usersync to transform AD usernames and/or group names to linux compliant format
Signed-off-by: Velmurugan Periasamy <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/incubator-ranger/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ranger/commit/3a4372e7 Tree: http://git-wip-us.apache.org/repos/asf/incubator-ranger/tree/3a4372e7 Diff: http://git-wip-us.apache.org/repos/asf/incubator-ranger/diff/3a4372e7 Branch: refs/heads/ranger-0.5 Commit: 3a4372e7354049c570ed1cec2f2232159c1f9816 Parents: f47cbd1 Author: Sailaja Polavarapu <[email protected]> Authored: Wed Oct 28 13:14:24 2015 -0700 Committer: Velmurugan Periasamy <[email protected]> Committed: Fri Oct 30 18:33:36 2015 -0400 ---------------------------------------------------------------------- ugsync/pom.xml | 5 ++ .../process/LdapUserGroupBuilder.java | 50 +++++++++++ .../config/UserGroupSyncConfig.java | 47 +++++++++++ .../ranger/usergroupsync/AbstractMapper.java | 40 +++++++++ .../org/apache/ranger/usergroupsync/Mapper.java | 26 ++++++ .../org/apache/ranger/usergroupsync/RegEx.java | 83 ++++++++++++++++++ .../apache/ranger/usergroupsync/RegExTest.java | 89 ++++++++++++++++++++ 7 files changed, 340 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/3a4372e7/ugsync/pom.xml ---------------------------------------------------------------------- diff --git a/ugsync/pom.xml b/ugsync/pom.xml index c72eeee..d0ecb2f 100644 --- a/ugsync/pom.xml +++ b/ugsync/pom.xml @@ -105,6 +105,11 @@ <version>${project.version}</version> </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> </dependencies> http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/3a4372e7/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapUserGroupBuilder.java ---------------------------------------------------------------------- diff --git a/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapUserGroupBuilder.java b/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapUserGroupBuilder.java index 63643c0..911c5d5 100644 --- a/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapUserGroupBuilder.java +++ b/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapUserGroupBuilder.java @@ -42,6 +42,7 @@ import javax.naming.ldap.PagedResultsResponseControl; import org.apache.log4j.Logger; import org.apache.ranger.unixusersync.config.UserGroupSyncConfig; +import org.apache.ranger.usergroupsync.AbstractMapper; import org.apache.ranger.usergroupsync.UserGroupSink; import org.apache.ranger.usergroupsync.UserGroupSource; @@ -91,6 +92,9 @@ public class LdapUserGroupBuilder implements UserGroupSource { private boolean groupNameLowerCaseFlag = false ; private boolean groupUserMapSyncEnabled = false; + + AbstractMapper userNameRegExInst = null; + AbstractMapper groupNameRegExInst = null; public static void main(String[] args) throws Throwable { LdapUserGroupBuilder ugBuilder = new LdapUserGroupBuilder(); @@ -120,6 +124,39 @@ public class LdapUserGroupBuilder implements UserGroupSource { groupNameLowerCaseFlag = UserGroupSyncConfig.UGSYNC_LOWER_CASE_CONVERSION_VALUE.equalsIgnoreCase(groupNameCaseConversion) ; } + String mappingUserNameHandler = config.getUserSyncMappingUserNameHandler(); + try { + if (mappingUserNameHandler != null) { + Class<AbstractMapper> regExClass = (Class<AbstractMapper>)Class.forName(mappingUserNameHandler); + userNameRegExInst = regExClass.newInstance(); + if (userNameRegExInst != null) { + userNameRegExInst.init(UserGroupSyncConfig.SYNC_MAPPING_USERNAME); + } else { + LOG.error("RegEx handler instance for username is null!"); + } + } + } catch (ClassNotFoundException cne) { + LOG.error("Failed to load " + mappingUserNameHandler + " " + cne); + } catch (Throwable te) { + LOG.error("Failed to instantiate " + mappingUserNameHandler + " " + te); + } + + String mappingGroupNameHandler = config.getUserSyncMappingGroupNameHandler(); + try { + if (mappingGroupNameHandler != null) { + Class<AbstractMapper> regExClass = (Class<AbstractMapper>)Class.forName(mappingGroupNameHandler); + groupNameRegExInst = regExClass.newInstance(); + if (groupNameRegExInst != null) { + groupNameRegExInst.init(UserGroupSyncConfig.SYNC_MAPPING_GROUPNAME); + } else { + LOG.error("RegEx handler instance for groupname is null!"); + } + } + } catch (ClassNotFoundException cne) { + LOG.error("Failed to load " + mappingGroupNameHandler + " " + cne); + } catch (Throwable te) { + LOG.error("Failed to instantiate " + mappingGroupNameHandler + " " + te); + } } @Override @@ -320,6 +357,10 @@ public class LdapUserGroupBuilder implements UserGroupSource { userName = userName.toUpperCase() ; } } + + if (userNameRegExInst != null) { + userName = userNameRegExInst.transform(userName); + } Set<String> groups = new HashSet<String>(); @@ -337,6 +378,9 @@ public class LdapUserGroupBuilder implements UserGroupSource { gName = gName.toUpperCase(); } } + if (groupNameRegExInst != null) { + gName = groupNameRegExInst.transform(gName); + } groups.add(gName); } } @@ -361,6 +405,9 @@ public class LdapUserGroupBuilder implements UserGroupSource { gName = gName.toUpperCase(); } } + if (groupNameRegExInst != null) { + gName = groupNameRegExInst.transform(gName); + } computedGroups.add(gName); } } @@ -453,6 +500,9 @@ public class LdapUserGroupBuilder implements UserGroupSource { gName = gName.toUpperCase(); } } + if (groupNameRegExInst != null) { + gName = groupNameRegExInst.transform(gName); + } groupNames.add(gName); } if (LOG.isInfoEnabled()) { http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/3a4372e7/ugsync/src/main/java/org/apache/ranger/unixusersync/config/UserGroupSyncConfig.java ---------------------------------------------------------------------- diff --git a/ugsync/src/main/java/org/apache/ranger/unixusersync/config/UserGroupSyncConfig.java b/ugsync/src/main/java/org/apache/ranger/unixusersync/config/UserGroupSyncConfig.java index c1b305b..ceeb836 100644 --- a/ugsync/src/main/java/org/apache/ranger/unixusersync/config/UserGroupSyncConfig.java +++ b/ugsync/src/main/java/org/apache/ranger/unixusersync/config/UserGroupSyncConfig.java @@ -24,7 +24,10 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; +import java.util.Enumeration; import java.util.HashSet; +import java.util.List; import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; @@ -174,6 +177,17 @@ public class UserGroupSyncConfig { private static final String SYNC_SOURCE = "ranger.usersync.sync.source"; private static final String LGSYNC_REFERRAL = "ranger.usersync.ldap.referral"; private static final String DEFAULT_LGSYNC_REFERRAL = "ignore"; + + public static final String SYNC_MAPPING_USERNAME = "ranger.usersync.mapping.username.regex"; + + public static final String SYNC_MAPPING_GROUPNAME = "ranger.usersync.mapping.groupname.regex"; + + private static final String SYNC_MAPPING_USERNAME_HANDLER = "ranger.usersync.mapping.username.handler"; + private static final String DEFAULT_SYNC_MAPPING_USERNAME_HANDLER = "org.apache.ranger.usergroupsync.RegEx"; + + private static final String SYNC_MAPPING_GROUPNAME_HANDLER = "ranger.usersync.mapping.groupname.handler"; + private static final String DEFAULT_SYNC_MAPPING_GROUPNAME_HANDLER = "org.apache.ranger.usergroupsync.RegEx"; + private Properties prop = new Properties() ; private static volatile UserGroupSyncConfig me = null ; @@ -738,4 +752,37 @@ public class UserGroupSyncConfig { } return referral; } + + public List<String> getAllRegexPatterns(String baseProperty) { + List<String> regexPatterns = new ArrayList<String>(); + if (prop != null) { + Enumeration<?> propertyNames = prop.propertyNames(); + while (propertyNames != null && propertyNames.hasMoreElements()) { + String propertyName = (String)propertyNames.nextElement(); + if (propertyName != null && propertyName.contains(baseProperty)) { + regexPatterns.add(prop.getProperty(propertyName)); + } + } + + } + return regexPatterns; + } + + public String getUserSyncMappingUserNameHandler() { + String val = prop.getProperty(SYNC_MAPPING_USERNAME_HANDLER) ; + + if(val == null) { + val = DEFAULT_SYNC_MAPPING_USERNAME_HANDLER; + } + return val; + } + + public String getUserSyncMappingGroupNameHandler() { + String val = prop.getProperty(SYNC_MAPPING_GROUPNAME_HANDLER) ; + + if(val == null) { + val = DEFAULT_SYNC_MAPPING_GROUPNAME_HANDLER; + } + return val; + } } http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/3a4372e7/ugsync/src/main/java/org/apache/ranger/usergroupsync/AbstractMapper.java ---------------------------------------------------------------------- diff --git a/ugsync/src/main/java/org/apache/ranger/usergroupsync/AbstractMapper.java b/ugsync/src/main/java/org/apache/ranger/usergroupsync/AbstractMapper.java new file mode 100644 index 0000000..fc5d10b --- /dev/null +++ b/ugsync/src/main/java/org/apache/ranger/usergroupsync/AbstractMapper.java @@ -0,0 +1,40 @@ +/* + * 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.ranger.usergroupsync; + +import org.apache.log4j.Logger; + +public abstract class AbstractMapper implements Mapper { + + static Logger logger = Logger.getLogger(AbstractMapper.class); + + @Override + public void init(String baseProperty) { + // TODO Auto-generated method stub + + } + + @Override + public String transform(String attrValue) { + // TODO Auto-generated method stub + return null; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/3a4372e7/ugsync/src/main/java/org/apache/ranger/usergroupsync/Mapper.java ---------------------------------------------------------------------- diff --git a/ugsync/src/main/java/org/apache/ranger/usergroupsync/Mapper.java b/ugsync/src/main/java/org/apache/ranger/usergroupsync/Mapper.java new file mode 100644 index 0000000..820fe20 --- /dev/null +++ b/ugsync/src/main/java/org/apache/ranger/usergroupsync/Mapper.java @@ -0,0 +1,26 @@ +/* + * 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.ranger.usergroupsync; + +public interface Mapper { + public void init(String baseProperty); + + public String transform(String attrValue); +} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/3a4372e7/ugsync/src/main/java/org/apache/ranger/usergroupsync/RegEx.java ---------------------------------------------------------------------- diff --git a/ugsync/src/main/java/org/apache/ranger/usergroupsync/RegEx.java b/ugsync/src/main/java/org/apache/ranger/usergroupsync/RegEx.java new file mode 100644 index 0000000..b655536 --- /dev/null +++ b/ugsync/src/main/java/org/apache/ranger/usergroupsync/RegEx.java @@ -0,0 +1,83 @@ +/* + * 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.ranger.usergroupsync; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.ranger.unixusersync.config.UserGroupSyncConfig; + +public class RegEx extends AbstractMapper { + private UserGroupSyncConfig config = UserGroupSyncConfig.getInstance(); + private LinkedHashMap<String, String> replacementPattern; + + public LinkedHashMap<String, String> getReplacementPattern() { + return replacementPattern; + } + + @Override + public void init (String baseProperty) { + logger.info("Initializing for " + baseProperty); + List<String> regexPatterns = config.getAllRegexPatterns(baseProperty); + populateReplacementPatterns(baseProperty, regexPatterns); + } + + protected void populateReplacementPatterns(String baseProperty, List<String> regexPatterns) { + replacementPattern = new LinkedHashMap<String, String>(); + Pattern p = Pattern.compile("s/([^/]*)/([^/]*)/(g)?"); + for (String regexPattern : regexPatterns) { + Matcher m = p.matcher(regexPattern); + if (!m.matches()) { + logger.warn("Invalid RegEx " + regexPattern + " and hence skipping this regex property"); + } + m = m.reset(); + while (m.find()) { + String matchPattern = m.group(1); + String replacement = m.group(2); + if (matchPattern != null && !matchPattern.isEmpty() && replacement != null) { + replacementPattern.put(matchPattern, Matcher.quoteReplacement(replacement)); + if (logger.isDebugEnabled()) { + logger.debug(baseProperty + " match pattern = " + matchPattern + " and replacement string = " + replacement); + } + } + } + } + } + + @Override + public String transform (String attrValue) { + String result = attrValue; + if (replacementPattern != null && !replacementPattern.isEmpty()) { + for (String matchPattern : replacementPattern.keySet()) { + Pattern p = Pattern.compile(matchPattern); + Matcher m = p.matcher(result); + if (m.find()) { + String replacement = replacementPattern.get(matchPattern); + if (replacement != null) { + result = m.replaceAll(replacement); + } + } + } + } + return result; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/3a4372e7/ugsync/src/test/java/org/apache/ranger/usergroupsync/RegExTest.java ---------------------------------------------------------------------- diff --git a/ugsync/src/test/java/org/apache/ranger/usergroupsync/RegExTest.java b/ugsync/src/test/java/org/apache/ranger/usergroupsync/RegExTest.java new file mode 100644 index 0000000..d74eb2b --- /dev/null +++ b/ugsync/src/test/java/org/apache/ranger/usergroupsync/RegExTest.java @@ -0,0 +1,89 @@ +/* + * 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.ranger.usergroupsync; + +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; + +public class RegExTest { + protected String userNameBaseProperty = "ranger.usersync.mapping.username.regex"; + protected String groupNameBaseProperty = "ranger.usersync.mapping.groupname.regex"; + protected RegEx userNameRegEx = null; + protected RegEx groupNameRegEx = null; + List<String> userRegexPatterns = null; + List<String> groupRegexPatterns = null; + + @Before + public void setUp() throws Exception { + userNameRegEx = new RegEx(); + //userNameRegEx.init(userNameBaseProperty); + userRegexPatterns = new ArrayList<String>(); + groupNameRegEx = new RegEx(); + //groupNameRegEx.init(groupNameBaseProperty); + groupRegexPatterns = new ArrayList<String>(); + } + + @Test + public void testUserNameTransform() { + userRegexPatterns.add("s/\\s/_/"); + userNameRegEx.populateReplacementPatterns(userNameBaseProperty, userRegexPatterns); + assertEquals("test_user", userNameRegEx.transform("test user")); + } + + @Test + public void testGroupNameTransform() { + groupRegexPatterns.add("s/\\s/_/g"); + groupRegexPatterns.add("s/_/$/g"); + groupNameRegEx.populateReplacementPatterns(userNameBaseProperty, groupRegexPatterns); + assertEquals("ldap$grp", groupNameRegEx.transform("ldap grp")); + } + + @Test + public void testEmptyTransform() { + assertEquals("test user", userNameRegEx.transform("test user")); + assertEquals("ldap grp", groupNameRegEx.transform("ldap grp")); + } + + @Test + public void testTransform() { + userRegexPatterns.add("s/\\s/_/g"); + userNameRegEx.populateReplacementPatterns(userNameBaseProperty, userRegexPatterns); + assertEquals("test_user", userNameRegEx.transform("test user")); + assertEquals("ldap grp", groupNameRegEx.transform("ldap grp")); + } + + @Test + public void testTransform1() { + userRegexPatterns.add("s/\\\\/ /g"); + userRegexPatterns.add("s//_/g"); + userNameRegEx.populateReplacementPatterns(userNameBaseProperty, userRegexPatterns); + groupRegexPatterns.add("s/\\s//g"); + groupRegexPatterns.add("s/\\s"); + groupNameRegEx.populateReplacementPatterns(userNameBaseProperty, groupRegexPatterns); + assertEquals("test user", userNameRegEx.transform("test\\user")); + assertEquals("ldapgrp", groupNameRegEx.transform("ldap grp")); + } + +}
