mneethiraj commented on code in PR #440: URL: https://github.com/apache/ranger/pull/440#discussion_r1879004080
########## ugsync-util/pom.xml: ########## @@ -26,6 +26,9 @@ <packaging>jar</packaging> <name>User Group Synchronizer Util</name> <description>User Group Synchronizer Util</description> + <properties> + <checkstyle.failOnViolation>true</checkstyle.failOnViolation> Review Comment: `<checkstyle.skip>false</checkstyle.skip>` would be needed as well. ########## ugsync/src/main/java/org/apache/ranger/ldapusersync/process/CustomSSLSocketFactory.java: ########## @@ -30,89 +42,70 @@ import java.security.KeyStore; import java.security.SecureRandom; -import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; - -import org.apache.ranger.unixusersync.config.UserGroupSyncConfig; -import org.apache.ranger.unixusersync.process.PolicyMgrUserGroupBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class CustomSSLSocketFactory extends SSLSocketFactory{ - private static final Logger LOG = LoggerFactory.getLogger(CustomSSLSocketFactory.class); - private SSLSocketFactory sockFactory; - private UserGroupSyncConfig config = UserGroupSyncConfig.getInstance(); +public class CustomSSLSocketFactory extends SSLSocketFactory { + private static final Logger LOG = LoggerFactory.getLogger(CustomSSLSocketFactory.class); + private SSLSocketFactory sockFactory; + private UserGroupSyncConfig config = UserGroupSyncConfig.getInstance(); public CustomSSLSocketFactory() { - SSLContext sslContext = null; - String keyStoreFile = config.getSSLKeyStorePath(); - String keyStoreFilepwd = config.getSSLKeyStorePathPassword(); - String trustStoreFile = config.getSSLTrustStorePath(); - String trustStoreFilepwd = config.getSSLTrustStorePathPassword(); - String keyStoreType = config.getSSLKeyStoreType(); - String trustStoreType = config.getSSLTrustStoreType(); - 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; - } - 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; - } - 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("TLSv1.2"); - - sslContext.init(kmList, tmList, new SecureRandom()); - sockFactory = sslContext.getSocketFactory(); - } - catch(Throwable t) { - throw new RuntimeException("Unable to create SSLConext for communication to policy manager", t); - } + SSLContext sslContext = null; + String keyStoreFile = config.getSSLKeyStorePath(); + String keyStoreFilepwd = config.getSSLKeyStorePathPassword(); + String trustStoreFile = config.getSSLTrustStorePath(); + String trustStoreFilepwd = config.getSSLTrustStorePathPassword(); + String keyStoreType = config.getSSLKeyStoreType(); + String trustStoreType = config.getSSLTrustStoreType(); + try { + KeyManager[] kmList = null; + TrustManager[] tmList = null; + + if (keyStoreFile != null && keyStoreFilepwd != null) { + KeyStore keyStore = KeyStore.getInstance(keyStoreType); + InputStream in = null; + try { Review Comment: Consider replacing finally with try-with-resource: `try (InputStream in getFileInputStream(keyStoreFile)) {`. Same at line 85 as well. ########## ugsync/src/main/java/org/apache/ranger/ldapusersync/process/CustomSSLSocketFactory.java: ########## @@ -30,89 +42,70 @@ import java.security.KeyStore; import java.security.SecureRandom; -import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; - -import org.apache.ranger.unixusersync.config.UserGroupSyncConfig; -import org.apache.ranger.unixusersync.process.PolicyMgrUserGroupBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class CustomSSLSocketFactory extends SSLSocketFactory{ - private static final Logger LOG = LoggerFactory.getLogger(CustomSSLSocketFactory.class); - private SSLSocketFactory sockFactory; - private UserGroupSyncConfig config = UserGroupSyncConfig.getInstance(); +public class CustomSSLSocketFactory extends SSLSocketFactory { + private static final Logger LOG = LoggerFactory.getLogger(CustomSSLSocketFactory.class); + private SSLSocketFactory sockFactory; Review Comment: I suggest separating static and non-static members with a blank line. ########## ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapUserGroupBuilder.java: ########## @@ -52,1240 +50,1161 @@ import javax.naming.ldap.StartTlsRequest; import javax.naming.ldap.StartTlsResponse; -import org.apache.commons.collections.MapUtils; -import org.apache.commons.lang.StringUtils; -import org.apache.hadoop.thirdparty.com.google.common.collect.HashBasedTable; -import org.apache.hadoop.thirdparty.com.google.common.collect.Table; -import org.apache.ranger.ugsyncutil.util.UgsyncCommonConstants; -import org.apache.ranger.unixusersync.config.UserGroupSyncConfig; -import org.apache.ranger.ugsyncutil.model.LdapSyncSourceInfo; -import org.apache.ranger.ugsyncutil.model.UgsyncAuditInfo; -import org.apache.ranger.usergroupsync.UserGroupSink; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.ranger.usergroupsync.UserGroupSource; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Properties; +import java.util.Set; +import java.util.UUID; public class LdapUserGroupBuilder implements UserGroupSource { - - private static final Logger LOG = LoggerFactory.getLogger(LdapUserGroupBuilder.class); - - private UserGroupSyncConfig config = UserGroupSyncConfig.getInstance(); - - private static final String DATA_TYPE_BYTEARRAY = "byte[]"; - private static final String DATE_FORMAT = "yyyyMMddHHmmss"; - private static final int PAGE_SIZE = 500; - 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 - - 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 String userCloudIdAttribute; - private int userSearchScope; - private String userObjectClass; - private String userSearchFilter; - private Set<String> groupNameSet; - private String extendedUserSearchFilter; - private SearchControls userSearchControls; - private Set<String> userGroupNameAttributeSet; - private Set<String> otherUserAttributes; - - private boolean pagedResultsEnabled = true; - private int pagedResultsSize = PAGE_SIZE; - - private boolean groupSearchFirstEnabled = true; - private boolean userSearchEnabled = true; - 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 String groupCloudIdAttribute; - private Set<String> otherGroupAttributes; - private int groupHierarchyLevels; - private int deleteCycles; - private String currentSyncSource; - - private LdapContext ldapContext; - StartTlsResponse tls; - - private Table<String, String, String> groupUserTable; - UgsyncAuditInfo ugsyncAuditInfo; - LdapSyncSourceInfo ldapSyncSourceInfo; - - private Map<String, Map<String, String>> sourceUsers; // key is user DN and value is map of user attributes containing original name, DN, etc... - private Map<String, Map<String, String>> sourceGroups; // key is group DN and value is map of group attributes containing original name, DN, etc... - private Map<String, Set<String>> sourceGroupUsers; // key is group DN and value is set of user DNs (members) - - public static void main(String[] args) throws Throwable { - LdapUserGroupBuilder ugBuilder = new LdapUserGroupBuilder(); - ugBuilder.init(); - } - - @Override - public void init() throws Throwable{ - deltaSyncUserTime = 0; - deltaSyncGroupTime = 0; - deleteCycles = 1; - DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT); - deltaSyncUserTimeStamp = dateFormat.format(new Date(0)); - deltaSyncGroupTimeStamp = dateFormat.format(new Date(0)); - setConfig(); - ugsyncAuditInfo = new UgsyncAuditInfo(); - ldapSyncSourceInfo = new LdapSyncSourceInfo(); - ldapSyncSourceInfo.setLdapUrl(ldapUrl); - ldapSyncSourceInfo.setIncrementalSycn(Boolean.toString(config.isDeltaSyncEnabled())); - ldapSyncSourceInfo.setUserSearchEnabled(Boolean.toString(userSearchEnabled)); - ldapSyncSourceInfo.setGroupSearchEnabled(Boolean.toString(groupSearchEnabled)); - ldapSyncSourceInfo.setGroupSearchFirstEnabled(Boolean.toString(groupSearchFirstEnabled)); - ldapSyncSourceInfo.setGroupHierarchyLevel(Integer.toString(groupHierarchyLevels)); - ugsyncAuditInfo.setSyncSource(currentSyncSource); - ugsyncAuditInfo.setLdapSyncSourceInfo(ldapSyncSourceInfo); - } - - 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"); - } - - if (StringUtils.isNotEmpty(userCloudIdAttribute)) { - if (config.getUserCloudIdAttributeDataType().equals(DATA_TYPE_BYTEARRAY)) { - env.put("java.naming.ldap.attributes.binary", userCloudIdAttribute); - } - } - - if (StringUtils.isNotEmpty(groupCloudIdAttribute)) { - if (config.getGroupCloudIdAttributeDataType().equals(DATA_TYPE_BYTEARRAY)) { - env.put("java.naming.ldap.attributes.binary", groupCloudIdAttribute); - } - } - - for (String otherUserAttribute : otherUserAttributes) { - String attrType = config.getOtherUserAttributeDataType(otherUserAttribute); - if (attrType.equals(DATA_TYPE_BYTEARRAY)) { - env.put("java.naming.ldap.attributes.binary", otherUserAttribute); - } - } - - for (String otherGroupAttribute : otherGroupAttributes) { - String attrType = config.getOtherGroupAttributeDataType(otherGroupAttribute); - if (attrType.equals(DATA_TYPE_BYTEARRAY)) { - env.put("java.naming.ldap.attributes.binary", otherGroupAttribute); - } - } - 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("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(); - searchBase = config.getSearchBase(); - - userSearchBase = config.getUserSearchBase().split(";"); - userSearchScope = config.getUserSearchScope(); - userObjectClass = config.getUserObjectClass(); - userSearchFilter = config.getUserSearchFilter(); - userNameAttribute = config.getUserNameAttribute(); - userCloudIdAttribute = config.getUserCloudIdAttribute(); - - Set<String> userSearchAttributes = new HashSet<String>(); - userSearchAttributes.add(userNameAttribute); - userGroupNameAttributeSet = config.getUserGroupNameAttributeSet(); - for (String useGroupNameAttribute : userGroupNameAttributeSet) { - userSearchAttributes.add(useGroupNameAttribute); - } - userSearchAttributes.add(userCloudIdAttribute); - otherUserAttributes = config.getOtherUserAttributes(); - for (String otherUserAttribute : otherUserAttributes) { - userSearchAttributes.add(otherUserAttribute); - } - 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(); - 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()])); - - 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 { - 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("LdapUserGroupBuilder updateSink started"); + private static final Logger LOG = LoggerFactory.getLogger(LdapUserGroupBuilder.class); + private static final String DATA_TYPE_BYTEARRAY = "byte[]"; + private static final String DATE_FORMAT = "yyyyMMddHHmmss"; + private static final String MEMBER_OF_ATTR = "memberof="; + private static final String GROUP_NAME_ATTRIBUTE = "cn="; + private static final int PAGE_SIZE = 500; + /* for AD uSNChanged */ + private static long deltaSyncUserTime; + private static long deltaSyncGroupTime; + /* ***************** */ + private boolean pagedResultsEnabled = true; + private boolean groupSearchFirstEnabled = true; + private boolean userSearchEnabled = true; + private boolean groupSearchEnabled = true; + private int pagedResultsSize = PAGE_SIZE; + private int groupHierarchyLevels; + private int deleteCycles; + private int userSearchScope; + private int groupSearchScope; + + private UserGroupSyncConfig config = UserGroupSyncConfig.getInstance(); + /* for OpenLdap modifyTimestamp */ + private String deltaSyncUserTimeStamp; + private String deltaSyncGroupTimeStamp; + /* ******************************** */ + private String ldapUrl; + private String ldapBindDn; + private String ldapBindPassword; + private String ldapAuthenticationMechanism; + private String ldapReferral; + private String searchBase; + private String userNameAttribute; + private String userCloudIdAttribute; + private String userObjectClass; + private String userSearchFilter; + private String extendedUserSearchFilter; + private String groupObjectClass; + private String groupSearchFilter; + private String extendedGroupSearchFilter; + private String extendedAllGroupsSearchFilter; + private String groupMemberAttributeName; + private String groupNameAttribute; + private String groupCloudIdAttribute; + private String currentSyncSource; + private String[] userSearchBase; + private String[] groupSearchBase; + private Set<String> groupNameSet; + private Set<String> userGroupNameAttributeSet; + private Set<String> otherUserAttributes; + private Set<String> otherGroupAttributes; + private LdapContext ldapContext; + private SearchControls userSearchControls; + private SearchControls groupSearchControls; + private Table<String, String, String> groupUserTable; + /* { key = user DN, value = map of user attributes {original name, DN, etc.}} */ + private Map<String, Map<String, String>> sourceUsers; + /* { key = group DN, value = map of group attributes {original name, DN, etc.}} */ + private Map<String, Map<String, String>> sourceGroups; + /* { key = group DN, value = set of user DNs (members) } */ + private Map<String, Set<String>> sourceGroupUsers; + + StartTlsResponse tls; + UgsyncAuditInfo ugsyncAuditInfo; + LdapSyncSourceInfo ldapSyncSourceInfo; + + public static void main(String[] args) throws Throwable { + LdapUserGroupBuilder ugBuilder = new LdapUserGroupBuilder(); + ugBuilder.init(); + } + + @Override + public void init() throws Throwable { + deltaSyncUserTime = 0; + deltaSyncGroupTime = 0; + deleteCycles = 1; + DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT); + deltaSyncUserTimeStamp = dateFormat.format(new Date(0)); + deltaSyncGroupTimeStamp = dateFormat.format(new Date(0)); + setConfig(); + ugsyncAuditInfo = new UgsyncAuditInfo(); + ldapSyncSourceInfo = new LdapSyncSourceInfo(); + ldapSyncSourceInfo.setLdapUrl(ldapUrl); + ldapSyncSourceInfo.setIncrementalSycn(Boolean.toString(config.isDeltaSyncEnabled())); + ldapSyncSourceInfo.setUserSearchEnabled(Boolean.toString(userSearchEnabled)); + ldapSyncSourceInfo.setGroupSearchEnabled(Boolean.toString(groupSearchEnabled)); + ldapSyncSourceInfo.setGroupSearchFirstEnabled(Boolean.toString(groupSearchFirstEnabled)); + ldapSyncSourceInfo.setGroupHierarchyLevel(Integer.toString(groupHierarchyLevels)); + ugsyncAuditInfo.setSyncSource(currentSyncSource); + ugsyncAuditInfo.setLdapSyncSourceInfo(ldapSyncSourceInfo); + } + + @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("LdapUserGroupBuilder updateSink started"); boolean computeDeletes = false; - groupUserTable = HashBasedTable.create(); - sourceGroups = new HashMap<>(); - sourceUsers = new HashMap<>(); - sourceGroupUsers = new HashMap<>(); - long highestdeltaSyncUserTime = 0; - long highestdeltaSyncGroupTime = 0; - - if (config.isUserSyncDeletesEnabled() && deleteCycles >= config.getUserSyncDeletesFrequency()) { - deleteCycles = 1; - computeDeletes = true; - if (LOG.isDebugEnabled()) { - LOG.debug("Compute deleted users/groups is enabled for this sync cycle"); - } - } - if (config.isUserSyncDeletesEnabled()) { - deleteCycles++; - } - if (groupSearchEnabled) { - highestdeltaSyncGroupTime = getGroups(computeDeletes); - } - if (userSearchEnabled) { - LOG.info("Performing user search to retrieve users from AD/LDAP"); - highestdeltaSyncUserTime = getUsers(computeDeletes); - } - - if (groupHierarchyLevels > 0) { - LOG.info("Going through group hierarchy for nested group evaluation"); + groupUserTable = HashBasedTable.create(); + sourceGroups = new HashMap<>(); + sourceUsers = new HashMap<>(); + sourceGroupUsers = new HashMap<>(); + long highestdeltaSyncUserTime = 0; + long highestdeltaSyncGroupTime = 0; + + if (config.isUserSyncDeletesEnabled() && deleteCycles >= config.getUserSyncDeletesFrequency()) { + deleteCycles = 1; + computeDeletes = true; + LOG.debug("Compute deleted users/groups is enabled for this sync cycle"); + } + if (config.isUserSyncDeletesEnabled()) { + deleteCycles++; + } + if (groupSearchEnabled) { + highestdeltaSyncGroupTime = getGroups(computeDeletes); + } + if (userSearchEnabled) { + LOG.info("Performing user search to retrieve users from AD/LDAP"); + highestdeltaSyncUserTime = getUsers(computeDeletes); + } + + if (groupHierarchyLevels > 0) { + LOG.info("Going through group hierarchy for nested group evaluation"); Set<String> groupFullNames = sourceGroups.keySet(); - for(String group : groupFullNames) { - Set<String> nextLevelGroups = groupUserTable.column(group).keySet(); - goUpGroupHierarchy(nextLevelGroups, groupHierarchyLevels-1, group); - } - LOG.info("Completed group hierarchy computation"); - } - - Iterator<String> groupUserTableIterator = groupUserTable.rowKeySet().iterator(); - while (groupUserTableIterator.hasNext()) { - String groupName = groupUserTableIterator.next(); - Map<String,String> groupUsersMap = groupUserTable.row(groupName); - Set<String> userSet = new HashSet<String>(); - for(Map.Entry<String, String> entry : groupUsersMap.entrySet()){ - if (sourceUsers.containsKey(entry.getValue())) { - userSet.add(entry.getValue()); - } - } - sourceGroupUsers.put(groupName, userSet); - } - - if (LOG.isDebugEnabled()) { - LOG.debug("Users = " + sourceUsers.keySet()); - LOG.debug("Groups = " + sourceGroups.keySet()); - LOG.debug("GroupUsers = " + sourceGroupUsers.keySet()); - } - - try { - sink.addOrUpdateUsersGroups(sourceGroups, sourceUsers, sourceGroupUsers, computeDeletes); - DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT); - LOG.info("deltaSyncUserTime = " + deltaSyncUserTime + " and highestdeltaSyncUserTime = " + highestdeltaSyncUserTime); - 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 1sec in order to avoid search record repetition for next sync cycle. - deltaSyncUserTimeStamp = dateFormat.format(new Date(highestdeltaSyncUserTime + 60l)); - } - - LOG.info("deltaSyncGroupTime = " + deltaSyncGroupTime + " and highestdeltaSyncGroupTime = " + highestdeltaSyncGroupTime); - // Update deltaSyncUserTime/deltaSyncUserTimeStamp here so that in case of failures, we get updates in next cycle - 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 + 60l)); - } - } catch (Throwable t) { - LOG.error("Failed to update ranger admin. Will retry in next sync cycle!!", t); - } - - ldapSyncSourceInfo.setUserSearchFilter(extendedUserSearchFilter); - ldapSyncSourceInfo.setGroupSearchFilter(extendedAllGroupsSearchFilter); - - try { - sink.postUserGroupAuditInfo(ugsyncAuditInfo); - } catch (Throwable t) { - LOG.error("sink.postUserGroupAuditInfo failed with exception: " + t.getMessage()); - } - } - - private long getUsers(boolean computeDeletes) throws Throwable { - NamingEnumeration<SearchResult> userSearchResultEnum = null; - NamingEnumeration<SearchResult> groupSearchResultEnum = null; - long highestdeltaSyncUserTime; - try { - createLdapContext(); - int total; - // Activate paged results - if (pagedResultsEnabled) { - ldapContext.setRequestControls(new Control[]{ - new PagedResultsControl(pagedResultsSize, Control.NONCRITICAL) }); - } - DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT); - if (groupUserTable.rowKeySet().size() != 0 || !config.isDeltaSyncEnabled() || (computeDeletes)) { - // Fix RANGER-1957: Perform full sync when there are updates to the groups or when incremental sync is not enabled - deltaSyncUserTime = 0; - deltaSyncUserTimeStamp = dateFormat.format(new Date(0)); - } - - 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); - - 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 { - int paged = 0; - 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) { - 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 userNameAttr = attributes.get(userNameAttribute); - if (userNameAttr == null) { - LOG.info(userNameAttribute + " missing for entry " + userEntry.getNameInNamespace() + - ", skipping sync"); - continue; - } - - String userFullName = (userEntry.getNameInNamespace()); - String userName = (String) userNameAttr.get(); - - if (userName == null || userName.trim().isEmpty()) { - 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; - } - } - } - - // 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 groupDN = (String) groupEnum.next(); - if (LOG.isDebugEnabled()) { - LOG.debug("Adding " + groupDN + " to " + userName); - } - Map<String, String> groupAttrMap = new HashMap<>(); - String groupName = getShortName(groupDN); - groupAttrMap.put(UgsyncCommonConstants.ORIGINAL_NAME, groupName); - groupAttrMap.put(UgsyncCommonConstants.FULL_NAME, groupDN); - groupAttrMap.put(UgsyncCommonConstants.SYNC_SOURCE, currentSyncSource); - groupAttrMap.put(UgsyncCommonConstants.LDAP_URL, config.getLdapUrl()); - sourceGroups.put(groupDN, groupAttrMap); - if (LOG.isDebugEnabled()) { - LOG.debug("As groupsearch is disabled, adding group " + groupName + " from user memberof attribute for user " + userName); - } - groupUserTable.put(groupDN, userFullName, userFullName); - } - } - } - } - - Map<String, String> userAttrMap = new HashMap<>(); - userAttrMap.put(UgsyncCommonConstants.ORIGINAL_NAME, userName); - userAttrMap.put(UgsyncCommonConstants.FULL_NAME, userFullName); - userAttrMap.put(UgsyncCommonConstants.SYNC_SOURCE, currentSyncSource); - userAttrMap.put(UgsyncCommonConstants.LDAP_URL, config.getLdapUrl()); - Attribute userCloudIdAttr = attributes.get(userCloudIdAttribute); - if (userCloudIdAttr != null) { - addToAttrMap(userAttrMap, "cloud_id", userCloudIdAttr, config.getUserCloudIdAttributeDataType()); - } - for (String otherUserAttribute : otherUserAttributes) { - if (attributes.get(otherUserAttribute) != null) { - String attrType = config.getOtherUserAttributeDataType(otherUserAttribute); - addToAttrMap(userAttrMap, otherUserAttribute, attributes.get(otherUserAttribute), attrType); - } - } - - sourceUsers.put(userFullName, userAttrMap); - if ((groupUserTable.containsColumn(userFullName) || groupUserTable.containsColumn(userName))) { - //Update the username in the groupUserTable with the one from username attribute. - Map<String, String> userMap = groupUserTable.column(userFullName); - if (MapUtils.isEmpty(userMap)) { - userMap = groupUserTable.column(userName); - } - for (Map.Entry<String, String> entry : userMap.entrySet()) { - if (LOG.isDebugEnabled()) { - LOG.debug("Updating groupUserTable " + entry.getValue() + " with: " + userName + " for " + entry.getKey()); - } - groupUserTable.put(entry.getKey(), userFullName, userFullName); - } - } - counter++; - - if (counter <= 2000) { - LOG.info("Updating user count: " + counter + ", userName: " + userName); - 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. <==="); + for (String group : groupFullNames) { + Set<String> nextLevelGroups = groupUserTable.column(group).keySet(); + goUpGroupHierarchy(nextLevelGroups, groupHierarchyLevels - 1, group); + } + LOG.info("Completed group hierarchy computation"); + } + + Iterator<String> groupUserTableIterator = groupUserTable.rowKeySet().iterator(); + while (groupUserTableIterator.hasNext()) { + String groupName = groupUserTableIterator.next(); + Map<String, String> groupUsersMap = groupUserTable.row(groupName); + Set<String> userSet = new HashSet<String>(); + for (Map.Entry<String, String> entry : groupUsersMap.entrySet()) { + if (sourceUsers.containsKey(entry.getValue())) { + userSet.add(entry.getValue()); + } + } + sourceGroupUsers.put(groupName, userSet); + } + + LOG.debug("Users = {}", sourceUsers.keySet()); + LOG.debug("Groups = {}", sourceGroups.keySet()); + LOG.debug("GroupUsers = {}", sourceGroupUsers.keySet()); + + try { + sink.addOrUpdateUsersGroups(sourceGroups, sourceUsers, sourceGroupUsers, computeDeletes); + DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT); + LOG.info("deltaSyncUserTime = {} and highestdeltaSyncUserTime = {}", deltaSyncUserTime, highestdeltaSyncUserTime); + 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 1sec in order to avoid search record repetition for next sync cycle. + deltaSyncUserTimeStamp = dateFormat.format(new Date(highestdeltaSyncUserTime + 60L)); + } + + LOG.info("deltaSyncGroupTime = {} and highestdeltaSyncGroupTime = {} ", deltaSyncGroupTime, highestdeltaSyncGroupTime); + // Update deltaSyncUserTime/deltaSyncUserTimeStamp here so that in case of failures, we get updates in next cycle + 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 + 60L)); + } + } catch (Throwable t) { + LOG.error("Failed to update ranger admin. Will retry in next sync cycle!!", t); + } + + ldapSyncSourceInfo.setUserSearchFilter(extendedUserSearchFilter); + ldapSyncSourceInfo.setGroupSearchFilter(extendedAllGroupsSearchFilter); + + try { + sink.postUserGroupAuditInfo(ugsyncAuditInfo); + } catch (Throwable t) { + LOG.error("sink.postUserGroupAuditInfo failed with exception: " + t.getMessage()); Review Comment: Review log messages to replace string concat with parameterization. ########## ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapUserGroupBuilder.java: ########## @@ -52,1240 +50,1161 @@ import javax.naming.ldap.StartTlsRequest; import javax.naming.ldap.StartTlsResponse; -import org.apache.commons.collections.MapUtils; -import org.apache.commons.lang.StringUtils; -import org.apache.hadoop.thirdparty.com.google.common.collect.HashBasedTable; -import org.apache.hadoop.thirdparty.com.google.common.collect.Table; -import org.apache.ranger.ugsyncutil.util.UgsyncCommonConstants; -import org.apache.ranger.unixusersync.config.UserGroupSyncConfig; -import org.apache.ranger.ugsyncutil.model.LdapSyncSourceInfo; -import org.apache.ranger.ugsyncutil.model.UgsyncAuditInfo; -import org.apache.ranger.usergroupsync.UserGroupSink; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.ranger.usergroupsync.UserGroupSource; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Properties; +import java.util.Set; +import java.util.UUID; public class LdapUserGroupBuilder implements UserGroupSource { - - private static final Logger LOG = LoggerFactory.getLogger(LdapUserGroupBuilder.class); - - private UserGroupSyncConfig config = UserGroupSyncConfig.getInstance(); - - private static final String DATA_TYPE_BYTEARRAY = "byte[]"; - private static final String DATE_FORMAT = "yyyyMMddHHmmss"; - private static final int PAGE_SIZE = 500; - 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 - - 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 String userCloudIdAttribute; - private int userSearchScope; - private String userObjectClass; - private String userSearchFilter; - private Set<String> groupNameSet; - private String extendedUserSearchFilter; - private SearchControls userSearchControls; - private Set<String> userGroupNameAttributeSet; - private Set<String> otherUserAttributes; - - private boolean pagedResultsEnabled = true; - private int pagedResultsSize = PAGE_SIZE; - - private boolean groupSearchFirstEnabled = true; - private boolean userSearchEnabled = true; - 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 String groupCloudIdAttribute; - private Set<String> otherGroupAttributes; - private int groupHierarchyLevels; - private int deleteCycles; - private String currentSyncSource; - - private LdapContext ldapContext; - StartTlsResponse tls; - - private Table<String, String, String> groupUserTable; - UgsyncAuditInfo ugsyncAuditInfo; - LdapSyncSourceInfo ldapSyncSourceInfo; - - private Map<String, Map<String, String>> sourceUsers; // key is user DN and value is map of user attributes containing original name, DN, etc... - private Map<String, Map<String, String>> sourceGroups; // key is group DN and value is map of group attributes containing original name, DN, etc... - private Map<String, Set<String>> sourceGroupUsers; // key is group DN and value is set of user DNs (members) - - public static void main(String[] args) throws Throwable { - LdapUserGroupBuilder ugBuilder = new LdapUserGroupBuilder(); - ugBuilder.init(); - } - - @Override - public void init() throws Throwable{ - deltaSyncUserTime = 0; - deltaSyncGroupTime = 0; - deleteCycles = 1; - DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT); - deltaSyncUserTimeStamp = dateFormat.format(new Date(0)); - deltaSyncGroupTimeStamp = dateFormat.format(new Date(0)); - setConfig(); - ugsyncAuditInfo = new UgsyncAuditInfo(); - ldapSyncSourceInfo = new LdapSyncSourceInfo(); - ldapSyncSourceInfo.setLdapUrl(ldapUrl); - ldapSyncSourceInfo.setIncrementalSycn(Boolean.toString(config.isDeltaSyncEnabled())); - ldapSyncSourceInfo.setUserSearchEnabled(Boolean.toString(userSearchEnabled)); - ldapSyncSourceInfo.setGroupSearchEnabled(Boolean.toString(groupSearchEnabled)); - ldapSyncSourceInfo.setGroupSearchFirstEnabled(Boolean.toString(groupSearchFirstEnabled)); - ldapSyncSourceInfo.setGroupHierarchyLevel(Integer.toString(groupHierarchyLevels)); - ugsyncAuditInfo.setSyncSource(currentSyncSource); - ugsyncAuditInfo.setLdapSyncSourceInfo(ldapSyncSourceInfo); - } - - 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"); - } - - if (StringUtils.isNotEmpty(userCloudIdAttribute)) { - if (config.getUserCloudIdAttributeDataType().equals(DATA_TYPE_BYTEARRAY)) { - env.put("java.naming.ldap.attributes.binary", userCloudIdAttribute); - } - } - - if (StringUtils.isNotEmpty(groupCloudIdAttribute)) { - if (config.getGroupCloudIdAttributeDataType().equals(DATA_TYPE_BYTEARRAY)) { - env.put("java.naming.ldap.attributes.binary", groupCloudIdAttribute); - } - } - - for (String otherUserAttribute : otherUserAttributes) { - String attrType = config.getOtherUserAttributeDataType(otherUserAttribute); - if (attrType.equals(DATA_TYPE_BYTEARRAY)) { - env.put("java.naming.ldap.attributes.binary", otherUserAttribute); - } - } - - for (String otherGroupAttribute : otherGroupAttributes) { - String attrType = config.getOtherGroupAttributeDataType(otherGroupAttribute); - if (attrType.equals(DATA_TYPE_BYTEARRAY)) { - env.put("java.naming.ldap.attributes.binary", otherGroupAttribute); - } - } - 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("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(); - searchBase = config.getSearchBase(); - - userSearchBase = config.getUserSearchBase().split(";"); - userSearchScope = config.getUserSearchScope(); - userObjectClass = config.getUserObjectClass(); - userSearchFilter = config.getUserSearchFilter(); - userNameAttribute = config.getUserNameAttribute(); - userCloudIdAttribute = config.getUserCloudIdAttribute(); - - Set<String> userSearchAttributes = new HashSet<String>(); - userSearchAttributes.add(userNameAttribute); - userGroupNameAttributeSet = config.getUserGroupNameAttributeSet(); - for (String useGroupNameAttribute : userGroupNameAttributeSet) { - userSearchAttributes.add(useGroupNameAttribute); - } - userSearchAttributes.add(userCloudIdAttribute); - otherUserAttributes = config.getOtherUserAttributes(); - for (String otherUserAttribute : otherUserAttributes) { - userSearchAttributes.add(otherUserAttribute); - } - 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(); - 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()])); - - 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 { - 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("LdapUserGroupBuilder updateSink started"); + private static final Logger LOG = LoggerFactory.getLogger(LdapUserGroupBuilder.class); + private static final String DATA_TYPE_BYTEARRAY = "byte[]"; + private static final String DATE_FORMAT = "yyyyMMddHHmmss"; + private static final String MEMBER_OF_ATTR = "memberof="; + private static final String GROUP_NAME_ATTRIBUTE = "cn="; + private static final int PAGE_SIZE = 500; + /* for AD uSNChanged */ + private static long deltaSyncUserTime; + private static long deltaSyncGroupTime; + /* ***************** */ + private boolean pagedResultsEnabled = true; + private boolean groupSearchFirstEnabled = true; + private boolean userSearchEnabled = true; + private boolean groupSearchEnabled = true; + private int pagedResultsSize = PAGE_SIZE; + private int groupHierarchyLevels; + private int deleteCycles; + private int userSearchScope; + private int groupSearchScope; + + private UserGroupSyncConfig config = UserGroupSyncConfig.getInstance(); + /* for OpenLdap modifyTimestamp */ + private String deltaSyncUserTimeStamp; + private String deltaSyncGroupTimeStamp; + /* ******************************** */ + private String ldapUrl; + private String ldapBindDn; + private String ldapBindPassword; + private String ldapAuthenticationMechanism; + private String ldapReferral; + private String searchBase; + private String userNameAttribute; + private String userCloudIdAttribute; + private String userObjectClass; + private String userSearchFilter; + private String extendedUserSearchFilter; + private String groupObjectClass; + private String groupSearchFilter; + private String extendedGroupSearchFilter; + private String extendedAllGroupsSearchFilter; + private String groupMemberAttributeName; + private String groupNameAttribute; + private String groupCloudIdAttribute; + private String currentSyncSource; + private String[] userSearchBase; + private String[] groupSearchBase; + private Set<String> groupNameSet; + private Set<String> userGroupNameAttributeSet; + private Set<String> otherUserAttributes; + private Set<String> otherGroupAttributes; + private LdapContext ldapContext; + private SearchControls userSearchControls; + private SearchControls groupSearchControls; + private Table<String, String, String> groupUserTable; + /* { key = user DN, value = map of user attributes {original name, DN, etc.}} */ + private Map<String, Map<String, String>> sourceUsers; + /* { key = group DN, value = map of group attributes {original name, DN, etc.}} */ + private Map<String, Map<String, String>> sourceGroups; + /* { key = group DN, value = set of user DNs (members) } */ + private Map<String, Set<String>> sourceGroupUsers; + + StartTlsResponse tls; + UgsyncAuditInfo ugsyncAuditInfo; + LdapSyncSourceInfo ldapSyncSourceInfo; + + public static void main(String[] args) throws Throwable { + LdapUserGroupBuilder ugBuilder = new LdapUserGroupBuilder(); + ugBuilder.init(); + } + + @Override + public void init() throws Throwable { + deltaSyncUserTime = 0; + deltaSyncGroupTime = 0; + deleteCycles = 1; + DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT); + deltaSyncUserTimeStamp = dateFormat.format(new Date(0)); + deltaSyncGroupTimeStamp = dateFormat.format(new Date(0)); + setConfig(); + ugsyncAuditInfo = new UgsyncAuditInfo(); + ldapSyncSourceInfo = new LdapSyncSourceInfo(); + ldapSyncSourceInfo.setLdapUrl(ldapUrl); + ldapSyncSourceInfo.setIncrementalSycn(Boolean.toString(config.isDeltaSyncEnabled())); + ldapSyncSourceInfo.setUserSearchEnabled(Boolean.toString(userSearchEnabled)); + ldapSyncSourceInfo.setGroupSearchEnabled(Boolean.toString(groupSearchEnabled)); + ldapSyncSourceInfo.setGroupSearchFirstEnabled(Boolean.toString(groupSearchFirstEnabled)); + ldapSyncSourceInfo.setGroupHierarchyLevel(Integer.toString(groupHierarchyLevels)); + ugsyncAuditInfo.setSyncSource(currentSyncSource); + ugsyncAuditInfo.setLdapSyncSourceInfo(ldapSyncSourceInfo); + } + + @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("LdapUserGroupBuilder updateSink started"); boolean computeDeletes = false; - groupUserTable = HashBasedTable.create(); - sourceGroups = new HashMap<>(); - sourceUsers = new HashMap<>(); - sourceGroupUsers = new HashMap<>(); - long highestdeltaSyncUserTime = 0; - long highestdeltaSyncGroupTime = 0; - - if (config.isUserSyncDeletesEnabled() && deleteCycles >= config.getUserSyncDeletesFrequency()) { - deleteCycles = 1; - computeDeletes = true; - if (LOG.isDebugEnabled()) { - LOG.debug("Compute deleted users/groups is enabled for this sync cycle"); - } - } - if (config.isUserSyncDeletesEnabled()) { - deleteCycles++; - } - if (groupSearchEnabled) { - highestdeltaSyncGroupTime = getGroups(computeDeletes); - } - if (userSearchEnabled) { - LOG.info("Performing user search to retrieve users from AD/LDAP"); - highestdeltaSyncUserTime = getUsers(computeDeletes); - } - - if (groupHierarchyLevels > 0) { - LOG.info("Going through group hierarchy for nested group evaluation"); + groupUserTable = HashBasedTable.create(); + sourceGroups = new HashMap<>(); + sourceUsers = new HashMap<>(); + sourceGroupUsers = new HashMap<>(); + long highestdeltaSyncUserTime = 0; + long highestdeltaSyncGroupTime = 0; + + if (config.isUserSyncDeletesEnabled() && deleteCycles >= config.getUserSyncDeletesFrequency()) { + deleteCycles = 1; + computeDeletes = true; + LOG.debug("Compute deleted users/groups is enabled for this sync cycle"); + } + if (config.isUserSyncDeletesEnabled()) { + deleteCycles++; + } + if (groupSearchEnabled) { + highestdeltaSyncGroupTime = getGroups(computeDeletes); + } + if (userSearchEnabled) { + LOG.info("Performing user search to retrieve users from AD/LDAP"); + highestdeltaSyncUserTime = getUsers(computeDeletes); + } + + if (groupHierarchyLevels > 0) { + LOG.info("Going through group hierarchy for nested group evaluation"); Set<String> groupFullNames = sourceGroups.keySet(); - for(String group : groupFullNames) { - Set<String> nextLevelGroups = groupUserTable.column(group).keySet(); - goUpGroupHierarchy(nextLevelGroups, groupHierarchyLevels-1, group); - } - LOG.info("Completed group hierarchy computation"); - } - - Iterator<String> groupUserTableIterator = groupUserTable.rowKeySet().iterator(); - while (groupUserTableIterator.hasNext()) { - String groupName = groupUserTableIterator.next(); - Map<String,String> groupUsersMap = groupUserTable.row(groupName); - Set<String> userSet = new HashSet<String>(); - for(Map.Entry<String, String> entry : groupUsersMap.entrySet()){ - if (sourceUsers.containsKey(entry.getValue())) { - userSet.add(entry.getValue()); - } - } - sourceGroupUsers.put(groupName, userSet); - } - - if (LOG.isDebugEnabled()) { - LOG.debug("Users = " + sourceUsers.keySet()); - LOG.debug("Groups = " + sourceGroups.keySet()); - LOG.debug("GroupUsers = " + sourceGroupUsers.keySet()); - } - - try { - sink.addOrUpdateUsersGroups(sourceGroups, sourceUsers, sourceGroupUsers, computeDeletes); - DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT); - LOG.info("deltaSyncUserTime = " + deltaSyncUserTime + " and highestdeltaSyncUserTime = " + highestdeltaSyncUserTime); - 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 1sec in order to avoid search record repetition for next sync cycle. - deltaSyncUserTimeStamp = dateFormat.format(new Date(highestdeltaSyncUserTime + 60l)); - } - - LOG.info("deltaSyncGroupTime = " + deltaSyncGroupTime + " and highestdeltaSyncGroupTime = " + highestdeltaSyncGroupTime); - // Update deltaSyncUserTime/deltaSyncUserTimeStamp here so that in case of failures, we get updates in next cycle - 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 + 60l)); - } - } catch (Throwable t) { - LOG.error("Failed to update ranger admin. Will retry in next sync cycle!!", t); - } - - ldapSyncSourceInfo.setUserSearchFilter(extendedUserSearchFilter); - ldapSyncSourceInfo.setGroupSearchFilter(extendedAllGroupsSearchFilter); - - try { - sink.postUserGroupAuditInfo(ugsyncAuditInfo); - } catch (Throwable t) { - LOG.error("sink.postUserGroupAuditInfo failed with exception: " + t.getMessage()); - } - } - - private long getUsers(boolean computeDeletes) throws Throwable { - NamingEnumeration<SearchResult> userSearchResultEnum = null; - NamingEnumeration<SearchResult> groupSearchResultEnum = null; - long highestdeltaSyncUserTime; - try { - createLdapContext(); - int total; - // Activate paged results - if (pagedResultsEnabled) { - ldapContext.setRequestControls(new Control[]{ - new PagedResultsControl(pagedResultsSize, Control.NONCRITICAL) }); - } - DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT); - if (groupUserTable.rowKeySet().size() != 0 || !config.isDeltaSyncEnabled() || (computeDeletes)) { - // Fix RANGER-1957: Perform full sync when there are updates to the groups or when incremental sync is not enabled - deltaSyncUserTime = 0; - deltaSyncUserTimeStamp = dateFormat.format(new Date(0)); - } - - 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); - - 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 { - int paged = 0; - 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) { - 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 userNameAttr = attributes.get(userNameAttribute); - if (userNameAttr == null) { - LOG.info(userNameAttribute + " missing for entry " + userEntry.getNameInNamespace() + - ", skipping sync"); - continue; - } - - String userFullName = (userEntry.getNameInNamespace()); - String userName = (String) userNameAttr.get(); - - if (userName == null || userName.trim().isEmpty()) { - 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; - } - } - } - - // 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 groupDN = (String) groupEnum.next(); - if (LOG.isDebugEnabled()) { - LOG.debug("Adding " + groupDN + " to " + userName); - } - Map<String, String> groupAttrMap = new HashMap<>(); - String groupName = getShortName(groupDN); - groupAttrMap.put(UgsyncCommonConstants.ORIGINAL_NAME, groupName); - groupAttrMap.put(UgsyncCommonConstants.FULL_NAME, groupDN); - groupAttrMap.put(UgsyncCommonConstants.SYNC_SOURCE, currentSyncSource); - groupAttrMap.put(UgsyncCommonConstants.LDAP_URL, config.getLdapUrl()); - sourceGroups.put(groupDN, groupAttrMap); - if (LOG.isDebugEnabled()) { - LOG.debug("As groupsearch is disabled, adding group " + groupName + " from user memberof attribute for user " + userName); - } - groupUserTable.put(groupDN, userFullName, userFullName); - } - } - } - } - - Map<String, String> userAttrMap = new HashMap<>(); - userAttrMap.put(UgsyncCommonConstants.ORIGINAL_NAME, userName); - userAttrMap.put(UgsyncCommonConstants.FULL_NAME, userFullName); - userAttrMap.put(UgsyncCommonConstants.SYNC_SOURCE, currentSyncSource); - userAttrMap.put(UgsyncCommonConstants.LDAP_URL, config.getLdapUrl()); - Attribute userCloudIdAttr = attributes.get(userCloudIdAttribute); - if (userCloudIdAttr != null) { - addToAttrMap(userAttrMap, "cloud_id", userCloudIdAttr, config.getUserCloudIdAttributeDataType()); - } - for (String otherUserAttribute : otherUserAttributes) { - if (attributes.get(otherUserAttribute) != null) { - String attrType = config.getOtherUserAttributeDataType(otherUserAttribute); - addToAttrMap(userAttrMap, otherUserAttribute, attributes.get(otherUserAttribute), attrType); - } - } - - sourceUsers.put(userFullName, userAttrMap); - if ((groupUserTable.containsColumn(userFullName) || groupUserTable.containsColumn(userName))) { - //Update the username in the groupUserTable with the one from username attribute. - Map<String, String> userMap = groupUserTable.column(userFullName); - if (MapUtils.isEmpty(userMap)) { - userMap = groupUserTable.column(userName); - } - for (Map.Entry<String, String> entry : userMap.entrySet()) { - if (LOG.isDebugEnabled()) { - LOG.debug("Updating groupUserTable " + entry.getValue() + " with: " + userName + " for " + entry.getKey()); - } - groupUserTable.put(entry.getKey(), userFullName, userFullName); - } - } - counter++; - - if (counter <= 2000) { - LOG.info("Updating user count: " + counter + ", userName: " + userName); - 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. <==="); + for (String group : groupFullNames) { + Set<String> nextLevelGroups = groupUserTable.column(group).keySet(); + goUpGroupHierarchy(nextLevelGroups, groupHierarchyLevels - 1, group); + } + LOG.info("Completed group hierarchy computation"); + } + + Iterator<String> groupUserTableIterator = groupUserTable.rowKeySet().iterator(); + while (groupUserTableIterator.hasNext()) { + String groupName = groupUserTableIterator.next(); + Map<String, String> groupUsersMap = groupUserTable.row(groupName); + Set<String> userSet = new HashSet<String>(); + for (Map.Entry<String, String> entry : groupUsersMap.entrySet()) { + if (sourceUsers.containsKey(entry.getValue())) { + userSet.add(entry.getValue()); + } + } + sourceGroupUsers.put(groupName, userSet); + } + + LOG.debug("Users = {}", sourceUsers.keySet()); + LOG.debug("Groups = {}", sourceGroups.keySet()); + LOG.debug("GroupUsers = {}", sourceGroupUsers.keySet()); + + try { + sink.addOrUpdateUsersGroups(sourceGroups, sourceUsers, sourceGroupUsers, computeDeletes); + DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT); + LOG.info("deltaSyncUserTime = {} and highestdeltaSyncUserTime = {}", deltaSyncUserTime, highestdeltaSyncUserTime); + 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 1sec in order to avoid search record repetition for next sync cycle. + deltaSyncUserTimeStamp = dateFormat.format(new Date(highestdeltaSyncUserTime + 60L)); + } + + LOG.info("deltaSyncGroupTime = {} and highestdeltaSyncGroupTime = {} ", deltaSyncGroupTime, highestdeltaSyncGroupTime); + // Update deltaSyncUserTime/deltaSyncUserTimeStamp here so that in case of failures, we get updates in next cycle + 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 + 60L)); + } + } catch (Throwable t) { + LOG.error("Failed to update ranger admin. Will retry in next sync cycle!!", t); + } + + ldapSyncSourceInfo.setUserSearchFilter(extendedUserSearchFilter); + ldapSyncSourceInfo.setGroupSearchFilter(extendedAllGroupsSearchFilter); + + try { + sink.postUserGroupAuditInfo(ugsyncAuditInfo); + } catch (Throwable t) { + LOG.error("sink.postUserGroupAuditInfo failed with exception: " + t.getMessage()); + } + } + + 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"); + } + + if (StringUtils.isNotEmpty(userCloudIdAttribute)) { + if (config.getUserCloudIdAttributeDataType().equals(DATA_TYPE_BYTEARRAY)) { + env.put("java.naming.ldap.attributes.binary", userCloudIdAttribute); + } + } + + if (StringUtils.isNotEmpty(groupCloudIdAttribute)) { + if (config.getGroupCloudIdAttributeDataType().equals(DATA_TYPE_BYTEARRAY)) { + env.put("java.naming.ldap.attributes.binary", groupCloudIdAttribute); + } + } + + for (String otherUserAttribute : otherUserAttributes) { + String attrType = config.getOtherUserAttributeDataType(otherUserAttribute); + if (attrType.equals(DATA_TYPE_BYTEARRAY)) { + env.put("java.naming.ldap.attributes.binary", otherUserAttribute); + } + } + + for (String otherGroupAttribute : otherGroupAttributes) { + String attrType = config.getOtherGroupAttributeDataType(otherGroupAttribute); + if (attrType.equals(DATA_TYPE_BYTEARRAY)) { + env.put("java.naming.ldap.attributes.binary", otherGroupAttribute); + } + } + 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("LdapUserGroupBuilder initialization started"); + groupSearchFirstEnabled = true; + currentSyncSource = config.getCurrentSyncSource(); + userSearchEnabled = config.isUserSearchEnabled(); + groupSearchEnabled = config.isGroupSearchEnabled(); + ldapUrl = config.getLdapUrl(); + ldapBindDn = config.getLdapBindDn(); + ldapBindPassword = config.getLdapBindPassword(); + 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(); + + Set<String> userSearchAttributes = new HashSet<String>(); + userSearchAttributes.add(userNameAttribute); + userGroupNameAttributeSet = config.getUserGroupNameAttributeSet(); + for (String useGroupNameAttribute : userGroupNameAttributeSet) { + userSearchAttributes.add(useGroupNameAttribute); + } + userSearchAttributes.add(userCloudIdAttribute); + otherUserAttributes = config.getOtherUserAttributes(); + for (String otherUserAttribute : otherUserAttributes) { + userSearchAttributes.add(otherUserAttribute); + } + 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(); + 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()])); + + 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 { + if (tls != null) { + tls.close(); + } + if (ldapContext != null) { + ldapContext.close(); + } + } + + private long getUsers(boolean computeDeletes) throws Throwable { + NamingEnumeration<SearchResult> userSearchResultEnum = null; + NamingEnumeration<SearchResult> groupSearchResultEnum = null; + long highestdeltaSyncUserTime; + try { + createLdapContext(); + int total; + // Activate paged results + if (pagedResultsEnabled) { + ldapContext.setRequestControls(new Control[] {new PagedResultsControl(pagedResultsSize, Control.NONCRITICAL)}); + } + DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT); + if (groupUserTable.rowKeySet().size() != 0 || !config.isDeltaSyncEnabled() || (computeDeletes)) { + // Fix RANGER-1957: Perform full sync when there are updates to the groups or when incremental sync is not enabled + deltaSyncUserTime = 0; + deltaSyncUserTimeStamp = dateFormat.format(new Date(0)); + } + + 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); + + highestdeltaSyncUserTime = deltaSyncUserTime; + + // When multiple OUs are configured, go through each OU as the user search base to search for users. + for (String s : userSearchBase) { + byte[] cookie = null; + int counter = 0; + try { + int paged = 0; + do { + userSearchResultEnum = ldapContext.search(s, extendedUserSearchFilter, userSearchControls); + + 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; } - } else { - if (LOG.isTraceEnabled()) { - LOG.trace("Updating user count: " + counter - + ", userName: " + userName); - } else { - if ( counter % 100 == 0) { - LOG.info("Synced " + counter + " users till now"); + + Attributes attributes = userEntry.getAttributes(); + if (attributes == null) { + LOG.info("attributes missing for entry {}, skipping sync", userEntry.getNameInNamespace()); + continue; + } + + Attribute userNameAttr = attributes.get(userNameAttribute); + if (userNameAttr == null) { + LOG.info("{} missing for entry {}, skipping sync", userNameAttribute, userEntry.getNameInNamespace()); + continue; + } + + String userFullName = userEntry.getNameInNamespace(); + String userName = (String) userNameAttr.get(); + + if (userName == null || userName.trim().isEmpty()) { + LOG.info("{} empty for entry {}, skipping sync", userNameAttribute, userEntry.getNameInNamespace()); + continue; + } + + Attribute timeStampAttr = attributes.get("uSNChanged"); + if (timeStampAttr != null) { + String uSNChangedVal = (String) timeStampAttr.get(); + long currentDeltaSyncTime = Long.parseLong(uSNChangedVal); + LOG.info("uSNChangedVal = {} and currentDeltaSyncTime = {}", uSNChangedVal, 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 = {} and currentDeltaSyncTime = {}", timeStampVal, currentDeltaSyncTime); + if (currentDeltaSyncTime > highestdeltaSyncUserTime) { + highestdeltaSyncUserTime = currentDeltaSyncTime; + deltaSyncUserTimeStamp = timeStampVal; + } + } + } + + // 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 groupDN = (String) groupEnum.next(); + if (LOG.isDebugEnabled()) { Review Comment: Consider removing `if (LOG.isDebugEnabled()) {`, unless arguments to log calls are expensive to compute. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: dev-unsubscr...@ranger.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org