From 5f5ceaa47a64a032693f3b9b9cc3f0a2ed157c2e Mon Sep 17 00:00:00 2001 From: James Moger <james.moger@gitblit.com> Date: Fri, 21 Feb 2014 08:36:18 -0500 Subject: [PATCH] Merged ticket #5 patchset 2 --- src/main/java/com/gitblit/auth/LdapAuthProvider.java | 195 +++++++++++++++++++++++++++++++----------------- 1 files changed, 126 insertions(+), 69 deletions(-) diff --git a/src/main/java/com/gitblit/auth/LdapAuthProvider.java b/src/main/java/com/gitblit/auth/LdapAuthProvider.java index 8fef620..3a688d8 100644 --- a/src/main/java/com/gitblit/auth/LdapAuthProvider.java +++ b/src/main/java/com/gitblit/auth/LdapAuthProvider.java @@ -19,12 +19,14 @@ import java.net.URI; import java.net.URISyntaxException; import java.security.GeneralSecurityException; +import java.text.MessageFormat; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; import com.gitblit.Constants; import com.gitblit.Constants.AccountType; @@ -32,6 +34,7 @@ import com.gitblit.auth.AuthenticationProvider.UsernamePasswordAuthenticationProvider; import com.gitblit.models.TeamModel; import com.gitblit.models.UserModel; +import com.gitblit.service.LdapSyncService; import com.gitblit.utils.ArrayUtils; import com.gitblit.utils.StringUtils; import com.unboundid.ldap.sdk.Attribute; @@ -57,101 +60,119 @@ */ public class LdapAuthProvider extends UsernamePasswordAuthenticationProvider { - private AtomicLong lastLdapUserSync = new AtomicLong(0L); + private final ScheduledExecutorService scheduledExecutorService; public LdapAuthProvider() { super("ldap"); + + scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); } - private long getSynchronizationPeriod() { - final String cacheDuration = settings.getString(Keys.realm.ldap.ldapCachePeriod, "2 MINUTES"); + private long getSynchronizationPeriodInMilliseconds() { + String period = settings.getString(Keys.realm.ldap.syncPeriod, null); + if (StringUtils.isEmpty(period)) { + period = settings.getString("realm.ldap.ldapCachePeriod", null); + if (StringUtils.isEmpty(period)) { + period = "5 MINUTES"; + } else { + logger.warn("realm.ldap.ldapCachePeriod is obsolete!"); + logger.warn(MessageFormat.format("Please set {0}={1} in gitblit.properties!", Keys.realm.ldap.syncPeriod, period)); + settings.overrideSetting(Keys.realm.ldap.syncPeriod, period); + } + } + try { - final String[] s = cacheDuration.split(" ", 2); - long duration = Long.parseLong(s[0]); + final String[] s = period.split(" ", 2); + long duration = Math.abs(Long.parseLong(s[0])); TimeUnit timeUnit = TimeUnit.valueOf(s[1]); return timeUnit.toMillis(duration); } catch (RuntimeException ex) { - throw new IllegalArgumentException(Keys.realm.ldap.ldapCachePeriod + " must have format '<long> <TimeUnit>' where <TimeUnit> is one of 'MILLISECONDS', 'SECONDS', 'MINUTES', 'HOURS', 'DAYS'"); + throw new IllegalArgumentException(Keys.realm.ldap.syncPeriod + " must have format '<long> <TimeUnit>' where <TimeUnit> is one of 'MILLISECONDS', 'SECONDS', 'MINUTES', 'HOURS', 'DAYS'"); } } @Override public void setup() { - synchronizeLdapUsers(); + configureSyncService(); } - protected synchronized void synchronizeLdapUsers() { - final boolean enabled = settings.getBoolean(Keys.realm.ldap.synchronizeUsers.enable, false); - if (enabled) { - if (System.currentTimeMillis() > (lastLdapUserSync.get() + getSynchronizationPeriod())) { - logger.info("Synchronizing with LDAP @ " + settings.getRequiredString(Keys.realm.ldap.server)); - final boolean deleteRemovedLdapUsers = settings.getBoolean(Keys.realm.ldap.synchronizeUsers.removeDeleted, true); - LDAPConnection ldapConnection = getLdapConnection(); - if (ldapConnection != null) { - try { - String accountBase = settings.getString(Keys.realm.ldap.accountBase, ""); - String uidAttribute = settings.getString(Keys.realm.ldap.uid, "uid"); - String accountPattern = settings.getString(Keys.realm.ldap.accountPattern, "(&(objectClass=person)(sAMAccountName=${username}))"); - accountPattern = StringUtils.replace(accountPattern, "${username}", "*"); + @Override + public void stop() { + scheduledExecutorService.shutdownNow(); + } - SearchResult result = doSearch(ldapConnection, accountBase, accountPattern); - if (result != null && result.getEntryCount() > 0) { - final Map<String, UserModel> ldapUsers = new HashMap<String, UserModel>(); + public synchronized void sync() { + final boolean enabled = settings.getBoolean(Keys.realm.ldap.synchronize, false); + if (enabled) { + logger.info("Synchronizing with LDAP @ " + settings.getRequiredString(Keys.realm.ldap.server)); + final boolean deleteRemovedLdapUsers = settings.getBoolean(Keys.realm.ldap.removeDeletedUsers, true); + LDAPConnection ldapConnection = getLdapConnection(); + if (ldapConnection != null) { + try { + String accountBase = settings.getString(Keys.realm.ldap.accountBase, ""); + String uidAttribute = settings.getString(Keys.realm.ldap.uid, "uid"); + String accountPattern = settings.getString(Keys.realm.ldap.accountPattern, "(&(objectClass=person)(sAMAccountName=${username}))"); + accountPattern = StringUtils.replace(accountPattern, "${username}", "*"); - for (SearchResultEntry loggingInUser : result.getSearchEntries()) { + SearchResult result = doSearch(ldapConnection, accountBase, accountPattern); + if (result != null && result.getEntryCount() > 0) { + final Map<String, UserModel> ldapUsers = new HashMap<String, UserModel>(); - final String username = loggingInUser.getAttribute(uidAttribute).getValue(); - logger.debug("LDAP synchronizing: " + username); + for (SearchResultEntry loggingInUser : result.getSearchEntries()) { - UserModel user = userManager.getUserModel(username); - if (user == null) { - user = new UserModel(username); - } + final String username = loggingInUser.getAttribute(uidAttribute).getValue(); + logger.debug("LDAP synchronizing: " + username); - if (!supportsTeamMembershipChanges()) { - getTeamsFromLdap(ldapConnection, username, loggingInUser, user); - } + UserModel user = userManager.getUserModel(username); + if (user == null) { + user = new UserModel(username); + } - // Get User Attributes - setUserAttributes(user, loggingInUser); + if (!supportsTeamMembershipChanges()) { + getTeamsFromLdap(ldapConnection, username, loggingInUser, user); + } - // store in map - ldapUsers.put(username.toLowerCase(), user); - } + // Get User Attributes + setUserAttributes(user, loggingInUser); - if (deleteRemovedLdapUsers) { - logger.debug("detecting removed LDAP users..."); + // store in map + ldapUsers.put(username.toLowerCase(), user); + } - for (UserModel userModel : userManager.getAllUsers()) { - if (Constants.EXTERNAL_ACCOUNT.equals(userModel.password)) { - if (!ldapUsers.containsKey(userModel.username)) { - logger.info("deleting removed LDAP user " + userModel.username + " from user service"); - userManager.deleteUser(userModel.username); - } - } - } - } + if (deleteRemovedLdapUsers) { + logger.debug("detecting removed LDAP users..."); - userManager.updateUserModels(ldapUsers.values()); + for (UserModel userModel : userManager.getAllUsers()) { + if (AccountType.LDAP == userModel.accountType) { + if (!ldapUsers.containsKey(userModel.username)) { + logger.info("deleting removed LDAP user " + userModel.username + " from user service"); + userManager.deleteUser(userModel.username); + } + } + } + } - if (!supportsTeamMembershipChanges()) { - final Map<String, TeamModel> userTeams = new HashMap<String, TeamModel>(); - for (UserModel user : ldapUsers.values()) { - for (TeamModel userTeam : user.teams) { - userTeams.put(userTeam.name, userTeam); - } - } - userManager.updateTeamModels(userTeams.values()); - } - } - lastLdapUserSync.set(System.currentTimeMillis()); - } finally { - ldapConnection.close(); - } - } - } - } - } + userManager.updateUserModels(ldapUsers.values()); + + if (!supportsTeamMembershipChanges()) { + final Map<String, TeamModel> userTeams = new HashMap<String, TeamModel>(); + for (UserModel user : ldapUsers.values()) { + for (TeamModel userTeam : user.teams) { + userTeams.put(userTeam.name, userTeam); + } + } + userManager.updateTeamModels(userTeams.values()); + } + } + if (!supportsTeamMembershipChanges()) { + getEmptyTeamsFromLdap(ldapConnection); + } + } finally { + ldapConnection.close(); + } + } + } + } private LDAPConnection getLdapConnection() { try { @@ -427,6 +448,29 @@ } } + private void getEmptyTeamsFromLdap(LDAPConnection ldapConnection) { + logger.info("Start fetching empty teams from ldap."); + String groupBase = settings.getString(Keys.realm.ldap.groupBase, ""); + String groupMemberPattern = settings.getString(Keys.realm.ldap.groupEmptyMemberPattern, "(&(objectClass=group)(!(member=*)))"); + + SearchResult teamMembershipResult = doSearch(ldapConnection, groupBase, true, groupMemberPattern, null); + if (teamMembershipResult != null && teamMembershipResult.getEntryCount() > 0) { + for (int i = 0; i < teamMembershipResult.getEntryCount(); i++) { + SearchResultEntry teamEntry = teamMembershipResult.getSearchEntries().get(i); + if (!teamEntry.hasAttribute("member")) { + String teamName = teamEntry.getAttribute("cn").getValue(); + + TeamModel teamModel = userManager.getTeamModel(teamName); + if (teamModel == null) { + teamModel = createTeamFromLdap(teamEntry); + userManager.updateTeamModel(teamModel); + } + } + } + } + logger.info("Finished fetching empty teams from ldap."); + } + private TeamModel createTeamFromLdap(SearchResultEntry teamEntry) { TeamModel answer = new TeamModel(teamEntry.getAttributeValue("cn")); answer.accountType = getAccountType(); @@ -519,4 +563,17 @@ } return sb.toString(); } + + private void configureSyncService() { + LdapSyncService ldapSyncService = new LdapSyncService(settings, this); + if (ldapSyncService.isReady()) { + long ldapSyncPeriod = getSynchronizationPeriodInMilliseconds(); + int delay = 1; + logger.info("Ldap sync service will update users and groups every {} minutes.", ldapSyncPeriod); + scheduledExecutorService.scheduleAtFixedRate(ldapSyncService, delay, ldapSyncPeriod, TimeUnit.MILLISECONDS); + } else { + logger.info("Ldap sync service is disabled."); + } + } + } -- Gitblit v1.9.1