releases.moxie | ●●●●● patch | view | raw | blame | history | |
src/main/distrib/data/gitblit.properties | ●●●●● patch | view | raw | blame | history | |
src/main/java/com/gitblit/auth/AuthenticationProvider.java | ●●●●● patch | view | raw | blame | history | |
src/main/java/com/gitblit/auth/LdapAuthProvider.java | ●●●●● patch | view | raw | blame | history | |
src/main/java/com/gitblit/manager/AuthenticationManager.java | ●●●●● patch | view | raw | blame | history | |
src/main/java/com/gitblit/service/LdapSyncService.java | ●●●●● patch | view | raw | blame | history | |
src/test/java/com/gitblit/tests/LdapAuthenticationTest.java | ●●●●● patch | view | raw | blame | history |
releases.moxie
@@ -33,6 +33,7 @@ - Reversed line links in blob view (issue-309) - Dashboard and Activity pages now obey the web.generateActivityGraph setting (issue-310) - Do not log passwords on failed authentication attempts (issue-316) - LDAP synchronization is now scheduled rather than on-demand (issue-336) - Show displayname and username in palettes (issue-364) - Updated default binary and Lucene ignore extensions - Change the WAR baseFolder context parameter to a JNDI env-entry to improve enterprise deployments @@ -82,6 +83,10 @@ - { name: 'git.defaultAccessRestriction', defaultValue: 'PUSH' } - { name: 'git.mirrorPeriod', defaultValue: '30 mins' } - { name: 'realm.authenticationProviders', defaultValue: ' ' } - { name: 'realm.ldap.groupEmptyMemberPattern', defaultValue: '(&(objectClass=group)(!(member=*)))' } - { name: 'realm.ldap.synchronize', defaultValue: 'false' } - { name: 'realm.ldap.syncPeriod', defaultValue: '5 MINUTES' } - { name: 'realm.ldap.removeDeletedUsers', defaultValue: 'true' } - { name: 'web.commitMessageRenderer', defaultValue: 'plain' } - { name: 'web.documents', defaultValue: 'readme home index changelog contributing submitting_patches copying license notice authors' } - { name: 'web.showBranchGraph', defaultValue: 'true' } src/main/distrib/data/gitblit.properties
@@ -1502,46 +1502,44 @@ # SINCE 1.0.0 realm.ldap.email = email # Defines the cache period to be used when caching LDAP queries. This is currently # only used for LDAP user synchronization. # # Must be of the form '<long> <TimeUnit>' where <TimeUnit> is one of 'MILLISECONDS', 'SECONDS', 'MINUTES', 'HOURS', 'DAYS' # default: 2 MINUTES # # RESTART REQUIRED realm.ldap.ldapCachePeriod = 2 MINUTES # Defines whether to synchronize all LDAP users into the backing user service # # Valid values: true, false # If left blank, false is assumed realm.ldap.synchronizeUsers.enable = false # Defines the period to be used when synchronizing users from ldap. This is currently # only used for LDAP user synchronization. # # Must be of the form '<long> <TimeUnit>' where <TimeUnit> is one of 'MILLISECONDS', 'SECONDS', 'MINUTES', 'HOURS', 'DAYS' # <long> is at least the value from realm.ldap.ldapCachePeriod if lower the value from realm.ldap.ldapCachePeriod is used. # default: 5 MINUTES # # RESTART REQUIRED # SINCE 1.4.0 realm.ldap.synchronizeUsers.ldapSyncPeriod = 5 MINUTES # Defines whether to delete non-existent LDAP users from the backing user service # during synchronization. depends on realm.ldap.synchronizeUsers.enable = true # # Valid values: true, false # If left blank, true is assumed realm.ldap.synchronizeUsers.removeDeleted = true # Attribute on the USER record that indicate their username to be used in gitblit # when synchronizing users from LDAP # if blank, Gitblit will use uid # For MS Active Directory this may be sAMAccountName # # SINCE 1.0.0 realm.ldap.uid = uid # Defines whether to synchronize all LDAP users and teams into the user service # # Valid values: true, false # If left blank, false is assumed # # SINCE 1.4.0 realm.ldap.synchronize = false # Defines the period to be used when synchronizing users and teams from ldap. # # Must be of the form '<long> <TimeUnit>' where <TimeUnit> is one of 'MILLISECONDS', 'SECONDS', 'MINUTES', 'HOURS', 'DAYS' # default: 5 MINUTES # # RESTART REQUIRED # SINCE 1.4.0 realm.ldap.syncPeriod = 5 MINUTES # Defines whether to delete non-existent LDAP users from the user service # during synchronization. depends on realm.ldap.synchronize = true # # Valid values: true, false # If left blank, true is assumed # # SINCE 1.4.0 realm.ldap.removeDeletedUsers = true # URL of the Redmine. # # SINCE 1.2.0 realm.redmine.url = http://example.com/redmine # src/main/java/com/gitblit/auth/AuthenticationProvider.java
@@ -100,6 +100,8 @@ public abstract void setup(); public abstract void stop(); public abstract UserModel authenticate(String username, char[] password); public abstract AccountType getAccountType(); @@ -145,6 +147,11 @@ protected UsernamePasswordAuthenticationProvider(String serviceName) { super(serviceName); } @Override public void stop() { } } public static class NullProvider extends AuthenticationProvider { @@ -159,6 +166,11 @@ } @Override public void stop() { } @Override public UserModel authenticate(String username, char[] password) { return null; } src/main/java/com/gitblit/auth/LdapAuthProvider.java
@@ -19,6 +19,7 @@ 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; @@ -26,7 +27,6 @@ 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; @@ -60,40 +60,52 @@ */ public class LdapAuthProvider extends UsernamePasswordAuthenticationProvider { private final AtomicLong lastLdapUserSync = new AtomicLong(0L); private final ScheduledExecutorService scheduledExecutorService; public LdapAuthProvider() { super("ldap"); scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); } private long getSynchronizationPeriodInMilliseconds(String name) { final String cacheDuration = settings.getString(name, "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); 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(name + " 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(); configureLdapSyncService(); configureSyncService(); } public void synchronizeWithLdapService() { synchronizeLdapUsers(); @Override public void stop() { scheduledExecutorService.shutdownNow(); } protected synchronized void synchronizeLdapUsers() { final boolean enabled = settings.getBoolean(Keys.realm.ldap.synchronizeUsers.enable, false); public synchronized void sync() { final boolean enabled = settings.getBoolean(Keys.realm.ldap.synchronize, false); if (enabled) { if (System.currentTimeMillis() > (lastLdapUserSync.get() + getSynchronizationPeriodInMilliseconds(Keys.realm.ldap.ldapCachePeriod))) { logger.info("Synchronizing with LDAP @ " + settings.getRequiredString(Keys.realm.ldap.server)); final boolean deleteRemovedLdapUsers = settings.getBoolean(Keys.realm.ldap.synchronizeUsers.removeDeleted, true); final boolean deleteRemovedLdapUsers = settings.getBoolean(Keys.realm.ldap.removeDeletedUsers, true); LDAPConnection ldapConnection = getLdapConnection(); if (ldapConnection != null) { try { @@ -131,7 +143,7 @@ logger.debug("detecting removed LDAP users..."); for (UserModel userModel : userManager.getAllUsers()) { if (Constants.EXTERNAL_ACCOUNT.equals(userModel.password)) { 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); @@ -155,10 +167,8 @@ if (!supportsTeamMembershipChanges()) { getEmptyTeamsFromLdap(ldapConnection); } lastLdapUserSync.set(System.currentTimeMillis()); } finally { ldapConnection.close(); } } } } @@ -439,7 +449,7 @@ } private void getEmptyTeamsFromLdap(LDAPConnection ldapConnection) { logger.info("Start fetching empty teams form ldap."); 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=*)))"); @@ -458,7 +468,7 @@ } } } logger.info("Finished fetching empty teams form ldap."); logger.info("Finished fetching empty teams from ldap."); } private TeamModel createTeamFromLdap(SearchResultEntry teamEntry) { @@ -554,24 +564,16 @@ return sb.toString(); } private void configureLdapSyncService() { logger.info("Start configuring ldap sync service"); private void configureSyncService() { LdapSyncService ldapSyncService = new LdapSyncService(settings, this); if (ldapSyncService.isReady()) { long ldapSyncPeriod = getSynchronizationPeriodInMilliseconds(Keys.realm.ldap.synchronizeUsers.ldapSyncPeriod); long ldapCachePeriod = getSynchronizationPeriodInMilliseconds(Keys.realm.ldap.synchronizeUsers.ldapSyncPeriod); if (ldapSyncPeriod < ldapCachePeriod) { ldapSyncPeriod = ldapCachePeriod; } long ldapSyncPeriod = getSynchronizationPeriodInMilliseconds(); int delay = 1; ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); logger.info("Ldap sync service will update users and groups every {} minutes.", ldapSyncPeriod); scheduledExecutorService.scheduleAtFixedRate(ldapSyncService, delay, ldapSyncPeriod, TimeUnit.MILLISECONDS); logger.info("Ldap sync service will update user and groups every {} minutes.", ldapSyncPeriod); logger.info("Next scheduled ldap sync is in {} minutes", delay); } else { logger.info("Ldap sync service is disabled."); } logger.info("Finished configuring ldap sync service"); } } src/main/java/com/gitblit/manager/AuthenticationManager.java
@@ -150,6 +150,13 @@ @Override public AuthenticationManager stop() { for (AuthenticationProvider provider : authenticationProviders) { try { provider.stop(); } catch (Exception e) { logger.error("Failed to stop " + provider.getClass().getSimpleName(), e); } } return this; } src/main/java/com/gitblit/service/LdapSyncService.java
@@ -1,5 +1,5 @@ /* * Copyright 2013 gitblit.com. * Copyright 2014 gitblit.com. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -51,14 +51,19 @@ public void run() { logger.info("Starting user and group sync with ldap service"); if (!running.getAndSet(true)) { ldapAuthProvider.synchronizeWithLdapService(); try { ldapAuthProvider.sync(); } catch (Exception e) { logger.error("Failed to synchronize with ldap", e); } finally { running.getAndSet(false); } } logger.info("Finished user and group sync with ldap service"); } public boolean isReady() { return settings.getBoolean(Keys.realm.ldap.synchronizeUsers.enable, false); return settings.getBoolean(Keys.realm.ldap.synchronize, false); } } src/test/java/com/gitblit/tests/LdapAuthenticationTest.java
@@ -196,7 +196,7 @@ public void addingUserInLdapShouldNotUpdateGitBlitUsersAndGroups() throws Exception { settings.put("realm.ldap.ldapCachePeriod", "0 MINUTES"); ds.addEntries(LDIFReader.readEntries(RESOURCE_DIR + "adduser.ldif")); ldap.synchronizeWithLdapService(); ldap.sync(); assertEquals("Number of ldap users in gitblit user model", 5, countLdapUsersInUserManager()); } @@ -205,7 +205,7 @@ settings.put("realm.ldap.synchronizeUsers.enable", "true"); settings.put("realm.ldap.ldapCachePeriod", "0 MINUTES"); ds.addEntries(LDIFReader.readEntries(RESOURCE_DIR + "adduser.ldif")); ldap.synchronizeWithLdapService(); ldap.sync(); assertEquals("Number of ldap users in gitblit user model", 6, countLdapUsersInUserManager()); } @@ -213,7 +213,7 @@ public void addingGroupsInLdapShouldNotUpdateGitBlitUsersAndGroups() throws Exception { settings.put("realm.ldap.ldapCachePeriod", "0 MINUTES"); ds.addEntries(LDIFReader.readEntries(RESOURCE_DIR + "addgroup.ldif")); ldap.synchronizeWithLdapService(); ldap.sync(); assertEquals("Number of ldap groups in gitblit team model", 0, countLdapTeamsInUserManager()); } @@ -222,7 +222,7 @@ settings.put("realm.ldap.synchronizeUsers.enable", "true"); settings.put("realm.ldap.ldapCachePeriod", "0 MINUTES"); ds.addEntries(LDIFReader.readEntries(RESOURCE_DIR + "addgroup.ldif")); ldap.synchronizeWithLdapService(); ldap.sync(); assertEquals("Number of ldap groups in gitblit team model", 1, countLdapTeamsInUserManager()); }