You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by ve...@apache.org on 2017/01/25 06:36:53 UTC
[2/2] incubator-ranger git commit: RANGER-1211: Support
incremental/Delta Sync with AD/LDAP for Ranger Usersync
RANGER-1211: Support incremental/Delta Sync with AD/LDAP for Ranger Usersync
Signed-off-by: Velmurugan Periasamy <ve...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/incubator-ranger/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ranger/commit/2261a9dc
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ranger/tree/2261a9dc
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ranger/diff/2261a9dc
Branch: refs/heads/master
Commit: 2261a9dca231b4b3009fc96e362ac64f9f09ece3
Parents: 7a1c722
Author: Sailaja Polavarapu <sp...@hortonworks.com>
Authored: Tue Jan 24 13:58:52 2017 -0800
Committer: Velmurugan Periasamy <ve...@apache.org>
Committed: Wed Jan 25 01:36:35 2017 -0500
----------------------------------------------------------------------
.../java/org/apache/ranger/biz/XUserMgr.java | 66 ++
.../java/org/apache/ranger/rest/XUserREST.java | 24 +
.../ranger/security/context/RangerAPIList.java | 1 +
.../org/apache/ranger/view/VXGroupUserInfo.java | 66 ++
.../process/LdapDeltaUserGroupBuilder.java | 819 +++++++++++++++++++
.../process/LdapPolicyMgrUserGroupBuilder.java | 809 ++++++++++++++++++
.../config/UserGroupSyncConfig.java | 69 +-
.../unixusersync/model/GroupUserInfo.java | 40 +
.../process/PolicyMgrUserGroupBuilder.java | 14 +
.../ranger/usergroupsync/UserGroupSink.java | 4 +
.../LdapPolicyMgrUserGroupBuilderTest.java | 89 ++
.../ranger/usergroupsync/TestLdapUserGroup.java | 107 ++-
ugsync/src/test/resources/ADSchema.ldif | 267 +++---
.../src/test/resources/ranger-ugsync-site.xml | 15 +
14 files changed, 2259 insertions(+), 131 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/2261a9dc/security-admin/src/main/java/org/apache/ranger/biz/XUserMgr.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/biz/XUserMgr.java b/security-admin/src/main/java/org/apache/ranger/biz/XUserMgr.java
index 189a254..dd6e6ca 100644
--- a/security-admin/src/main/java/org/apache/ranger/biz/XUserMgr.java
+++ b/security-admin/src/main/java/org/apache/ranger/biz/XUserMgr.java
@@ -88,6 +88,7 @@ import org.apache.ranger.view.VXGroup;
import org.apache.ranger.view.VXGroupGroup;
import org.apache.ranger.view.VXGroupList;
import org.apache.ranger.view.VXGroupUser;
+import org.apache.ranger.view.VXGroupUserInfo;
import org.apache.ranger.view.VXGroupUserList;
import org.apache.ranger.view.VXLong;
import org.apache.ranger.view.VXPermMap;
@@ -541,6 +542,71 @@ public class XUserMgr extends XUserMgrBase {
return vxUGInfo;
}
+
+ @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
+ public VXGroupUserInfo createXGroupUserFromMap(
+ VXGroupUserInfo vXGroupUserInfo) {
+ checkAdminAccess();
+ VXGroupUserInfo vxGUInfo = new VXGroupUserInfo();
+
+ VXGroup vXGroup = vXGroupUserInfo.getXgroupInfo();
+ // Add the group user mappings for a given group to x_group_user table
+ /*XXGroup xGroup = daoManager.getXXGroup().findByGroupName(vXGroup.getName());
+ if (xGroup == null) {
+ return vxGUInfo;
+ }*/
+
+ List<VXUser> vxu = new ArrayList<VXUser>();
+
+ for (VXUser vXUser : vXGroupUserInfo.getXuserInfo()) {
+ XXUser xUser = daoManager.getXXUser().findByUserName(vXUser.getName());
+ if (xUser != null) {
+ // Add or update group user mapping only if the user already exists in x_user table.
+ vXGroup = xGroupService.createXGroupWithOutLogin(vXGroup);
+ vxGUInfo.setXgroupInfo(vXGroup);
+ vxu.add(vXUser);
+ VXGroupUser vXGroupUser = new VXGroupUser();
+ vXGroupUser.setUserId(xUser.getId());
+ vXGroupUser.setName(vXGroup.getName());
+ vXGroupUser = xGroupUserService
+ .createXGroupUserWithOutLogin(vXGroupUser);
+ }
+ }
+
+ vxGUInfo.setXuserInfo(vxu);
+
+ return vxGUInfo;
+ }
+
+ public VXGroupUserInfo getXGroupUserFromMap(
+ String groupName) {
+ checkAdminAccess();
+ VXGroupUserInfo vxGUInfo = new VXGroupUserInfo();
+
+ XXGroup xGroup = daoManager.getXXGroup().findByGroupName(groupName);
+ if (xGroup == null) {
+ return vxGUInfo;
+ }
+ SearchCriteria searchCriteria = new SearchCriteria();
+ searchCriteria.addParam("xGroupId", xGroup.getId());
+
+ VXGroupUserList vxGroupUserList = searchXGroupUsers(searchCriteria);
+ List<VXUser> vxu = new ArrayList<VXUser>();
+ logger.debug("removing all the group user mapping for : " + xGroup.getName());
+ for (VXGroupUser groupUser : vxGroupUserList.getList()) {
+ XXUser xUser = daoManager.getXXUser().getById(groupUser.getUserId());
+ if (xUser != null) {
+ VXUser vxUser = new VXUser();
+ vxUser.setName(xUser.getName());
+ vxu.add(vxUser);
+ }
+
+ }
+ vxGUInfo.setXuserInfo(vxu);
+
+ return vxGUInfo;
+ }
+
public VXUser createXUserWithOutLogin(VXUser vXUser) {
checkAdminAccess();
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/2261a9dc/security-admin/src/main/java/org/apache/ranger/rest/XUserREST.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/XUserREST.java b/security-admin/src/main/java/org/apache/ranger/rest/XUserREST.java
index 646ade6..75ecec9 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/XUserREST.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/XUserREST.java
@@ -67,6 +67,7 @@ import org.apache.ranger.view.VXGroupList;
import org.apache.ranger.view.VXGroupPermission;
import org.apache.ranger.view.VXGroupPermissionList;
import org.apache.ranger.view.VXGroupUser;
+import org.apache.ranger.view.VXGroupUserInfo;
import org.apache.ranger.view.VXGroupUserList;
import org.apache.ranger.view.VXLong;
import org.apache.ranger.view.VXModuleDef;
@@ -173,6 +174,14 @@ public class XUserREST {
}
@POST
+ @Path("/groups/groupinfo")
+ @Produces({ "application/xml", "application/json" })
+ @PreAuthorize("hasRole('ROLE_SYS_ADMIN')")
+ public VXGroupUserInfo createXGroupUserFromMap(VXGroupUserInfo vXGroupUserInfo) {
+ return xUserMgr.createXGroupUserFromMap(vXGroupUserInfo);
+ }
+
+ @POST
@Path("/secure/groups")
@Produces({ "application/xml", "application/json" })
@PreAuthorize("hasRole('ROLE_SYS_ADMIN')")
@@ -413,6 +422,21 @@ public class XUserREST {
request, xGroupUserService.sortFields);
return xUserMgr.searchXGroupUsers(searchCriteria);
}
+
+ /**
+ * Implements the traditional search functionalities for XGroupUsers by Group name
+ *
+ * @param request
+ * @return
+ */
+ @GET
+ @Path("/groupusers/groupName/{groupName}")
+ @Produces({ "application/xml", "application/json" })
+ @PreAuthorize("@rangerPreAuthSecurityHandler.isAPIAccessible(\"" + RangerAPIList.GET_X_GROUP_USERS_BY_GROUP_NAME + "\")")
+ public VXGroupUserInfo getXGroupUsersByGroupName(@Context HttpServletRequest request,
+ @PathParam("groupName") String groupName) {
+ return xUserMgr.getXGroupUserFromMap(groupName);
+ }
@GET
@Path("/groupusers/count")
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/2261a9dc/security-admin/src/main/java/org/apache/ranger/security/context/RangerAPIList.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/security/context/RangerAPIList.java b/security-admin/src/main/java/org/apache/ranger/security/context/RangerAPIList.java
index dd74e8f..460c7fd 100644
--- a/security-admin/src/main/java/org/apache/ranger/security/context/RangerAPIList.java
+++ b/security-admin/src/main/java/org/apache/ranger/security/context/RangerAPIList.java
@@ -154,6 +154,7 @@ public class RangerAPIList {
public static final String UPDATE_X_GROUP_USER = "XUserREST.updateXGroupUser";
public static final String DELETE_X_GROUP_USER = "XUserREST.deleteXGroupUser";
public static final String SEARCH_X_GROUP_USERS = "XUserREST.searchXGroupUsers";
+ public static final String GET_X_GROUP_USERS_BY_GROUP_NAME = "XUserREST.getXGroupUsersByGroupName";
public static final String COUNT_X_GROUP_USERS = "XUserREST.countXGroupUsers";
public static final String GET_X_GROUP_GROUP = "XUserREST.getXGroupGroup";
public static final String CREATE_X_GROUP_GROUP = "XUserREST.createXGroupGroup";
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/2261a9dc/security-admin/src/main/java/org/apache/ranger/view/VXGroupUserInfo.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/view/VXGroupUserInfo.java b/security-admin/src/main/java/org/apache/ranger/view/VXGroupUserInfo.java
new file mode 100644
index 0000000..9501a21
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/view/VXGroupUserInfo.java
@@ -0,0 +1,66 @@
+/*
+ * 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.view;
+
+/**
+ * UserGroupInfo
+ *
+ */
+
+import java.util.List;
+
+import javax.xml.bind.annotation.*;
+
+import org.codehaus.jackson.annotate.JsonAutoDetect;
+import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+@JsonAutoDetect(getterVisibility=Visibility.NONE, setterVisibility=Visibility.NONE, fieldVisibility=Visibility.ANY)
+@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL )
+@JsonIgnoreProperties(ignoreUnknown=true)
+@XmlRootElement
+public class VXGroupUserInfo extends VXDataObject implements java.io.Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ VXGroup xgroupInfo;
+ List<VXUser> xuserInfo;
+
+ public VXGroupUserInfo ( ) {
+ }
+
+ public VXGroup getXgroupInfo() {
+ return xgroupInfo;
+ }
+
+ public void setXgroupInfo(VXGroup xgroupInfo) {
+ this.xgroupInfo = xgroupInfo;
+ }
+
+ public List<VXUser> getXuserInfo() {
+ return xuserInfo;
+ }
+
+ public void setXuserInfo(List<VXUser> xuserInfo) {
+ this.xuserInfo = xuserInfo;
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/2261a9dc/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapDeltaUserGroupBuilder.java
----------------------------------------------------------------------
diff --git a/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapDeltaUserGroupBuilder.java b/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapDeltaUserGroupBuilder.java
new file mode 100644
index 0000000..0779918
--- /dev/null
+++ b/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapDeltaUserGroupBuilder.java
@@ -0,0 +1,819 @@
+/*
+ * 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.ldapusersync.process;
+
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import javax.naming.Context;
+import javax.naming.InvalidNameException;
+import javax.naming.NamingEnumeration;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+import javax.naming.ldap.Control;
+import javax.naming.ldap.InitialLdapContext;
+import javax.naming.ldap.LdapContext;
+import javax.naming.ldap.PagedResultsControl;
+import javax.naming.ldap.PagedResultsResponseControl;
+import javax.naming.ldap.StartTlsRequest;
+import javax.naming.ldap.StartTlsResponse;
+
+import org.apache.log4j.Logger;
+import org.apache.ranger.unixusersync.config.UserGroupSyncConfig;
+import org.apache.ranger.usergroupsync.AbstractUserGroupSource;
+import org.apache.ranger.usergroupsync.UserGroupSink;
+
+import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.Table;
+
+public class LdapDeltaUserGroupBuilder extends AbstractUserGroupSource {
+
+ private static final Logger LOG = Logger.getLogger(LdapDeltaUserGroupBuilder.class);
+
+ private static final int PAGE_SIZE = 500;
+ 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
+
+ private String ldapUrl;
+ private String ldapBindDn;
+ private String ldapBindPassword;
+ private String ldapAuthenticationMechanism;
+ private String ldapReferral;
+ private String searchBase;
+
+ private String[] userSearchBase;
+ private String userNameAttribute;
+ private int userSearchScope;
+ private String userObjectClass;
+ private String userSearchFilter;
+ private String extendedUserSearchFilter;
+ private SearchControls userSearchControls;
+ private Set<String> userGroupNameAttributeSet;
+
+ private boolean pagedResultsEnabled = true;
+ private int pagedResultsSize = 500;
+
+ private boolean groupSearchFirstEnabled = false;
+ private boolean userSearchEnabled = false;
+ private boolean groupSearchEnabled = true;
+ private String[] groupSearchBase;
+ private int groupSearchScope;
+ private String groupObjectClass;
+ private String groupSearchFilter;
+ private String extendedGroupSearchFilter;
+ private String extendedAllGroupsSearchFilter;
+ private SearchControls groupSearchControls;
+ private String groupMemberAttributeName;
+ private String groupNameAttribute;
+
+ private LdapContext ldapContext;
+ StartTlsResponse tls;
+
+ private boolean userNameCaseConversionFlag = false;
+ private boolean groupNameCaseConversionFlag = false;
+ private boolean userNameLowerCaseFlag = false;
+ private boolean groupNameLowerCaseFlag = false;
+
+ private boolean groupUserMapSyncEnabled = false;
+
+ //private Map<String, UserInfo> userGroupMap;
+
+ private Table<String, String, String> groupUserTable;
+
+ public static void main(String[] args) throws Throwable {
+ LdapDeltaUserGroupBuilder ugBuilder = new LdapDeltaUserGroupBuilder();
+ ugBuilder.init();
+ }
+
+ public LdapDeltaUserGroupBuilder() {
+ super();
+ LOG.info("LdapDeltaUserGroupBuilder created");
+
+ String userNameCaseConversion = config.getUserNameCaseConversion();
+
+ if (UserGroupSyncConfig.UGSYNC_NONE_CASE_CONVERSION_VALUE.equalsIgnoreCase(userNameCaseConversion)) {
+ userNameCaseConversionFlag = false;
+ }
+ else {
+ userNameCaseConversionFlag = true;
+ userNameLowerCaseFlag = UserGroupSyncConfig.UGSYNC_LOWER_CASE_CONVERSION_VALUE.equalsIgnoreCase(userNameCaseConversion);
+ }
+
+ String groupNameCaseConversion = config.getGroupNameCaseConversion();
+
+ if (UserGroupSyncConfig.UGSYNC_NONE_CASE_CONVERSION_VALUE.equalsIgnoreCase(groupNameCaseConversion)) {
+ groupNameCaseConversionFlag = false;
+ }
+ else {
+ groupNameCaseConversionFlag = true;
+ groupNameLowerCaseFlag = UserGroupSyncConfig.UGSYNC_LOWER_CASE_CONVERSION_VALUE.equalsIgnoreCase(groupNameCaseConversion);
+ }
+ }
+
+ @Override
+ public void init() throws Throwable{
+ deltaSyncUserTime = 0;
+ deltaSyncGroupTime = 0;
+ DateFormat dateFormat = new SimpleDateFormat("yyyyMMddhhmmss");
+ deltaSyncUserTimeStamp = dateFormat.format(new Date(0));
+ deltaSyncGroupTimeStamp = dateFormat.format(new Date(0));
+ setConfig();
+ }
+
+ private void createLdapContext() throws Throwable {
+ Properties env = new Properties();
+ env.put(Context.INITIAL_CONTEXT_FACTORY,
+ "com.sun.jndi.ldap.LdapCtxFactory");
+ env.put(Context.PROVIDER_URL, ldapUrl);
+ if (ldapUrl.startsWith("ldaps") && (config.getSSLTrustStorePath() != null && !config.getSSLTrustStorePath().trim().isEmpty())) {
+ env.put("java.naming.ldap.factory.socket", "org.apache.ranger.ldapusersync.process.CustomSSLSocketFactory");
+ }
+
+ ldapContext = new InitialLdapContext(env, null);
+ if (!ldapUrl.startsWith("ldaps")) {
+ if (config.isStartTlsEnabled()) {
+ tls = (StartTlsResponse) ldapContext.extendedOperation(new StartTlsRequest());
+ if (config.getSSLTrustStorePath() != null && !config.getSSLTrustStorePath().trim().isEmpty()) {
+ tls.negotiate(CustomSSLSocketFactory.getDefault());
+ } else {
+ tls.negotiate();
+ }
+ LOG.info("Starting TLS session...");
+ }
+ }
+
+ ldapContext.addToEnvironment(Context.SECURITY_PRINCIPAL, ldapBindDn);
+ ldapContext.addToEnvironment(Context.SECURITY_CREDENTIALS, ldapBindPassword);
+ ldapContext.addToEnvironment(Context.SECURITY_AUTHENTICATION, ldapAuthenticationMechanism);
+ ldapContext.addToEnvironment(Context.REFERRAL, ldapReferral);
+ }
+
+ private void setConfig() throws Throwable {
+ LOG.info("LdapDeltaUserGroupBuilder initialization started");
+
+ groupSearchFirstEnabled = config.isGroupSearchFirstEnabled();
+ 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();
+
+ Set<String> userSearchAttributes = new HashSet<String>();
+ userSearchAttributes.add(userNameAttribute);
+ // For Group based search, user's group name attribute should not be added to the user search attributes
+ if (!groupSearchFirstEnabled && !groupSearchEnabled) {
+ userGroupNameAttributeSet = config.getUserGroupNameAttributeSet();
+ for (String useGroupNameAttribute : userGroupNameAttributeSet) {
+ userSearchAttributes.add(useGroupNameAttribute);
+ }
+ }
+ userSearchAttributes.add("uSNChanged");
+ userSearchAttributes.add("modifytimestamp");
+ userSearchControls = new SearchControls();
+ userSearchControls.setSearchScope(userSearchScope);
+ userSearchControls.setReturningAttributes(userSearchAttributes.toArray(
+ new String[userSearchAttributes.size()]));
+
+ 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();
+
+ extendedGroupSearchFilter = "(&" + extendedGroupSearchFilter + "(|(" + groupMemberAttributeName + "={0})(" + groupMemberAttributeName + "={1})))";
+ groupUserMapSyncEnabled = config.isGroupUserMapSyncEnabled();
+
+ groupSearchControls = new SearchControls();
+ groupSearchControls.setSearchScope(groupSearchScope);
+
+ Set<String> groupSearchAttributes = new HashSet<String>();
+ groupSearchAttributes.add(groupNameAttribute);
+ groupSearchAttributes.add(groupMemberAttributeName);
+ groupSearchAttributes.add("uSNChanged");
+ groupSearchAttributes.add("modifytimestamp");
+ groupSearchControls.setReturningAttributes(groupSearchAttributes.toArray(
+ new String[groupSearchAttributes.size()]));
+
+ if (LOG.isInfoEnabled()) {
+ LOG.info("LdapDeltaUserGroupBuilder 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
+ + ", 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
+ + ", groupUserMapSyncEnabled: " + groupUserMapSyncEnabled
+ + ", groupSearchFirstEnabled: " + groupSearchFirstEnabled
+ + ", userSearchEnabled: " + userSearchEnabled
+ + ", ldapReferral: " + ldapReferral
+ );
+ }
+
+ }
+
+ private void closeLdapContext() throws Throwable {
+ if (tls != null) {
+ tls.close();
+ }
+ if (ldapContext != null) {
+ ldapContext.close();
+ }
+ }
+
+ @Override
+ public boolean isChanged() {
+ // we do not want to get the full ldap dit and check whether anything has changed
+ return true;
+ }
+
+ @Override
+ public void updateSink(UserGroupSink sink) throws Throwable {
+ LOG.info("LdapDeltaUserGroupBuilder updateSink started");
+ //userGroupMap = new HashMap<String, UserInfo>();
+ groupUserTable = HashBasedTable.create();
+ if (!groupSearchFirstEnabled) {
+ LOG.info("Performing user search first");
+ getUsers(sink);
+ if (groupSearchEnabled) {
+ getGroups(sink);
+ }
+ //LOG.debug("Total No. of users saved = " + groupUserTable.columnKeySet().size());
+
+ } else {
+ LOG.info("Performing Group search first");
+ getGroups(sink);
+ if (userSearchEnabled) {
+ LOG.info("User search is enabled and hence computing user membership.");
+ getUsers(sink);
+ }
+ }
+ if (groupUserTable.isEmpty()) {
+ //System.out.println("groupUserTable is empty!!");
+ return;
+ }
+ Iterator<String> groupUserTableIterator = groupUserTable.rowKeySet().iterator();
+ while (groupUserTableIterator.hasNext()) {
+ String groupName = groupUserTableIterator.next();
+ //System.out.println("Group name from the groupUserTable: " + groupName);
+ Map<String,String> groupUsersMap = groupUserTable.row(groupName);
+ Set<String> userSet = new HashSet<String>();
+ for(Map.Entry<String, String> entry : groupUsersMap.entrySet()){
+ String transformUserName = userNameTransform(entry.getKey());
+ userSet.add(transformUserName);
+ }
+ List<String> userList = new ArrayList<>(userSet);
+ String transformGroupName = groupNameTransform(groupName);
+ try {
+ sink.addOrUpdateGroup(transformGroupName, userList);
+ } catch (Throwable t) {
+ LOG.error("sink.addOrUpdateGroup failed with exception: " + t.getMessage()
+ + ", for group: " + transformGroupName
+ + ", users: " + userList);
+ }
+ }
+ }
+
+ private void getUsers(UserGroupSink sink) throws Throwable {
+ NamingEnumeration<SearchResult> userSearchResultEnum = null;
+ NamingEnumeration<SearchResult> groupSearchResultEnum = null;
+ try {
+ createLdapContext();
+ int total;
+ // Activate paged results
+ if (pagedResultsEnabled) {
+ ldapContext.setRequestControls(new Control[]{
+ new PagedResultsControl(pagedResultsSize, Control.NONCRITICAL) });
+ }
+ DateFormat dateFormat = new SimpleDateFormat("yyyyMMddhhmmss");
+ extendedUserSearchFilter = "(objectclass=" + userObjectClass + ")(|(uSNChanged>=" + deltaSyncUserTime + ")(modifyTimestamp>=" + deltaSyncUserTimeStamp + "Z))";
+
+ if (userSearchFilter != null && !userSearchFilter.trim().isEmpty()) {
+ String customFilter = userSearchFilter.trim();
+ if (!customFilter.startsWith("(")) {
+ customFilter = "(" + customFilter + ")";
+ }
+
+ extendedUserSearchFilter = "(&" + extendedUserSearchFilter + customFilter + ")";
+ } else {
+ extendedUserSearchFilter = "(&" + extendedUserSearchFilter + ")";
+ }
+ LOG.info("extendedUserSearchFilter = " + extendedUserSearchFilter);
+
+ long highestdeltaSyncUserTime = deltaSyncUserTime;
+
+ // When multiple OUs are configured, go through each OU as the user search base to search for users.
+ for (int ou=0; ou<userSearchBase.length; ou++) {
+ byte[] cookie = null;
+ int counter = 0;
+ try {
+ do {
+ userSearchResultEnum = ldapContext
+ .search(userSearchBase[ou], extendedUserSearchFilter,
+ userSearchControls);
+
+ while (userSearchResultEnum.hasMore()) {
+ // searchResults contains all the user entries
+ final SearchResult userEntry = userSearchResultEnum.next();
+
+ if (userEntry == null) {
+ if (LOG.isInfoEnabled()) {
+ LOG.info("userEntry null, skipping sync for the entry");
+ }
+ continue;
+ }
+
+ Attributes attributes = userEntry.getAttributes();
+ if (attributes == null) {
+ if (LOG.isInfoEnabled()) {
+ LOG.info("attributes missing for entry " + userEntry.getNameInNamespace() +
+ ", skipping sync");
+ }
+ continue;
+ }
+
+ Attribute userNameAttr = attributes.get(userNameAttribute);
+ if (userNameAttr == null) {
+ if (LOG.isInfoEnabled()) {
+ LOG.info(userNameAttribute + " missing for entry " + userEntry.getNameInNamespace() +
+ ", skipping sync");
+ }
+ continue;
+ }
+
+ String userName = (String) userNameAttr.get();
+
+ if (userName == null || userName.trim().isEmpty()) {
+ if (LOG.isInfoEnabled()) {
+ LOG.info(userNameAttribute + " empty for entry " + userEntry.getNameInNamespace() +
+ ", skipping sync");
+ }
+ continue;
+ }
+
+ Attribute timeStampAttr = attributes.get("uSNChanged");
+ if (timeStampAttr != null) {
+ String uSNChangedVal = (String) timeStampAttr.get();
+ long currentDeltaSyncTime = Long.parseLong(uSNChangedVal);
+ LOG.info("uSNChangedVal = " + uSNChangedVal + "and currentDeltaSyncTime = " + currentDeltaSyncTime);
+ if (currentDeltaSyncTime > highestdeltaSyncUserTime) {
+ highestdeltaSyncUserTime = currentDeltaSyncTime;
+ }
+ } else {
+ timeStampAttr = attributes.get("modifytimestamp");
+ if (timeStampAttr != null) {
+ String timeStampVal = (String) timeStampAttr.get();
+ Date parseDate = dateFormat.parse(timeStampVal);
+ long currentDeltaSyncTime = parseDate.getTime();
+ LOG.info("timeStampVal = " + timeStampVal + "and currentDeltaSyncTime = " + currentDeltaSyncTime);
+ if (currentDeltaSyncTime > highestdeltaSyncUserTime) {
+ highestdeltaSyncUserTime = currentDeltaSyncTime;
+ deltaSyncUserTimeStamp = timeStampVal;
+ }
+ }
+ }
+
+ if (!groupSearchFirstEnabled) {
+ String transformUserName = userNameTransform(userName);
+ try {
+ sink.addOrUpdateUser(transformUserName);
+ } catch (Throwable t) {
+ LOG.error("sink.addOrUpdateUser failed with exception: " + t.getMessage()
+ + ", for user: " + transformUserName);
+ }
+ Set<String> groups = new HashSet<String>();
+
+ // Get all the groups from the group name attribute of the user only when group search is not enabled.
+ if (!groupSearchEnabled) {
+ for (String useGroupNameAttribute : userGroupNameAttributeSet) {
+ Attribute userGroupfAttribute = userEntry.getAttributes().get(useGroupNameAttribute);
+ if (userGroupfAttribute != null) {
+ NamingEnumeration<?> groupEnum = userGroupfAttribute.getAll();
+ while (groupEnum.hasMore()) {
+ String gName = getShortGroupName((String) groupEnum
+ .next());
+ String transformGroupName = groupNameTransform(gName);
+ groups.add(transformGroupName);
+ }
+ }
+ }
+ }
+
+ List<String> groupList = new ArrayList<String>(groups);
+ try {
+ sink.addOrUpdateUser(transformUserName, groupList);
+ } catch (Throwable t) {
+ LOG.error("sink.addOrUpdateUserGroups failed with exception: " + t.getMessage()
+ + ", for user: " + transformUserName + " and groups: " + groupList);
+ }
+ counter++;
+ if (counter <= 2000) {
+ if (LOG.isInfoEnabled()) {
+ LOG.info("Updating user count: " + counter
+ + ", userName: " + userName + ", groupList: "
+ + groupList);
+ }
+ if ( counter == 2000 ) {
+ LOG.info("===> 2000 user 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 user count: " + counter
+ + ", userName: " + userName + ", groupList: "
+ + groupList);
+ } else {
+ if ( counter % 100 == 0) {
+ LOG.info("Synced " + counter + " users till now");
+ }
+ }
+ }
+ } else {
+ // If the user from the search result is present in the group user table,
+ // then addorupdate user to ranger admin.
+ String userFullName = (userEntry.getNameInNamespace()).toLowerCase();
+ LOG.debug("Chekcing if the user " + userFullName + " is part of the retrieved groups");
+ if (groupUserTable.containsColumn(userFullName) || groupUserTable.containsColumn(userName)) {
+ String transformUserName = userNameTransform(userName);
+ try {
+ sink.addOrUpdateUser(transformUserName);
+ } catch (Throwable t) {
+ LOG.error("sink.addOrUpdateUser failed with exception: " + t.getMessage()
+ + ", for user: " + transformUserName);
+ }
+ }
+ }
+
+ }
+
+ // 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) {
+ LOG.debug("END-OF-PAGE total : " + total);
+ } else {
+ LOG.debug("END-OF-PAGE total : unknown");
+ }
+ cookie = prrc.getCookie();
+ }
+ }
+ } else {
+ LOG.debug("No controls were sent from the server");
+ }
+ // Re-activate paged results
+ if (pagedResultsEnabled) {
+ ldapContext.setRequestControls(new Control[]{
+ new PagedResultsControl(PAGE_SIZE, cookie, Control.CRITICAL) });
+ }
+ } while (cookie != null);
+ LOG.info("LdapDeltaUserGroupBuilder.getUsers() completed with user count: "
+ + counter);
+ } catch (Throwable t) {
+ LOG.error("LdapDeltaUserGroupBuilder.getUsers() failed with exception: " + t);
+ LOG.info("LdapDeltaUserGroupBuilder.getUsers() user count: "
+ + counter);
+ }
+ }
+ if (deltaSyncUserTime < highestdeltaSyncUserTime) {
+ // Incrementing highestdeltaSyncUserTime (for AD) in order to avoid search record repetition for next sync cycle.
+ deltaSyncUserTime = highestdeltaSyncUserTime+1;
+ // Incrementing the highest timestamp value (for Openldap) with 1min in order to avoid search record repetition for next sync cycle.
+ deltaSyncUserTimeStamp = dateFormat.format(new Date(highestdeltaSyncUserTime + 60000l));
+ }
+
+ } finally {
+ if (userSearchResultEnum != null) {
+ userSearchResultEnum.close();
+ }
+ if (groupSearchResultEnum != null) {
+ groupSearchResultEnum.close();
+ }
+ closeLdapContext();
+ }
+ }
+
+ private void getGroups(UserGroupSink sink) throws Throwable {
+ NamingEnumeration<SearchResult> groupSearchResultEnum = null;
+ try {
+ createLdapContext();
+ int total;
+ // Activate paged results
+ if (pagedResultsEnabled) {
+ ldapContext.setRequestControls(new Control[]{
+ new PagedResultsControl(pagedResultsSize, Control.NONCRITICAL) });
+ }
+ extendedGroupSearchFilter = "(objectclass=" + groupObjectClass + ")";
+ if (groupSearchFilter != null && !groupSearchFilter.trim().isEmpty()) {
+ String customFilter = groupSearchFilter.trim();
+ if (!customFilter.startsWith("(")) {
+ customFilter = "(" + customFilter + ")";
+ }
+ extendedGroupSearchFilter = extendedGroupSearchFilter + customFilter;
+ }
+
+ DateFormat dateFormat = new SimpleDateFormat("yyyyMMddhhmmss");
+ extendedAllGroupsSearchFilter = "(&" + extendedGroupSearchFilter + "(|(uSNChanged>=" + deltaSyncGroupTime + ")(modifyTimestamp>=" + deltaSyncGroupTimeStamp + "Z)))";
+
+ LOG.info("extendedAllGroupsSearchFilter = " + extendedAllGroupsSearchFilter);
+ long highestdeltaSyncGroupTime = deltaSyncGroupTime;
+ for (int ou=0; ou<groupSearchBase.length; ou++) {
+ byte[] cookie = null;
+ int counter = 0;
+ try {
+ do {
+ groupSearchResultEnum = ldapContext
+ .search(groupSearchBase[ou], extendedAllGroupsSearchFilter,
+ groupSearchControls);
+ while (groupSearchResultEnum.hasMore()) {
+ final SearchResult groupEntry = groupSearchResultEnum.next();
+ if (groupEntry == null) {
+ if (LOG.isInfoEnabled()) {
+ LOG.info("groupEntry null, skipping sync for the entry");
+ }
+ continue;
+ }
+ counter++;
+ Attribute groupNameAttr = groupEntry.getAttributes().get(groupNameAttribute);
+ if (groupNameAttr == null) {
+ if (LOG.isInfoEnabled()) {
+ LOG.info(groupNameAttribute + " empty for entry " + groupEntry.getNameInNamespace() +
+ ", skipping sync");
+ }
+ continue;
+ }
+ String gName = (String) groupNameAttr.get();
+ String transformGroupName = groupNameTransform(gName);
+ // If group based search is enabled, then
+ // update the group name to ranger admin
+ // check for group members and populate userInfo object with user's full name and group mapping
+ if (groupSearchFirstEnabled) {
+ LOG.debug("Update Ranger admin with " + transformGroupName);
+ sink.addOrUpdateGroup(transformGroupName);
+ }
+ Attribute timeStampAttr = groupEntry.getAttributes().get("uSNChanged");
+ if (timeStampAttr != null) {
+ String uSNChangedVal = (String) timeStampAttr.get();
+ long currentDeltaSyncTime = Long.parseLong(uSNChangedVal);
+ if (currentDeltaSyncTime > highestdeltaSyncGroupTime) {
+ highestdeltaSyncGroupTime = currentDeltaSyncTime;
+ }
+ } else {
+ timeStampAttr = groupEntry.getAttributes().get("modifytimestamp");
+ if (timeStampAttr != null) {
+ String timeStampVal = (String) timeStampAttr.get();
+ Date parseDate = dateFormat.parse(timeStampVal);
+ long currentDeltaSyncTime = parseDate.getTime();
+ LOG.info("timeStampVal = " + timeStampVal + "and currentDeltaSyncTime = " + currentDeltaSyncTime);
+ if (currentDeltaSyncTime > highestdeltaSyncGroupTime) {
+ highestdeltaSyncGroupTime = currentDeltaSyncTime;
+ deltaSyncGroupTimeStamp = timeStampVal;
+ }
+ }
+ }
+ Attribute groupMemberAttr = groupEntry.getAttributes().get(groupMemberAttributeName);
+ int userCount = 0;
+ if (groupMemberAttr == null || groupMemberAttr.size() <= 0) {
+ LOG.info("No members available for " + gName);
+ continue;
+ }
+
+ NamingEnumeration<?> userEnum = groupMemberAttr.getAll();
+ while (userEnum.hasMore()) {
+ String originalUserFullName = (String) userEnum.next();
+ if (originalUserFullName == null || originalUserFullName.trim().isEmpty()) {
+ continue;
+ }
+ userCount++;
+ String userName = getShortUserName(originalUserFullName);
+ if (groupSearchFirstEnabled && !userSearchEnabled) {
+ String transformUserName = userNameTransform(userName);
+ try {
+ sink.addOrUpdateUser(transformUserName);
+ } catch (Throwable t) {
+ LOG.error("sink.addOrUpdateUser failed with exception: " + t.getMessage()
+ + ", for user: " + transformUserName);
+ }
+ }
+ groupUserTable.put(gName, userName, userName);
+ }
+ LOG.info("No. of members in the group " + gName + " = " + userCount);
+ }
+ // 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) {
+ LOG.debug("END-OF-PAGE total : " + total);
+ } else {
+ LOG.debug("END-OF-PAGE total : unknown");
+ }
+ cookie = prrc.getCookie();
+ }
+ }
+ } else {
+ LOG.debug("No controls were sent from the server");
+ }
+ // Re-activate paged results
+ if (pagedResultsEnabled) {
+ ldapContext.setRequestControls(new Control[]{
+ new PagedResultsControl(PAGE_SIZE, cookie, Control.CRITICAL) });
+ }
+ } while (cookie != null);
+ LOG.info("LdapDeltaUserGroupBuilder.getGroups() completed with group count: "
+ + counter);
+ } catch (Throwable t) {
+ LOG.error("LdapDeltaUserGroupBuilder.getGroups() failed with exception: " + t.getStackTrace());
+ LOG.info("LdapDeltaUserGroupBuilder.getGroups() group count: "
+ + counter);
+ }
+ }
+ if (deltaSyncGroupTime < highestdeltaSyncGroupTime) {
+ // Incrementing highestdeltaSyncGroupTime (for AD) in order to avoid search record repetition for next sync cycle.
+ deltaSyncGroupTime = highestdeltaSyncGroupTime+1;
+ // Incrementing the highest timestamp value (for OpenLdap) with 1min in order to avoid search record repetition for next sync cycle.
+ deltaSyncGroupTimeStamp = dateFormat.format(new Date(highestdeltaSyncGroupTime + 60000l));
+ }
+
+ } finally {
+ if (groupSearchResultEnum != null) {
+ groupSearchResultEnum.close();
+ }
+ closeLdapContext();
+ }
+ }
+
+
+ private static String getShortGroupName(String longGroupName) throws InvalidNameException {
+ if (longGroupName == null) {
+ return null;
+ }
+ StringTokenizer stc = new StringTokenizer(longGroupName, ",");
+ String firstToken = stc.nextToken();
+ StringTokenizer ste = new StringTokenizer(firstToken, "=");
+ String groupName = ste.nextToken();
+ if (ste.hasMoreTokens()) {
+ groupName = ste.nextToken();
+ }
+ groupName = groupName.trim();
+ LOG.info("longGroupName: " + longGroupName + ", groupName: " + groupName);
+ return groupName;
+ }
+
+ private static String getShortUserName(String longUserName) throws InvalidNameException {
+ if (longUserName == null) {
+ return null;
+ }
+ StringTokenizer stc = new StringTokenizer(longUserName, ",");
+ String firstToken = stc.nextToken();
+ StringTokenizer ste = new StringTokenizer(firstToken, "=");
+ String userName = ste.nextToken();
+ if (ste.hasMoreTokens()) {
+ userName = ste.nextToken();
+ }
+ userName = userName.trim();
+ LOG.info("longUserName: " + longUserName + ", userName: " + userName);
+ return userName;
+ }
+
+ private String userNameTransform(String userName) {
+ //String userNameTransform = userName;
+ if (userNameCaseConversionFlag) {
+ if (userNameLowerCaseFlag) {
+ userName = userName.toLowerCase();
+ }
+ else {
+ userName = userName.toUpperCase();
+ }
+ }
+
+ if (userNameRegExInst != null) {
+ userName = userNameRegExInst.transform(userName);
+ }
+
+ return userName;
+ }
+
+ private String groupNameTransform(String groupName) {
+ //String userNameTransform = userName;
+ if (groupNameCaseConversionFlag) {
+ if (groupNameLowerCaseFlag) {
+ groupName = groupName.toLowerCase();
+ }
+ else {
+ groupName = groupName.toUpperCase();
+ }
+ }
+
+ if (groupNameRegExInst != null) {
+ groupName = groupNameRegExInst.transform(groupName);
+ }
+
+ return groupName;
+ }
+
+}
+
+/*class UserInfo {
+ private String userName;
+ private String userFullName;
+ private Set<String> groupList;
+
+ public UserInfo(String userName, String userFullName) {
+ this.userName = userName;
+ this.userFullName = userFullName;
+ this.groupList = new HashSet<String>();
+ }
+
+ public void updateUserName(String userName) {
+ this.userName = userName;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+ public String getUserFullName() {
+ return userFullName;
+ }
+ public void addGroups(Set<String> groups) {
+ groupList.addAll(groups);
+ }
+ public void addGroup(String group) {
+ groupList.add(group);
+ }
+ public List<String> getGroups() {
+ return (new ArrayList<String>(groupList));
+ }
+}*/
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/2261a9dc/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapPolicyMgrUserGroupBuilder.java
----------------------------------------------------------------------
diff --git a/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapPolicyMgrUserGroupBuilder.java b/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapPolicyMgrUserGroupBuilder.java
new file mode 100644
index 0000000..0b909d1
--- /dev/null
+++ b/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapPolicyMgrUserGroupBuilder.java
@@ -0,0 +1,809 @@
+/*
+ * 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.ldapusersync.process;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.UnknownHostException;
+import java.security.KeyStore;
+import java.security.PrivilegedAction;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.security.auth.Subject;
+import javax.ws.rs.core.MediaType;
+
+import org.apache.hadoop.security.SecureClientLogin;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.ranger.unixusersync.config.UserGroupSyncConfig;
+import org.apache.ranger.unixusersync.model.GroupUserInfo;
+import org.apache.ranger.unixusersync.model.MUserInfo;
+import org.apache.ranger.unixusersync.model.UserGroupInfo;
+import org.apache.ranger.unixusersync.model.XGroupInfo;
+import org.apache.ranger.unixusersync.model.XUserGroupInfo;
+import org.apache.ranger.unixusersync.model.XUserInfo;
+import org.apache.ranger.usergroupsync.UserGroupSink;
+import org.apache.ranger.usersync.util.UserSyncUtil;
+
+import com.google.common.collect.Table;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.WebResource;
+import com.sun.jersey.api.client.config.ClientConfig;
+import com.sun.jersey.api.client.config.DefaultClientConfig;
+import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
+import com.sun.jersey.client.urlconnection.HTTPSProperties;
+
+public class LdapPolicyMgrUserGroupBuilder implements UserGroupSink {
+
+private static final Logger LOG = Logger.getLogger(LdapPolicyMgrUserGroupBuilder.class);
+
+ private static final String AUTHENTICATION_TYPE = "hadoop.security.authentication";
+ private String AUTH_KERBEROS = "kerberos";
+ private static final String PRINCIPAL = "ranger.usersync.kerberos.principal";
+ private static final String KEYTAB = "ranger.usersync.kerberos.keytab";
+ private static final String NAME_RULE = "hadoop.security.auth_to_local";
+
+ public static final String PM_USER_LIST_URI = "/service/xusers/users/"; // GET
+ private static final String PM_ADD_USER_GROUP_INFO_URI = "/service/xusers/users/userinfo"; // POST
+
+ private static final String PM_ADD_GROUP_USER_INFO_URI = "/service/xusers/groups/groupinfo"; // POST
+
+ public static final String PM_GROUP_LIST_URI = "/service/xusers/groups/"; // GET
+ private static final String PM_ADD_GROUP_URI = "/service/xusers/groups/"; // POST
+
+ private static final String PM_DEL_USER_GROUP_LINK_URI = "/service/xusers/group/${groupName}/user/${userName}"; // DELETE
+
+ public static final String PM_USER_GROUP_MAP_LIST_URI = "/service/xusers/groupusers/"; // GET
+
+ public static final String PM_GET_GROUP_USER_MAP_LIST_URI = "/service/xusers/groupusers/groupName/${groupName}"; // GET
+
+ private static final String PM_ADD_LOGIN_USER_URI = "/service/users/default"; // POST
+ private static final String GROUP_SOURCE_EXTERNAL ="1";
+ private static String LOCAL_HOSTNAME = "unknown";
+ private boolean isMockRun = false;
+ private String policyMgrBaseUrl;
+
+ private UserGroupSyncConfig config = UserGroupSyncConfig.getInstance();
+
+ private UserGroupInfo usergroupInfo = new UserGroupInfo();
+ private GroupUserInfo groupuserInfo = new GroupUserInfo();
+
+ Table<String, String, String> groupsUsersTable;
+
+ private String keyStoreFile = null;
+ private String keyStoreFilepwd = null;
+ private String trustStoreFile = null;
+ private String trustStoreFilepwd = null;
+ private String keyStoreType = null;
+ private String trustStoreType = null;
+ private HostnameVerifier hv = null;
+
+ private SSLContext sslContext = null;
+ private String authenticationType = null;
+ String principal;
+ String keytab;
+ String nameRules;
+
+ static {
+ try {
+ LOCAL_HOSTNAME = java.net.InetAddress.getLocalHost().getCanonicalHostName();
+ } catch (UnknownHostException e) {
+ LOCAL_HOSTNAME = "unknown";
+ }
+ }
+
+ @Override
+ public void init() throws Throwable {
+ policyMgrBaseUrl = config.getPolicyManagerBaseURL();
+ isMockRun = config.isMockRunEnabled();
+
+ if (isMockRun) {
+ LOG.setLevel(Level.DEBUG);
+ }
+
+ keyStoreFile = config.getSSLKeyStorePath();
+ keyStoreFilepwd = config.getSSLKeyStorePathPassword();
+ trustStoreFile = config.getSSLTrustStorePath();
+ trustStoreFilepwd = config.getSSLTrustStorePathPassword();
+ keyStoreType = KeyStore.getDefaultType();
+ trustStoreType = KeyStore.getDefaultType();
+ authenticationType = config.getProperty(AUTHENTICATION_TYPE,"simple");
+ try {
+ principal = SecureClientLogin.getPrincipal(config.getProperty(PRINCIPAL,""), LOCAL_HOSTNAME);
+ } catch (IOException ignored) {
+ // do nothing
+ }
+ keytab = config.getProperty(KEYTAB,"");
+ nameRules = config.getProperty(NAME_RULE,"DEFAULT");
+
+ }
+
+ @Override
+ public void addOrUpdateUser(String userName, List<String> groups) throws Throwable {
+ //* Add user to groups mapping in the x_user table.
+ //* Here the assumption is that the user already exists in x_portal_user table.
+ if ( ! isMockRun ) {
+ // If the rest call to ranger admin fails,
+ // propagate the failure to the caller for retry in next sync cycle.
+ if (addUserGroupInfo(userName, groups) == null ) {
+ String msg = "Failed to add addorUpdate user group info";
+ LOG.error(msg);
+ throw new Exception(msg);
+ }
+ }
+
+ }
+
+ @Override
+ public void addOrUpdateGroup(String groupName) throws Throwable {
+ //* Build the group info object and do the rest call
+ if ( ! isMockRun ) {
+ if ( addGroupInfo(groupName) == null) {
+ String msg = "Failed to add addorUpdate group info";
+ LOG.error(msg);
+ throw new Exception(msg);
+ }
+ }
+
+ }
+
+ private XGroupInfo addGroupInfo(final String groupName){
+ XGroupInfo ret = null;
+ XGroupInfo group = null;
+
+ LOG.debug("INFO: addPMXAGroup(" + groupName + ")" );
+ if (! isMockRun) {
+ group = addXGroupInfo(groupName);
+ }
+ if (authenticationType != null && AUTH_KERBEROS.equalsIgnoreCase(authenticationType) && SecureClientLogin.isKerberosCredentialExists(principal,keytab)) {
+ try {
+ LOG.info("Using principal = " + principal + " and keytab = " + keytab);
+ Subject sub = SecureClientLogin.loginUserFromKeytab(principal, keytab, nameRules);
+ final XGroupInfo groupInfo = group;
+ ret = Subject.doAs(sub, new PrivilegedAction<XGroupInfo>() {
+ @Override
+ public XGroupInfo run() {
+ try {
+ return getAddedGroupInfo(groupInfo);
+ } catch (Exception e) {
+ LOG.error("Failed to build Group List : ", e);
+ }
+ return null;
+ }
+ });
+ return ret;
+ } catch (Exception e) {
+ LOG.error("Failed to Authenticate Using given Principal and Keytab : ", e);
+ }
+ return null;
+ } else {
+ return getAddedGroupInfo(group);
+ }
+ }
+
+ private XGroupInfo addXGroupInfo(String aGroupName) {
+
+ XGroupInfo addGroup = new XGroupInfo();
+
+ addGroup.setName(aGroupName);
+
+ addGroup.setDescription(aGroupName + " - add from Unix box");
+
+ addGroup.setGroupType("1");
+
+ addGroup.setGroupSource(GROUP_SOURCE_EXTERNAL);
+ groupuserInfo.setXgroupInfo(addGroup);
+
+ return addGroup;
+ }
+
+ private XGroupInfo getAddedGroupInfo(XGroupInfo group){
+ XGroupInfo ret = null;
+
+ Client c = getClient();
+
+ WebResource r = c.resource(getURL(PM_ADD_GROUP_URI));
+
+ Gson gson = new GsonBuilder().create();
+
+ String jsonString = gson.toJson(group);
+
+ LOG.debug("Group" + jsonString);
+
+ String response = r.accept(MediaType.APPLICATION_JSON_TYPE).type(MediaType.APPLICATION_JSON_TYPE).post(String.class, jsonString);
+
+ LOG.debug("RESPONSE: [" + response + "]");
+
+ ret = gson.fromJson(response, XGroupInfo.class);
+
+ return ret;
+ }
+
+ public static void main(String[] args) throws Throwable {
+ LdapPolicyMgrUserGroupBuilder ugbuilder = new LdapPolicyMgrUserGroupBuilder();
+ ugbuilder.init();
+
+ }
+
+ @Override
+ public void addOrUpdateUser(String userName) throws Throwable {
+ // First add to x_portal_user
+ LOG.debug("INFO: addPMAccount(" + userName + ")" );
+ if (! isMockRun) {
+ if (addMUser(userName) == null) {
+ String msg = "Failed to add portal user";
+ LOG.error(msg);
+ throw new Exception(msg);
+ }
+ }
+ List<String> groups = new ArrayList<String>();
+ //* Build the user group info object with empty groups and do the rest call
+ if ( ! isMockRun ) {
+ // If the rest call to ranger admin fails,
+ // propagate the failure to the caller for retry in next sync cycle.
+ if (addUserGroupInfo(userName, groups) == null ) {
+ String msg = "Failed to add addorUpdate user group info";
+ LOG.error(msg);
+ throw new Exception(msg);
+ }
+ }
+
+ }
+
+ private UserGroupInfo addUserGroupInfo(String userName, List<String> groups){
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("==> LdapPolicyMgrUserGroupBuilder.addUserGroupInfo " + userName + " and groups");
+ }
+ UserGroupInfo ret = null;
+ XUserInfo user = null;
+ LOG.debug("INFO: addPMXAUser(" + userName + ")" );
+
+ if (! isMockRun) {
+ user = addXUserInfo(userName);
+ }
+ for(String g : groups) {
+ LOG.debug("INFO: addPMXAGroupToUser(" + userName + "," + g + ")" );
+ }
+ if (! isMockRun ) {
+ addXUserGroupInfo(user, groups);
+ }
+ if (authenticationType != null && AUTH_KERBEROS.equalsIgnoreCase(authenticationType) && SecureClientLogin.isKerberosCredentialExists(principal, keytab)){
+ try {
+ Subject sub = SecureClientLogin.loginUserFromKeytab(principal, keytab, nameRules);
+ final UserGroupInfo result = ret;
+ ret = Subject.doAs(sub, new PrivilegedAction<UserGroupInfo>() {
+ @Override
+ public UserGroupInfo run() {
+ try {
+ return getUsergroupInfo(result);
+ } catch (Exception e) {
+ LOG.error("Failed to add User Group Info : ", e);
+ }
+ return null;
+ }
+ });
+ return ret;
+ } catch (Exception e) {
+ LOG.error("Failed to Authenticate Using given Principal and Keytab : " , e);
+ }
+ return null;
+ }else{
+ return getUsergroupInfo(ret);
+ }
+ }
+
+ private XUserInfo addXUserInfo(String aUserName) {
+
+ XUserInfo xuserInfo = new XUserInfo();
+
+ xuserInfo.setName(aUserName);
+
+ xuserInfo.setDescription(aUserName + " - add from Unix box");
+
+ usergroupInfo.setXuserInfo(xuserInfo);
+
+ return xuserInfo;
+ }
+
+ private void addXUserGroupInfo(XUserInfo aUserInfo, List<String> aGroupList) {
+
+ List<XGroupInfo> xGroupInfoList = new ArrayList<XGroupInfo>();
+
+ for(String groupName : aGroupList) {
+ XGroupInfo group = addXGroupInfo(groupName);
+ xGroupInfoList.add(group);
+ addXUserGroupInfo(aUserInfo, group);
+ }
+
+ usergroupInfo.setXgroupInfo(xGroupInfoList);
+ }
+
+ private XUserGroupInfo addXUserGroupInfo(XUserInfo aUserInfo, XGroupInfo aGroupInfo) {
+
+
+ XUserGroupInfo ugInfo = new XUserGroupInfo();
+
+ ugInfo.setUserId(aUserInfo.getId());
+
+ ugInfo.setGroupName(aGroupInfo.getName());
+
+ // ugInfo.setParentGroupId("1");
+
+ return ugInfo;
+ }
+
+ private UserGroupInfo getUsergroupInfo(UserGroupInfo ret) {
+ Client c = getClient();
+
+ WebResource r = c.resource(getURL(PM_ADD_USER_GROUP_INFO_URI));
+
+ Gson gson = new GsonBuilder().create();
+
+ String jsonString = gson.toJson(usergroupInfo);
+
+ LOG.debug("USER GROUP MAPPING" + jsonString);
+
+ String response = r.accept(MediaType.APPLICATION_JSON_TYPE).type(MediaType.APPLICATION_JSON_TYPE).post(String.class, jsonString);
+
+ LOG.debug("RESPONSE: [" + response + "]");
+
+ ret = gson.fromJson(response, UserGroupInfo.class);
+
+ return ret;
+ }
+
+ @Override
+ public void addOrUpdateGroup(String groupName, List<String> users) throws Throwable {
+ // First get the existing group user mappings from Ranger admin.
+ // Then compute the delta and send the updated group user mappings to ranger admin.
+ GroupUserInfo groupUserInfo = new GroupUserInfo();
+ if (authenticationType != null && AUTH_KERBEROS.equalsIgnoreCase(authenticationType) && SecureClientLogin.isKerberosCredentialExists(principal,keytab)) {
+ try {
+ LOG.info("Using principal = " + principal + " and keytab = " + keytab);
+ Subject sub = SecureClientLogin.loginUserFromKeytab(principal, keytab, nameRules);
+ final GroupUserInfo groupInfo = groupUserInfo;
+ final String gName = groupName;
+ Subject.doAs(sub, new PrivilegedAction<Void>() {
+ @Override
+ public Void run() {
+ try {
+ getGroupUserInfo(gName, groupInfo);
+ } catch (Exception e) {
+ LOG.error("Failed to build Group List : ", e);
+ }
+ return null;
+ }
+ });
+ groupUserInfo = groupInfo;
+ } catch (Exception e) {
+ LOG.error("Failed to Authenticate Using given Principal and Keytab : ", e);
+ }
+ } else {
+ getGroupUserInfo(groupName, groupUserInfo);
+ }
+
+ //GroupUserInfo groupUserInfo = getGroupUserInfo(groupName);
+ LOG.debug("Returned users for group " + groupUserInfo.getXgroupInfo() + " are: " + groupUserInfo.getXuserInfo());
+ List<String> oldUsers = new ArrayList<String>();
+ if (groupUserInfo.getXuserInfo() != null) {
+ for (XUserInfo xUserInfo : groupUserInfo.getXuserInfo()) {
+ oldUsers.add(xUserInfo.getName());
+ }
+ }
+ List<String> addUsers = new ArrayList<String>();
+ List<String> delUsers = new ArrayList<String>();
+
+ for (String user : oldUsers) {
+ if (!users.contains(user)) {
+ delUsers.add(user);
+ }
+ }
+ if (oldUsers.isEmpty()) {
+ addUsers = users;
+ } else {
+ for (String user : users) {
+ if (!oldUsers.contains(user)) {
+ addUsers.add(user);
+ }
+ }
+ }
+
+ LOG.debug("addUsers = " + addUsers);
+ delXGroupUserInfo(groupName, delUsers);
+
+ //* Add user to group mapping in the x_group_user table.
+ //* Here the assumption is that the user already exists in x_portal_user table.
+ if ( ! isMockRun ) {
+ // If the rest call to ranger admin fails,
+ // propagate the failure to the caller for retry in next sync cycle.
+ if (addGroupUserInfo(groupName, addUsers) == null ) {
+ String msg = "Failed to add addorUpdate group user info";
+ LOG.error(msg);
+ throw new Exception(msg);
+ }
+ }
+ }
+
+ private void delXGroupUserInfo(final String groupName, List<String> userList) {
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("==> LdapPolicyMgrUserGroupBuilder.delXGroupUserInfo " + groupName + " and " + userList);
+ }
+ for(final String userName : userList) {
+ if (authenticationType != null && AUTH_KERBEROS.equalsIgnoreCase(authenticationType) && SecureClientLogin.isKerberosCredentialExists(principal, keytab)) {
+ try {
+ LOG.info("Using principal = " + principal + " and keytab = " + keytab);
+ Subject sub = SecureClientLogin.loginUserFromKeytab(principal, keytab, nameRules);
+ Subject.doAs(sub, new PrivilegedAction<Void>() {
+ @Override
+ public Void run() {
+ try {
+ delXGroupUserInfo(groupName, userName);
+ } catch (Exception e) {
+ LOG.error("Failed to build Group List : ", e);
+ }
+ return null;
+ }
+ });
+ } catch (Exception e) {
+ LOG.error("Failed to Authenticate Using given Principal and Keytab : ",e);
+ }
+ } else {
+ delXGroupUserInfo(groupName, userName);
+ }
+ }
+ }
+
+ private void delXGroupUserInfo(String groupName, String userName) {
+
+ try {
+
+ Client c = getClient();
+
+ String uri = PM_DEL_USER_GROUP_LINK_URI.replaceAll(Pattern.quote("${groupName}"),
+ UserSyncUtil.encodeURIParam(groupName)).replaceAll(Pattern.quote("${userName}"), UserSyncUtil.encodeURIParam(userName));
+
+ WebResource r = c.resource(getURL(uri));
+
+ ClientResponse response = r.delete(ClientResponse.class);
+
+ if ( LOG.isDebugEnabled() ) {
+ LOG.debug("RESPONSE: [" + response.toString() + "]");
+ }
+
+ } catch (Exception e) {
+
+ LOG.warn( "ERROR: Unable to delete GROUP: " + groupName + " from USER:" + userName , e);
+ }
+
+ }
+
+ private GroupUserInfo addGroupUserInfo(String groupName, List<String> users){
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("==> LdapPolicyMgrUserGroupBuilder.addGroupUserInfo " + groupName + " and " + users);
+ }
+ GroupUserInfo ret = null;
+ XGroupInfo group = null;
+
+ LOG.debug("INFO: addPMXAGroup(" + groupName + ")" );
+ if (! isMockRun) {
+ group = addXGroupInfo(groupName);
+ }
+ for(String u : users) {
+ LOG.debug("INFO: addPMXAGroupToUser(" + groupName + "," + u + ")" );
+ }
+ if (! isMockRun ) {
+ addXGroupUserInfo(group, users);
+ }
+ if (authenticationType != null && AUTH_KERBEROS.equalsIgnoreCase(authenticationType) && SecureClientLogin.isKerberosCredentialExists(principal, keytab)){
+ try {
+ Subject sub = SecureClientLogin.loginUserFromKeytab(principal, keytab, nameRules);
+ final GroupUserInfo result = ret;
+ ret = Subject.doAs(sub, new PrivilegedAction<GroupUserInfo>() {
+ @Override
+ public GroupUserInfo run() {
+ try {
+ return getGroupUserInfo(result);
+ } catch (Exception e) {
+ LOG.error("Failed to add User Group Info : ", e);
+ }
+ return null;
+ }
+ });
+ return ret;
+ } catch (Exception e) {
+ LOG.error("Failed to Authenticate Using given Principal and Keytab : " , e);
+ }
+ return null;
+ }else{
+ return getGroupUserInfo(ret);
+ }
+ }
+
+ private void addXGroupUserInfo(XGroupInfo aGroupInfo, List<String> aUserList) {
+
+ List<XUserInfo> xUserInfoList = new ArrayList<XUserInfo>();
+
+ for(String userName : aUserList) {
+ XUserInfo user = addXUserInfo(userName);
+ xUserInfoList.add(user);
+ addXUserGroupInfo(user, aGroupInfo);
+ }
+
+ groupuserInfo.setXuserInfo(xUserInfoList);
+ }
+
+ private GroupUserInfo getGroupUserInfo(GroupUserInfo ret) {
+ Client c = getClient();
+
+ WebResource r = c.resource(getURL(PM_ADD_GROUP_USER_INFO_URI));
+
+ Gson gson = new GsonBuilder().create();
+
+ String jsonString = gson.toJson(groupuserInfo);
+
+ LOG.debug("GROUP USER MAPPING" + jsonString);
+
+ String response = r.accept(MediaType.APPLICATION_JSON_TYPE).type(MediaType.APPLICATION_JSON_TYPE).post(String.class, jsonString);
+
+ LOG.debug("RESPONSE: [" + response + "]");
+
+ ret = gson.fromJson(response, GroupUserInfo.class);
+
+ return ret;
+ }
+
+
+ private MUserInfo addMUser(String aUserName) {
+ MUserInfo ret = null;
+ MUserInfo userInfo = new MUserInfo();
+
+ userInfo.setLoginId(aUserName);
+ userInfo.setFirstName(aUserName);
+ userInfo.setLastName(aUserName);
+
+ if (authenticationType != null && AUTH_KERBEROS.equalsIgnoreCase(authenticationType) && SecureClientLogin.isKerberosCredentialExists(principal, keytab)) {
+ try {
+ Subject sub = SecureClientLogin.loginUserFromKeytab(principal, keytab, nameRules);
+ final MUserInfo result = ret;
+ final MUserInfo userInfoFinal = userInfo;
+ ret = Subject.doAs(sub, new PrivilegedAction<MUserInfo>() {
+ @Override
+ public MUserInfo run() {
+ try {
+ return getMUser(userInfoFinal, result);
+ } catch (Exception e) {
+ LOG.error("Failed to add User : ", e);
+ }
+ return null;
+ }
+ });
+ return ret;
+ } catch (Exception e) {
+ LOG.error("Failed to Authenticate Using given Principal and Keytab : " , e);
+ }
+ return null;
+ } else {
+ return getMUser(userInfo, ret);
+ }
+ }
+
+
+ private MUserInfo getMUser(MUserInfo userInfo, MUserInfo ret) {
+ Client c = getClient();
+
+ WebResource r = c.resource(getURL(PM_ADD_LOGIN_USER_URI));
+
+ Gson gson = new GsonBuilder().create();
+
+ String jsonString = gson.toJson(userInfo);
+
+ String response = r.accept(MediaType.APPLICATION_JSON_TYPE).type(MediaType.APPLICATION_JSON_TYPE).post(String.class, jsonString);
+
+ LOG.debug("RESPONSE[" + response + "]");
+
+ ret = gson.fromJson(response, MUserInfo.class);
+
+ LOG.debug("MUser Creation successful " + ret);
+
+ return ret;
+ }
+
+ public void getGroupUserInfo(String groupName, GroupUserInfo ret) {
+ //GroupUserInfo ret = null;
+ try {
+
+ Client c = getClient();
+
+ String uri = PM_GET_GROUP_USER_MAP_LIST_URI.replaceAll(Pattern.quote("${groupName}"),
+ UserSyncUtil.encodeURIParam(groupName));
+
+ WebResource r = c.resource(getURL(uri));
+
+ String response = r.accept(MediaType.APPLICATION_JSON_TYPE).get(String.class);
+
+ Gson gson = new GsonBuilder().create();
+
+ LOG.debug("RESPONSE: [" + response + "]");
+
+ ret = gson.fromJson(response, GroupUserInfo.class);
+ LOG.debug("return value = " + ret);
+
+ } catch (Exception e) {
+
+ LOG.warn( "ERROR: Unable to get group user mappings for: " + groupName, e);
+ }
+ }
+
+ private String getURL(String uri) {
+ String ret = null;
+ ret = policyMgrBaseUrl + (uri.startsWith("/") ? uri : ("/" + uri));
+ return ret;
+ }
+
+ private synchronized Client getClient() {
+
+ Client ret = null;
+
+ if (policyMgrBaseUrl.startsWith("https://")) {
+
+ ClientConfig config = new DefaultClientConfig();
+
+ if (sslContext == null) {
+
+ try {
+
+ KeyManager[] kmList = null;
+ TrustManager[] tmList = null;
+
+ if (keyStoreFile != null && keyStoreFilepwd != null) {
+
+ KeyStore keyStore = KeyStore.getInstance(keyStoreType);
+ InputStream in = null;
+ try {
+ in = getFileInputStream(keyStoreFile);
+ if (in == null) {
+ LOG.error("Unable to obtain keystore from file [" + keyStoreFile + "]");
+ return ret;
+ }
+ keyStore.load(in, keyStoreFilepwd.toCharArray());
+ KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ keyManagerFactory.init(keyStore, keyStoreFilepwd.toCharArray());
+ kmList = keyManagerFactory.getKeyManagers();
+ }
+ finally {
+ if (in != null) {
+ in.close();
+ }
+ }
+
+ }
+
+ if (trustStoreFile != null && trustStoreFilepwd != null) {
+
+ KeyStore trustStore = KeyStore.getInstance(trustStoreType);
+ InputStream in = null;
+ try {
+ in = getFileInputStream(trustStoreFile);
+ if (in == null) {
+ LOG.error("Unable to obtain keystore from file [" + trustStoreFile + "]");
+ return ret;
+ }
+ trustStore.load(in, trustStoreFilepwd.toCharArray());
+ TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ trustManagerFactory.init(trustStore);
+ tmList = trustManagerFactory.getTrustManagers();
+ }
+ finally {
+ if (in != null) {
+ in.close();
+ }
+ }
+ }
+
+ sslContext = SSLContext.getInstance("SSL");
+
+ sslContext.init(kmList, tmList, new SecureRandom());
+
+ hv = new HostnameVerifier() {
+ public boolean verify(String urlHostName, SSLSession session) {
+ return session.getPeerHost().equals(urlHostName);
+ }
+ };
+ }
+ catch(Throwable t) {
+ throw new RuntimeException("Unable to create SSLConext for communication to policy manager", t);
+ }
+
+ }
+
+ config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new HTTPSProperties(hv, sslContext));
+
+ ret = Client.create(config);
+
+
+ }
+ else {
+ ClientConfig cc = new DefaultClientConfig();
+ cc.getProperties().put(ClientConfig.PROPERTY_FOLLOW_REDIRECTS, true);
+ ret = Client.create(cc);
+ }
+ if(!(authenticationType != null && AUTH_KERBEROS.equalsIgnoreCase(authenticationType) && SecureClientLogin.isKerberosCredentialExists(principal, keytab))){
+ if(ret!=null){
+ String username = config.getPolicyMgrUserName();
+ String password = config.getPolicyMgrPassword();
+ if(username==null||password==null||username.trim().isEmpty()||password.trim().isEmpty()){
+ username=config.getDefaultPolicyMgrUserName();
+ password=config.getDefaultPolicyMgrPassword();
+ }
+ if(username!=null && password!=null){
+ ret.addFilter(new HTTPBasicAuthFilter(username, password));
+ }
+ }
+ }
+ return ret;
+ }
+
+ private InputStream getFileInputStream(String path) throws FileNotFoundException {
+
+ InputStream ret = null;
+
+ File f = new File(path);
+
+ if (f.exists()) {
+ ret = new FileInputStream(f);
+ } else {
+ ret = LdapPolicyMgrUserGroupBuilder.class.getResourceAsStream(path);
+
+ if (ret == null) {
+ if (! path.startsWith("/")) {
+ ret = getClass().getResourceAsStream("/" + path);
+ }
+ }
+
+ if (ret == null) {
+ ret = ClassLoader.getSystemClassLoader().getResourceAsStream(path);
+ if (ret == null) {
+ if (! path.startsWith("/")) {
+ ret = ClassLoader.getSystemResourceAsStream("/" + path);
+ }
+ }
+ }
+ }
+
+ return ret;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/2261a9dc/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 734dc58..25c0824 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
@@ -68,6 +68,8 @@ public class UserGroupSyncConfig {
public static final String UGSYNC_MOCK_RUN_PROP = "ranger.usersync.policymanager.mockrun";
+ public static final String UGSYNC_TEST_RUN_PROP = "ranger.usersync.policymanager.testrun";
+
public static final String UGSYNC_SOURCE_FILE_PROC = "ranger.usersync.filesource.file";
public static final String UGSYNC_SOURCE_FILE_DELIMITER = "ranger.usersync.filesource.text.delimiter";
@@ -97,9 +99,16 @@ public class UserGroupSyncConfig {
private static final String UGSYNC_SINK_CLASS = "org.apache.ranger.unixusersync.process.PolicyMgrUserGroupBuilder";
+ private static final String LGSYNC_DELTASYNC_SINK_CLASS = "org.apache.ranger.ldapusersync.process.LdapPolicyMgrUserGroupBuilder";
+
private static final String LGSYNC_SOURCE_CLASS = "org.apache.ranger.ldapusersync.process.LdapUserGroupBuilder";
+ private static final String LGSYNC_DELTASYNC_SOURCE_CLASS = "org.apache.ranger.ldapusersync.process.LdapDeltaUserGroupBuilder";
+
private static final String LGSYNC_LDAP_URL = "ranger.usersync.ldap.url";
+
+ private static final String LGSYNC_LDAP_DELTASYNC_ENABLED = "ranger.usersync.ldap.deltasync";
+ private static final boolean DEFAULT_LGSYNC_LDAP_DELTASYNC_ENABLED = false;
private static final String LGSYNC_LDAP_STARTTLS_ENABLED = "ranger.usersync.ldap.starttls";
private static final boolean DEFAULT_LGSYNC_LDAP_STARTTLS_ENABLED = false;
@@ -382,6 +391,11 @@ public class UserGroupSyncConfig {
String val = prop.getProperty(UGSYNC_MOCK_RUN_PROP);
return (val != null && val.trim().equalsIgnoreCase("true"));
}
+
+ public boolean isTestRunEnabled() {
+ String val = prop.getProperty(UGSYNC_TEST_RUN_PROP);
+ return (val != null && val.trim().equalsIgnoreCase("true"));
+ }
public String getPolicyManagerBaseURL() {
return prop.getProperty(UGSYNC_PM_URL_PROP);
@@ -456,7 +470,7 @@ public class UserGroupSyncConfig {
} else {
min_interval = UGSYNC_SLEEP_TIME_IN_MILLIS_BETWEEN_CYCLE_MIN_VALUE;
}
- if(ret < min_interval)
+ if((!isTestRunEnabled()) && (ret < min_interval))
{
LOG.info("Sleep Time Between Cycle can not be lower than [" + min_interval + "] millisec. resetting to min value.");
ret = min_interval;
@@ -465,27 +479,40 @@ public class UserGroupSyncConfig {
}
}
-
- public UserGroupSource getUserGroupSource() throws Throwable {
-
+ private String getUserGroupSourceClassName() {
String val = prop.getProperty(UGSYNC_SOURCE_CLASS_PARAM);
-
+ String className = null;
+
String syncSource = null;
if(val == null || val.trim().isEmpty()) {
syncSource=getSyncSource();
}
else {
+ if (val.equalsIgnoreCase(LGSYNC_SOURCE_CLASS) && isDeltaSyncEnabled()) {
+ val = LGSYNC_DELTASYNC_SOURCE_CLASS;
+ }
syncSource = val;
}
- String className = val;
+ className = val;
if(syncSource!=null && syncSource.equalsIgnoreCase("UNIX")){
className = UGSYNC_SOURCE_CLASS;
}else if(syncSource!=null && syncSource.equalsIgnoreCase("LDAP")){
- className = LGSYNC_SOURCE_CLASS;
- }
+ if (!isDeltaSyncEnabled()) {
+ className = LGSYNC_SOURCE_CLASS;
+ } else {
+ className = LGSYNC_DELTASYNC_SOURCE_CLASS;
+ }
+ }
+
+ return className;
+ }
+
+ public UserGroupSource getUserGroupSource() throws Throwable {
+
+ String className = getUserGroupSourceClassName();
Class<UserGroupSource> ugSourceClass = (Class<UserGroupSource>)Class.forName(className);
@@ -494,12 +521,16 @@ public class UserGroupSyncConfig {
return ret;
}
-
public UserGroupSink getUserGroupSink() throws Throwable {
String val = prop.getProperty(UGSYNC_SINK_CLASS_PARAM);
+ String className = getUserGroupSourceClassName();
- if(val == null || val.trim().isEmpty()) {
- val = UGSYNC_SINK_CLASS;
+ if (className.equals(LGSYNC_DELTASYNC_SOURCE_CLASS)) {
+ val = LGSYNC_DELTASYNC_SINK_CLASS;
+ } else {
+ if(val == null || val.trim().isEmpty()) {
+ val = UGSYNC_SINK_CLASS;
+ }
}
Class<UserGroupSink> ugSinkClass = (Class<UserGroupSink>)Class.forName(val);
@@ -892,6 +923,17 @@ public class UserGroupSyncConfig {
}
return starttlsEnabled;
}
+
+ public boolean isDeltaSyncEnabled() {
+ boolean deltaSyncEnabled;
+ String val = prop.getProperty(LGSYNC_LDAP_DELTASYNC_ENABLED);
+ if(val == null || val.trim().isEmpty()) {
+ deltaSyncEnabled = DEFAULT_LGSYNC_LDAP_DELTASYNC_ENABLED;
+ } else {
+ deltaSyncEnabled = Boolean.valueOf(val);
+ }
+ return deltaSyncEnabled;
+ }
/* Used only for unit testing */
public void setUserSearchFilter(String filter) {
@@ -952,4 +994,9 @@ public class UserGroupSyncConfig {
public void setGroupObjectClass(String groupObjectClass) {
prop.setProperty(LGSYNC_GROUP_OBJECT_CLASS, groupObjectClass);
}
+
+ /* Used only for unit testing */
+ public void setDeltaSync(boolean deltaSyncEnabled) {
+ prop.setProperty(LGSYNC_LDAP_DELTASYNC_ENABLED, String.valueOf(deltaSyncEnabled));
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/2261a9dc/ugsync/src/main/java/org/apache/ranger/unixusersync/model/GroupUserInfo.java
----------------------------------------------------------------------
diff --git a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/GroupUserInfo.java b/ugsync/src/main/java/org/apache/ranger/unixusersync/model/GroupUserInfo.java
new file mode 100644
index 0000000..a2cfa7b
--- /dev/null
+++ b/ugsync/src/main/java/org/apache/ranger/unixusersync/model/GroupUserInfo.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.unixusersync.model;
+
+import java.util.List;
+
+public class GroupUserInfo {
+ XGroupInfo xgroupInfo;
+ List<XUserInfo> xuserInfo;
+
+ public XGroupInfo getXgroupInfo() {
+ return xgroupInfo;
+ }
+ public void setXgroupInfo(XGroupInfo xgroupInfo) {
+ this.xgroupInfo = xgroupInfo;
+ }
+ public List<XUserInfo> getXuserInfo() {
+ return xuserInfo;
+ }
+ public void setXuserInfo(List<XUserInfo> xuserInfo) {
+ this.xuserInfo = xuserInfo;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/2261a9dc/ugsync/src/main/java/org/apache/ranger/unixusersync/process/PolicyMgrUserGroupBuilder.java
----------------------------------------------------------------------
diff --git a/ugsync/src/main/java/org/apache/ranger/unixusersync/process/PolicyMgrUserGroupBuilder.java b/ugsync/src/main/java/org/apache/ranger/unixusersync/process/PolicyMgrUserGroupBuilder.java
index 7e4d41a..c5e8721 100644
--- a/ugsync/src/main/java/org/apache/ranger/unixusersync/process/PolicyMgrUserGroupBuilder.java
+++ b/ugsync/src/main/java/org/apache/ranger/unixusersync/process/PolicyMgrUserGroupBuilder.java
@@ -1063,5 +1063,19 @@ public class PolicyMgrUserGroupBuilder implements UserGroupSink {
return ret;
}
+
+ @Override
+ public void addOrUpdateUser(String user) throws Throwable {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ @Override
+ public void addOrUpdateGroup(String group, List<String> users) throws Throwable {
+ // TODO Auto-generated method stub
+
+ }
+
}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/2261a9dc/ugsync/src/main/java/org/apache/ranger/usergroupsync/UserGroupSink.java
----------------------------------------------------------------------
diff --git a/ugsync/src/main/java/org/apache/ranger/usergroupsync/UserGroupSink.java b/ugsync/src/main/java/org/apache/ranger/usergroupsync/UserGroupSink.java
index bb3ef82..494efc2 100644
--- a/ugsync/src/main/java/org/apache/ranger/usergroupsync/UserGroupSink.java
+++ b/ugsync/src/main/java/org/apache/ranger/usergroupsync/UserGroupSink.java
@@ -26,5 +26,9 @@ public interface UserGroupSink {
void addOrUpdateUser(String user, List<String> groups) throws Throwable;
+ void addOrUpdateUser(String user) throws Throwable;
+
void addOrUpdateGroup(String group) throws Throwable;
+
+ void addOrUpdateGroup(String group, List<String> users) throws Throwable;
}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/2261a9dc/ugsync/src/test/java/org/apache/ranger/usergroupsync/LdapPolicyMgrUserGroupBuilderTest.java
----------------------------------------------------------------------
diff --git a/ugsync/src/test/java/org/apache/ranger/usergroupsync/LdapPolicyMgrUserGroupBuilderTest.java b/ugsync/src/test/java/org/apache/ranger/usergroupsync/LdapPolicyMgrUserGroupBuilderTest.java
new file mode 100644
index 0000000..99bc2b4
--- /dev/null
+++ b/ugsync/src/test/java/org/apache/ranger/usergroupsync/LdapPolicyMgrUserGroupBuilderTest.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 java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.ranger.ldapusersync.process.LdapPolicyMgrUserGroupBuilder;
+
+public class LdapPolicyMgrUserGroupBuilderTest extends LdapPolicyMgrUserGroupBuilder {
+ private Set<String> allGroups;
+ private Set<String> allUsers;
+
+ @Override
+ public void init() throws Throwable {
+ allGroups = new HashSet<>();
+ allUsers = new HashSet<>();
+ }
+
+ @Override
+ public void addOrUpdateUser(String user, List<String> groups) {
+ allGroups.addAll(groups);
+ //allUsers.add(user);
+ //System.out.println("Username: " + user + " and associated groups: " + groups);
+ }
+
+ @Override
+ public void addOrUpdateGroup(String group) {
+ allGroups.add(group);
+ //System.out.println("Groupname: " + group);
+ }
+
+ @Override
+ public void addOrUpdateUser(String user) {
+ allUsers.add(user);
+ //System.out.println("Username: " + user);
+ }
+
+ @Override
+ public void addOrUpdateGroup(String group, List<String> users) {
+ boolean addGroup = false;
+ for (String user : users) {
+ if (allUsers.contains(user)) {
+ addGroup = true;
+ break;
+ }
+ }
+ if (addGroup) {
+ allGroups.add(group);
+ }
+ //allUsers.addAll(users);
+ //System.out.println("Groupname: " + group + " and associated users: " + users);
+ }
+
+ public int getTotalUsers() {
+ return allUsers.size();
+ }
+
+ public int getTotalGroups() {
+ //System.out.println("Groups = " + allGroups);
+ return allGroups.size();
+ }
+
+ public Set<String> getAllGroups() {
+ return allGroups;
+ }
+
+ public Set<String> getAllUsers() {
+ return allUsers;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/2261a9dc/ugsync/src/test/java/org/apache/ranger/usergroupsync/TestLdapUserGroup.java
----------------------------------------------------------------------
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 81d952e..b4c9065 100644
--- a/ugsync/src/test/java/org/apache/ranger/usergroupsync/TestLdapUserGroup.java
+++ b/ugsync/src/test/java/org/apache/ranger/usergroupsync/TestLdapUserGroup.java
@@ -73,7 +73,7 @@ partitions =
)
public class TestLdapUserGroup extends AbstractLdapTestUnit{
private UserGroupSyncConfig config;
- private LdapUserGroupBuilder ldapBuilder;
+ private UserGroupSource ldapBuilder;
@Before
public void setup() throws Exception {
@@ -553,6 +553,111 @@ public class TestLdapUserGroup extends AbstractLdapTestUnit{
assertEquals(110, sink.getTotalUsers());
assertEquals(0, sink.getTotalGroups());
}
+
+ @Test
+ public void testDeltaUpdateSinkTotalGroups() throws Throwable {
+ config.setUserSearchBase("cn=users,DC=ranger,DC=qe,DC=hortonworks,DC=com");
+ config.setUserSearchFilter("");
+ config.setGroupSearchBase("OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
+ config.setGroupSearchFilter("");
+ config.setUserGroupMemberAttributeName("member");
+ config.setUserObjectClass("organizationalPerson");
+ config.setGroupObjectClass("groupOfNames");
+ config.setGroupSearchEnabled(true);
+ config.setGroupSearchFirstEnabled(false);
+ config.setDeltaSync(true);
+ //UserGroupSource ldapDeltaBuilder = config.getUserGroupSource();
+ ldapBuilder = config.getUserGroupSource();
+ ldapBuilder.init();
+ LdapPolicyMgrUserGroupBuilderTest sink = new LdapPolicyMgrUserGroupBuilderTest();
+ sink.init();
+ ldapBuilder.updateSink(sink);
+ assertEquals(10, sink.getTotalGroups());
+ }
+
+ @Test
+ public void testDeltaUpdateSinkMultipleOUGroups() throws Throwable {
+ config.setUserSearchBase("cn=users,DC=ranger,DC=qe,DC=hortonworks,DC=com;ou=HadoopUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com;ou=BusinessUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com");
+ config.setUserSearchFilter("cn=*");
+ config.setGroupSearchBase("OU=HdpGroups,OU=HadoopUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com;OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
+ config.setGroupSearchFilter("cn=*Group10");
+ config.setUserGroupMemberAttributeName("member");
+ config.setUserObjectClass("organizationalPerson");
+ config.setGroupObjectClass("groupOfNames");
+ config.setGroupSearchEnabled(true);
+ config.setGroupSearchFirstEnabled(false);
+ config.setDeltaSync(true);
+ ldapBuilder = config.getUserGroupSource();
+ ldapBuilder.init();
+ LdapPolicyMgrUserGroupBuilderTest sink = new LdapPolicyMgrUserGroupBuilderTest();
+ sink.init();
+ ldapBuilder.updateSink(sink);
+ assertEquals(111, sink.getTotalUsers());
+ assertEquals(2, sink.getTotalGroups());
+ }
+
+ @Test
+ public void testDeltaGroupBasedWithUserFilter() throws Throwable {
+ config.setUserSearchBase("DC=ranger,DC=qe,DC=hortonworks,DC=com;");
+ config.setUserSearchFilter("cn=User*");
+ config.setGroupSearchBase("OU=HdpGroups,OU=HadoopUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com;OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
+ config.setGroupSearchFilter("cn=*Group10");
+ config.setUserGroupMemberAttributeName("member");
+ config.setUserObjectClass("organizationalPerson");
+ config.setGroupObjectClass("groupOfNames");
+ config.setGroupSearchFirstEnabled(true);
+ config.setUserSearchEnabled(true);
+ config.setDeltaSync(true);
+ ldapBuilder = config.getUserGroupSource();
+ ldapBuilder.init();
+ LdapPolicyMgrUserGroupBuilderTest sink = new LdapPolicyMgrUserGroupBuilderTest();
+ sink.init();
+ ldapBuilder.updateSink(sink);
+ assertEquals(1, sink.getTotalUsers());
+ assertEquals(2, sink.getTotalGroups());
+ }
+
+ @Test
+ public void testDeltaGroupBasedWithNoUsers() throws Throwable {
+ config.setUserSearchBase("DC=ranger,DC=qe,DC=hortonworks,DC=com;");
+ config.setUserSearchFilter("cn=*");
+ config.setGroupSearchBase("OU=HdpGroups,OU=HadoopUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com;OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
+ config.setGroupSearchFilter("cn=Group2*");
+ config.setUserGroupMemberAttributeName("member");
+ config.setUserObjectClass("organizationalPerson");
+ config.setGroupObjectClass("groupOfNames");
+ config.setGroupSearchFirstEnabled(true);
+ config.setUserSearchEnabled(true);
+ config.setDeltaSync(true);
+ ldapBuilder = config.getUserGroupSource();
+ ldapBuilder.init();
+ LdapPolicyMgrUserGroupBuilderTest sink = new LdapPolicyMgrUserGroupBuilderTest();
+ sink.init();
+ ldapBuilder.updateSink(sink);
+ assertEquals(0, sink.getTotalUsers());
+ assertEquals(2, sink.getTotalGroups());
+ }
+
+ @Test
+ public void testDeltaGBWithUserSearchDisabled() throws Throwable {
+ config.setUserSearchBase("DC=ranger,DC=qe,DC=hortonworks,DC=com;");
+ config.setUserSearchFilter("cn=User*");
+ config.setGroupSearchBase("OU=HdpGroups,OU=HadoopUsers,DC=ranger,DC=qe,DC=hortonworks,DC=com;OU=Groups,DC=ranger,DC=qe,DC=hortonworks,DC=com");
+ config.setGroupSearchFilter("cn=*Group10");
+ config.setUserGroupMemberAttributeName("member");
+ config.setUserObjectClass("organizationalPerson");
+ config.setGroupObjectClass("groupOfNames");
+ config.setGroupSearchFirstEnabled(true);
+ config.setUserSearchEnabled(false);
+ config.setDeltaSync(true);
+ ldapBuilder = config.getUserGroupSource();
+ ldapBuilder.init();
+ LdapPolicyMgrUserGroupBuilderTest sink = new LdapPolicyMgrUserGroupBuilderTest();
+ sink.init();
+ ldapBuilder.updateSink(sink);
+ assertEquals(2, sink.getTotalUsers());
+ assertEquals(2, sink.getTotalGroups());
+ }
@After
public void shutdown() throws Exception {