You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by sp...@apache.org on 2022/03/09 01:59:13 UTC

[ranger] branch master updated: RANGER-3630: Added code to support wildcards, group short names, and list of memberof attribute DNs for computing user search filter

This is an automated email from the ASF dual-hosted git repository.

spolavarapu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ranger.git


The following commit(s) were added to refs/heads/master by this push:
     new 63704db  RANGER-3630: Added code to support wildcards, group short names, and list of memberof attribute DNs for computing user search filter
63704db is described below

commit 63704db998840b8f5d50575945691de2e46f3260
Author: Sailaja Polavarapu <sp...@cloudera.com>
AuthorDate: Tue Mar 8 17:58:54 2022 -0800

    RANGER-3630: Added code to support wildcards, group short names, and list of memberof attribute DNs for computing user search filter
---
 .../ldapusersync/process/LdapUserGroupBuilder.java | 379 ++++++++++++++++-----
 .../unixusersync/config/UserGroupSyncConfig.java   |  22 ++
 .../ranger/usergroupsync/TestLdapUserGroup.java    | 111 +++++-
 3 files changed, 421 insertions(+), 91 deletions(-)

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 dae78e9..550775f 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
@@ -75,7 +75,9 @@ public class LdapUserGroupBuilder implements UserGroupSource {
 	private static final String DATA_TYPE_BYTEARRAY = "byte[]";
 	private static final String DATE_FORMAT = "yyyyMMddHHmmss";
 	private static final int PAGE_SIZE = 500;
-	private static long deltaSyncUserTime = 0; // Used for AD uSNChanged 
+	private static final String MEMBER_OF_ATTR = "memberof=";
+	private static final String GROUP_NAME_ATTRIBUTE = "cn=";
+	private static long deltaSyncUserTime = 0; // Used for AD uSNChanged
 	private static long deltaSyncGroupTime = 0; // Used for AD uSNChanged
 	private String deltaSyncUserTimeStamp; // Used for OpenLdap modifyTimestamp
 	private String deltaSyncGroupTimeStamp; // Used for OpenLdap modifyTimestamp
@@ -93,6 +95,7 @@ public class LdapUserGroupBuilder implements UserGroupSource {
   private int    userSearchScope;
   private String userObjectClass;
   private String userSearchFilter;
+  private Set<String> groupNameSet;
   private String extendedUserSearchFilter;
   private SearchControls userSearchControls;
   private Set<String> userGroupNameAttributeSet;
@@ -116,8 +119,8 @@ public class LdapUserGroupBuilder implements UserGroupSource {
 	private String groupCloudIdAttribute;
 	private Set<String> otherGroupAttributes;
 	private int groupHierarchyLevels;
-	private int deleteCycles;
-	private String currentSyncSource;
+    private int deleteCycles;
+    private String currentSyncSource;
 
 	private LdapContext ldapContext;
 	StartTlsResponse tls;
@@ -139,7 +142,7 @@ public class LdapUserGroupBuilder implements UserGroupSource {
 	public void init() throws Throwable{
 		deltaSyncUserTime = 0;
 		deltaSyncGroupTime = 0;
-		deleteCycles = 1;
+        deleteCycles = 1;
 		DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
 		deltaSyncUserTimeStamp = dateFormat.format(new Date(0));
 		deltaSyncGroupTimeStamp = dateFormat.format(new Date(0));
@@ -190,7 +193,6 @@ public class LdapUserGroupBuilder implements UserGroupSource {
 				env.put("java.naming.ldap.attributes.binary", otherGroupAttribute);
 			}
 		}
-
 		ldapContext = new InitialLdapContext(env, null);
 		if (!ldapUrl.startsWith("ldaps")) {
 			if (config.isStartTlsEnabled()) {
@@ -214,22 +216,21 @@ public class LdapUserGroupBuilder implements UserGroupSource {
 		LOG.info("LdapUserGroupBuilder initialization started");
 
 		currentSyncSource = config.getCurrentSyncSource();
-		groupSearchFirstEnabled =   true;
-		userSearchEnabled =   config.isUserSearchEnabled();
-		groupSearchEnabled =   config.isGroupSearchEnabled();
-    ldapUrl = config.getLdapUrl();
-    ldapBindDn = config.getLdapBindDn();
-    ldapBindPassword = config.getLdapBindPassword();
-    //ldapBindPassword = "admin-password";
-    ldapAuthenticationMechanism = config.getLdapAuthenticationMechanism();
-    ldapReferral = config.getContextReferral();
+		groupSearchFirstEnabled = true;
+		userSearchEnabled = config.isUserSearchEnabled();
+		groupSearchEnabled = config.isGroupSearchEnabled();
+		ldapUrl = config.getLdapUrl();
+		ldapBindDn = config.getLdapBindDn();
+		ldapBindPassword = config.getLdapBindPassword();
+		//ldapBindPassword = "admin-password";
+		ldapAuthenticationMechanism = config.getLdapAuthenticationMechanism();
+		ldapReferral = config.getContextReferral();
 		searchBase = config.getSearchBase();
 
 		userSearchBase = config.getUserSearchBase().split(";");
 		userSearchScope = config.getUserSearchScope();
 		userObjectClass = config.getUserObjectClass();
 		userSearchFilter = config.getUserSearchFilter();
-
 		userNameAttribute = config.getUserNameAttribute();
 		userCloudIdAttribute = config.getUserCloudIdAttribute();
 
@@ -251,67 +252,92 @@ public class LdapUserGroupBuilder implements UserGroupSource {
 		userSearchControls.setReturningAttributes(userSearchAttributes.toArray(
 				new String[userSearchAttributes.size()]));
 
-    pagedResultsEnabled =   config.isPagedResultsEnabled();
-    pagedResultsSize =   config.getPagedResultsSize();
+		pagedResultsEnabled = config.isPagedResultsEnabled();
+		pagedResultsSize = config.getPagedResultsSize();
 
-    groupSearchBase = config.getGroupSearchBase().split(";");
-    groupSearchScope = config.getGroupSearchScope();
-    groupObjectClass = config.getGroupObjectClass();
-    groupSearchFilter = config.getGroupSearchFilter();
-    groupMemberAttributeName =  config.getUserGroupMemberAttributeName();
-    groupNameAttribute = config.getGroupNameAttribute();
-    groupCloudIdAttribute = config.getGroupCloudIdAttribute();
+		groupSearchBase = config.getGroupSearchBase().split(";");
+		groupSearchScope = config.getGroupSearchScope();
+		groupObjectClass = config.getGroupObjectClass();
+		groupSearchFilter = config.getGroupSearchFilter();
+		groupMemberAttributeName = config.getUserGroupMemberAttributeName();
+		groupNameAttribute = config.getGroupNameAttribute();
+		groupCloudIdAttribute = config.getGroupCloudIdAttribute();
 		groupHierarchyLevels = config.getGroupHierarchyLevels();
 
-    extendedGroupSearchFilter =  "(&"  + extendedGroupSearchFilter + "(|(" + groupMemberAttributeName + "={0})(" + groupMemberAttributeName + "={1})))";
-
-    groupSearchControls = new SearchControls();
-    groupSearchControls.setSearchScope(groupSearchScope);
-
-    Set<String> groupSearchAttributes = new HashSet<String>();
-    groupSearchAttributes.add(groupNameAttribute);
-    groupSearchAttributes.add(groupCloudIdAttribute);
-    groupSearchAttributes.add(groupMemberAttributeName);
-    groupSearchAttributes.add("uSNChanged");
-    groupSearchAttributes.add("modifytimestamp");
-    otherGroupAttributes = config.getOtherGroupAttributes();
-    for (String otherGroupAttribute : otherGroupAttributes) {
-		groupSearchAttributes.add(otherGroupAttribute);
-    }
-    groupSearchControls.setReturningAttributes(groupSearchAttributes.toArray(
-			new String[groupSearchAttributes.size()]));
-
-			LOG.info("LdapUserGroupBuilder initialization completed with --  "
-					+ "ldapUrl: " + ldapUrl
-					+ ",  ldapBindDn: " + ldapBindDn
-					+ ",  ldapBindPassword: ***** "
-					+ ",  ldapAuthenticationMechanism: " + ldapAuthenticationMechanism
-          + ",  searchBase: " + searchBase
-          + ",  userSearchBase: " + Arrays.toString(userSearchBase)
-          + ",  userSearchScope: " + userSearchScope
-					+ ",  userObjectClass: " + userObjectClass
-					+ ",  userSearchFilter: " + userSearchFilter
-					+ ",  extendedUserSearchFilter: " + extendedUserSearchFilter
-					+ ",  userNameAttribute: " + userNameAttribute
-					+ ",  userSearchAttributes: " + userSearchAttributes
-					+ ",  userGroupNameAttributeSet: " + userGroupNameAttributeSet
-			+ ",  otherUserAttributes: " + otherUserAttributes
-          + ",  pagedResultsEnabled: " + pagedResultsEnabled
-          + ",  pagedResultsSize: " + pagedResultsSize
-          + ",  groupSearchEnabled: " + groupSearchEnabled
-          + ",  groupSearchBase: " + Arrays.toString(groupSearchBase)
-          + ",  groupSearchScope: " + groupSearchScope
-          + ",  groupObjectClass: " + groupObjectClass
-          + ",  groupSearchFilter: " + groupSearchFilter
-          + ",  extendedGroupSearchFilter: " + extendedGroupSearchFilter
-          + ",  extendedAllGroupsSearchFilter: " + extendedAllGroupsSearchFilter
-          + ",  groupMemberAttributeName: " + groupMemberAttributeName
-          + ",  groupNameAttribute: " + groupNameAttribute
-          + ", groupSearchAttributes: " + groupSearchAttributes
-          + ", groupSearchFirstEnabled: " + groupSearchFirstEnabled
-          + ", userSearchEnabled: " + userSearchEnabled
-          + ",  ldapReferral: " + ldapReferral
-      );
+		extendedGroupSearchFilter = "(&" + extendedGroupSearchFilter + "(|(" + groupMemberAttributeName + "={0})(" + groupMemberAttributeName + "={1})))";
+
+		groupSearchControls = new SearchControls();
+		groupSearchControls.setSearchScope(groupSearchScope);
+
+		Set<String> groupSearchAttributes = new HashSet<String>();
+		groupSearchAttributes.add(groupNameAttribute);
+		groupSearchAttributes.add(groupCloudIdAttribute);
+		groupSearchAttributes.add(groupMemberAttributeName);
+		groupSearchAttributes.add("uSNChanged");
+		groupSearchAttributes.add("modifytimestamp");
+		otherGroupAttributes = config.getOtherGroupAttributes();
+		for (String otherGroupAttribute : otherGroupAttributes) {
+			groupSearchAttributes.add(otherGroupAttribute);
+		}
+		groupSearchControls.setReturningAttributes(groupSearchAttributes.toArray(
+				new String[groupSearchAttributes.size()]));
+
+		if (StringUtils.isEmpty(userSearchFilter)) {
+			groupNameSet = config.getGroupNameSet();
+			String computedSearchFilter = "";
+			for (String groupName : groupNameSet) {
+				if (LOG.isDebugEnabled()) {
+					LOG.debug("groupName = " + groupName);
+				}
+				if (!groupName.startsWith(MEMBER_OF_ATTR) && !groupName.startsWith(GROUP_NAME_ATTRIBUTE)){
+					LOG.info("Ignoring unsupported format for " + groupName );
+					continue;
+				}
+				String searchFilter = groupName;
+				if (groupName.startsWith(MEMBER_OF_ATTR)) {
+					searchFilter = groupName.substring(MEMBER_OF_ATTR.length());
+				}
+				searchFilter = getFirstRDN(searchFilter);
+				computedSearchFilter += getDNForMemberOf(searchFilter);
+			}
+			if (StringUtils.isNotEmpty(computedSearchFilter)) {
+				computedSearchFilter = "(|" + computedSearchFilter + ")";
+			}
+			LOG.info("Final computedSearchFilter = " + computedSearchFilter);
+			userSearchFilter = computedSearchFilter;
+		}
+
+		LOG.info("LdapUserGroupBuilder initialization completed with --  "
+				+ "ldapUrl: " + ldapUrl
+				+ ",  ldapBindDn: " + ldapBindDn
+				+ ",  ldapBindPassword: ***** "
+				+ ",  ldapAuthenticationMechanism: " + ldapAuthenticationMechanism
+				+ ",  searchBase: " + searchBase
+				+ ",  userSearchBase: " + Arrays.toString(userSearchBase)
+				+ ",  userSearchScope: " + userSearchScope
+				+ ",  userObjectClass: " + userObjectClass
+				+ ",  userSearchFilter: " + userSearchFilter
+				+ ",  extendedUserSearchFilter: " + extendedUserSearchFilter
+				+ ",  userNameAttribute: " + userNameAttribute
+				+ ",  userSearchAttributes: " + userSearchAttributes
+				+ ",  userGroupNameAttributeSet: " + userGroupNameAttributeSet
+				+ ",  otherUserAttributes: " + otherUserAttributes
+				+ ",  pagedResultsEnabled: " + pagedResultsEnabled
+				+ ",  pagedResultsSize: " + pagedResultsSize
+				+ ",  groupSearchEnabled: " + groupSearchEnabled
+				+ ",  groupSearchBase: " + Arrays.toString(groupSearchBase)
+				+ ",  groupSearchScope: " + groupSearchScope
+				+ ",  groupObjectClass: " + groupObjectClass
+				+ ",  groupSearchFilter: " + groupSearchFilter
+				+ ",  extendedGroupSearchFilter: " + extendedGroupSearchFilter
+				+ ",  extendedAllGroupsSearchFilter: " + extendedAllGroupsSearchFilter
+				+ ",  groupMemberAttributeName: " + groupMemberAttributeName
+				+ ",  groupNameAttribute: " + groupNameAttribute
+				+ ", groupSearchAttributes: " + groupSearchAttributes
+				+ ", groupSearchFirstEnabled: " + groupSearchFirstEnabled
+				+ ", userSearchEnabled: " + userSearchEnabled
+				+ ",  ldapReferral: " + ldapReferral
+		);
 	}
 
 	private void closeLdapContext() throws Throwable {
@@ -332,7 +358,7 @@ public class LdapUserGroupBuilder implements UserGroupSource {
 	@Override
 	public void updateSink(UserGroupSink sink) throws Throwable {
 		LOG.info("LdapUserGroupBuilder updateSink started");
-		boolean computeDeletes = false;
+        boolean computeDeletes = false;
 		groupUserTable = HashBasedTable.create();
 		sourceGroups = new HashMap<>();
 		sourceUsers = new HashMap<>();
@@ -710,10 +736,10 @@ public class LdapUserGroupBuilder implements UserGroupSource {
 							String groupFullName = (groupEntry.getNameInNamespace());
 							String gName = (String) groupNameAttr.get();
 							Map<String, String> groupAttrMap = new HashMap<>();
-							groupAttrMap.put(UgsyncCommonConstants.ORIGINAL_NAME, gName);
-							groupAttrMap.put(UgsyncCommonConstants.FULL_NAME, groupFullName);
-							groupAttrMap.put(UgsyncCommonConstants.SYNC_SOURCE, currentSyncSource);
-							groupAttrMap.put(UgsyncCommonConstants.LDAP_URL, config.getLdapUrl());
+                            groupAttrMap.put(UgsyncCommonConstants.ORIGINAL_NAME, gName);
+                            groupAttrMap.put(UgsyncCommonConstants.FULL_NAME, groupFullName);
+                            groupAttrMap.put(UgsyncCommonConstants.SYNC_SOURCE, currentSyncSource);
+                            groupAttrMap.put(UgsyncCommonConstants.LDAP_URL, config.getLdapUrl());
 							Attribute groupCloudIdAttr = attributes.get(groupCloudIdAttribute);
 							if (groupCloudIdAttr != null) {
 								addToAttrMap(groupAttrMap, "cloud_id", groupCloudIdAttr, config.getGroupCloudIdAttributeDataType());
@@ -762,13 +788,14 @@ public class LdapUserGroupBuilder implements UserGroupSource {
 									continue;
 								}
 								userCount++;
+
 								if (!userSearchEnabled) {
 									Map<String, String> userAttrMap = new HashMap<>();
 									String userName = getShortName(originalUserFullName);
-									userAttrMap.put(UgsyncCommonConstants.ORIGINAL_NAME, userName);
-									userAttrMap.put(UgsyncCommonConstants.FULL_NAME, originalUserFullName);
-									userAttrMap.put(UgsyncCommonConstants.SYNC_SOURCE, currentSyncSource);
-									userAttrMap.put(UgsyncCommonConstants.LDAP_URL, config.getLdapUrl());
+                                    userAttrMap.put(UgsyncCommonConstants.ORIGINAL_NAME, userName);
+                                    userAttrMap.put(UgsyncCommonConstants.FULL_NAME, originalUserFullName);
+                                    userAttrMap.put(UgsyncCommonConstants.SYNC_SOURCE, currentSyncSource);
+                                    userAttrMap.put(UgsyncCommonConstants.LDAP_URL, config.getLdapUrl());
 									sourceUsers.put(originalUserFullName, userAttrMap);
 									if (LOG.isDebugEnabled()) {
 										LOG.debug("As usersearch is disabled, adding user " + userName + " from group member attribute for group " + gName);
@@ -941,10 +968,10 @@ public class LdapUserGroupBuilder implements UserGroupSource {
 
 
 							Map<String, String> groupAttrMap = new HashMap<>();
-							groupAttrMap.put(UgsyncCommonConstants.ORIGINAL_NAME, gName);
-							groupAttrMap.put(UgsyncCommonConstants.FULL_NAME, groupFullName);
-							groupAttrMap.put(UgsyncCommonConstants.SYNC_SOURCE, currentSyncSource);
-							groupAttrMap.put(UgsyncCommonConstants.LDAP_URL, config.getLdapUrl());
+                            groupAttrMap.put(UgsyncCommonConstants.ORIGINAL_NAME, gName);
+                            groupAttrMap.put(UgsyncCommonConstants.FULL_NAME, groupFullName);
+                            groupAttrMap.put(UgsyncCommonConstants.SYNC_SOURCE, currentSyncSource);
+                            groupAttrMap.put(UgsyncCommonConstants.LDAP_URL, config.getLdapUrl());
 							for (String otherGroupAttribute : otherGroupAttributes) {
 								Attribute otherGroupAttr = groupEntry.getAttributes().get(otherGroupAttribute);
 								if (otherGroupAttr != null) {
@@ -963,10 +990,10 @@ public class LdapUserGroupBuilder implements UserGroupSource {
 								if (!userSearchEnabled && !sourceGroups.containsKey(originalUserFullName)) {
 									Map<String, String> userAttrMap = new HashMap<>();
 									String userName = getShortName(originalUserFullName);
-									userAttrMap.put(UgsyncCommonConstants.ORIGINAL_NAME, userName);
-									userAttrMap.put(UgsyncCommonConstants.FULL_NAME, originalUserFullName);
-									userAttrMap.put(UgsyncCommonConstants.SYNC_SOURCE, currentSyncSource);
-									userAttrMap.put(UgsyncCommonConstants.LDAP_URL, config.getLdapUrl());
+                                    userAttrMap.put(UgsyncCommonConstants.ORIGINAL_NAME, userName);
+                                    userAttrMap.put(UgsyncCommonConstants.FULL_NAME, originalUserFullName);
+                                    userAttrMap.put(UgsyncCommonConstants.SYNC_SOURCE, currentSyncSource);
+                                    userAttrMap.put(UgsyncCommonConstants.LDAP_URL, config.getLdapUrl());
 									sourceUsers.put(originalUserFullName, userAttrMap);
 								}
 								groupUserTable.put(groupFullName, originalUserFullName, originalUserFullName);
@@ -1089,4 +1116,176 @@ public class LdapUserGroupBuilder implements UserGroupSource {
 		LOG.info("longName: " + longName + ", userName: " + shortName);
 		return shortName;
 	}
+
+	private String getFirstRDN(String name) {
+		if (StringUtils.isEmpty(name)) {
+			return null;
+		}
+		String shortName = "";
+		try {
+			LdapName subjectDN = new LdapName(name);
+			List<Rdn> rdns = subjectDN.getRdns();
+			for (int i = rdns.size() - 1; i >= 0; i--) {
+				if (StringUtils.isNotEmpty(shortName)) {
+					break;
+				}
+				Rdn rdn = rdns.get(i);
+				Attributes attributes = rdn.toAttributes();
+				try {
+					Attribute cn = attributes.get("cn");
+					if (cn != null) {
+						Object value = cn.get();
+						if (value != null) {
+							shortName = GROUP_NAME_ATTRIBUTE + value.toString();
+						}
+					}
+				} catch (NoSuchElementException ignore) {
+					LOG.warn("NoSuchElementException while retrieving first RDN for " + name);
+				} catch (NamingException ignore) {
+					LOG.warn("NamingException while retrieving first RDN for " + name);
+				}
+			}
+		} catch (InvalidNameException ex) {
+			LOG.warn("InvalidNameException while retrieving first RDN for " + name);
+		}
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("Input group name: " + name + ", first RDN: " + shortName);
+		}
+		return shortName;
+	}
+
+	private String getDNForMemberOf(String searchFilter) throws Throwable {
+		NamingEnumeration<SearchResult> userSearchResultEnum = null;
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("getDNForMemberOf(" + searchFilter + ")");
+		}
+		String computedSearchFilter = "";
+		try {
+			createLdapContext();
+			int total;
+			// Activate paged results
+			if (pagedResultsEnabled)   {
+				ldapContext.setRequestControls(new Control[]{
+						new PagedResultsControl(pagedResultsSize, Control.NONCRITICAL) });
+			}
+			SearchControls searchControls = new SearchControls();
+			searchControls.setSearchScope(groupSearchScope);
+
+			Set<String> searchAttributes = new HashSet<String>();
+			searchAttributes.add(groupNameAttribute);
+			searchControls.setReturningAttributes(searchAttributes.toArray(
+					new String[searchAttributes.size()]));
+
+
+			// When multiple OUs are configured, go through each OU as the user search base to search for users.
+			for (int ou=0; ou<groupSearchBase.length; ou++) {
+				byte[] cookie = null;
+				int counter = 0;
+				try {
+					int paged = 0;
+					do {
+						userSearchResultEnum = ldapContext
+								.search(groupSearchBase[ou], "(&(objectclass=" + groupObjectClass + ")(" + searchFilter + "))",
+										searchControls);
+
+						while (userSearchResultEnum.hasMore()) {
+							// searchResults contains all the user entries
+							final SearchResult userEntry = userSearchResultEnum.next();
+
+							if (userEntry == null)  {
+								LOG.info("userEntry null, skipping sync for the entry");
+								continue;
+							}
+
+							Attributes attributes =   userEntry.getAttributes();
+							if (attributes == null)  {
+								LOG.info("attributes  missing for entry " + userEntry.getNameInNamespace() +
+											", skipping sync");
+								continue;
+							}
+
+							Attribute groupNameAttr  = attributes.get(groupNameAttribute);
+							if (groupNameAttr == null)  {
+								LOG.info(groupNameAttribute + " missing for entry " + userEntry.getNameInNamespace() +
+											", skipping sync");
+								continue;
+							}
+
+							String groupFullName = (userEntry.getNameInNamespace());
+							LOG.info("groupFullName = " + groupFullName);
+							computedSearchFilter += "(" + MEMBER_OF_ATTR + groupFullName + ")";
+							counter++;
+
+							if (counter <= 2000) {
+								LOG.info("Updating group count: " + counter
+											+ ", groupName: " + groupFullName);
+								if ( counter == 2000 ) {
+									LOG.info("===> 2000 group records have been synchronized so far. From now on, only a summary progress log will be written for every 100 users. To continue to see detailed log for every user, please enable Trace level logging. <===");
+								}
+							} else {
+								if (LOG.isTraceEnabled()) {
+									LOG.trace("Updating group count: " + counter
+											+ ", groupName: " + groupFullName);
+								} else  {
+									if ( counter % 100 == 0) {
+										LOG.info("Synced " + counter + " groups till now");
+									}
+								}
+							}
+
+						}
+
+						// Examine the paged results control response
+						Control[] controls = ldapContext.getResponseControls();
+						if (controls != null) {
+							for (int i = 0; i < controls.length; i++) {
+								if (controls[i] instanceof PagedResultsResponseControl) {
+									PagedResultsResponseControl prrc =
+											(PagedResultsResponseControl)controls[i];
+									total = prrc.getResultSize();
+									if (total != 0) {
+										if (LOG.isDebugEnabled()) {
+											LOG.debug("END-OF-PAGE total : " + total);
+										}
+									} else {
+										if (LOG.isDebugEnabled()) {
+											LOG.debug("END-OF-PAGE total : unknown");
+										}
+									}
+									cookie = prrc.getCookie();
+								}
+							}
+						} else {
+							if (LOG.isDebugEnabled()) {
+								LOG.debug("No controls were sent from the server");
+							}
+						}
+						// Re-activate paged results
+						if (pagedResultsEnabled)   {
+							if (LOG.isDebugEnabled()) {
+								LOG.debug(String.format("Fetched paged results round: %s", ++paged));
+							}
+							ldapContext.setRequestControls(new Control[]{
+									new PagedResultsControl(pagedResultsSize, cookie, Control.CRITICAL) });
+						}
+					} while (cookie != null);
+					LOG.info("LdapUserGroupBuilder.getDNForMemberOf() completed with group count: "
+							+ counter);
+				} catch (Exception t) {
+					LOG.error("LdapUserGroupBuilder.getDNForMemberOf() failed with exception: ", t);
+					LOG.info("LdapUserGroupBuilder.getDNForMemberOf() group count: "
+							+ counter);
+				}
+			}
+		} finally {
+			if (userSearchResultEnum != null) {
+				userSearchResultEnum.close();
+			}
+			closeLdapContext();
+		}
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("computedSearchFilter = " + computedSearchFilter);
+		}
+		return computedSearchFilter;
+	}
 }
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 5f30165..531e35a 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
@@ -141,6 +141,7 @@ public class UserGroupSyncConfig  {
 	private static final String LGSYNC_USER_OBJECT_CLASS = "ranger.usersync.ldap.user.objectclass";
 	private static final String DEFAULT_USER_OBJECT_CLASS = "person";
 
+    private static final String LGSYNC_GROUPNAMES = "ranger.usersync.ldap.groupnames";
 	private static final String LGSYNC_USER_SEARCH_FILTER = "ranger.usersync.ldap.user.searchfilter";
 
 	private static final String LGSYNC_USER_NAME_ATTRIBUTE = "ranger.usersync.ldap.user.nameattribute";
@@ -679,6 +680,22 @@ public class UserGroupSyncConfig  {
 		return val;
 	}
 
+    public String getGroupNames() {
+        return prop.getProperty(LGSYNC_GROUPNAMES);
+    }
+
+    public Set<String> getGroupNameSet() {
+        String groupNames =  getGroupNames();
+		Set<String> groupNamegSet = new HashSet<String>();
+		if (StringUtils.isNotEmpty(groupNames)) {
+			StringTokenizer st = new StringTokenizer(groupNames, ";");
+			while (st.hasMoreTokens()) {
+				groupNamegSet.add(st.nextToken().trim().toLowerCase());
+			}
+		}
+        return groupNamegSet;
+    }
+
 	public Set<String> getUserGroupNameAttributeSet() {
 		String uga =  getUserGroupNameAttribute();
 		StringTokenizer st = new StringTokenizer(uga, ",");
@@ -1201,6 +1218,11 @@ public class UserGroupSyncConfig  {
 		prop.setProperty(LGSYNC_GROUP_HIERARCHY_LEVELS, String.valueOf(groupHierarchyLevel));
 	}
 
+	/* Used only for unit testing */
+	public void setGroupnames(String groupnames) {
+		prop.setProperty(LGSYNC_GROUPNAMES, groupnames);
+	}
+
 	public String getUserSyncMetricsFileName() throws IOException {
 		String val = prop.getProperty(UGSYNC_METRICS_FILEPATH);
 		if (StringUtils.isBlank(val)) {
diff --git a/ugsync/src/test/java/org/apache/ranger/usergroupsync/TestLdapUserGroup.java b/ugsync/src/test/java/org/apache/ranger/usergroupsync/TestLdapUserGroup.java
index 78bc56c..2011b5b 100644
--- a/ugsync/src/test/java/org/apache/ranger/usergroupsync/TestLdapUserGroup.java
+++ b/ugsync/src/test/java/org/apache/ranger/usergroupsync/TestLdapUserGroup.java
@@ -95,6 +95,114 @@ public class TestLdapUserGroup extends AbstractLdapTestUnit{
 	}
 
 	@Test
+	public void testUserSearchFilterWithWildcards() throws Throwable {
+		config.setUserNameAttribute("sAMAccountName");
+		config.setUserSearchBase("DC=ranger,DC=qe,DC=hortonworks,DC=com");
+		config.setUserSearchFilter("");
+		config.setGroupSearchBase("OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
+		config.setUserGroupMemberAttributeName("member");
+		config.setUserObjectClass("organizationalPerson");
+		config.setGroupObjectClass("groupOfNames");
+		config.setGroupSearchEnabled(true);
+		config.setPagedResultsEnabled(true);
+		config.setGroupnames("memberof=cn=Group2*");
+		ldapBuilder.init();
+		sink.init();
+		ldapBuilder.updateSink(sink);
+		assertEquals(10, sink.getTotalUsers());
+	}
+
+	@Test
+	public void testUserSearchFilterWithShortname() throws Throwable {
+		config.setUserNameAttribute("sAMAccountName");
+		config.setUserSearchBase("DC=ranger,DC=qe,DC=hortonworks,DC=com");
+		config.setUserSearchFilter("");
+		config.setGroupSearchBase("OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
+		config.setUserGroupMemberAttributeName("member");
+		config.setUserObjectClass("organizationalPerson");
+		config.setGroupObjectClass("groupOfNames");
+		config.setGroupSearchEnabled(true);
+		config.setPagedResultsEnabled(true);
+		config.setGroupnames("memberof=CN=Group20");
+		ldapBuilder.init();
+		sink.init();
+		ldapBuilder.updateSink(sink);
+		assertEquals(10, sink.getTotalUsers());
+	}
+
+	@Test
+	public void testUserSearchFilterWithMultipleShortname() throws Throwable {
+		config.setUserNameAttribute("sAMAccountName");
+		config.setUserSearchBase("DC=ranger,DC=qe,DC=hortonworks,DC=com");
+		config.setUserSearchFilter("");
+		config.setGroupSearchBase("OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
+		config.setUserGroupMemberAttributeName("member");
+		config.setUserObjectClass("organizationalPerson");
+		config.setGroupObjectClass("groupOfNames");
+		config.setGroupSearchEnabled(true);
+		config.setPagedResultsEnabled(true);
+		config.setGroupnames("memberof=CN=Group20;CN=Group19");
+		ldapBuilder.init();
+		sink.init();
+		ldapBuilder.updateSink(sink);
+		assertEquals(21, sink.getTotalUsers());
+	}
+
+	@Test
+	public void testUserSearchFilterWithMultipleWildcards() throws Throwable {
+		config.setUserNameAttribute("sAMAccountName");
+		config.setUserSearchBase("DC=ranger,DC=qe,DC=hortonworks,DC=com");
+		config.setUserSearchFilter("");
+		config.setGroupSearchBase("OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
+		config.setUserGroupMemberAttributeName("member");
+		config.setUserObjectClass("organizationalPerson");
+		config.setGroupObjectClass("groupOfNames");
+		config.setGroupSearchEnabled(true);
+		config.setPagedResultsEnabled(true);
+		config.setGroupnames("memberof=CN=Group2*;memberof=CN=Group1*");
+		ldapBuilder.init();
+		sink.init();
+		ldapBuilder.updateSink(sink);
+		assertEquals(111, sink.getTotalUsers());
+	}
+
+	@Test
+	public void testUserSearchFilterWithMultipleDNs() throws Throwable {
+		config.setUserNameAttribute("sAMAccountName");
+		config.setUserSearchBase("DC=ranger,DC=qe,DC=hortonworks,DC=com");
+		config.setUserSearchFilter("");
+		config.setGroupSearchBase("OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
+		config.setUserGroupMemberAttributeName("member");
+		config.setUserObjectClass("organizationalPerson");
+		config.setGroupObjectClass("groupOfNames");
+		config.setGroupSearchEnabled(true);
+		config.setPagedResultsEnabled(true);
+		config.setGroupnames("memberof=CN=Group14,OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com;memberof=CN=Group20,OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
+		ldapBuilder.init();
+		sink.init();
+		ldapBuilder.updateSink(sink);
+		assertEquals(21, sink.getTotalUsers());
+	}
+
+	@Test
+	public void testUserSearchFilterWithInvalidDNs() throws Throwable {
+		config.setUserNameAttribute("sAMAccountName");
+		config.setUserSearchBase("DC=ranger,DC=qe,DC=hortonworks,DC=com");
+		config.setUserSearchFilter("");
+		config.setGroupSearchBase("OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
+		config.setUserGroupMemberAttributeName("member");
+		config.setUserObjectClass("organizationalPerson");
+		config.setGroupObjectClass("groupOfNames");
+		config.setGroupSearchEnabled(true);
+		config.setPagedResultsEnabled(true);
+		config.setGroupnames("uid=Group14,OU=Groups,DC=ranger;memberuid=Group20,OU=Groups,DC=ranger,DC=qe");
+		ldapBuilder.init();
+		sink.init();
+		ldapBuilder.updateSink(sink);
+		assertEquals(111, sink.getTotalUsers());
+	}
+
+	@Test
 	public void testUpdateSinkTotalUsers() throws Throwable {
 		config.setUserNameAttribute("sAMAccountName");
 		config.setUserSearchBase("cn=users,DC=ranger,DC=qe,DC=hortonworks,DC=com");
@@ -126,6 +234,7 @@ public class TestLdapUserGroup extends AbstractLdapTestUnit{
 		config.setGroupSearchEnabled(false);
 		config.setPagedResultsEnabled(false);
 		config.setGroupSearchFirstEnabled(false);
+		config.setGroupnames("");
 		//config.setGroupHierarchyLevel(0);
 		ldapBuilder.init();
 		sink.init();
@@ -137,7 +246,6 @@ public class TestLdapUserGroup extends AbstractLdapTestUnit{
 	public void testUpdateSinkUserFilter() throws Throwable {
 		config.setUserNameAttribute("sAMAccountName");
 		config.setUserSearchBase("cn=users,DC=ranger,DC=qe,DC=hortonworks,DC=com");
-		//config.setUserSearchFilter("(|(memberof=cn=usersGroup9,ou=Group,dc=openstacklocal)(memberof=cn=usersGroup4,ou=Group,dc=openstacklocal))");
 		config.setUserSearchFilter("(|(memberof=CN=Group10,OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com)(memberof=CN=Group11,OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com))");
 		config.setGroupSearchBase("OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
 		config.setUserGroupMemberAttributeName("member");
@@ -256,6 +364,7 @@ public class TestLdapUserGroup extends AbstractLdapTestUnit{
 		config.setGroupSearchEnabled(false);
 		config.setPagedResultsEnabled(true);
 		config.setGroupSearchFirstEnabled(false);
+		config.setGroupnames("");
 		ldapBuilder.init();
 		sink.init();
 		ldapBuilder.updateSink(sink);