summaryrefslogtreecommitdiffstats
path: root/src/main/java/com
diff options
context:
space:
mode:
authorJames Moger <james.moger@gitblit.com>2013-11-24 23:18:50 -0500
committerJames Moger <james.moger@gitblit.com>2013-11-29 11:05:51 -0500
commit04a98505a4ab8f48aee22800fcac193d9367d0ae (patch)
treeeb05bc77eeafda1c5b7af9d7b5b27012065f7a98 /src/main/java/com
parentf8f6aa4d07cdfaaf23e24bf9eaf0a5fb9b437dda (diff)
downloadgitblit-04a98505a4ab8f48aee22800fcac193d9367d0ae.tar.gz
gitblit-04a98505a4ab8f48aee22800fcac193d9367d0ae.zip
Refactor user services and separate authentication (issue-281)
Change-Id: I336e005e02623fc5e11a4f8b4408bea5465a43fd
Diffstat (limited to 'src/main/java/com')
-rw-r--r--src/main/java/com/gitblit/ConfigUserService.java202
-rw-r--r--src/main/java/com/gitblit/Constants.java11
-rw-r--r--src/main/java/com/gitblit/DaggerModule.java18
-rw-r--r--src/main/java/com/gitblit/GitBlit.java55
-rw-r--r--src/main/java/com/gitblit/GitblitUserService.java325
-rw-r--r--src/main/java/com/gitblit/IUserService.java93
-rw-r--r--src/main/java/com/gitblit/auth/AuthenticationProvider.java182
-rw-r--r--src/main/java/com/gitblit/auth/HtpasswdAuthProvider.java (renamed from src/main/java/com/gitblit/HtpasswdUserService.java)219
-rw-r--r--src/main/java/com/gitblit/auth/LdapAuthProvider.java (renamed from src/main/java/com/gitblit/LdapUserService.java)1038
-rw-r--r--src/main/java/com/gitblit/auth/PAMAuthProvider.java (renamed from src/main/java/com/gitblit/PAMUserService.java)269
-rw-r--r--src/main/java/com/gitblit/auth/RedmineAuthProvider.java (renamed from src/main/java/com/gitblit/RedmineUserService.java)389
-rw-r--r--src/main/java/com/gitblit/auth/SalesforceAuthProvider.java (renamed from src/main/java/com/gitblit/SalesforceUserService.java)45
-rw-r--r--src/main/java/com/gitblit/auth/WindowsAuthProvider.java (renamed from src/main/java/com/gitblit/WindowsUserService.java)372
-rw-r--r--src/main/java/com/gitblit/client/EditTeamDialog.java1
-rw-r--r--src/main/java/com/gitblit/client/EditUserDialog.java16
-rw-r--r--src/main/java/com/gitblit/git/GitblitUploadPackFactory.java10
-rw-r--r--src/main/java/com/gitblit/manager/AuthenticationManager.java511
-rw-r--r--src/main/java/com/gitblit/manager/GitblitManager.java7
-rw-r--r--src/main/java/com/gitblit/manager/IAuthenticationManager.java (renamed from src/main/java/com/gitblit/manager/ISessionManager.java)43
-rw-r--r--src/main/java/com/gitblit/manager/IUserManager.java261
-rw-r--r--src/main/java/com/gitblit/manager/SessionManager.java340
-rw-r--r--src/main/java/com/gitblit/manager/UserManager.java221
-rw-r--r--src/main/java/com/gitblit/models/ServerSettings.java8
-rw-r--r--src/main/java/com/gitblit/models/TeamModel.java7
-rw-r--r--src/main/java/com/gitblit/servlet/AccessRestrictionFilter.java6
-rw-r--r--src/main/java/com/gitblit/servlet/AuthenticationFilter.java10
-rw-r--r--src/main/java/com/gitblit/servlet/DownloadZipFilter.java6
-rw-r--r--src/main/java/com/gitblit/servlet/EnforceAuthenticationFilter.java10
-rw-r--r--src/main/java/com/gitblit/servlet/GitFilter.java6
-rw-r--r--src/main/java/com/gitblit/servlet/GitblitContext.java4
-rw-r--r--src/main/java/com/gitblit/servlet/PagesFilter.java6
-rw-r--r--src/main/java/com/gitblit/servlet/RpcFilter.java6
-rw-r--r--src/main/java/com/gitblit/servlet/SparkleShareInviteServlet.java10
-rw-r--r--src/main/java/com/gitblit/servlet/SyndicationFilter.java6
-rw-r--r--src/main/java/com/gitblit/wicket/GitBlitWebApp.java12
-rw-r--r--src/main/java/com/gitblit/wicket/pages/ChangePasswordPage.java4
-rw-r--r--src/main/java/com/gitblit/wicket/pages/EditTeamPage.java2
-rw-r--r--src/main/java/com/gitblit/wicket/pages/EditUserPage.java14
-rw-r--r--src/main/java/com/gitblit/wicket/pages/LogoutPage.java2
-rw-r--r--src/main/java/com/gitblit/wicket/pages/RootPage.java6
-rw-r--r--src/main/java/com/gitblit/wicket/pages/SessionPage.java4
-rw-r--r--src/main/java/com/gitblit/wicket/panels/TeamsPanel.java2
-rw-r--r--src/main/java/com/gitblit/wicket/panels/UsersPanel.java3
43 files changed, 2011 insertions, 2751 deletions
diff --git a/src/main/java/com/gitblit/ConfigUserService.java b/src/main/java/com/gitblit/ConfigUserService.java
index 39374e88..aae7c14c 100644
--- a/src/main/java/com/gitblit/ConfigUserService.java
+++ b/src/main/java/com/gitblit/ConfigUserService.java
@@ -96,6 +96,8 @@ public class ConfigUserService implements IUserService {
private static final String LOCALE = "locale";
+ private static final String ACCOUNTTYPE = "accountType";
+
private final File realmFile;
private final Logger logger = LoggerFactory.getLogger(ConfigUserService.class);
@@ -125,60 +127,6 @@ public class ConfigUserService implements IUserService {
}
/**
- * Does the user service support changes to credentials?
- *
- * @return true or false
- * @since 1.0.0
- */
- @Override
- public boolean supportsCredentialChanges() {
- return true;
- }
-
- /**
- * Does the user service support changes to user display name?
- *
- * @return true or false
- * @since 1.0.0
- */
- @Override
- public boolean supportsDisplayNameChanges() {
- return true;
- }
-
- /**
- * Does the user service support changes to user email address?
- *
- * @return true or false
- * @since 1.0.0
- */
- @Override
- public boolean supportsEmailAddressChanges() {
- return true;
- }
-
- /**
- * Does the user service support changes to team memberships?
- *
- * @return true or false
- * @since 1.0.0
- */
- @Override
- public boolean supportsTeamMembershipChanges() {
- return true;
- }
-
- /**
- * Does the user service support cookie authentication?
- *
- * @return true or false
- */
- @Override
- public boolean supportsCookies() {
- return true;
- }
-
- /**
* Returns the cookie value for the specified user.
*
* @param model
@@ -197,13 +145,13 @@ public class ConfigUserService implements IUserService {
}
/**
- * Authenticate a user based on their cookie.
+ * Gets the user object for the specified cookie.
*
* @param cookie
* @return a user object or null
*/
@Override
- public synchronized UserModel authenticate(char[] cookie) {
+ public synchronized UserModel getUserModel(char[] cookie) {
String hash = new String(cookie);
if (StringUtils.isEmpty(hash)) {
return null;
@@ -223,49 +171,6 @@ public class ConfigUserService implements IUserService {
}
/**
- * Authenticate a user based on a username and password.
- *
- * @param username
- * @param password
- * @return a user object or null
- */
- @Override
- public UserModel authenticate(String username, char[] password) {
- UserModel returnedUser = null;
- UserModel user = getUserModel(username);
- if (user == null) {
- return null;
- }
- if (user.password.startsWith(StringUtils.MD5_TYPE)) {
- // password digest
- String md5 = StringUtils.MD5_TYPE + StringUtils.getMD5(new String(password));
- if (user.password.equalsIgnoreCase(md5)) {
- returnedUser = user;
- }
- } else if (user.password.startsWith(StringUtils.COMBINED_MD5_TYPE)) {
- // username+password digest
- String md5 = StringUtils.COMBINED_MD5_TYPE
- + StringUtils.getMD5(username.toLowerCase() + new String(password));
- if (user.password.equalsIgnoreCase(md5)) {
- returnedUser = user;
- }
- } else if (user.password.equals(new String(password))) {
- // plain-text password
- returnedUser = user;
- }
- return returnedUser;
- }
-
- /**
- * Logout a user.
- *
- * @param user
- */
- @Override
- public void logout(UserModel user) {
- }
-
- /**
* Retrieve the user object for the specified username.
*
* @param username
@@ -357,6 +262,10 @@ public class ConfigUserService implements IUserService {
public synchronized boolean updateUserModel(String username, UserModel model) {
UserModel originalUser = null;
try {
+ if (!model.isLocalAccount()) {
+ // do not persist password
+ model.password = Constants.EXTERNAL_ACCOUNT;
+ }
read();
originalUser = users.remove(username.toLowerCase());
users.put(model.username.toLowerCase(), model);
@@ -505,45 +414,6 @@ public class ConfigUserService implements IUserService {
}
/**
- * Sets the list of all teams who are allowed to bypass the access
- * restriction placed on the specified repository.
- *
- * @param role
- * the repository name
- * @param teamnames
- * @return true if successful
- */
- @Override
- public synchronized boolean setTeamnamesForRepositoryRole(String role, List<String> teamnames) {
- try {
- Set<String> specifiedTeams = new HashSet<String>();
- for (String teamname : teamnames) {
- specifiedTeams.add(teamname.toLowerCase());
- }
-
- read();
-
- // identify teams which require add or remove role
- for (TeamModel team : teams.values()) {
- // team has role, check against revised team list
- if (specifiedTeams.contains(team.name.toLowerCase())) {
- team.addRepositoryPermission(role);
- } else {
- // remove role from team
- team.removeRepositoryPermission(role);
- }
- }
-
- // persist changes
- write();
- return true;
- } catch (Throwable t) {
- logger.error(MessageFormat.format("Failed to set teams for role {0}!", role), t);
- }
- return false;
- }
-
- /**
* Retrieve the team object for the specified team name.
*
* @param teamname
@@ -716,46 +586,6 @@ public class ConfigUserService implements IUserService {
}
/**
- * Sets the list of all uses who are allowed to bypass the access
- * restriction placed on the specified repository.
- *
- * @param role
- * the repository name
- * @param usernames
- * @return true if successful
- */
- @Override
- @Deprecated
- public synchronized boolean setUsernamesForRepositoryRole(String role, List<String> usernames) {
- try {
- Set<String> specifiedUsers = new HashSet<String>();
- for (String username : usernames) {
- specifiedUsers.add(username.toLowerCase());
- }
-
- read();
-
- // identify users which require add or remove role
- for (UserModel user : users.values()) {
- // user has role, check against revised user list
- if (specifiedUsers.contains(user.username.toLowerCase())) {
- user.addRepositoryPermission(role);
- } else {
- // remove role from user
- user.removeRepositoryPermission(role);
- }
- }
-
- // persist changes
- write();
- return true;
- } catch (Throwable t) {
- logger.error(MessageFormat.format("Failed to set usernames for role {0}!", role), t);
- }
- return false;
- }
-
- /**
* Renames a repository role.
*
* @param oldRole
@@ -846,6 +676,9 @@ public class ConfigUserService implements IUserService {
if (!StringUtils.isEmpty(model.emailAddress)) {
config.setString(USER, model.username, EMAILADDRESS, model.emailAddress);
}
+ if (model.accountType != null) {
+ config.setString(USER, model.username, ACCOUNTTYPE, model.accountType.name());
+ }
if (!StringUtils.isEmpty(model.organizationalUnit)) {
config.setString(USER, model.username, ORGANIZATIONALUNIT, model.organizationalUnit);
}
@@ -928,6 +761,9 @@ public class ConfigUserService implements IUserService {
roles.add(Constants.NO_ROLE);
}
config.setStringList(TEAM, model.name, ROLE, roles);
+ if (model.accountType != null) {
+ config.setString(TEAM, model.name, ACCOUNTTYPE, model.accountType.name());
+ }
if (!model.canAdmin) {
// write team permission for non-admin teams
@@ -1021,6 +857,10 @@ public class ConfigUserService implements IUserService {
user.password = config.getString(USER, username, PASSWORD);
user.displayName = config.getString(USER, username, DISPLAYNAME);
user.emailAddress = config.getString(USER, username, EMAILADDRESS);
+ user.accountType = AccountType.fromString(config.getString(USER, username, ACCOUNTTYPE));
+ if (Constants.EXTERNAL_ACCOUNT.equals(user.password) && user.accountType.isLocal()) {
+ user.accountType = null;
+ }
user.organizationalUnit = config.getString(USER, username, ORGANIZATIONALUNIT);
user.organization = config.getString(USER, username, ORGANIZATION);
user.locality = config.getString(USER, username, LOCALITY);
@@ -1074,6 +914,7 @@ public class ConfigUserService implements IUserService {
team.canAdmin = roles.contains(Constants.ADMIN_ROLE);
team.canFork = roles.contains(Constants.FORK_ROLE);
team.canCreate = roles.contains(Constants.CREATE_ROLE);
+ team.accountType = AccountType.fromString(config.getString(TEAM, teamname, ACCOUNTTYPE));
if (!team.canAdmin) {
// non-admin team, read permissions
@@ -1112,9 +953,4 @@ public class ConfigUserService implements IUserService {
public String toString() {
return getClass().getSimpleName() + "(" + realmFile.getAbsolutePath() + ")";
}
-
- @Override
- public AccountType getAccountType() {
- return AccountType.LOCAL;
- }
}
diff --git a/src/main/java/com/gitblit/Constants.java b/src/main/java/com/gitblit/Constants.java
index 43c60a39..439a944d 100644
--- a/src/main/java/com/gitblit/Constants.java
+++ b/src/main/java/com/gitblit/Constants.java
@@ -499,7 +499,16 @@ public class Constants {
}
public static enum AccountType {
- LOCAL, EXTERNAL, LDAP, REDMINE, SALESFORCE, WINDOWS, PAM, HTPASSWD;
+ LOCAL, EXTERNAL, CONTAINER, LDAP, REDMINE, SALESFORCE, WINDOWS, PAM, HTPASSWD;
+
+ public static AccountType fromString(String value) {
+ for (AccountType type : AccountType.values()) {
+ if (type.name().equalsIgnoreCase(value)) {
+ return type;
+ }
+ }
+ return AccountType.LOCAL;
+ }
public boolean isLocal() {
return this == LOCAL;
diff --git a/src/main/java/com/gitblit/DaggerModule.java b/src/main/java/com/gitblit/DaggerModule.java
index 5e49a97d..cc836940 100644
--- a/src/main/java/com/gitblit/DaggerModule.java
+++ b/src/main/java/com/gitblit/DaggerModule.java
@@ -20,8 +20,10 @@ import javax.inject.Singleton;
import org.apache.wicket.protocol.http.WebApplication;
import com.gitblit.git.GitServlet;
+import com.gitblit.manager.AuthenticationManager;
import com.gitblit.manager.FederationManager;
import com.gitblit.manager.GitblitManager;
+import com.gitblit.manager.IAuthenticationManager;
import com.gitblit.manager.IFederationManager;
import com.gitblit.manager.IGitblitManager;
import com.gitblit.manager.INotificationManager;
@@ -29,14 +31,12 @@ import com.gitblit.manager.IProjectManager;
import com.gitblit.manager.IRepositoryManager;
import com.gitblit.manager.IRuntimeManager;
import com.gitblit.manager.IServicesManager;
-import com.gitblit.manager.ISessionManager;
import com.gitblit.manager.IUserManager;
import com.gitblit.manager.NotificationManager;
import com.gitblit.manager.ProjectManager;
import com.gitblit.manager.RepositoryManager;
import com.gitblit.manager.RuntimeManager;
import com.gitblit.manager.ServicesManager;
-import com.gitblit.manager.SessionManager;
import com.gitblit.manager.UserManager;
import com.gitblit.servlet.BranchGraphServlet;
import com.gitblit.servlet.DownloadZipFilter;
@@ -74,7 +74,7 @@ import dagger.Provides;
IRuntimeManager.class,
INotificationManager.class,
IUserManager.class,
- ISessionManager.class,
+ IAuthenticationManager.class,
IRepositoryManager.class,
IProjectManager.class,
IGitblitManager.class,
@@ -122,11 +122,11 @@ public class DaggerModule {
return new UserManager(runtimeManager);
}
- @Provides @Singleton ISessionManager provideSessionManager(
+ @Provides @Singleton IAuthenticationManager provideAuthenticationManager(
IRuntimeManager runtimeManager,
IUserManager userManager) {
- return new SessionManager(
+ return new AuthenticationManager(
runtimeManager,
userManager);
}
@@ -179,7 +179,7 @@ public class DaggerModule {
IRuntimeManager runtimeManager,
INotificationManager notificationManager,
IUserManager userManager,
- ISessionManager sessionManager,
+ IAuthenticationManager authenticationManager,
IRepositoryManager repositoryManager,
IProjectManager projectManager,
IGitblitManager gitblitManager,
@@ -189,7 +189,7 @@ public class DaggerModule {
runtimeManager,
notificationManager,
userManager,
- sessionManager,
+ authenticationManager,
repositoryManager,
projectManager,
gitblitManager,
@@ -204,7 +204,7 @@ public class DaggerModule {
IRuntimeManager runtimeManager,
INotificationManager notificationManager,
IUserManager userManager,
- ISessionManager sessionManager,
+ IAuthenticationManager authenticationManager,
IRepositoryManager repositoryManager,
IProjectManager projectManager,
IGitblitManager gitblitManager,
@@ -214,7 +214,7 @@ public class DaggerModule {
runtimeManager,
notificationManager,
userManager,
- sessionManager,
+ authenticationManager,
repositoryManager,
projectManager,
gitblitManager,
diff --git a/src/main/java/com/gitblit/GitBlit.java b/src/main/java/com/gitblit/GitBlit.java
index 0dcc765b..d4e89b02 100644
--- a/src/main/java/com/gitblit/GitBlit.java
+++ b/src/main/java/com/gitblit/GitBlit.java
@@ -29,13 +29,13 @@ import org.eclipse.jgit.lib.Repository;
import com.gitblit.Constants.FederationRequest;
import com.gitblit.Constants.FederationToken;
+import com.gitblit.manager.IAuthenticationManager;
import com.gitblit.manager.IFederationManager;
import com.gitblit.manager.IGitblitManager;
import com.gitblit.manager.INotificationManager;
import com.gitblit.manager.IProjectManager;
import com.gitblit.manager.IRepositoryManager;
import com.gitblit.manager.IRuntimeManager;
-import com.gitblit.manager.ISessionManager;
import com.gitblit.manager.IUserManager;
import com.gitblit.models.FederationModel;
import com.gitblit.models.FederationProposal;
@@ -65,7 +65,7 @@ import com.gitblit.models.UserModel;
public class GitBlit implements IRuntimeManager,
INotificationManager,
IUserManager,
- ISessionManager,
+ IAuthenticationManager,
IRepositoryManager,
IProjectManager,
IGitblitManager,
@@ -77,7 +77,7 @@ public class GitBlit implements IRuntimeManager,
private final IUserManager userManager;
- private final ISessionManager sessionManager;
+ private final IAuthenticationManager authenticationManager;
private final IRepositoryManager repositoryManager;
@@ -91,7 +91,7 @@ public class GitBlit implements IRuntimeManager,
IRuntimeManager runtimeManager,
INotificationManager notificationManager,
IUserManager userManager,
- ISessionManager sessionManager,
+ IAuthenticationManager authenticationManager,
IRepositoryManager repositoryManager,
IProjectManager projectManager,
IGitblitManager gitblitManager,
@@ -100,7 +100,7 @@ public class GitBlit implements IRuntimeManager,
this.runtimeManager = runtimeManager;
this.notificationManager = notificationManager;
this.userManager = userManager;
- this.sessionManager = sessionManager;
+ this.authenticationManager = authenticationManager;
this.repositoryManager = repositoryManager;
this.projectManager = projectManager;
this.gitblitManager = gitblitManager;
@@ -239,55 +239,59 @@ public class GitBlit implements IRuntimeManager,
@Override
public UserModel authenticate(String username, char[] password) {
- return sessionManager.authenticate(username, password);
+ return authenticationManager.authenticate(username, password);
}
@Override
public UserModel authenticate(HttpServletRequest httpRequest) {
- return sessionManager.authenticate(httpRequest, false);
+ return authenticationManager.authenticate(httpRequest, false);
}
@Override
public UserModel authenticate(HttpServletRequest httpRequest, boolean requiresCertificate) {
- return sessionManager.authenticate(httpRequest, requiresCertificate);
+ return authenticationManager.authenticate(httpRequest, requiresCertificate);
}
@Override
public void setCookie(HttpServletResponse response, UserModel user) {
- sessionManager.setCookie(response, user);
+ authenticationManager.setCookie(response, user);
}
@Override
public void logout(HttpServletResponse response, UserModel user) {
- sessionManager.logout(response, user);
- }
-
- /*
- * USER MANAGER
- */
-
- @Override
- public boolean supportsAddUser() {
- return userManager.supportsAddUser();
+ authenticationManager.logout(response, user);
}
@Override
public boolean supportsCredentialChanges(UserModel user) {
- return userManager.supportsCredentialChanges(user);
+ return authenticationManager.supportsCredentialChanges(user);
}
@Override
public boolean supportsDisplayNameChanges(UserModel user) {
- return userManager.supportsDisplayNameChanges(user);
+ return authenticationManager.supportsDisplayNameChanges(user);
}
@Override
public boolean supportsEmailAddressChanges(UserModel user) {
- return userManager.supportsEmailAddressChanges(user);
+ return authenticationManager.supportsEmailAddressChanges(user);
}
@Override
public boolean supportsTeamMembershipChanges(UserModel user) {
- return userManager.supportsTeamMembershipChanges(user);
+ return authenticationManager.supportsTeamMembershipChanges(user);
+ }
+
+ @Override
+ public boolean supportsTeamMembershipChanges(TeamModel team) {
+ return authenticationManager.supportsTeamMembershipChanges(team);
+ }
+
+ /*
+ * USER MANAGER
+ */
+
+ @Override
+ public void setup(IRuntimeManager runtimeManager) {
}
@Override
@@ -321,11 +325,6 @@ public class GitBlit implements IRuntimeManager,
}
@Override
- public boolean supportsCookies() {
- return userManager.supportsCookies();
- }
-
- @Override
public String getCookie(UserModel model) {
return userManager.getCookie(model);
}
diff --git a/src/main/java/com/gitblit/GitblitUserService.java b/src/main/java/com/gitblit/GitblitUserService.java
deleted file mode 100644
index 715aed9d..00000000
--- a/src/main/java/com/gitblit/GitblitUserService.java
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * Copyright 2011 gitblit.com.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.gitblit;
-
-import java.io.File;
-import java.io.IOException;
-import java.text.MessageFormat;
-import java.util.Collection;
-import java.util.List;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.gitblit.Constants.AccountType;
-import com.gitblit.manager.IRuntimeManager;
-import com.gitblit.models.TeamModel;
-import com.gitblit.models.UserModel;
-import com.gitblit.utils.DeepCopier;
-import com.gitblit.utils.StringUtils;
-
-/**
- * This class wraps the default user service and is recommended as the starting
- * point for custom user service implementations.
- *
- * This does seem a little convoluted, but the idea is to allow IUserService to
- * evolve with new methods and implementations without breaking custom
- * authentication implementations.
- *
- * The most common implementation of a custom IUserService is to only override
- * authentication and then delegate all other functionality to one of Gitblit's
- * user services. This class optimizes that use-case.
- *
- * Extending GitblitUserService allows for authentication customization without
- * having to keep-up-with IUSerService API changes.
- *
- * @author James Moger
- *
- */
-public class GitblitUserService implements IUserService {
-
- protected IUserService serviceImpl;
-
- private final Logger logger = LoggerFactory.getLogger(GitblitUserService.class);
-
- public GitblitUserService() {
- }
-
- @Override
- public void setup(IRuntimeManager runtimeManager) {
- File realmFile = runtimeManager.getFileOrFolder(Keys.realm.userService, "${baseFolder}/users.conf");
- serviceImpl = createUserService(realmFile);
- logger.info("GUS delegating to " + serviceImpl.toString());
- }
-
- protected IUserService createUserService(File realmFile) {
- IUserService service = null;
- if (realmFile.getName().toLowerCase().endsWith(".conf")) {
- // v0.8.0+ config-based realm file
- service = new ConfigUserService(realmFile);
- }
-
- assert service != null;
-
- if (!realmFile.exists()) {
- // Create the Administrator account for a new realm file
- try {
- realmFile.createNewFile();
- } catch (IOException x) {
- logger.error(MessageFormat.format("COULD NOT CREATE REALM FILE {0}!", realmFile), x);
- }
- UserModel admin = new UserModel("admin");
- admin.password = "admin";
- admin.canAdmin = true;
- admin.excludeFromFederation = true;
- service.updateUserModel(admin);
- }
-
- return service;
- }
-
- @Override
- public String toString() {
- return getClass().getSimpleName();
- }
-
- @Override
- public boolean supportsCredentialChanges() {
- return serviceImpl.supportsCredentialChanges();
- }
-
- @Override
- public boolean supportsDisplayNameChanges() {
- return serviceImpl.supportsDisplayNameChanges();
- }
-
- @Override
- public boolean supportsEmailAddressChanges() {
- return serviceImpl.supportsEmailAddressChanges();
- }
-
- @Override
- public boolean supportsTeamMembershipChanges() {
- return serviceImpl.supportsTeamMembershipChanges();
- }
-
- @Override
- public boolean supportsCookies() {
- return serviceImpl.supportsCookies();
- }
-
- @Override
- public String getCookie(UserModel model) {
- return serviceImpl.getCookie(model);
- }
-
- /**
- * Authenticate a user based on their cookie.
- *
- * @param cookie
- * @return a user object or null
- */
- @Override
- public UserModel authenticate(char[] cookie) {
- UserModel user = serviceImpl.authenticate(cookie);
- setAccountType(user);
- return user;
- }
-
- @Override
- public UserModel authenticate(String username, char[] password) {
- UserModel user = serviceImpl.authenticate(username, password);
- setAccountType(user);
- return user;
- }
-
- @Override
- public void logout(UserModel user) {
- serviceImpl.logout(user);
- }
-
- @Override
- public UserModel getUserModel(String username) {
- UserModel user = serviceImpl.getUserModel(username);
- setAccountType(user);
- return user;
- }
-
- @Override
- public boolean updateUserModel(UserModel model) {
- return serviceImpl.updateUserModel(model);
- }
-
- @Override
- public boolean updateUserModels(Collection<UserModel> models) {
- return serviceImpl.updateUserModels(models);
- }
-
- @Override
- public boolean updateUserModel(String username, UserModel model) {
- if (model.isLocalAccount() || supportsCredentialChanges()) {
- if (!model.isLocalAccount() && !supportsTeamMembershipChanges()) {
- // teams are externally controlled - copy from original model
- UserModel existingModel = getUserModel(username);
-
- model = DeepCopier.copy(model);
- model.teams.clear();
- model.teams.addAll(existingModel.teams);
- }
- return serviceImpl.updateUserModel(username, model);
- }
- if (model.username.equals(username)) {
- // passwords are not persisted by the backing user service
- model.password = null;
- if (!model.isLocalAccount() && !supportsTeamMembershipChanges()) {
- // teams are externally controlled- copy from original model
- UserModel existingModel = getUserModel(username);
-
- model = DeepCopier.copy(model);
- model.teams.clear();
- model.teams.addAll(existingModel.teams);
- }
- return serviceImpl.updateUserModel(username, model);
- }
- logger.error("Users can not be renamed!");
- return false;
- }
- @Override
- public boolean deleteUserModel(UserModel model) {
- return serviceImpl.deleteUserModel(model);
- }
-
- @Override
- public boolean deleteUser(String username) {
- return serviceImpl.deleteUser(username);
- }
-
- @Override
- public List<String> getAllUsernames() {
- return serviceImpl.getAllUsernames();
- }
-
- @Override
- public List<UserModel> getAllUsers() {
- List<UserModel> users = serviceImpl.getAllUsers();
- for (UserModel user : users) {
- setAccountType(user);
- }
- return users;
- }
-
- @Override
- public List<String> getAllTeamNames() {
- return serviceImpl.getAllTeamNames();
- }
-
- @Override
- public List<TeamModel> getAllTeams() {
- return serviceImpl.getAllTeams();
- }
-
- @Override
- public List<String> getTeamNamesForRepositoryRole(String role) {
- return serviceImpl.getTeamNamesForRepositoryRole(role);
- }
-
- @Override
- @Deprecated
- public boolean setTeamnamesForRepositoryRole(String role, List<String> teamnames) {
- return serviceImpl.setTeamnamesForRepositoryRole(role, teamnames);
- }
-
- @Override
- public TeamModel getTeamModel(String teamname) {
- return serviceImpl.getTeamModel(teamname);
- }
-
- @Override
- public boolean updateTeamModel(TeamModel model) {
- return serviceImpl.updateTeamModel(model);
- }
-
- @Override
- public boolean updateTeamModels(Collection<TeamModel> models) {
- return serviceImpl.updateTeamModels(models);
- }
-
- @Override
- public boolean updateTeamModel(String teamname, TeamModel model) {
- if (!supportsTeamMembershipChanges()) {
- // teams are externally controlled - copy from original model
- TeamModel existingModel = getTeamModel(teamname);
-
- model = DeepCopier.copy(model);
- model.users.clear();
- model.users.addAll(existingModel.users);
- }
- return serviceImpl.updateTeamModel(teamname, model);
- }
-
- @Override
- public boolean deleteTeamModel(TeamModel model) {
- return serviceImpl.deleteTeamModel(model);
- }
-
- @Override
- public boolean deleteTeam(String teamname) {
- return serviceImpl.deleteTeam(teamname);
- }
-
- @Override
- public List<String> getUsernamesForRepositoryRole(String role) {
- return serviceImpl.getUsernamesForRepositoryRole(role);
- }
-
- @Override
- @Deprecated
- public boolean setUsernamesForRepositoryRole(String role, List<String> usernames) {
- return serviceImpl.setUsernamesForRepositoryRole(role, usernames);
- }
-
- @Override
- public boolean renameRepositoryRole(String oldRole, String newRole) {
- return serviceImpl.renameRepositoryRole(oldRole, newRole);
- }
-
- @Override
- public boolean deleteRepositoryRole(String role) {
- return serviceImpl.deleteRepositoryRole(role);
- }
-
- protected boolean isLocalAccount(String username) {
- UserModel user = getUserModel(username);
- return user != null && user.isLocalAccount();
- }
-
- protected void setAccountType(UserModel user) {
- if (user != null) {
- if (!StringUtils.isEmpty(user.password)
- && !Constants.EXTERNAL_ACCOUNT.equalsIgnoreCase(user.password)
- && !"StoredInLDAP".equalsIgnoreCase(user.password)) {
- user.accountType = AccountType.LOCAL;
- } else {
- user.accountType = getAccountType();
- }
- }
- }
-
- @Override
- public AccountType getAccountType() {
- return AccountType.LOCAL;
- }
-}
diff --git a/src/main/java/com/gitblit/IUserService.java b/src/main/java/com/gitblit/IUserService.java
index 316e4a55..053f1790 100644
--- a/src/main/java/com/gitblit/IUserService.java
+++ b/src/main/java/com/gitblit/IUserService.java
@@ -18,7 +18,6 @@ package com.gitblit;
import java.util.Collection;
import java.util.List;
-import com.gitblit.Constants.AccountType;
import com.gitblit.manager.IRuntimeManager;
import com.gitblit.models.TeamModel;
import com.gitblit.models.UserModel;
@@ -43,45 +42,6 @@ public interface IUserService {
void setup(IRuntimeManager runtimeManager);
/**
- * Does the user service support changes to credentials?
- *
- * @return true or false
- * @since 1.0.0
- */
- boolean supportsCredentialChanges();
-
- /**
- * Does the user service support changes to user display name?
- *
- * @return true or false
- * @since 1.0.0
- */
- boolean supportsDisplayNameChanges();
-
- /**
- * Does the user service support changes to user email address?
- *
- * @return true or false
- * @since 1.0.0
- */
- boolean supportsEmailAddressChanges();
-
- /**
- * Does the user service support changes to team memberships?
- *
- * @return true or false
- * @since 1.0.0
- */
- boolean supportsTeamMembershipChanges();
-
- /**
- * Does the user service support cookie authentication?
- *
- * @return true or false
- */
- boolean supportsCookies();
-
- /**
* Returns the cookie value for the specified user.
*
* @param model
@@ -90,28 +50,12 @@ public interface IUserService {
String getCookie(UserModel model);
/**
- * Authenticate a user based on their cookie.
+ * Retrieve a user object for the specified cookie.
*
* @param cookie
* @return a user object or null
*/
- UserModel authenticate(char[] cookie);
-
- /**
- * Authenticate a user based on a username and password.
- *
- * @param username
- * @param password
- * @return a user object or null
- */
- UserModel authenticate(String username, char[] password);
-
- /**
- * Logout a user.
- *
- * @param user
- */
- void logout(UserModel user);
+ UserModel getUserModel(char[] cookie);
/**
* Retrieve the user object for the specified username.
@@ -209,19 +153,6 @@ public interface IUserService {
List<String> getTeamNamesForRepositoryRole(String role);
/**
- * Sets the list of all teams who are allowed to bypass the access
- * restriction placed on the specified repository.
- *
- * @param role
- * the repository name
- * @param teamnames
- * @return true if successful
- * @since 0.8.0
- */
- @Deprecated
- boolean setTeamnamesForRepositoryRole(String role, List<String> teamnames);
-
- /**
* Retrieve the team object for the specified team name.
*
* @param teamname
@@ -291,18 +222,6 @@ public interface IUserService {
List<String> getUsernamesForRepositoryRole(String role);
/**
- * Sets the list of all uses who are allowed to bypass the access
- * restriction placed on the specified repository.
- *
- * @param role
- * the repository name
- * @param usernames
- * @return true if successful
- */
- @Deprecated
- boolean setUsernamesForRepositoryRole(String role, List<String> usernames);
-
- /**
* Renames a repository role.
*
* @param oldRole
@@ -320,14 +239,6 @@ public interface IUserService {
boolean deleteRepositoryRole(String role);
/**
- * Returns the account type for the user models.
- *
- * @return the account type
- * @since 1.4.0
- */
- AccountType getAccountType();
-
- /**
* @See java.lang.Object.toString();
* @return string representation of the login service
*/
diff --git a/src/main/java/com/gitblit/auth/AuthenticationProvider.java b/src/main/java/com/gitblit/auth/AuthenticationProvider.java
new file mode 100644
index 00000000..b8aaf079
--- /dev/null
+++ b/src/main/java/com/gitblit/auth/AuthenticationProvider.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2013 gitblit.com.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit.auth;
+
+import java.io.File;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.gitblit.Constants.AccountType;
+import com.gitblit.IStoredSettings;
+import com.gitblit.manager.IRuntimeManager;
+import com.gitblit.manager.IUserManager;
+import com.gitblit.models.TeamModel;
+import com.gitblit.models.UserModel;
+
+public abstract class AuthenticationProvider {
+
+ public static NullProvider NULL_PROVIDER = new NullProvider();
+
+ protected final Logger logger = LoggerFactory.getLogger(getClass());
+
+ protected final String serviceName;
+
+ protected File baseFolder;
+
+ protected IStoredSettings settings;
+
+ protected IRuntimeManager runtimeManager;
+
+ protected IUserManager userManager;
+
+ protected AuthenticationProvider(String serviceName) {
+ this.serviceName = serviceName;
+ }
+
+ /**
+ * Returns the file object for the specified configuration key.
+ *
+ * @return the file
+ */
+ public File getFileOrFolder(String key, String defaultFileOrFolder) {
+ return runtimeManager.getFileOrFolder(key, defaultFileOrFolder);
+ }
+
+ public final void setup(IRuntimeManager runtimeManager, IUserManager userManager) {
+ this.baseFolder = runtimeManager.getBaseFolder();
+ this.settings = runtimeManager.getSettings();
+ this.runtimeManager = runtimeManager;
+ this.userManager = userManager;
+ setup();
+ }
+
+ public String getServiceName() {
+ return serviceName;
+ }
+
+ protected void updateUser(UserModel userModel) {
+ // TODO implement user model change detection
+ // account for new user and revised user
+
+ // username
+ // displayname
+ // email address
+ // cookie
+
+ userManager.updateUserModel(userModel);
+ }
+
+ protected void updateTeam(TeamModel teamModel) {
+ // TODO implement team model change detection
+ // account for new team and revised team
+
+ // memberships
+
+ userManager.updateTeamModel(teamModel);
+ }
+
+ public abstract void setup();
+
+ public abstract UserModel authenticate(String username, char[] password);
+
+ public abstract AccountType getAccountType();
+
+ /**
+ * Does the user service support changes to credentials?
+ *
+ * @return true or false
+ * @since 1.0.0
+ */
+ public abstract boolean supportsCredentialChanges();
+
+ /**
+ * Returns true if the user's display name can be changed.
+ *
+ * @param user
+ * @return true if the user service supports display name changes
+ */
+ public abstract boolean supportsDisplayNameChanges();
+
+ /**
+ * Returns true if the user's email address can be changed.
+ *
+ * @param user
+ * @return true if the user service supports email address changes
+ */
+ public abstract boolean supportsEmailAddressChanges();
+
+ /**
+ * Returns true if the user's team memberships can be changed.
+ *
+ * @param user
+ * @return true if the user service supports team membership changes
+ */
+ public abstract boolean supportsTeamMembershipChanges();
+
+ @Override
+ public String toString() {
+ return getServiceName() + " (" + getClass().getName() + ")";
+ }
+
+ public abstract static class UsernamePasswordAuthenticationProvider extends AuthenticationProvider {
+ protected UsernamePasswordAuthenticationProvider(String serviceName) {
+ super(serviceName);
+ }
+ }
+
+ public static class NullProvider extends AuthenticationProvider {
+
+ protected NullProvider() {
+ super("NULL");
+ }
+
+ @Override
+ public void setup() {
+
+ }
+
+ @Override
+ public UserModel authenticate(String username, char[] password) {
+ return null;
+ }
+
+ @Override
+ public AccountType getAccountType() {
+ return AccountType.LOCAL;
+ }
+
+ @Override
+ public boolean supportsCredentialChanges() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsDisplayNameChanges() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsEmailAddressChanges() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsTeamMembershipChanges() {
+ return false;
+ }
+ }
+}
diff --git a/src/main/java/com/gitblit/HtpasswdUserService.java b/src/main/java/com/gitblit/auth/HtpasswdAuthProvider.java
index ca5295c9..559a0fa0 100644
--- a/src/main/java/com/gitblit/HtpasswdUserService.java
+++ b/src/main/java/com/gitblit/auth/HtpasswdAuthProvider.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.gitblit;
+package com.gitblit.auth;
import java.io.File;
import java.io.FileInputStream;
@@ -29,11 +29,11 @@ import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.Crypt;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.codec.digest.Md5Crypt;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import com.gitblit.Constants;
import com.gitblit.Constants.AccountType;
-import com.gitblit.manager.IRuntimeManager;
+import com.gitblit.Keys;
+import com.gitblit.auth.AuthenticationProvider.UsernamePasswordAuthenticationProvider;
import com.gitblit.models.UserModel;
import com.gitblit.utils.ArrayUtils;
import com.gitblit.utils.StringUtils;
@@ -64,52 +64,25 @@ import com.gitblit.utils.StringUtils;
* @author Florian Zschocke
*
*/
-public class HtpasswdUserService extends GitblitUserService
-{
-
- private static final String KEY_BACKING_US = Keys.realm.htpasswd.backingUserService;
- private static final String DEFAULT_BACKING_US = "${baseFolder}/users.conf";
+public class HtpasswdAuthProvider extends UsernamePasswordAuthenticationProvider {
private static final String KEY_HTPASSWD_FILE = Keys.realm.htpasswd.userfile;
private static final String DEFAULT_HTPASSWD_FILE = "${baseFolder}/htpasswd";
- private static final String KEY_OVERRIDE_LOCALAUTH = Keys.realm.htpasswd.overrideLocalAuthentication;
- private static final boolean DEFAULT_OVERRIDE_LOCALAUTH = true;
-
private static final String KEY_SUPPORT_PLAINTEXT_PWD = "realm.htpasswd.supportPlaintextPasswords";
- private final boolean SUPPORT_PLAINTEXT_PWD;
+ private boolean supportPlainTextPwd;
- private IRuntimeManager runtimeManager;
- private IStoredSettings settings;
private File htpasswdFile;
-
- private final Logger logger = LoggerFactory.getLogger(HtpasswdUserService.class);
-
private final Map<String, String> htUsers = new ConcurrentHashMap<String, String>();
private volatile long lastModified;
- private volatile boolean forceReload;
-
-
-
- public HtpasswdUserService()
- {
- super();
-
- String os = System.getProperty("os.name").toLowerCase();
- if (os.startsWith("windows") || os.startsWith("netware")) {
- SUPPORT_PLAINTEXT_PWD = true;
- }
- else {
- SUPPORT_PLAINTEXT_PWD = false;
- }
+ public HtpasswdAuthProvider() {
+ super("htpasswd");
}
-
-
/**
* Setup the user service.
*
@@ -118,42 +91,40 @@ public class HtpasswdUserService extends GitblitUserService
* In addition the setup tries to read and parse the htpasswd file to be used
* for authentication.
*
- * @param runtimeManager
- * @since 1.4.0
+ * @param settings
+ * @since 0.7.0
*/
@Override
- public void setup(IRuntimeManager runtimeManager)
- {
- this.runtimeManager = runtimeManager;
- this.settings = runtimeManager.getSettings();
-
- // This is done in two steps in order to avoid calling GitBlit.getFileOrFolder(String, String) which will segfault for unit tests.
- String file = settings.getString(KEY_BACKING_US, DEFAULT_BACKING_US);
- File realmFile = runtimeManager.getFileOrFolder(file);
- serviceImpl = createUserService(realmFile);
- logger.info("Htpasswd User Service backed by " + serviceImpl.toString());
-
+ public void setup() {
+ String os = System.getProperty("os.name").toLowerCase();
+ if (os.startsWith("windows") || os.startsWith("netware")) {
+ supportPlainTextPwd = true;
+ } else {
+ supportPlainTextPwd = false;
+ }
read();
-
logger.debug("Read " + htUsers.size() + " users from htpasswd file: " + this.htpasswdFile);
}
-
-
- /**
- * For now, credentials are defined in the htpasswd file and can not be manipulated
- * from Gitblit.
- *
- * @return false
- * @since 1.0.0
- */
@Override
- public boolean supportsCredentialChanges()
- {
+ public boolean supportsCredentialChanges() {
return false;
}
+ @Override
+ public boolean supportsDisplayNameChanges() {
+ return true;
+ }
+
+ @Override
+ public boolean supportsEmailAddressChanges() {
+ return true;
+ }
+ @Override
+ public boolean supportsTeamMembershipChanges() {
+ return true;
+ }
/**
* Authenticate a user based on a username and password.
@@ -168,14 +139,7 @@ public class HtpasswdUserService extends GitblitUserService
* @return a user object or null
*/
@Override
- public UserModel authenticate(String username, char[] password)
- {
- if (isLocalAccount(username)) {
- // local account, bypass htpasswd authentication
- return super.authenticate(username, password);
- }
-
-
+ public UserModel authenticate(String username, char[] password) {
read();
String storedPwd = htUsers.get(username);
if (storedPwd != null) {
@@ -183,27 +147,27 @@ public class HtpasswdUserService extends GitblitUserService
final String passwd = new String(password);
// test Apache MD5 variant encrypted password
- if ( storedPwd.startsWith("$apr1$") ) {
- if ( storedPwd.equals(Md5Crypt.apr1Crypt(passwd, storedPwd)) ) {
+ if (storedPwd.startsWith("$apr1$")) {
+ if (storedPwd.equals(Md5Crypt.apr1Crypt(passwd, storedPwd))) {
logger.debug("Apache MD5 encoded password matched for user '" + username + "'");
authenticated = true;
}
}
// test unsalted SHA password
- else if ( storedPwd.startsWith("{SHA}") ) {
+ else if (storedPwd.startsWith("{SHA}")) {
String passwd64 = Base64.encodeBase64String(DigestUtils.sha1(passwd));
- if ( storedPwd.substring("{SHA}".length()).equals(passwd64) ) {
+ if (storedPwd.substring("{SHA}".length()).equals(passwd64)) {
logger.debug("Unsalted SHA-1 encoded password matched for user '" + username + "'");
authenticated = true;
}
}
// test libc crypt() encoded password
- else if ( supportCryptPwd() && storedPwd.equals(Crypt.crypt(passwd, storedPwd)) ) {
+ else if (supportCryptPwd() && storedPwd.equals(Crypt.crypt(passwd, storedPwd))) {
logger.debug("Libc crypt encoded password matched for user '" + username + "'");
authenticated = true;
}
// test clear text
- else if ( supportPlaintextPwd() && storedPwd.equals(passwd) ){
+ else if (supportPlaintextPwd() && storedPwd.equals(passwd)){
logger.debug("Clear text password matched for user '" + username + "'");
authenticated = true;
}
@@ -212,10 +176,13 @@ public class HtpasswdUserService extends GitblitUserService
if (authenticated) {
logger.debug("Htpasswd authenticated: " + username);
- UserModel user = getUserModel(username);
- if (user == null) {
+ UserModel curr = userManager.getUserModel(username);
+ UserModel user;
+ if (curr == null) {
// create user object for new authenticated user
user = new UserModel(username);
+ } else {
+ user = curr;
}
// create a user cookie
@@ -228,7 +195,7 @@ public class HtpasswdUserService extends GitblitUserService
user.accountType = getAccountType();
// Push the looked up values to backing file
- super.updateUserModel(user);
+ updateUser(user);
return user;
}
@@ -237,70 +204,29 @@ public class HtpasswdUserService extends GitblitUserService
return null;
}
-
-
- /**
- * Determine if the account is to be treated as a local account.
- *
- * This influences authentication. A local account will be authenticated
- * by the backing user service while an external account will be handled
- * by this user service.
- * <br/>
- * The decision also depends on the setting of the key
- * realm.htpasswd.overrideLocalAuthentication.
- * If it is set to true, then passwords will first be checked against the
- * htpasswd store. If an account exists and is marked as local in the backing
- * user service, that setting will be overwritten by the result. This
- * means that an account that looks local to the backing user service will
- * be turned into an external account upon valid login of a user that has
- * an entry in the htpasswd file.
- * If the key is set to false, then it is determined if the account is local
- * according to the logic of the GitblitUserService.
- */
- @Override
- protected boolean isLocalAccount(String username)
- {
- if ( settings.getBoolean(KEY_OVERRIDE_LOCALAUTH, DEFAULT_OVERRIDE_LOCALAUTH) ) {
- read();
- if ( htUsers.containsKey(username) ) return false;
- }
- return super.isLocalAccount(username);
- }
-
-
-
/**
* Get the account type used for this user service.
*
* @return AccountType.HTPASSWD
*/
@Override
- public AccountType getAccountType()
- {
+ public AccountType getAccountType() {
return AccountType.HTPASSWD;
}
-
-
- private String htpasswdFilePath = null;
/**
* Reads the realm file and rebuilds the in-memory lookup tables.
*/
- protected synchronized void read()
- {
-
- // This is done in two steps in order to avoid calling GitBlit.getFileOrFolder(String, String) which will segfault for unit tests.
- String file = settings.getString(KEY_HTPASSWD_FILE, DEFAULT_HTPASSWD_FILE);
- if ( !file.equals(htpasswdFilePath) ) {
- // The htpasswd file setting changed. Rediscover the file.
- this.htpasswdFilePath = file;
- this.htpasswdFile = runtimeManager.getFileOrFolder(file);
+ protected synchronized void read() {
+ boolean forceReload = false;
+ File file = getFileOrFolder(KEY_HTPASSWD_FILE, DEFAULT_HTPASSWD_FILE);
+ if (!file.equals(htpasswdFile)) {
+ this.htpasswdFile = file;
this.htUsers.clear();
- this.forceReload = true;
+ forceReload = true;
}
if (htpasswdFile.exists() && (forceReload || (htpasswdFile.lastModified() != lastModified))) {
- forceReload = false;
lastModified = htpasswdFile.lastModified();
htUsers.clear();
@@ -309,53 +235,42 @@ public class HtpasswdUserService extends GitblitUserService
Scanner scanner = null;
try {
scanner = new Scanner(new FileInputStream(htpasswdFile));
- while( scanner.hasNextLine()) {
+ while (scanner.hasNextLine()) {
String line = scanner.nextLine().trim();
- if ( !line.isEmpty() && !line.startsWith("#") ) {
+ if (!line.isEmpty() && !line.startsWith("#")) {
Matcher m = entry.matcher(line);
- if ( m.matches() ) {
+ if (m.matches()) {
htUsers.put(m.group(1), m.group(2));
}
}
}
} catch (Exception e) {
logger.error(MessageFormat.format("Failed to read {0}", htpasswdFile), e);
- }
- finally {
- if (scanner != null) scanner.close();
+ } finally {
+ if (scanner != null) {
+ scanner.close();
+ }
}
}
}
-
-
- private boolean supportPlaintextPwd()
- {
- return this.settings.getBoolean(KEY_SUPPORT_PLAINTEXT_PWD, SUPPORT_PLAINTEXT_PWD);
+ private boolean supportPlaintextPwd() {
+ return this.settings.getBoolean(KEY_SUPPORT_PLAINTEXT_PWD, supportPlainTextPwd);
}
-
- private boolean supportCryptPwd()
- {
+ private boolean supportCryptPwd() {
return !supportPlaintextPwd();
}
-
-
- @Override
- public String toString()
- {
- return getClass().getSimpleName() + "(" + ((htpasswdFile != null) ? htpasswdFile.getAbsolutePath() : "null") + ")";
- }
-
-
-
-
/*
* Method only used for unit tests. Return number of users read from htpasswd file.
*/
- public int getNumberHtpasswdUsers()
- {
+ public int getNumberHtpasswdUsers() {
return this.htUsers.size();
}
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "(" + ((htpasswdFile != null) ? htpasswdFile.getAbsolutePath() : "null") + ")";
+ }
}
diff --git a/src/main/java/com/gitblit/LdapUserService.java b/src/main/java/com/gitblit/auth/LdapAuthProvider.java
index c075afca..7a6b74df 100644
--- a/src/main/java/com/gitblit/LdapUserService.java
+++ b/src/main/java/com/gitblit/auth/LdapAuthProvider.java
@@ -1,530 +1,508 @@
-/*
- * Copyright 2012 John Crygier
- * Copyright 2012 gitblit.com
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.gitblit;
-
-import java.io.File;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.security.GeneralSecurityException;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicLong;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.gitblit.Constants.AccountType;
-import com.gitblit.manager.IRuntimeManager;
-import com.gitblit.models.TeamModel;
-import com.gitblit.models.UserModel;
-import com.gitblit.utils.ArrayUtils;
-import com.gitblit.utils.StringUtils;
-import com.unboundid.ldap.sdk.Attribute;
-import com.unboundid.ldap.sdk.DereferencePolicy;
-import com.unboundid.ldap.sdk.ExtendedResult;
-import com.unboundid.ldap.sdk.LDAPConnection;
-import com.unboundid.ldap.sdk.LDAPException;
-import com.unboundid.ldap.sdk.LDAPSearchException;
-import com.unboundid.ldap.sdk.ResultCode;
-import com.unboundid.ldap.sdk.SearchRequest;
-import com.unboundid.ldap.sdk.SearchResult;
-import com.unboundid.ldap.sdk.SearchResultEntry;
-import com.unboundid.ldap.sdk.SearchScope;
-import com.unboundid.ldap.sdk.SimpleBindRequest;
-import com.unboundid.ldap.sdk.extensions.StartTLSExtendedRequest;
-import com.unboundid.util.ssl.SSLUtil;
-import com.unboundid.util.ssl.TrustAllTrustManager;
-
-/**
- * Implementation of an LDAP user service.
- *
- * @author John Crygier
- */
-public class LdapUserService extends GitblitUserService {
-
- public static final Logger logger = LoggerFactory.getLogger(LdapUserService.class);
-
- private IStoredSettings settings;
- private AtomicLong lastLdapUserSync = new AtomicLong(0L);
-
- public LdapUserService() {
- super();
- }
-
- private long getSynchronizationPeriod() {
- final String cacheDuration = settings.getString(Keys.realm.ldap.ldapCachePeriod, "2 MINUTES");
- try {
- final String[] s = cacheDuration.split(" ", 2);
- long duration = 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'");
- }
- }
-
- @Override
- public void setup(IRuntimeManager runtimeManager) {
- this.settings = runtimeManager.getSettings();
- String file = settings.getString(Keys.realm.ldap.backingUserService, "${baseFolder}/users.conf");
- File realmFile = runtimeManager.getFileOrFolder(file);
-
- serviceImpl = createUserService(realmFile);
- logger.info("LDAP User Service backed by " + serviceImpl.toString());
-
- synchronizeLdapUsers();
- }
-
- 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}", "*");
-
- SearchResult result = doSearch(ldapConnection, accountBase, accountPattern);
- if (result != null && result.getEntryCount() > 0) {
- final Map<String, UserModel> ldapUsers = new HashMap<String, UserModel>();
-
- for (SearchResultEntry loggingInUser : result.getSearchEntries()) {
-
- final String username = loggingInUser.getAttribute(uidAttribute).getValue();
- logger.debug("LDAP synchronizing: " + username);
-
- UserModel user = getUserModel(username);
- if (user == null) {
- user = new UserModel(username);
- }
-
- if (!supportsTeamMembershipChanges())
- getTeamsFromLdap(ldapConnection, username, loggingInUser, user);
-
- // Get User Attributes
- setUserAttributes(user, loggingInUser);
-
- // store in map
- ldapUsers.put(username.toLowerCase(), user);
- }
-
- if (deleteRemovedLdapUsers) {
- logger.debug("detecting removed LDAP users...");
-
- for (UserModel userModel : super.getAllUsers()) {
- if (Constants.EXTERNAL_ACCOUNT.equals(userModel.password)) {
- if (! ldapUsers.containsKey(userModel.username)) {
- logger.info("deleting removed LDAP user " + userModel.username + " from backing user service");
- super.deleteUser(userModel.username);
- }
- }
- }
- }
-
- super.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);
- }
- }
- updateTeamModels(userTeams.values());
- }
- }
- lastLdapUserSync.set(System.currentTimeMillis());
- } finally {
- ldapConnection.close();
- }
- }
- }
- }
- }
-
- private LDAPConnection getLdapConnection() {
- try {
-
- URI ldapUrl = new URI(settings.getRequiredString(Keys.realm.ldap.server));
- String ldapHost = ldapUrl.getHost();
- int ldapPort = ldapUrl.getPort();
- String bindUserName = settings.getString(Keys.realm.ldap.username, "");
- String bindPassword = settings.getString(Keys.realm.ldap.password, "");
-
-
- LDAPConnection conn;
- if (ldapUrl.getScheme().equalsIgnoreCase("ldaps")) { // SSL
- SSLUtil sslUtil = new SSLUtil(new TrustAllTrustManager());
- conn = new LDAPConnection(sslUtil.createSSLSocketFactory());
- } else if (ldapUrl.getScheme().equalsIgnoreCase("ldap") || ldapUrl.getScheme().equalsIgnoreCase("ldap+tls")) { // no encryption or StartTLS
- conn = new LDAPConnection();
- } else {
- logger.error("Unsupported LDAP URL scheme: " + ldapUrl.getScheme());
- return null;
- }
-
- conn.connect(ldapHost, ldapPort);
-
- if (ldapUrl.getScheme().equalsIgnoreCase("ldap+tls")) {
- SSLUtil sslUtil = new SSLUtil(new TrustAllTrustManager());
- ExtendedResult extendedResult = conn.processExtendedOperation(
- new StartTLSExtendedRequest(sslUtil.createSSLContext()));
- if (extendedResult.getResultCode() != ResultCode.SUCCESS) {
- throw new LDAPException(extendedResult.getResultCode());
- }
- }
-
- if ( ! StringUtils.isEmpty(bindUserName) || ! StringUtils.isEmpty(bindPassword)) {
- conn.bind(new SimpleBindRequest(bindUserName, bindPassword));
- }
-
- return conn;
-
- } catch (URISyntaxException e) {
- logger.error("Bad LDAP URL, should be in the form: ldap(s|+tls)://<server>:<port>", e);
- } catch (GeneralSecurityException e) {
- logger.error("Unable to create SSL Connection", e);
- } catch (LDAPException e) {
- logger.error("Error Connecting to LDAP", e);
- }
-
- return null;
- }
-
- /**
- * Credentials are defined in the LDAP server and can not be manipulated
- * from Gitblit.
- *
- * @return false
- * @since 1.0.0
- */
- @Override
- public boolean supportsCredentialChanges() {
- return false;
- }
-
- /**
- * If no displayName pattern is defined then Gitblit can manage the display name.
- *
- * @return true if Gitblit can manage the user display name
- * @since 1.0.0
- */
- @Override
- public boolean supportsDisplayNameChanges() {
- return StringUtils.isEmpty(settings.getString(Keys.realm.ldap.displayName, ""));
- }
-
- /**
- * If no email pattern is defined then Gitblit can manage the email address.
- *
- * @return true if Gitblit can manage the user email address
- * @since 1.0.0
- */
- @Override
- public boolean supportsEmailAddressChanges() {
- return StringUtils.isEmpty(settings.getString(Keys.realm.ldap.email, ""));
- }
-
-
- /**
- * If the LDAP server will maintain team memberships then LdapUserService
- * will not allow team membership changes. In this scenario all team
- * changes must be made on the LDAP server by the LDAP administrator.
- *
- * @return true or false
- * @since 1.0.0
- */
- @Override
- public boolean supportsTeamMembershipChanges() {
- return !settings.getBoolean(Keys.realm.ldap.maintainTeams, false);
- }
-
- @Override
- public AccountType getAccountType() {
- return AccountType.LDAP;
- }
-
- @Override
- public UserModel authenticate(String username, char[] password) {
- if (isLocalAccount(username)) {
- // local account, bypass LDAP authentication
- return super.authenticate(username, password);
- }
-
- String simpleUsername = getSimpleUsername(username);
-
- LDAPConnection ldapConnection = getLdapConnection();
- if (ldapConnection != null) {
- try {
- // Find the logging in user's DN
- String accountBase = settings.getString(Keys.realm.ldap.accountBase, "");
- String accountPattern = settings.getString(Keys.realm.ldap.accountPattern, "(&(objectClass=person)(sAMAccountName=${username}))");
- accountPattern = StringUtils.replace(accountPattern, "${username}", escapeLDAPSearchFilter(simpleUsername));
-
- SearchResult result = doSearch(ldapConnection, accountBase, accountPattern);
- if (result != null && result.getEntryCount() == 1) {
- SearchResultEntry loggingInUser = result.getSearchEntries().get(0);
- String loggingInUserDN = loggingInUser.getDN();
-
- if (isAuthenticated(ldapConnection, loggingInUserDN, new String(password))) {
- logger.debug("LDAP authenticated: " + username);
-
- UserModel user = null;
- synchronized (this) {
- user = getUserModel(simpleUsername);
- if (user == null) // create user object for new authenticated user
- user = new UserModel(simpleUsername);
-
- // create a user cookie
- if (StringUtils.isEmpty(user.cookie) && !ArrayUtils.isEmpty(password)) {
- user.cookie = StringUtils.getSHA1(user.username + new String(password));
- }
-
- if (!supportsTeamMembershipChanges())
- getTeamsFromLdap(ldapConnection, simpleUsername, loggingInUser, user);
-
- // Get User Attributes
- setUserAttributes(user, loggingInUser);
-
- // Push the ldap looked up values to backing file
- super.updateUserModel(user);
- if (!supportsTeamMembershipChanges()) {
- for (TeamModel userTeam : user.teams)
- updateTeamModel(userTeam);
- }
- }
-
- return user;
- }
- }
- } finally {
- ldapConnection.close();
- }
- }
- return null;
- }
-
- /**
- * Set the admin attribute from team memberships retrieved from LDAP.
- * If we are not storing teams in LDAP and/or we have not defined any
- * administrator teams, then do not change the admin flag.
- *
- * @param user
- */
- private void setAdminAttribute(UserModel user) {
- if (!supportsTeamMembershipChanges()) {
- List<String> admins = settings.getStrings(Keys.realm.ldap.admins);
- // if we have defined administrative teams, then set admin flag
- // otherwise leave admin flag unchanged
- if (!ArrayUtils.isEmpty(admins)) {
- user.canAdmin = false;
- for (String admin : admins) {
- if (admin.startsWith("@")) { // Team
- if (user.getTeam(admin.substring(1)) != null)
- user.canAdmin = true;
- } else
- if (user.getName().equalsIgnoreCase(admin))
- user.canAdmin = true;
- }
- }
- }
- }
-
- private void setUserAttributes(UserModel user, SearchResultEntry userEntry) {
- // Is this user an admin?
- setAdminAttribute(user);
-
- // Don't want visibility into the real password, make up a dummy
- user.password = Constants.EXTERNAL_ACCOUNT;
- user.accountType = getAccountType();
-
- // Get full name Attribute
- String displayName = settings.getString(Keys.realm.ldap.displayName, "");
- if (!StringUtils.isEmpty(displayName)) {
- // Replace embedded ${} with attributes
- if (displayName.contains("${")) {
- for (Attribute userAttribute : userEntry.getAttributes())
- displayName = StringUtils.replace(displayName, "${" + userAttribute.getName() + "}", userAttribute.getValue());
-
- user.displayName = displayName;
- } else {
- Attribute attribute = userEntry.getAttribute(displayName);
- if (attribute != null && attribute.hasValue()) {
- user.displayName = attribute.getValue();
- }
- }
- }
-
- // Get email address Attribute
- String email = settings.getString(Keys.realm.ldap.email, "");
- if (!StringUtils.isEmpty(email)) {
- if (email.contains("${")) {
- for (Attribute userAttribute : userEntry.getAttributes())
- email = StringUtils.replace(email, "${" + userAttribute.getName() + "}", userAttribute.getValue());
-
- user.emailAddress = email;
- } else {
- Attribute attribute = userEntry.getAttribute(email);
- if (attribute != null && attribute.hasValue()) {
- user.emailAddress = attribute.getValue();
- }
- }
- }
- }
-
- private void getTeamsFromLdap(LDAPConnection ldapConnection, String simpleUsername, SearchResultEntry loggingInUser, UserModel user) {
- String loggingInUserDN = loggingInUser.getDN();
-
- user.teams.clear(); // Clear the users team memberships - we're going to get them from LDAP
- String groupBase = settings.getString(Keys.realm.ldap.groupBase, "");
- String groupMemberPattern = settings.getString(Keys.realm.ldap.groupMemberPattern, "(&(objectClass=group)(member=${dn}))");
-
- groupMemberPattern = StringUtils.replace(groupMemberPattern, "${dn}", escapeLDAPSearchFilter(loggingInUserDN));
- groupMemberPattern = StringUtils.replace(groupMemberPattern, "${username}", escapeLDAPSearchFilter(simpleUsername));
-
- // Fill in attributes into groupMemberPattern
- for (Attribute userAttribute : loggingInUser.getAttributes())
- groupMemberPattern = StringUtils.replace(groupMemberPattern, "${" + userAttribute.getName() + "}", escapeLDAPSearchFilter(userAttribute.getValue()));
-
- SearchResult teamMembershipResult = doSearch(ldapConnection, groupBase, true, groupMemberPattern, Arrays.asList("cn"));
- if (teamMembershipResult != null && teamMembershipResult.getEntryCount() > 0) {
- for (int i = 0; i < teamMembershipResult.getEntryCount(); i++) {
- SearchResultEntry teamEntry = teamMembershipResult.getSearchEntries().get(i);
- String teamName = teamEntry.getAttribute("cn").getValue();
-
- TeamModel teamModel = getTeamModel(teamName);
- if (teamModel == null)
- teamModel = createTeamFromLdap(teamEntry);
-
- user.teams.add(teamModel);
- teamModel.addUser(user.getName());
- }
- }
- }
-
- private TeamModel createTeamFromLdap(SearchResultEntry teamEntry) {
- TeamModel answer = new TeamModel(teamEntry.getAttributeValue("cn"));
- // potentially retrieve other attributes here in the future
-
- return answer;
- }
-
- private SearchResult doSearch(LDAPConnection ldapConnection, String base, String filter) {
- try {
- return ldapConnection.search(base, SearchScope.SUB, filter);
- } catch (LDAPSearchException e) {
- logger.error("Problem Searching LDAP", e);
-
- return null;
- }
- }
-
- private SearchResult doSearch(LDAPConnection ldapConnection, String base, boolean dereferenceAliases, String filter, List<String> attributes) {
- try {
- SearchRequest searchRequest = new SearchRequest(base, SearchScope.SUB, filter);
- if ( dereferenceAliases ) {
- searchRequest.setDerefPolicy(DereferencePolicy.SEARCHING);
- }
- if (attributes != null) {
- searchRequest.setAttributes(attributes);
- }
- return ldapConnection.search(searchRequest);
-
- } catch (LDAPSearchException e) {
- logger.error("Problem Searching LDAP", e);
-
- return null;
- } catch (LDAPException e) {
- logger.error("Problem creating LDAP search", e);
- return null;
- }
- }
-
- private boolean isAuthenticated(LDAPConnection ldapConnection, String userDn, String password) {
- try {
- // Binding will stop any LDAP-Injection Attacks since the searched-for user needs to bind to that DN
- ldapConnection.bind(userDn, password);
- return true;
- } catch (LDAPException e) {
- logger.error("Error authenticating user", e);
- return false;
- }
- }
-
- @Override
- public List<String> getAllUsernames() {
- synchronizeLdapUsers();
- return super.getAllUsernames();
- }
-
- @Override
- public List<UserModel> getAllUsers() {
- synchronizeLdapUsers();
- return super.getAllUsers();
- }
-
- /**
- * Returns a simple username without any domain prefixes.
- *
- * @param username
- * @return a simple username
- */
- protected String getSimpleUsername(String username) {
- int lastSlash = username.lastIndexOf('\\');
- if (lastSlash > -1) {
- username = username.substring(lastSlash + 1);
- }
-
- return username;
- }
-
- // From: https://www.owasp.org/index.php/Preventing_LDAP_Injection_in_Java
- public static final String escapeLDAPSearchFilter(String filter) {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < filter.length(); i++) {
- char curChar = filter.charAt(i);
- switch (curChar) {
- case '\\':
- sb.append("\\5c");
- break;
- case '*':
- sb.append("\\2a");
- break;
- case '(':
- sb.append("\\28");
- break;
- case ')':
- sb.append("\\29");
- break;
- case '\u0000':
- sb.append("\\00");
- break;
- default:
- sb.append(curChar);
- }
- }
- return sb.toString();
- }
-}
+/*
+ * Copyright 2012 John Crygier
+ * Copyright 2012 gitblit.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit.auth;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.GeneralSecurityException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+import com.gitblit.Constants;
+import com.gitblit.Constants.AccountType;
+import com.gitblit.Keys;
+import com.gitblit.auth.AuthenticationProvider.UsernamePasswordAuthenticationProvider;
+import com.gitblit.models.TeamModel;
+import com.gitblit.models.UserModel;
+import com.gitblit.utils.ArrayUtils;
+import com.gitblit.utils.StringUtils;
+import com.unboundid.ldap.sdk.Attribute;
+import com.unboundid.ldap.sdk.DereferencePolicy;
+import com.unboundid.ldap.sdk.ExtendedResult;
+import com.unboundid.ldap.sdk.LDAPConnection;
+import com.unboundid.ldap.sdk.LDAPException;
+import com.unboundid.ldap.sdk.LDAPSearchException;
+import com.unboundid.ldap.sdk.ResultCode;
+import com.unboundid.ldap.sdk.SearchRequest;
+import com.unboundid.ldap.sdk.SearchResult;
+import com.unboundid.ldap.sdk.SearchResultEntry;
+import com.unboundid.ldap.sdk.SearchScope;
+import com.unboundid.ldap.sdk.SimpleBindRequest;
+import com.unboundid.ldap.sdk.extensions.StartTLSExtendedRequest;
+import com.unboundid.util.ssl.SSLUtil;
+import com.unboundid.util.ssl.TrustAllTrustManager;
+
+/**
+ * Implementation of an LDAP user service.
+ *
+ * @author John Crygier
+ */
+public class LdapAuthProvider extends UsernamePasswordAuthenticationProvider {
+
+ private AtomicLong lastLdapUserSync = new AtomicLong(0L);
+
+ public LdapAuthProvider() {
+ super("ldap");
+ }
+
+ private long getSynchronizationPeriod() {
+ final String cacheDuration = settings.getString(Keys.realm.ldap.ldapCachePeriod, "2 MINUTES");
+ try {
+ final String[] s = cacheDuration.split(" ", 2);
+ long duration = 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'");
+ }
+ }
+
+ @Override
+ public void setup() {
+ synchronizeLdapUsers();
+ }
+
+ 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}", "*");
+
+ SearchResult result = doSearch(ldapConnection, accountBase, accountPattern);
+ if (result != null && result.getEntryCount() > 0) {
+ final Map<String, UserModel> ldapUsers = new HashMap<String, UserModel>();
+
+ for (SearchResultEntry loggingInUser : result.getSearchEntries()) {
+
+ final String username = loggingInUser.getAttribute(uidAttribute).getValue();
+ logger.debug("LDAP synchronizing: " + username);
+
+ UserModel user = userManager.getUserModel(username);
+ if (user == null) {
+ user = new UserModel(username);
+ }
+
+ if (!supportsTeamMembershipChanges()) {
+ getTeamsFromLdap(ldapConnection, username, loggingInUser, user);
+ }
+
+ // Get User Attributes
+ setUserAttributes(user, loggingInUser);
+
+ // store in map
+ ldapUsers.put(username.toLowerCase(), user);
+ }
+
+ if (deleteRemovedLdapUsers) {
+ logger.debug("detecting removed LDAP users...");
+
+ 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);
+ }
+ }
+ }
+ }
+
+ 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());
+ }
+ }
+ lastLdapUserSync.set(System.currentTimeMillis());
+ } finally {
+ ldapConnection.close();
+ }
+ }
+ }
+ }
+ }
+
+ private LDAPConnection getLdapConnection() {
+ try {
+
+ URI ldapUrl = new URI(settings.getRequiredString(Keys.realm.ldap.server));
+ String ldapHost = ldapUrl.getHost();
+ int ldapPort = ldapUrl.getPort();
+ String bindUserName = settings.getString(Keys.realm.ldap.username, "");
+ String bindPassword = settings.getString(Keys.realm.ldap.password, "");
+
+
+ LDAPConnection conn;
+ if (ldapUrl.getScheme().equalsIgnoreCase("ldaps")) {
+ // SSL
+ SSLUtil sslUtil = new SSLUtil(new TrustAllTrustManager());
+ conn = new LDAPConnection(sslUtil.createSSLSocketFactory());
+ } else if (ldapUrl.getScheme().equalsIgnoreCase("ldap") || ldapUrl.getScheme().equalsIgnoreCase("ldap+tls")) {
+ // no encryption or StartTLS
+ conn = new LDAPConnection();
+ } else {
+ logger.error("Unsupported LDAP URL scheme: " + ldapUrl.getScheme());
+ return null;
+ }
+
+ conn.connect(ldapHost, ldapPort);
+
+ if (ldapUrl.getScheme().equalsIgnoreCase("ldap+tls")) {
+ SSLUtil sslUtil = new SSLUtil(new TrustAllTrustManager());
+ ExtendedResult extendedResult = conn.processExtendedOperation(
+ new StartTLSExtendedRequest(sslUtil.createSSLContext()));
+ if (extendedResult.getResultCode() != ResultCode.SUCCESS) {
+ throw new LDAPException(extendedResult.getResultCode());
+ }
+ }
+
+ if (!StringUtils.isEmpty(bindUserName) || !StringUtils.isEmpty(bindPassword)) {
+ conn.bind(new SimpleBindRequest(bindUserName, bindPassword));
+ }
+
+ return conn;
+
+ } catch (URISyntaxException e) {
+ logger.error("Bad LDAP URL, should be in the form: ldap(s|+tls)://<server>:<port>", e);
+ } catch (GeneralSecurityException e) {
+ logger.error("Unable to create SSL Connection", e);
+ } catch (LDAPException e) {
+ logger.error("Error Connecting to LDAP", e);
+ }
+
+ return null;
+ }
+
+ /**
+ * Credentials are defined in the LDAP server and can not be manipulated
+ * from Gitblit.
+ *
+ * @return false
+ * @since 1.0.0
+ */
+ @Override
+ public boolean supportsCredentialChanges() {
+ return false;
+ }
+
+ /**
+ * If no displayName pattern is defined then Gitblit can manage the display name.
+ *
+ * @return true if Gitblit can manage the user display name
+ * @since 1.0.0
+ */
+ @Override
+ public boolean supportsDisplayNameChanges() {
+ return StringUtils.isEmpty(settings.getString(Keys.realm.ldap.displayName, ""));
+ }
+
+ /**
+ * If no email pattern is defined then Gitblit can manage the email address.
+ *
+ * @return true if Gitblit can manage the user email address
+ * @since 1.0.0
+ */
+ @Override
+ public boolean supportsEmailAddressChanges() {
+ return StringUtils.isEmpty(settings.getString(Keys.realm.ldap.email, ""));
+ }
+
+
+ /**
+ * If the LDAP server will maintain team memberships then LdapUserService
+ * will not allow team membership changes. In this scenario all team
+ * changes must be made on the LDAP server by the LDAP administrator.
+ *
+ * @return true or false
+ * @since 1.0.0
+ */
+ @Override
+ public boolean supportsTeamMembershipChanges() {
+ return !settings.getBoolean(Keys.realm.ldap.maintainTeams, false);
+ }
+
+ @Override
+ public AccountType getAccountType() {
+ return AccountType.LDAP;
+ }
+
+ @Override
+ public UserModel authenticate(String username, char[] password) {
+ String simpleUsername = getSimpleUsername(username);
+
+ LDAPConnection ldapConnection = getLdapConnection();
+ if (ldapConnection != null) {
+ try {
+ // Find the logging in user's DN
+ String accountBase = settings.getString(Keys.realm.ldap.accountBase, "");
+ String accountPattern = settings.getString(Keys.realm.ldap.accountPattern, "(&(objectClass=person)(sAMAccountName=${username}))");
+ accountPattern = StringUtils.replace(accountPattern, "${username}", escapeLDAPSearchFilter(simpleUsername));
+
+ SearchResult result = doSearch(ldapConnection, accountBase, accountPattern);
+ if (result != null && result.getEntryCount() == 1) {
+ SearchResultEntry loggingInUser = result.getSearchEntries().get(0);
+ String loggingInUserDN = loggingInUser.getDN();
+
+ if (isAuthenticated(ldapConnection, loggingInUserDN, new String(password))) {
+ logger.debug("LDAP authenticated: " + username);
+
+ UserModel user = null;
+ synchronized (this) {
+ user = userManager.getUserModel(simpleUsername);
+ if (user == null) // create user object for new authenticated user
+ user = new UserModel(simpleUsername);
+
+ // create a user cookie
+ if (StringUtils.isEmpty(user.cookie) && !ArrayUtils.isEmpty(password)) {
+ user.cookie = StringUtils.getSHA1(user.username + new String(password));
+ }
+
+ if (!supportsTeamMembershipChanges())
+ getTeamsFromLdap(ldapConnection, simpleUsername, loggingInUser, user);
+
+ // Get User Attributes
+ setUserAttributes(user, loggingInUser);
+
+ // Push the ldap looked up values to backing file
+ updateUser(user);
+
+ if (!supportsTeamMembershipChanges()) {
+ for (TeamModel userTeam : user.teams)
+ updateTeam(userTeam);
+ }
+ }
+
+ return user;
+ }
+ }
+ } finally {
+ ldapConnection.close();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Set the admin attribute from team memberships retrieved from LDAP.
+ * If we are not storing teams in LDAP and/or we have not defined any
+ * administrator teams, then do not change the admin flag.
+ *
+ * @param user
+ */
+ private void setAdminAttribute(UserModel user) {
+ if (!supportsTeamMembershipChanges()) {
+ List<String> admins = settings.getStrings(Keys.realm.ldap.admins);
+ // if we have defined administrative teams, then set admin flag
+ // otherwise leave admin flag unchanged
+ if (!ArrayUtils.isEmpty(admins)) {
+ user.canAdmin = false;
+ for (String admin : admins) {
+ if (admin.startsWith("@")) { // Team
+ if (user.getTeam(admin.substring(1)) != null)
+ user.canAdmin = true;
+ } else
+ if (user.getName().equalsIgnoreCase(admin))
+ user.canAdmin = true;
+ }
+ }
+ }
+ }
+
+ private void setUserAttributes(UserModel user, SearchResultEntry userEntry) {
+ // Is this user an admin?
+ setAdminAttribute(user);
+
+ // Don't want visibility into the real password, make up a dummy
+ user.password = Constants.EXTERNAL_ACCOUNT;
+ user.accountType = getAccountType();
+
+ // Get full name Attribute
+ String displayName = settings.getString(Keys.realm.ldap.displayName, "");
+ if (!StringUtils.isEmpty(displayName)) {
+ // Replace embedded ${} with attributes
+ if (displayName.contains("${")) {
+ for (Attribute userAttribute : userEntry.getAttributes())
+ displayName = StringUtils.replace(displayName, "${" + userAttribute.getName() + "}", userAttribute.getValue());
+
+ user.displayName = displayName;
+ } else {
+ Attribute attribute = userEntry.getAttribute(displayName);
+ if (attribute != null && attribute.hasValue()) {
+ user.displayName = attribute.getValue();
+ }
+ }
+ }
+
+ // Get email address Attribute
+ String email = settings.getString(Keys.realm.ldap.email, "");
+ if (!StringUtils.isEmpty(email)) {
+ if (email.contains("${")) {
+ for (Attribute userAttribute : userEntry.getAttributes())
+ email = StringUtils.replace(email, "${" + userAttribute.getName() + "}", userAttribute.getValue());
+
+ user.emailAddress = email;
+ } else {
+ Attribute attribute = userEntry.getAttribute(email);
+ if (attribute != null && attribute.hasValue()) {
+ user.emailAddress = attribute.getValue();
+ }
+ }
+ }
+ }
+
+ private void getTeamsFromLdap(LDAPConnection ldapConnection, String simpleUsername, SearchResultEntry loggingInUser, UserModel user) {
+ String loggingInUserDN = loggingInUser.getDN();
+
+ user.teams.clear(); // Clear the users team memberships - we're going to get them from LDAP
+ String groupBase = settings.getString(Keys.realm.ldap.groupBase, "");
+ String groupMemberPattern = settings.getString(Keys.realm.ldap.groupMemberPattern, "(&(objectClass=group)(member=${dn}))");
+
+ groupMemberPattern = StringUtils.replace(groupMemberPattern, "${dn}", escapeLDAPSearchFilter(loggingInUserDN));
+ groupMemberPattern = StringUtils.replace(groupMemberPattern, "${username}", escapeLDAPSearchFilter(simpleUsername));
+
+ // Fill in attributes into groupMemberPattern
+ for (Attribute userAttribute : loggingInUser.getAttributes()) {
+ groupMemberPattern = StringUtils.replace(groupMemberPattern, "${" + userAttribute.getName() + "}", escapeLDAPSearchFilter(userAttribute.getValue()));
+ }
+
+ SearchResult teamMembershipResult = doSearch(ldapConnection, groupBase, true, groupMemberPattern, Arrays.asList("cn"));
+ if (teamMembershipResult != null && teamMembershipResult.getEntryCount() > 0) {
+ for (int i = 0; i < teamMembershipResult.getEntryCount(); i++) {
+ SearchResultEntry teamEntry = teamMembershipResult.getSearchEntries().get(i);
+ String teamName = teamEntry.getAttribute("cn").getValue();
+
+ TeamModel teamModel = userManager.getTeamModel(teamName);
+ if (teamModel == null) {
+ teamModel = createTeamFromLdap(teamEntry);
+ }
+
+ user.teams.add(teamModel);
+ teamModel.addUser(user.getName());
+ }
+ }
+ }
+
+ private TeamModel createTeamFromLdap(SearchResultEntry teamEntry) {
+ TeamModel answer = new TeamModel(teamEntry.getAttributeValue("cn"));
+ answer.accountType = getAccountType();
+ // potentially retrieve other attributes here in the future
+
+ return answer;
+ }
+
+ private SearchResult doSearch(LDAPConnection ldapConnection, String base, String filter) {
+ try {
+ return ldapConnection.search(base, SearchScope.SUB, filter);
+ } catch (LDAPSearchException e) {
+ logger.error("Problem Searching LDAP", e);
+
+ return null;
+ }
+ }
+
+ private SearchResult doSearch(LDAPConnection ldapConnection, String base, boolean dereferenceAliases, String filter, List<String> attributes) {
+ try {
+ SearchRequest searchRequest = new SearchRequest(base, SearchScope.SUB, filter);
+ if (dereferenceAliases) {
+ searchRequest.setDerefPolicy(DereferencePolicy.SEARCHING);
+ }
+ if (attributes != null) {
+ searchRequest.setAttributes(attributes);
+ }
+ return ldapConnection.search(searchRequest);
+
+ } catch (LDAPSearchException e) {
+ logger.error("Problem Searching LDAP", e);
+
+ return null;
+ } catch (LDAPException e) {
+ logger.error("Problem creating LDAP search", e);
+ return null;
+ }
+ }
+
+ private boolean isAuthenticated(LDAPConnection ldapConnection, String userDn, String password) {
+ try {
+ // Binding will stop any LDAP-Injection Attacks since the searched-for user needs to bind to that DN
+ ldapConnection.bind(userDn, password);
+ return true;
+ } catch (LDAPException e) {
+ logger.error("Error authenticating user", e);
+ return false;
+ }
+ }
+
+ /**
+ * Returns a simple username without any domain prefixes.
+ *
+ * @param username
+ * @return a simple username
+ */
+ protected String getSimpleUsername(String username) {
+ int lastSlash = username.lastIndexOf('\\');
+ if (lastSlash > -1) {
+ username = username.substring(lastSlash + 1);
+ }
+
+ return username;
+ }
+
+ // From: https://www.owasp.org/index.php/Preventing_LDAP_Injection_in_Java
+ public static final String escapeLDAPSearchFilter(String filter) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < filter.length(); i++) {
+ char curChar = filter.charAt(i);
+ switch (curChar) {
+ case '\\':
+ sb.append("\\5c");
+ break;
+ case '*':
+ sb.append("\\2a");
+ break;
+ case '(':
+ sb.append("\\28");
+ break;
+ case ')':
+ sb.append("\\29");
+ break;
+ case '\u0000':
+ sb.append("\\00");
+ break;
+ default:
+ sb.append(curChar);
+ }
+ }
+ return sb.toString();
+ }
+}
diff --git a/src/main/java/com/gitblit/PAMUserService.java b/src/main/java/com/gitblit/auth/PAMAuthProvider.java
index db569fbf..bbc82d84 100644
--- a/src/main/java/com/gitblit/PAMUserService.java
+++ b/src/main/java/com/gitblit/auth/PAMAuthProvider.java
@@ -1,143 +1,126 @@
-/*
- * Copyright 2013 gitblit.com.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.gitblit;
-
-import java.io.File;
-
-import org.jvnet.libpam.PAM;
-import org.jvnet.libpam.PAMException;
-import org.jvnet.libpam.impl.CLibrary;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.gitblit.Constants.AccountType;
-import com.gitblit.manager.IRuntimeManager;
-import com.gitblit.models.UserModel;
-import com.gitblit.utils.ArrayUtils;
-import com.gitblit.utils.StringUtils;
-
-/**
- * Implementation of a PAM user service for Linux/Unix/MacOSX.
- *
- * @author James Moger
- */
-public class PAMUserService extends GitblitUserService {
-
- private final Logger logger = LoggerFactory.getLogger(PAMUserService.class);
-
- private IStoredSettings settings;
-
- public PAMUserService() {
- super();
- }
-
- @Override
- public void setup(IRuntimeManager runtimeManager) {
- this.settings = runtimeManager.getSettings();
-
- String file = settings.getString(Keys.realm.pam.backingUserService, "${baseFolder}/users.conf");
- File realmFile = runtimeManager.getFileOrFolder(file);
-
- serviceImpl = createUserService(realmFile);
- logger.info("PAM User Service backed by " + serviceImpl.toString());
-
- // Try to identify the passwd database
- String [] files = { "/etc/shadow", "/etc/master.passwd" };
- File passwdFile = null;
- for (String name : files) {
- File f = new File(name);
- if (f.exists()) {
- passwdFile = f;
- break;
- }
- }
- if (passwdFile == null) {
- logger.error("PAM User Service could not find a passwd database!");
- } else if (!passwdFile.canRead()) {
- logger.error("PAM User Service can not read passwd database {}! PAM authentications may fail!", passwdFile);
- }
- }
-
- @Override
- public boolean supportsCredentialChanges() {
- return false;
- }
-
- @Override
- public boolean supportsDisplayNameChanges() {
- return true;
- }
-
- @Override
- public boolean supportsEmailAddressChanges() {
- return true;
- }
-
- @Override
- public boolean supportsTeamMembershipChanges() {
- return true;
- }
-
- @Override
- public AccountType getAccountType() {
- return AccountType.PAM;
- }
-
- @Override
- public UserModel authenticate(String username, char[] password) {
- if (isLocalAccount(username)) {
- // local account, bypass PAM authentication
- return super.authenticate(username, password);
- }
-
- if (CLibrary.libc.getpwnam(username) == null) {
- logger.warn("Can not get PAM passwd for " + username);
- return null;
- }
-
- PAM pam = null;
- try {
- String serviceName = settings.getString(Keys.realm.pam.serviceName, "system-auth");
- pam = new PAM(serviceName);
- pam.authenticate(username, new String(password));
- } catch (PAMException e) {
- logger.error(e.getMessage());
- return null;
- } finally {
- pam.dispose();
- }
-
- UserModel user = getUserModel(username);
- if (user == null) // create user object for new authenticated user
- user = new UserModel(username.toLowerCase());
-
- // create a user cookie
- if (StringUtils.isEmpty(user.cookie) && !ArrayUtils.isEmpty(password)) {
- user.cookie = StringUtils.getSHA1(user.username + new String(password));
- }
-
- // update user attributes from UnixUser
- user.accountType = getAccountType();
- user.password = Constants.EXTERNAL_ACCOUNT;
-
- // TODO consider mapping PAM groups to teams
-
- // push the changes to the backing user service
- super.updateUserModel(user);
-
- return user;
- }
-}
+/*
+ * Copyright 2013 gitblit.com.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit.auth;
+
+import java.io.File;
+
+import org.jvnet.libpam.PAM;
+import org.jvnet.libpam.PAMException;
+import org.jvnet.libpam.impl.CLibrary;
+
+import com.gitblit.Constants;
+import com.gitblit.Constants.AccountType;
+import com.gitblit.Keys;
+import com.gitblit.auth.AuthenticationProvider.UsernamePasswordAuthenticationProvider;
+import com.gitblit.models.UserModel;
+import com.gitblit.utils.ArrayUtils;
+import com.gitblit.utils.StringUtils;
+
+/**
+ * Implementation of PAM authentication for Linux/Unix/MacOSX.
+ *
+ * @author James Moger
+ */
+public class PAMAuthProvider extends UsernamePasswordAuthenticationProvider {
+
+ public PAMAuthProvider() {
+ super("pam");
+ }
+
+ @Override
+ public void setup() {
+ // Try to identify the passwd database
+ String [] files = { "/etc/shadow", "/etc/master.passwd" };
+ File passwdFile = null;
+ for (String name : files) {
+ File f = new File(name);
+ if (f.exists()) {
+ passwdFile = f;
+ break;
+ }
+ }
+ if (passwdFile == null) {
+ logger.error("PAM Authentication could not find a passwd database!");
+ } else if (!passwdFile.canRead()) {
+ logger.error("PAM Authentication can not read passwd database {}! PAM authentications may fail!", passwdFile);
+ }
+ }
+
+ @Override
+ public boolean supportsCredentialChanges() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsDisplayNameChanges() {
+ return true;
+ }
+
+ @Override
+ public boolean supportsEmailAddressChanges() {
+ return true;
+ }
+
+ @Override
+ public boolean supportsTeamMembershipChanges() {
+ return true;
+ }
+
+ @Override
+ public AccountType getAccountType() {
+ return AccountType.PAM;
+ }
+
+ @Override
+ public UserModel authenticate(String username, char[] password) {
+ if (CLibrary.libc.getpwnam(username) == null) {
+ logger.warn("Can not get PAM passwd for " + username);
+ return null;
+ }
+
+ PAM pam = null;
+ try {
+ String serviceName = settings.getString(Keys.realm.pam.serviceName, "system-auth");
+ pam = new PAM(serviceName);
+ pam.authenticate(username, new String(password));
+ } catch (PAMException e) {
+ logger.error(e.getMessage());
+ return null;
+ } finally {
+ pam.dispose();
+ }
+
+ UserModel user = userManager.getUserModel(username);
+ if (user == null) // create user object for new authenticated user
+ user = new UserModel(username.toLowerCase());
+
+ // create a user cookie
+ if (StringUtils.isEmpty(user.cookie) && !ArrayUtils.isEmpty(password)) {
+ user.cookie = StringUtils.getSHA1(user.username + new String(password));
+ }
+
+ // update user attributes from UnixUser
+ user.accountType = getAccountType();
+ user.password = Constants.EXTERNAL_ACCOUNT;
+
+ // TODO consider mapping PAM groups to teams
+
+ // push the changes to the backing user service
+ updateUser(user);
+
+ return user;
+ }
+}
diff --git a/src/main/java/com/gitblit/RedmineUserService.java b/src/main/java/com/gitblit/auth/RedmineAuthProvider.java
index 7c38ef2f..176c576b 100644
--- a/src/main/java/com/gitblit/RedmineUserService.java
+++ b/src/main/java/com/gitblit/auth/RedmineAuthProvider.java
@@ -1,203 +1,186 @@
-/*
- * Copyright 2012 gitblit.com.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.gitblit;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.net.HttpURLConnection;
-
-import org.apache.wicket.util.io.IOUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.gitblit.Constants.AccountType;
-import com.gitblit.manager.IRuntimeManager;
-import com.gitblit.models.UserModel;
-import com.gitblit.utils.ArrayUtils;
-import com.gitblit.utils.ConnectionUtils;
-import com.gitblit.utils.StringUtils;
-import com.google.gson.Gson;
-
-/**
- * Implementation of an Redmine user service.<br>
- * you can login to gitblit with Redmine user id and api key.
- */
-public class RedmineUserService extends GitblitUserService {
-
- private final Logger logger = LoggerFactory.getLogger(RedmineUserService.class);
-
- private IStoredSettings settings;
-
- private String testingJson;
-
- private class RedmineCurrent {
- private class RedmineUser {
- public String login;
- public String firstname;
- public String lastname;
- public String mail;
- }
-
- public RedmineUser user;
- }
-
- public RedmineUserService() {
- super();
- }
-
- @Override
- public void setup(IRuntimeManager runtimeManager) {
- this.settings = runtimeManager.getSettings();
-
- String file = settings.getString(Keys.realm.redmine.backingUserService, "${baseFolder}/users.conf");
- File realmFile = runtimeManager.getFileOrFolder(file);
-
- serviceImpl = createUserService(realmFile);
- logger.info("Redmine User Service backed by " + serviceImpl.toString());
- }
-
- @Override
- public boolean supportsCredentialChanges() {
- return false;
- }
-
- @Override
- public boolean supportsDisplayNameChanges() {
- return false;
- }
-
- @Override
- public boolean supportsEmailAddressChanges() {
- return false;
- }
-
- @Override
- public boolean supportsTeamMembershipChanges() {
- return false;
- }
-
- @Override
- public AccountType getAccountType() {
- return AccountType.REDMINE;
- }
-
- @Override
- public UserModel authenticate(String username, char[] password) {
- if (isLocalAccount(username)) {
- // local account, bypass Redmine authentication
- return super.authenticate(username, password);
- }
-
- String jsonString = null;
- try {
- // first attempt by username/password
- jsonString = getCurrentUserAsJson(username, password);
- } catch (Exception e1) {
- logger.warn("Failed to authenticate via username/password against Redmine");
- try {
- // second attempt is by apikey
- jsonString = getCurrentUserAsJson(null, password);
- username = null;
- } catch (Exception e2) {
- logger.error("Failed to authenticate via apikey against Redmine", e2);
- return null;
- }
- }
-
- if (StringUtils.isEmpty(jsonString)) {
- logger.error("Received empty authentication response from Redmine");
- return null;
- }
-
- RedmineCurrent current = null;
- try {
- current = new Gson().fromJson(jsonString, RedmineCurrent.class);
- } catch (Exception e) {
- logger.error("Failed to deserialize Redmine json response: " + jsonString, e);
- return null;
- }
-
- if (StringUtils.isEmpty(username)) {
- // if the username has been reset because of apikey authentication
- // then use the email address of the user. this is the original
- // behavior as contributed by github/mallowlabs
- username = current.user.mail;
- }
-
- UserModel user = getUserModel(username);
- if (user == null) // create user object for new authenticated user
- user = new UserModel(username.toLowerCase());
-
- // create a user cookie
- if (StringUtils.isEmpty(user.cookie) && !ArrayUtils.isEmpty(password)) {
- user.cookie = StringUtils.getSHA1(user.username + new String(password));
- }
-
- // update user attributes from Redmine
- user.accountType = getAccountType();
- user.displayName = current.user.firstname + " " + current.user.lastname;
- user.emailAddress = current.user.mail;
- user.password = Constants.EXTERNAL_ACCOUNT;
- if (!StringUtils.isEmpty(current.user.login)) {
- // only admin users can get login name
- // evidently this is an undocumented behavior of Redmine
- user.canAdmin = true;
- }
-
- // TODO consider Redmine group mapping for team membership
- // http://www.redmine.org/projects/redmine/wiki/Rest_Users
-
- // push the changes to the backing user service
- super.updateUserModel(user);
-
- return user;
- }
-
- private String getCurrentUserAsJson(String username, char [] password) throws IOException {
- if (testingJson != null) { // for testing
- return testingJson;
- }
-
- String url = this.settings.getString(Keys.realm.redmine.url, "");
- if (!url.endsWith("/")) {
- url = url.concat("/");
- }
- HttpURLConnection http;
- if (username == null) {
- // apikey authentication
- String apiKey = String.valueOf(password);
- String apiUrl = url + "users/current.json?key=" + apiKey;
- http = (HttpURLConnection) ConnectionUtils.openConnection(apiUrl, null, null);
- } else {
- // username/password BASIC authentication
- String apiUrl = url + "users/current.json";
- http = (HttpURLConnection) ConnectionUtils.openConnection(apiUrl, username, password);
- }
- http.setRequestMethod("GET");
- http.connect();
- InputStreamReader reader = new InputStreamReader(http.getInputStream());
- return IOUtils.toString(reader);
- }
-
- /**
- * set json response. do NOT invoke from production code.
- * @param json json
- */
- public void setTestingCurrentUserAsJson(String json) {
- this.testingJson = json;
- }
-}
+/*
+ * Copyright 2012 gitblit.com.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit.auth;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+
+import org.apache.wicket.util.io.IOUtils;
+
+import com.gitblit.Constants;
+import com.gitblit.Constants.AccountType;
+import com.gitblit.Keys;
+import com.gitblit.auth.AuthenticationProvider.UsernamePasswordAuthenticationProvider;
+import com.gitblit.models.UserModel;
+import com.gitblit.utils.ArrayUtils;
+import com.gitblit.utils.ConnectionUtils;
+import com.gitblit.utils.StringUtils;
+import com.google.gson.Gson;
+
+/**
+ * Implementation of Redmine authentication.<br>
+ * you can login to gitblit with Redmine user id and api key.
+ */
+public class RedmineAuthProvider extends UsernamePasswordAuthenticationProvider {
+
+ private String testingJson;
+
+ private class RedmineCurrent {
+ private class RedmineUser {
+ public String login;
+ public String firstname;
+ public String lastname;
+ public String mail;
+ }
+
+ public RedmineUser user;
+ }
+
+ public RedmineAuthProvider() {
+ super("redmine");
+ }
+
+ @Override
+ public void setup() {
+ }
+
+ @Override
+ public boolean supportsCredentialChanges() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsDisplayNameChanges() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsEmailAddressChanges() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsTeamMembershipChanges() {
+ return false;
+ }
+
+ @Override
+ public AccountType getAccountType() {
+ return AccountType.REDMINE;
+ }
+
+ @Override
+ public UserModel authenticate(String username, char[] password) {
+ String jsonString = null;
+ try {
+ // first attempt by username/password
+ jsonString = getCurrentUserAsJson(username, password);
+ } catch (Exception e1) {
+ logger.warn("Failed to authenticate via username/password against Redmine");
+ try {
+ // second attempt is by apikey
+ jsonString = getCurrentUserAsJson(null, password);
+ username = null;
+ } catch (Exception e2) {
+ logger.error("Failed to authenticate via apikey against Redmine", e2);
+ return null;
+ }
+ }
+
+ if (StringUtils.isEmpty(jsonString)) {
+ logger.error("Received empty authentication response from Redmine");
+ return null;
+ }
+
+ RedmineCurrent current = null;
+ try {
+ current = new Gson().fromJson(jsonString, RedmineCurrent.class);
+ } catch (Exception e) {
+ logger.error("Failed to deserialize Redmine json response: " + jsonString, e);
+ return null;
+ }
+
+ if (StringUtils.isEmpty(username)) {
+ // if the username has been reset because of apikey authentication
+ // then use the email address of the user. this is the original
+ // behavior as contributed by github/mallowlabs
+ username = current.user.mail;
+ }
+
+ UserModel user = userManager.getUserModel(username);
+ if (user == null) // create user object for new authenticated user
+ user = new UserModel(username.toLowerCase());
+
+ // create a user cookie
+ if (StringUtils.isEmpty(user.cookie) && !ArrayUtils.isEmpty(password)) {
+ user.cookie = StringUtils.getSHA1(user.username + new String(password));
+ }
+
+ // update user attributes from Redmine
+ user.accountType = getAccountType();
+ user.displayName = current.user.firstname + " " + current.user.lastname;
+ user.emailAddress = current.user.mail;
+ user.password = Constants.EXTERNAL_ACCOUNT;
+ if (!StringUtils.isEmpty(current.user.login)) {
+ // only admin users can get login name
+ // evidently this is an undocumented behavior of Redmine
+ user.canAdmin = true;
+ }
+
+ // TODO consider Redmine group mapping for team membership
+ // http://www.redmine.org/projects/redmine/wiki/Rest_Users
+
+ // push the changes to the backing user service
+ updateUser(user);
+
+ return user;
+ }
+
+ private String getCurrentUserAsJson(String username, char [] password) throws IOException {
+ if (testingJson != null) { // for testing
+ return testingJson;
+ }
+
+ String url = this.settings.getString(Keys.realm.redmine.url, "");
+ if (!url.endsWith("/")) {
+ url = url.concat("/");
+ }
+ HttpURLConnection http;
+ if (username == null) {
+ // apikey authentication
+ String apiKey = String.valueOf(password);
+ String apiUrl = url + "users/current.json?key=" + apiKey;
+ http = (HttpURLConnection) ConnectionUtils.openConnection(apiUrl, null, null);
+ } else {
+ // username/password BASIC authentication
+ String apiUrl = url + "users/current.json";
+ http = (HttpURLConnection) ConnectionUtils.openConnection(apiUrl, username, password);
+ }
+ http.setRequestMethod("GET");
+ http.connect();
+ InputStreamReader reader = new InputStreamReader(http.getInputStream());
+ return IOUtils.toString(reader);
+ }
+
+ /**
+ * set json response. do NOT invoke from production code.
+ * @param json json
+ */
+ public void setTestingCurrentUserAsJson(String json) {
+ this.testingJson = json;
+ }
+}
diff --git a/src/main/java/com/gitblit/SalesforceUserService.java b/src/main/java/com/gitblit/auth/SalesforceAuthProvider.java
index 6161ba93..fdda32af 100644
--- a/src/main/java/com/gitblit/SalesforceUserService.java
+++ b/src/main/java/com/gitblit/auth/SalesforceAuthProvider.java
@@ -1,12 +1,9 @@
-package com.gitblit;
-
-import java.io.File;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+package com.gitblit.auth;
+import com.gitblit.Constants;
import com.gitblit.Constants.AccountType;
-import com.gitblit.manager.IRuntimeManager;
+import com.gitblit.Keys;
+import com.gitblit.auth.AuthenticationProvider.UsernamePasswordAuthenticationProvider;
import com.gitblit.models.UserModel;
import com.gitblit.utils.ArrayUtils;
import com.gitblit.utils.StringUtils;
@@ -16,10 +13,11 @@ import com.sforce.soap.partner.PartnerConnection;
import com.sforce.ws.ConnectionException;
import com.sforce.ws.ConnectorConfig;
-public class SalesforceUserService extends GitblitUserService {
+public class SalesforceAuthProvider extends UsernamePasswordAuthenticationProvider {
- public static final Logger logger = LoggerFactory.getLogger(SalesforceUserService.class);
- private IStoredSettings settings;
+ public SalesforceAuthProvider() {
+ super("salesforce");
+ }
@Override
public AccountType getAccountType() {
@@ -27,26 +25,11 @@ public class SalesforceUserService extends GitblitUserService {
}
@Override
- public void setup(IRuntimeManager runtimeManager) {
- this.settings = runtimeManager.getSettings();
- String file = settings.getString(
- Keys.realm.salesforce.backingUserService,
- "${baseFolder}/users.conf");
- File realmFile = runtimeManager.getFileOrFolder(file);
-
- serviceImpl = createUserService(realmFile);
-
- logger.info("Salesforce User Service backed by "
- + serviceImpl.toString());
+ public void setup() {
}
@Override
public UserModel authenticate(String username, char[] password) {
- if (isLocalAccount(username)) {
- // local account, bypass Salesforce authentication
- return super.authenticate(username, password);
- }
-
ConnectorConfig config = new ConnectorConfig();
config.setUsername(username);
config.setPassword(new String(password));
@@ -78,7 +61,7 @@ public class SalesforceUserService extends GitblitUserService {
UserModel user = null;
synchronized (this) {
- user = getUserModel(simpleUsername);
+ user = userManager.getUserModel(simpleUsername);
if (user == null)
user = new UserModel(simpleUsername);
@@ -90,7 +73,7 @@ public class SalesforceUserService extends GitblitUserService {
setUserAttributes(user, info);
- super.updateUserModel(user);
+ updateUser(user);
}
return user;
@@ -122,6 +105,7 @@ public class SalesforceUserService extends GitblitUserService {
return email.split("@")[0];
}
+
@Override
public boolean supportsCredentialChanges() {
return false;
@@ -136,4 +120,9 @@ public class SalesforceUserService extends GitblitUserService {
public boolean supportsEmailAddressChanges() {
return false;
}
+
+ @Override
+ public boolean supportsTeamMembershipChanges() {
+ return true;
+ }
}
diff --git a/src/main/java/com/gitblit/WindowsUserService.java b/src/main/java/com/gitblit/auth/WindowsAuthProvider.java
index 99077c67..d455d58f 100644
--- a/src/main/java/com/gitblit/WindowsUserService.java
+++ b/src/main/java/com/gitblit/auth/WindowsAuthProvider.java
@@ -1,195 +1,177 @@
-/*
- * Copyright 2013 gitblit.com.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.gitblit;
-
-import java.io.File;
-import java.util.Set;
-import java.util.TreeSet;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import waffle.windows.auth.IWindowsAccount;
-import waffle.windows.auth.IWindowsAuthProvider;
-import waffle.windows.auth.IWindowsComputer;
-import waffle.windows.auth.IWindowsIdentity;
-import waffle.windows.auth.impl.WindowsAuthProviderImpl;
-
-import com.gitblit.Constants.AccountType;
-import com.gitblit.manager.IRuntimeManager;
-import com.gitblit.models.UserModel;
-import com.gitblit.utils.ArrayUtils;
-import com.gitblit.utils.StringUtils;
-import com.sun.jna.platform.win32.Win32Exception;
-
-/**
- * Implementation of a Windows user service.
- *
- * @author James Moger
- */
-public class WindowsUserService extends GitblitUserService {
-
- private final Logger logger = LoggerFactory.getLogger(WindowsUserService.class);
-
- private IStoredSettings settings;
-
- private IWindowsAuthProvider waffle;
-
- public WindowsUserService() {
- super();
- }
-
- @Override
- public void setup(IRuntimeManager runtimeManager) {
- this.settings = runtimeManager.getSettings();
-
- String file = settings.getString(Keys.realm.windows.backingUserService, "${baseFolder}/users.conf");
- File realmFile = runtimeManager.getFileOrFolder(file);
-
- serviceImpl = createUserService(realmFile);
- logger.info("Windows User Service backed by " + serviceImpl.toString());
-
- waffle = new WindowsAuthProviderImpl();
- IWindowsComputer computer = waffle.getCurrentComputer();
- logger.info(" name = " + computer.getComputerName());
- logger.info(" status = " + describeJoinStatus(computer.getJoinStatus()));
- logger.info(" memberOf = " + computer.getMemberOf());
- //logger.info(" groups = " + Arrays.asList(computer.getGroups()));
- }
-
- protected String describeJoinStatus(String value) {
- if ("NetSetupUnknownStatus".equals(value)) {
- return "unknown";
- } else if ("NetSetupUnjoined".equals(value)) {
- return "not joined";
- } else if ("NetSetupWorkgroupName".equals(value)) {
- return "joined to a workgroup";
- } else if ("NetSetupDomainName".equals(value)) {
- return "joined to a domain";
- }
- return value;
- }
-
- @Override
- public boolean supportsCredentialChanges() {
- return false;
- }
-
- @Override
- public boolean supportsDisplayNameChanges() {
- return false;
- }
-
- @Override
- public boolean supportsEmailAddressChanges() {
- return true;
- }
-
- @Override
- public boolean supportsTeamMembershipChanges() {
- return true;
- }
-
- @Override
- public AccountType getAccountType() {
- return AccountType.WINDOWS;
- }
-
- @Override
- public UserModel authenticate(String username, char[] password) {
- if (isLocalAccount(username)) {
- // local account, bypass Windows authentication
- return super.authenticate(username, password);
- }
-
- String defaultDomain = settings.getString(Keys.realm.windows.defaultDomain, null);
- if (StringUtils.isEmpty(defaultDomain)) {
- // ensure that default domain is null
- defaultDomain = null;
- }
-
- if (defaultDomain != null) {
- // sanitize username
- if (username.startsWith(defaultDomain + "\\")) {
- // strip default domain from domain\ username
- username = username.substring(defaultDomain.length() + 1);
- } else if (username.endsWith("@" + defaultDomain)) {
- // strip default domain from username@domain
- username = username.substring(0, username.lastIndexOf('@'));
- }
- }
-
- IWindowsIdentity identity = null;
- try {
- if (username.indexOf('@') > -1 || username.indexOf('\\') > -1) {
- // manually specified domain
- identity = waffle.logonUser(username, new String(password));
- } else {
- // no domain specified, use default domain
- identity = waffle.logonDomainUser(username, defaultDomain, new String(password));
- }
- } catch (Win32Exception e) {
- logger.error(e.getMessage());
- return null;
- }
-
- if (identity.isGuest() && !settings.getBoolean(Keys.realm.windows.allowGuests, false)) {
- logger.warn("Guest account access is disabled");
- identity.dispose();
- return null;
- }
-
- UserModel user = getUserModel(username);
- if (user == null) // create user object for new authenticated user
- user = new UserModel(username.toLowerCase());
-
- // create a user cookie
- if (StringUtils.isEmpty(user.cookie) && !ArrayUtils.isEmpty(password)) {
- user.cookie = StringUtils.getSHA1(user.username + new String(password));
- }
-
- // update user attributes from Windows identity
- user.accountType = getAccountType();
- String fqn = identity.getFqn();
- if (fqn.indexOf('\\') > -1) {
- user.displayName = fqn.substring(fqn.lastIndexOf('\\') + 1);
- } else {
- user.displayName = fqn;
- }
- user.password = Constants.EXTERNAL_ACCOUNT;
-
- Set<String> groupNames = new TreeSet<String>();
- for (IWindowsAccount group : identity.getGroups()) {
- groupNames.add(group.getFqn());
- }
-
- if (groupNames.contains("BUILTIN\\Administrators")) {
- // local administrator
- user.canAdmin = true;
- }
-
- // TODO consider mapping Windows groups to teams
-
- // push the changes to the backing user service
- super.updateUserModel(user);
-
-
- // cleanup resources
- identity.dispose();
-
- return user;
- }
-}
+/*
+ * Copyright 2013 gitblit.com.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit.auth;
+
+import java.util.Set;
+import java.util.TreeSet;
+
+import waffle.windows.auth.IWindowsAccount;
+import waffle.windows.auth.IWindowsAuthProvider;
+import waffle.windows.auth.IWindowsComputer;
+import waffle.windows.auth.IWindowsIdentity;
+import waffle.windows.auth.impl.WindowsAuthProviderImpl;
+
+import com.gitblit.Constants;
+import com.gitblit.Constants.AccountType;
+import com.gitblit.Keys;
+import com.gitblit.auth.AuthenticationProvider.UsernamePasswordAuthenticationProvider;
+import com.gitblit.models.UserModel;
+import com.gitblit.utils.ArrayUtils;
+import com.gitblit.utils.StringUtils;
+import com.sun.jna.platform.win32.Win32Exception;
+
+/**
+ * Implementation of a Windows authentication provider.
+ *
+ * @author James Moger
+ */
+public class WindowsAuthProvider extends UsernamePasswordAuthenticationProvider {
+
+ private IWindowsAuthProvider waffle;
+
+ public WindowsAuthProvider() {
+ super("windows");
+ }
+
+ @Override
+ public void setup() {
+
+ waffle = new WindowsAuthProviderImpl();
+ IWindowsComputer computer = waffle.getCurrentComputer();
+ logger.info("Windows Authentication Provider");
+ logger.info(" name = " + computer.getComputerName());
+ logger.info(" status = " + describeJoinStatus(computer.getJoinStatus()));
+ logger.info(" memberOf = " + computer.getMemberOf());
+ //logger.info(" groups = " + Arrays.asList(computer.getGroups()));
+ }
+
+ protected String describeJoinStatus(String value) {
+ if ("NetSetupUnknownStatus".equals(value)) {
+ return "unknown";
+ } else if ("NetSetupUnjoined".equals(value)) {
+ return "not joined";
+ } else if ("NetSetupWorkgroupName".equals(value)) {
+ return "joined to a workgroup";
+ } else if ("NetSetupDomainName".equals(value)) {
+ return "joined to a domain";
+ }
+ return value;
+ }
+
+ @Override
+ public boolean supportsCredentialChanges() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsDisplayNameChanges() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsEmailAddressChanges() {
+ return true;
+ }
+
+ @Override
+ public boolean supportsTeamMembershipChanges() {
+ return true;
+ }
+
+ @Override
+ public AccountType getAccountType() {
+ return AccountType.WINDOWS;
+ }
+
+ @Override
+ public UserModel authenticate(String username, char[] password) {
+ String defaultDomain = settings.getString(Keys.realm.windows.defaultDomain, null);
+ if (StringUtils.isEmpty(defaultDomain)) {
+ // ensure that default domain is null
+ defaultDomain = null;
+ }
+
+ if (defaultDomain != null) {
+ // sanitize username
+ if (username.startsWith(defaultDomain + "\\")) {
+ // strip default domain from domain\ username
+ username = username.substring(defaultDomain.length() + 1);
+ } else if (username.endsWith("@" + defaultDomain)) {
+ // strip default domain from username@domain
+ username = username.substring(0, username.lastIndexOf('@'));
+ }
+ }
+
+ IWindowsIdentity identity = null;
+ try {
+ if (username.indexOf('@') > -1 || username.indexOf('\\') > -1) {
+ // manually specified domain
+ identity = waffle.logonUser(username, new String(password));
+ } else {
+ // no domain specified, use default domain
+ identity = waffle.logonDomainUser(username, defaultDomain, new String(password));
+ }
+ } catch (Win32Exception e) {
+ logger.error(e.getMessage());
+ return null;
+ }
+
+ if (identity.isGuest() && !settings.getBoolean(Keys.realm.windows.allowGuests, false)) {
+ logger.warn("Guest account access is disabled");
+ identity.dispose();
+ return null;
+ }
+
+ UserModel user = userManager.getUserModel(username);
+ if (user == null) // create user object for new authenticated user
+ user = new UserModel(username.toLowerCase());
+
+ // create a user cookie
+ if (StringUtils.isEmpty(user.cookie) && !ArrayUtils.isEmpty(password)) {
+ user.cookie = StringUtils.getSHA1(user.username + new String(password));
+ }
+
+ // update user attributes from Windows identity
+ user.accountType = getAccountType();
+ String fqn = identity.getFqn();
+ if (fqn.indexOf('\\') > -1) {
+ user.displayName = fqn.substring(fqn.lastIndexOf('\\') + 1);
+ } else {
+ user.displayName = fqn;
+ }
+ user.password = Constants.EXTERNAL_ACCOUNT;
+
+ Set<String> groupNames = new TreeSet<String>();
+ for (IWindowsAccount group : identity.getGroups()) {
+ groupNames.add(group.getFqn());
+ }
+
+ if (groupNames.contains("BUILTIN\\Administrators")) {
+ // local administrator
+ user.canAdmin = true;
+ }
+
+ // TODO consider mapping Windows groups to teams
+
+ // push the changes to the backing user service
+ updateUser(user);
+
+ // cleanup resources
+ identity.dispose();
+
+ return user;
+ }
+}
diff --git a/src/main/java/com/gitblit/client/EditTeamDialog.java b/src/main/java/com/gitblit/client/EditTeamDialog.java
index 3c0b928c..0b5b3505 100644
--- a/src/main/java/com/gitblit/client/EditTeamDialog.java
+++ b/src/main/java/com/gitblit/client/EditTeamDialog.java
@@ -146,7 +146,6 @@ public class EditTeamDialog extends JDialog {
final Insets _insets = new Insets(5, 5, 5, 5);
repositoryPalette = new RegistrantPermissionsPanel(RegistrantType.REPOSITORY);
userPalette = new JPalette<String>();
- userPalette.setEnabled(settings.supportsTeamMembershipChanges);
JPanel fieldsPanelTop = new JPanel(new BorderLayout());
fieldsPanelTop.add(fieldsPanel, BorderLayout.NORTH);
diff --git a/src/main/java/com/gitblit/client/EditUserDialog.java b/src/main/java/com/gitblit/client/EditUserDialog.java
index fd5cf79d..2936a29d 100644
--- a/src/main/java/com/gitblit/client/EditUserDialog.java
+++ b/src/main/java/com/gitblit/client/EditUserDialog.java
@@ -161,18 +161,9 @@ public class EditUserDialog extends JDialog {
countryCodeField = new JTextField(anUser.countryCode == null ? "" : anUser.countryCode, 15);
// credentials are optionally controlled by 3rd-party authentication
- usernameField.setEnabled(settings.supportsCredentialChanges);
- passwordField.setEnabled(settings.supportsCredentialChanges);
- confirmPasswordField.setEnabled(settings.supportsCredentialChanges);
-
- displayNameField.setEnabled(settings.supportsDisplayNameChanges);
- emailAddressField.setEnabled(settings.supportsEmailAddressChanges);
-
- organizationalUnitField.setEnabled(settings.supportsDisplayNameChanges);
- organizationField.setEnabled(settings.supportsDisplayNameChanges);
- localityField.setEnabled(settings.supportsDisplayNameChanges);
- stateProvinceField.setEnabled(settings.supportsDisplayNameChanges);
- countryCodeField.setEnabled(settings.supportsDisplayNameChanges);
+ usernameField.setEnabled(anUser.isLocalAccount());
+ passwordField.setEnabled(anUser.isLocalAccount());
+ confirmPasswordField.setEnabled(anUser.isLocalAccount());
JPanel fieldsPanel = new JPanel(new GridLayout(0, 1));
fieldsPanel.add(newFieldPanel(Translation.get("gb.username"), usernameField));
@@ -196,7 +187,6 @@ public class EditUserDialog extends JDialog {
final Insets _insets = new Insets(5, 5, 5, 5);
repositoryPalette = new RegistrantPermissionsPanel(RegistrantType.REPOSITORY);
teamsPalette = new JPalette<TeamModel>();
- teamsPalette.setEnabled(settings.supportsTeamMembershipChanges);
JPanel fieldsPanelTop = new JPanel(new BorderLayout());
fieldsPanelTop.add(fieldsPanel, BorderLayout.NORTH);
diff --git a/src/main/java/com/gitblit/git/GitblitUploadPackFactory.java b/src/main/java/com/gitblit/git/GitblitUploadPackFactory.java
index 2afdde1d..d4e3ca15 100644
--- a/src/main/java/com/gitblit/git/GitblitUploadPackFactory.java
+++ b/src/main/java/com/gitblit/git/GitblitUploadPackFactory.java
@@ -23,7 +23,7 @@ import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
import org.eclipse.jgit.transport.resolver.UploadPackFactory;
-import com.gitblit.manager.ISessionManager;
+import com.gitblit.manager.IAuthenticationManager;
import com.gitblit.models.UserModel;
/**
@@ -36,10 +36,10 @@ import com.gitblit.models.UserModel;
*/
public class GitblitUploadPackFactory<X> implements UploadPackFactory<X> {
- private final ISessionManager sessionManager;
+ private final IAuthenticationManager authenticationManager;
- public GitblitUploadPackFactory(ISessionManager sessionManager) {
- this.sessionManager = sessionManager;
+ public GitblitUploadPackFactory(IAuthenticationManager authenticationManager) {
+ this.authenticationManager = authenticationManager;
}
@Override
@@ -51,7 +51,7 @@ public class GitblitUploadPackFactory<X> implements UploadPackFactory<X> {
if (req instanceof HttpServletRequest) {
// http/https request may or may not be authenticated
- user = sessionManager.authenticate((HttpServletRequest) req);
+ user = authenticationManager.authenticate((HttpServletRequest) req);
if (user == null) {
user = UserModel.ANONYMOUS;
}
diff --git a/src/main/java/com/gitblit/manager/AuthenticationManager.java b/src/main/java/com/gitblit/manager/AuthenticationManager.java
new file mode 100644
index 00000000..6e541c45
--- /dev/null
+++ b/src/main/java/com/gitblit/manager/AuthenticationManager.java
@@ -0,0 +1,511 @@
+/*
+ * Copyright 2013 gitblit.com.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit.manager;
+
+import java.nio.charset.Charset;
+import java.security.Principal;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.wicket.RequestCycle;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.gitblit.Constants;
+import com.gitblit.Constants.AccountType;
+import com.gitblit.Constants.AuthenticationType;
+import com.gitblit.IStoredSettings;
+import com.gitblit.Keys;
+import com.gitblit.auth.AuthenticationProvider;
+import com.gitblit.auth.AuthenticationProvider.UsernamePasswordAuthenticationProvider;
+import com.gitblit.auth.HtpasswdAuthProvider;
+import com.gitblit.auth.LdapAuthProvider;
+import com.gitblit.auth.PAMAuthProvider;
+import com.gitblit.auth.RedmineAuthProvider;
+import com.gitblit.auth.SalesforceAuthProvider;
+import com.gitblit.auth.WindowsAuthProvider;
+import com.gitblit.models.TeamModel;
+import com.gitblit.models.UserModel;
+import com.gitblit.utils.Base64;
+import com.gitblit.utils.HttpUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.utils.X509Utils.X509Metadata;
+import com.gitblit.wicket.GitBlitWebSession;
+
+/**
+ * The authentication manager handles user login & logout.
+ *
+ * @author James Moger
+ *
+ */
+public class AuthenticationManager implements IAuthenticationManager {
+
+ private final Logger logger = LoggerFactory.getLogger(getClass());
+
+ private final IStoredSettings settings;
+
+ private final IRuntimeManager runtimeManager;
+
+ private final IUserManager userManager;
+
+ private final List<AuthenticationProvider> authenticationProviders;
+
+ private final Map<String, Class<? extends AuthenticationProvider>> providerNames;
+
+ private final Map<String, String> legacyRedirects;
+
+ public AuthenticationManager(
+ IRuntimeManager runtimeManager,
+ IUserManager userManager) {
+
+ this.settings = runtimeManager.getSettings();
+ this.runtimeManager = runtimeManager;
+ this.userManager = userManager;
+ this.authenticationProviders = new ArrayList<AuthenticationProvider>();
+
+ // map of shortcut provider names
+ providerNames = new HashMap<String, Class<? extends AuthenticationProvider>>();
+ providerNames.put("htpasswd", HtpasswdAuthProvider.class);
+ providerNames.put("ldap", LdapAuthProvider.class);
+ providerNames.put("pam", PAMAuthProvider.class);
+ providerNames.put("redmine", RedmineAuthProvider.class);
+ providerNames.put("salesforce", SalesforceAuthProvider.class);
+ providerNames.put("windows", WindowsAuthProvider.class);
+
+ // map of legacy external user services
+ legacyRedirects = new HashMap<String, String>();
+ legacyRedirects.put("com.gitblit.HtpasswdUserService", "htpasswd");
+ legacyRedirects.put("com.gitblit.LdapUserService", "ldap");
+ legacyRedirects.put("com.gitblit.PAMUserService", "pam");
+ legacyRedirects.put("com.gitblit.RedmineUserService", "redmine");
+ legacyRedirects.put("com.gitblit.SalesforceUserService", "salesforce");
+ legacyRedirects.put("com.gitblit.WindowsUserService", "windows");
+ }
+
+ @Override
+ public AuthenticationManager start() {
+ // automatically adjust legacy configurations
+ String realm = settings.getString(Keys.realm.userService, "${baseFolder}/users.conf");
+ if (legacyRedirects.containsKey(realm)) {
+ logger.warn("");
+ logger.warn("#################################################################");
+ logger.warn(" IUserService '{}' is obsolete!", realm);
+ logger.warn(" Please set '{}={}'", "realm.authenticationProviders", legacyRedirects.get(realm));
+ logger.warn("#################################################################");
+ logger.warn("");
+
+ // conditionally override specified authentication providers
+ if (StringUtils.isEmpty(settings.getString(Keys.realm.authenticationProviders, null))) {
+ settings.overrideSetting(Keys.realm.authenticationProviders, legacyRedirects.get(realm));
+ }
+ }
+
+ // instantiate and setup specified authentication providers
+ List<String> providers = settings.getStrings(Keys.realm.authenticationProviders);
+ if (providers.isEmpty()) {
+ logger.info("External authentication disabled.");
+ } else {
+ for (String provider : providers) {
+ try {
+ Class<?> authClass;
+ if (providerNames.containsKey(provider)) {
+ // map the name -> class
+ authClass = providerNames.get(provider);
+ } else {
+ // reflective lookup
+ authClass = Class.forName(provider);
+ }
+ logger.info("setting up {}", authClass.getName());
+ AuthenticationProvider authImpl = (AuthenticationProvider) authClass.newInstance();
+ authImpl.setup(runtimeManager, userManager);
+ authenticationProviders.add(authImpl);
+ } catch (Exception e) {
+ logger.error("", e);
+ }
+ }
+ }
+ return this;
+ }
+
+ @Override
+ public AuthenticationManager stop() {
+ return this;
+ }
+
+ /**
+ * Authenticate a user based on HTTP request parameters.
+ *
+ * Authentication by X509Certificate is tried first and then by cookie.
+ *
+ * @param httpRequest
+ * @return a user object or null
+ */
+ @Override
+ public UserModel authenticate(HttpServletRequest httpRequest) {
+ return authenticate(httpRequest, false);
+ }
+
+ /**
+ * Authenticate a user based on HTTP request parameters.
+ *
+ * Authentication by servlet container principal, X509Certificate, cookie,
+ * and finally BASIC header.
+ *
+ * @param httpRequest
+ * @param requiresCertificate
+ * @return a user object or null
+ */
+ @Override
+ public UserModel authenticate(HttpServletRequest httpRequest, boolean requiresCertificate) {
+ // try to authenticate by servlet container principal
+ if (!requiresCertificate) {
+ Principal principal = httpRequest.getUserPrincipal();
+ if (principal != null) {
+ String username = principal.getName();
+ if (!StringUtils.isEmpty(username)) {
+ boolean internalAccount = isInternalAccount(username);
+ UserModel user = userManager.getUserModel(username);
+ if (user != null) {
+ // existing user
+ flagWicketSession(AuthenticationType.CONTAINER);
+ logger.debug(MessageFormat.format("{0} authenticated by servlet container principal from {1}",
+ user.username, httpRequest.getRemoteAddr()));
+ return user;
+ } else if (settings.getBoolean(Keys.realm.container.autoCreateAccounts, false)
+ && !internalAccount) {
+ // auto-create user from an authenticated container principal
+ user = new UserModel(username.toLowerCase());
+ user.displayName = username;
+ user.password = Constants.EXTERNAL_ACCOUNT;
+ user.accountType = AccountType.CONTAINER;
+ userManager.updateUserModel(user);
+ flagWicketSession(AuthenticationType.CONTAINER);
+ logger.debug(MessageFormat.format("{0} authenticated and created by servlet container principal from {1}",
+ user.username, httpRequest.getRemoteAddr()));
+ return user;
+ } else if (!internalAccount) {
+ logger.warn(MessageFormat.format("Failed to find UserModel for {0}, attempted servlet container authentication from {1}",
+ principal.getName(), httpRequest.getRemoteAddr()));
+ }
+ }
+ }
+ }
+
+ // try to authenticate by certificate
+ boolean checkValidity = settings.getBoolean(Keys.git.enforceCertificateValidity, true);
+ String [] oids = settings.getStrings(Keys.git.certificateUsernameOIDs).toArray(new String[0]);
+ UserModel model = HttpUtils.getUserModelFromCertificate(httpRequest, checkValidity, oids);
+ if (model != null) {
+ // grab real user model and preserve certificate serial number
+ UserModel user = userManager.getUserModel(model.username);
+ X509Metadata metadata = HttpUtils.getCertificateMetadata(httpRequest);
+ if (user != null) {
+ flagWicketSession(AuthenticationType.CERTIFICATE);
+ logger.debug(MessageFormat.format("{0} authenticated by client certificate {1} from {2}",
+ user.username, metadata.serialNumber, httpRequest.getRemoteAddr()));
+ return user;
+ } else {
+ logger.warn(MessageFormat.format("Failed to find UserModel for {0}, attempted client certificate ({1}) authentication from {2}",
+ model.username, metadata.serialNumber, httpRequest.getRemoteAddr()));
+ }
+ }
+
+ if (requiresCertificate) {
+ // caller requires client certificate authentication (e.g. git servlet)
+ return null;
+ }
+
+ // try to authenticate by cookie
+ UserModel user = authenticate(httpRequest.getCookies());
+ if (user != null) {
+ flagWicketSession(AuthenticationType.COOKIE);
+ logger.debug(MessageFormat.format("{0} authenticated by cookie from {1}",
+ user.username, httpRequest.getRemoteAddr()));
+ return user;
+ }
+
+ // try to authenticate by BASIC
+ final String authorization = httpRequest.getHeader("Authorization");
+ if (authorization != null && authorization.startsWith("Basic")) {
+ // Authorization: Basic base64credentials
+ String base64Credentials = authorization.substring("Basic".length()).trim();
+ String credentials = new String(Base64.decode(base64Credentials),
+ Charset.forName("UTF-8"));
+ // credentials = username:password
+ final String[] values = credentials.split(":", 2);
+
+ if (values.length == 2) {
+ String username = values[0];
+ char[] password = values[1].toCharArray();
+ user = authenticate(username, password);
+ if (user != null) {
+ flagWicketSession(AuthenticationType.CREDENTIALS);
+ logger.debug(MessageFormat.format("{0} authenticated by BASIC request header from {1}",
+ user.username, httpRequest.getRemoteAddr()));
+ return user;
+ } else {
+ logger.warn(MessageFormat.format("Failed login attempt for {0}, invalid credentials from {1}",
+ username, httpRequest.getRemoteAddr()));
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Authenticate a user based on their cookie.
+ *
+ * @param cookies
+ * @return a user object or null
+ */
+ protected UserModel authenticate(Cookie[] cookies) {
+ if (settings.getBoolean(Keys.web.allowCookieAuthentication, true)) {
+ if (cookies != null && cookies.length > 0) {
+ for (Cookie cookie : cookies) {
+ if (cookie.getName().equals(Constants.NAME)) {
+ String value = cookie.getValue();
+ return userManager.getUserModel(value.toCharArray());
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ protected void flagWicketSession(AuthenticationType authenticationType) {
+ RequestCycle requestCycle = RequestCycle.get();
+ if (requestCycle != null) {
+ // flag the Wicket session, if this is a Wicket request
+ GitBlitWebSession session = GitBlitWebSession.get();
+ session.authenticationType = authenticationType;
+ }
+ }
+
+ /**
+ * Authenticate a user based on a username and password.
+ *
+ * @see IUserService.authenticate(String, char[])
+ * @param username
+ * @param password
+ * @return a user object or null
+ */
+ @Override
+ public UserModel authenticate(String username, char[] password) {
+ if (StringUtils.isEmpty(username)) {
+ // can not authenticate empty username
+ return null;
+ }
+
+ String usernameDecoded = StringUtils.decodeUsername(username);
+ String pw = new String(password);
+ if (StringUtils.isEmpty(pw)) {
+ // can not authenticate empty password
+ return null;
+ }
+ // check to see if this is the federation user
+// if (canFederate()) {
+// if (usernameDecoded.equalsIgnoreCase(Constants.FEDERATION_USER)) {
+// List<String> tokens = getFederationTokens();
+// if (tokens.contains(pw)) {
+// return getFederationUser();
+// }
+// }
+// }
+
+ // try local authentication
+ UserModel user = userManager.getUserModel(usernameDecoded);
+ if (user != null) {
+ UserModel returnedUser = null;
+ if (user.password.startsWith(StringUtils.MD5_TYPE)) {
+ // password digest
+ String md5 = StringUtils.MD5_TYPE + StringUtils.getMD5(new String(password));
+ if (user.password.equalsIgnoreCase(md5)) {
+ returnedUser = user;
+ }
+ } else if (user.password.startsWith(StringUtils.COMBINED_MD5_TYPE)) {
+ // username+password digest
+ String md5 = StringUtils.COMBINED_MD5_TYPE
+ + StringUtils.getMD5(username.toLowerCase() + new String(password));
+ if (user.password.equalsIgnoreCase(md5)) {
+ returnedUser = user;
+ }
+ } else if (user.password.equals(new String(password))) {
+ // plain-text password
+ returnedUser = user;
+ }
+ return returnedUser;
+ }
+
+ // try registered external authentication providers
+ if (user == null) {
+ for (AuthenticationProvider provider : authenticationProviders) {
+ if (provider instanceof UsernamePasswordAuthenticationProvider) {
+ user = provider.authenticate(usernameDecoded, password);
+ if (user != null) {
+ // user authenticated
+ user.accountType = provider.getAccountType();
+ return user;
+ }
+ }
+ }
+ }
+ return user;
+ }
+
+ /**
+ * Sets a cookie for the specified user.
+ *
+ * @param response
+ * @param user
+ */
+ @Override
+ public void setCookie(HttpServletResponse response, UserModel user) {
+ if (settings.getBoolean(Keys.web.allowCookieAuthentication, true)) {
+ GitBlitWebSession session = GitBlitWebSession.get();
+ boolean standardLogin = session.authenticationType.isStandard();
+
+ if (standardLogin) {
+ Cookie userCookie;
+ if (user == null) {
+ // clear cookie for logout
+ userCookie = new Cookie(Constants.NAME, "");
+ } else {
+ // set cookie for login
+ String cookie = userManager.getCookie(user);
+ if (StringUtils.isEmpty(cookie)) {
+ // create empty cookie
+ userCookie = new Cookie(Constants.NAME, "");
+ } else {
+ // create real cookie
+ userCookie = new Cookie(Constants.NAME, cookie);
+ userCookie.setMaxAge(Integer.MAX_VALUE);
+ }
+ }
+ userCookie.setPath("/");
+ response.addCookie(userCookie);
+ }
+ }
+ }
+
+ /**
+ * Logout a user.
+ *
+ * @param user
+ */
+ @Override
+ public void logout(HttpServletResponse response, UserModel user) {
+ setCookie(response, null);
+ }
+
+ /**
+ * Returns true if the user's credentials can be changed.
+ *
+ * @param user
+ * @return true if the user service supports credential changes
+ */
+ @Override
+ public boolean supportsCredentialChanges(UserModel user) {
+ return (user != null && user.isLocalAccount()) || findProvider(user).supportsCredentialChanges();
+ }
+
+ /**
+ * Returns true if the user's display name can be changed.
+ *
+ * @param user
+ * @return true if the user service supports display name changes
+ */
+ @Override
+ public boolean supportsDisplayNameChanges(UserModel user) {
+ return (user != null && user.isLocalAccount()) || findProvider(user).supportsDisplayNameChanges();
+ }
+
+ /**
+ * Returns true if the user's email address can be changed.
+ *
+ * @param user
+ * @return true if the user service supports email address changes
+ */
+ @Override
+ public boolean supportsEmailAddressChanges(UserModel user) {
+ return (user != null && user.isLocalAccount()) || findProvider(user).supportsEmailAddressChanges();
+ }
+
+ /**
+ * Returns true if the user's team memberships can be changed.
+ *
+ * @param user
+ * @return true if the user service supports team membership changes
+ */
+ @Override
+ public boolean supportsTeamMembershipChanges(UserModel user) {
+ return (user != null && user.isLocalAccount()) || findProvider(user).supportsTeamMembershipChanges();
+ }
+
+ /**
+ * Returns true if the team memberships can be changed.
+ *
+ * @param user
+ * @return true if the team membership can be changed
+ */
+ @Override
+ public boolean supportsTeamMembershipChanges(TeamModel team) {
+ return (team != null && team.isLocalTeam()) || findProvider(team).supportsTeamMembershipChanges();
+ }
+
+ protected AuthenticationProvider findProvider(UserModel user) {
+ for (AuthenticationProvider provider : authenticationProviders) {
+ if (provider.getAccountType().equals(user.accountType)) {
+ return provider;
+ }
+ }
+ return AuthenticationProvider.NULL_PROVIDER;
+ }
+
+ protected AuthenticationProvider findProvider(TeamModel team) {
+ for (AuthenticationProvider provider : authenticationProviders) {
+ if (provider.getAccountType().equals(team.accountType)) {
+ return provider;
+ }
+ }
+ return AuthenticationProvider.NULL_PROVIDER;
+ }
+
+ /**
+ * Returns true if the username represents an internal account
+ *
+ * @param username
+ * @return true if the specified username represents an internal account
+ */
+ protected boolean isInternalAccount(String username) {
+ return !StringUtils.isEmpty(username)
+ && (username.equalsIgnoreCase(Constants.FEDERATION_USER)
+ || username.equalsIgnoreCase(UserModel.ANONYMOUS.username));
+ }
+
+// protected UserModel getFederationUser() {
+// // the federation user is an administrator
+// UserModel federationUser = new UserModel(Constants.FEDERATION_USER);
+// federationUser.canAdmin = true;
+// return federationUser;
+// }
+}
diff --git a/src/main/java/com/gitblit/manager/GitblitManager.java b/src/main/java/com/gitblit/manager/GitblitManager.java
index 2e6a33e3..9947382a 100644
--- a/src/main/java/com/gitblit/manager/GitblitManager.java
+++ b/src/main/java/com/gitblit/manager/GitblitManager.java
@@ -101,13 +101,6 @@ public class GitblitManager implements IGitblitManager {
* @return Map<String, SettingModel>
*/
private void loadSettingModels(ServerSettings settingsModel) {
- // this entire "supports" concept will go away with user service refactoring
- UserModel externalUser = new UserModel(Constants.EXTERNAL_ACCOUNT);
- externalUser.password = Constants.EXTERNAL_ACCOUNT;
- settingsModel.supportsCredentialChanges = userManager.supportsCredentialChanges(externalUser);
- settingsModel.supportsDisplayNameChanges = userManager.supportsDisplayNameChanges(externalUser);
- settingsModel.supportsEmailAddressChanges = userManager.supportsEmailAddressChanges(externalUser);
- settingsModel.supportsTeamMembershipChanges = userManager.supportsTeamMembershipChanges(externalUser);
try {
// Read bundled Gitblit properties to extract setting descriptions.
// This copy is pristine and only used for populating the setting
diff --git a/src/main/java/com/gitblit/manager/ISessionManager.java b/src/main/java/com/gitblit/manager/IAuthenticationManager.java
index 29f17096..093f44d9 100644
--- a/src/main/java/com/gitblit/manager/ISessionManager.java
+++ b/src/main/java/com/gitblit/manager/IAuthenticationManager.java
@@ -18,9 +18,10 @@ package com.gitblit.manager;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import com.gitblit.models.TeamModel;
import com.gitblit.models.UserModel;
-public interface ISessionManager extends IManager {
+public interface IAuthenticationManager extends IManager {
/**
* Authenticate a user based on HTTP request parameters.
@@ -69,4 +70,44 @@ public interface ISessionManager extends IManager {
*/
void logout(HttpServletResponse response, UserModel user);
+ /**
+ * Does the user service support changes to credentials?
+ *
+ * @return true or false
+ * @since 1.0.0
+ */
+ boolean supportsCredentialChanges(UserModel user);
+
+ /**
+ * Returns true if the user's display name can be changed.
+ *
+ * @param user
+ * @return true if the user service supports display name changes
+ */
+ boolean supportsDisplayNameChanges(UserModel user);
+
+ /**
+ * Returns true if the user's email address can be changed.
+ *
+ * @param user
+ * @return true if the user service supports email address changes
+ */
+ boolean supportsEmailAddressChanges(UserModel user);
+
+ /**
+ * Returns true if the user's team memberships can be changed.
+ *
+ * @param user
+ * @return true if the user service supports team membership changes
+ */
+ boolean supportsTeamMembershipChanges(UserModel user);
+
+ /**
+ * Returns true if the team memberships can be changed.
+ *
+ * @param user
+ * @return true if the team memberships can be changed
+ */
+ boolean supportsTeamMembershipChanges(TeamModel team);
+
} \ No newline at end of file
diff --git a/src/main/java/com/gitblit/manager/IUserManager.java b/src/main/java/com/gitblit/manager/IUserManager.java
index 387a7208..5815bcaf 100644
--- a/src/main/java/com/gitblit/manager/IUserManager.java
+++ b/src/main/java/com/gitblit/manager/IUserManager.java
@@ -15,266 +15,9 @@
*/
package com.gitblit.manager;
-import java.util.Collection;
-import java.util.List;
+import com.gitblit.IUserService;
-import com.gitblit.models.TeamModel;
-import com.gitblit.models.UserModel;
+public interface IUserManager extends IManager, IUserService {
-public interface IUserManager extends IManager {
-
- boolean supportsAddUser();
-
- /**
- * Does the user service support changes to credentials?
- *
- * @return true or false
- * @since 1.0.0
- */
- boolean supportsCredentialChanges(UserModel user);
-
- /**
- * Returns true if the user's display name can be changed.
- *
- * @param user
- * @return true if the user service supports display name changes
- */
- boolean supportsDisplayNameChanges(UserModel user);
-
- /**
- * Returns true if the user's email address can be changed.
- *
- * @param user
- * @return true if the user service supports email address changes
- */
- boolean supportsEmailAddressChanges(UserModel user);
-
- /**
- * Returns true if the user's team memberships can be changed.
- *
- * @param user
- * @return true if the user service supports team membership changes
- */
- boolean supportsTeamMembershipChanges(UserModel user);
-
- /**
- * Does the user service support cookie authentication?
- *
- * @return true or false
- */
- boolean supportsCookies();
-
- /**
- * Returns the cookie value for the specified user.
- *
- * @param model
- * @return cookie value
- */
- String getCookie(UserModel model);
-
- /**
- * Authenticate a user based on their cookie.
- *
- * @param cookie
- * @return a user object or null
- */
- UserModel authenticate(char[] cookie);
-
- /**
- * Authenticate a user based on a username and password.
- *
- * @param username
- * @param password
- * @return a user object or null
- */
- UserModel authenticate(String username, char[] password);
-
- /**
- * Logout a user.
- *
- * @param user
- */
- void logout(UserModel user);
-
- /**
- * Retrieve the user object for the specified username.
- *
- * @param username
- * @return a user object or null
- */
- UserModel getUserModel(String username);
-
- /**
- * Updates/writes a complete user object.
- *
- * @param model
- * @return true if update is successful
- */
- boolean updateUserModel(UserModel model);
-
- /**
- * Updates/writes all specified user objects.
- *
- * @param models a list of user models
- * @return true if update is successful
- * @since 1.2.0
- */
- boolean updateUserModels(Collection<UserModel> models);
-
- /**
- * Adds/updates a user object keyed by username. This method allows for
- * renaming a user.
- *
- * @param username
- * the old username
- * @param model
- * the user object to use for username
- * @return true if update is successful
- */
- boolean updateUserModel(String username, UserModel model);
-
- /**
- * Deletes the user object from the user service.
- *
- * @param model
- * @return true if successful
- */
- boolean deleteUserModel(UserModel model);
-
- /**
- * Delete the user object with the specified username
- *
- * @param username
- * @return true if successful
- */
- boolean deleteUser(String username);
-
- /**
- * Returns the list of all users available to the login service.
- *
- * @return list of all usernames
- */
- List<String> getAllUsernames();
-
- /**
- * Returns the list of all users available to the login service.
- *
- * @return list of all users
- * @since 0.8.0
- */
- List<UserModel> getAllUsers();
-
- /**
- * Returns the list of all teams available to the login service.
- *
- * @return list of all teams
- * @since 0.8.0
- */
- List<String> getAllTeamNames();
-
- /**
- * Returns the list of all teams available to the login service.
- *
- * @return list of all teams
- * @since 0.8.0
- */
- List<TeamModel> getAllTeams();
-
- /**
- * Returns the list of all users who are allowed to bypass the access
- * restriction placed on the specified repository.
- *
- * @param role
- * the repository name
- * @return list of all usernames that can bypass the access restriction
- * @since 0.8.0
- */
- List<String> getTeamNamesForRepositoryRole(String role);
-
- /**
- * Retrieve the team object for the specified team name.
- *
- * @param teamname
- * @return a team object or null
- * @since 0.8.0
- */
- TeamModel getTeamModel(String teamname);
-
- /**
- * Updates/writes a complete team object.
- *
- * @param model
- * @return true if update is successful
- * @since 0.8.0
- */
- boolean updateTeamModel(TeamModel model);
-
- /**
- * Updates/writes all specified team objects.
- *
- * @param models a list of team models
- * @return true if update is successful
- * @since 1.2.0
- */
- boolean updateTeamModels(Collection<TeamModel> models);
-
- /**
- * Updates/writes and replaces a complete team object keyed by teamname.
- * This method allows for renaming a team.
- *
- * @param teamname
- * the old teamname
- * @param model
- * the team object to use for teamname
- * @return true if update is successful
- * @since 0.8.0
- */
- boolean updateTeamModel(String teamname, TeamModel model);
-
- /**
- * Deletes the team object from the user service.
- *
- * @param model
- * @return true if successful
- * @since 0.8.0
- */
- boolean deleteTeamModel(TeamModel model);
-
- /**
- * Delete the team object with the specified teamname
- *
- * @param teamname
- * @return true if successful
- * @since 0.8.0
- */
- boolean deleteTeam(String teamname);
-
- /**
- * Returns the list of all users who are allowed to bypass the access
- * restriction placed on the specified repository.
- *
- * @param role
- * the repository name
- * @return list of all usernames that can bypass the access restriction
- * @since 0.8.0
- */
- List<String> getUsernamesForRepositoryRole(String role);
-
- /**
- * Renames a repository role.
- *
- * @param oldRole
- * @param newRole
- * @return true if successful
- */
- boolean renameRepositoryRole(String oldRole, String newRole);
-
- /**
- * Removes a repository role from all users.
- *
- * @param role
- * @return true if successful
- */
- boolean deleteRepositoryRole(String role);
} \ No newline at end of file
diff --git a/src/main/java/com/gitblit/manager/SessionManager.java b/src/main/java/com/gitblit/manager/SessionManager.java
deleted file mode 100644
index 6a85da89..00000000
--- a/src/main/java/com/gitblit/manager/SessionManager.java
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * Copyright 2013 gitblit.com.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.gitblit.manager;
-
-import java.nio.charset.Charset;
-import java.security.Principal;
-import java.text.MessageFormat;
-import java.util.List;
-
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.wicket.RequestCycle;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.gitblit.Constants;
-import com.gitblit.Constants.AuthenticationType;
-import com.gitblit.IStoredSettings;
-import com.gitblit.Keys;
-import com.gitblit.models.UserModel;
-import com.gitblit.utils.Base64;
-import com.gitblit.utils.HttpUtils;
-import com.gitblit.utils.StringUtils;
-import com.gitblit.utils.X509Utils.X509Metadata;
-import com.gitblit.wicket.GitBlitWebSession;
-
-/**
- * The session manager handles user login & logout.
- *
- * @author James Moger
- *
- */
-public class SessionManager implements ISessionManager {
-
- private final Logger logger = LoggerFactory.getLogger(getClass());
-
- private final IStoredSettings settings;
-
- private final IRuntimeManager runtimeManager;
-
- private final IUserManager userManager;
-
- public SessionManager(
- IRuntimeManager runtimeManager,
- IUserManager userManager) {
-
- this.settings = runtimeManager.getSettings();
- this.runtimeManager = runtimeManager;
- this.userManager = userManager;
- }
-
- @Override
- public SessionManager start() {
- List<String> services = settings.getStrings("realm.authenticationServices");
- for (String service : services) {
- // TODO populate authentication services here
- }
- return this;
- }
-
- @Override
- public SessionManager stop() {
- return this;
- }
-
- /**
- * Authenticate a user based on HTTP request parameters.
- *
- * Authentication by X509Certificate is tried first and then by cookie.
- *
- * @param httpRequest
- * @return a user object or null
- */
- @Override
- public UserModel authenticate(HttpServletRequest httpRequest) {
- return authenticate(httpRequest, false);
- }
-
- /**
- * Authenticate a user based on HTTP request parameters.
- *
- * Authentication by X509Certificate, servlet container principal, cookie,
- * and BASIC header.
- *
- * @param httpRequest
- * @param requiresCertificate
- * @return a user object or null
- */
- @Override
- public UserModel authenticate(HttpServletRequest httpRequest, boolean requiresCertificate) {
- // try to authenticate by certificate
- boolean checkValidity = settings.getBoolean(Keys.git.enforceCertificateValidity, true);
- String [] oids = settings.getStrings(Keys.git.certificateUsernameOIDs).toArray(new String[0]);
- UserModel model = HttpUtils.getUserModelFromCertificate(httpRequest, checkValidity, oids);
- if (model != null) {
- // grab real user model and preserve certificate serial number
- UserModel user = userManager.getUserModel(model.username);
- X509Metadata metadata = HttpUtils.getCertificateMetadata(httpRequest);
- if (user != null) {
- flagWicketSession(AuthenticationType.CERTIFICATE);
- logger.debug(MessageFormat.format("{0} authenticated by client certificate {1} from {2}",
- user.username, metadata.serialNumber, httpRequest.getRemoteAddr()));
- return user;
- } else {
- logger.warn(MessageFormat.format("Failed to find UserModel for {0}, attempted client certificate ({1}) authentication from {2}",
- model.username, metadata.serialNumber, httpRequest.getRemoteAddr()));
- }
- }
-
- if (requiresCertificate) {
- // caller requires client certificate authentication (e.g. git servlet)
- return null;
- }
-
- // try to authenticate by servlet container principal
- Principal principal = httpRequest.getUserPrincipal();
- if (principal != null) {
- String username = principal.getName();
- if (!StringUtils.isEmpty(username)) {
- boolean internalAccount = isInternalAccount(username);
- UserModel user = userManager.getUserModel(username);
- if (user != null) {
- // existing user
- flagWicketSession(AuthenticationType.CONTAINER);
- logger.debug(MessageFormat.format("{0} authenticated by servlet container principal from {1}",
- user.username, httpRequest.getRemoteAddr()));
- return user;
- } else if (settings.getBoolean(Keys.realm.container.autoCreateAccounts, false)
- && !internalAccount) {
- // auto-create user from an authenticated container principal
- user = new UserModel(username.toLowerCase());
- user.displayName = username;
- user.password = Constants.EXTERNAL_ACCOUNT;
- userManager.updateUserModel(user);
- flagWicketSession(AuthenticationType.CONTAINER);
- logger.debug(MessageFormat.format("{0} authenticated and created by servlet container principal from {1}",
- user.username, httpRequest.getRemoteAddr()));
- return user;
- } else if (!internalAccount) {
- logger.warn(MessageFormat.format("Failed to find UserModel for {0}, attempted servlet container authentication from {1}",
- principal.getName(), httpRequest.getRemoteAddr()));
- }
- }
- }
-
- // try to authenticate by cookie
- if (userManager.supportsCookies()) {
- UserModel user = authenticate(httpRequest.getCookies());
- if (user != null) {
- flagWicketSession(AuthenticationType.COOKIE);
- logger.debug(MessageFormat.format("{0} authenticated by cookie from {1}",
- user.username, httpRequest.getRemoteAddr()));
- return user;
- }
- }
-
- // try to authenticate by BASIC
- final String authorization = httpRequest.getHeader("Authorization");
- if (authorization != null && authorization.startsWith("Basic")) {
- // Authorization: Basic base64credentials
- String base64Credentials = authorization.substring("Basic".length()).trim();
- String credentials = new String(Base64.decode(base64Credentials),
- Charset.forName("UTF-8"));
- // credentials = username:password
- final String[] values = credentials.split(":", 2);
-
- if (values.length == 2) {
- String username = values[0];
- char[] password = values[1].toCharArray();
- UserModel user = authenticate(username, password);
- if (user != null) {
- flagWicketSession(AuthenticationType.CREDENTIALS);
- logger.debug(MessageFormat.format("{0} authenticated by BASIC request header from {1}",
- user.username, httpRequest.getRemoteAddr()));
- return user;
- } else {
- logger.warn(MessageFormat.format("Failed login attempt for {0}, invalid credentials from {1}",
- username, httpRequest.getRemoteAddr()));
- }
- }
- }
- return null;
- }
-
- /**
- * Authenticate a user based on their cookie.
- *
- * @param cookies
- * @return a user object or null
- */
- protected UserModel authenticate(Cookie[] cookies) {
- if (userManager.supportsCookies()) {
- if (cookies != null && cookies.length > 0) {
- for (Cookie cookie : cookies) {
- if (cookie.getName().equals(Constants.NAME)) {
- String value = cookie.getValue();
- return userManager.authenticate(value.toCharArray());
- }
- }
- }
- }
- return null;
- }
-
- protected void flagWicketSession(AuthenticationType authenticationType) {
- RequestCycle requestCycle = RequestCycle.get();
- if (requestCycle != null) {
- // flag the Wicket session, if this is a Wicket request
- GitBlitWebSession session = GitBlitWebSession.get();
- session.authenticationType = authenticationType;
- }
- }
-
- /**
- * Authenticate a user based on a username and password.
- *
- * @see IUserService.authenticate(String, char[])
- * @param username
- * @param password
- * @return a user object or null
- */
- @Override
- public UserModel authenticate(String username, char[] password) {
- if (StringUtils.isEmpty(username)) {
- // can not authenticate empty username
- return null;
- }
-
- String usernameDecoded = StringUtils.decodeUsername(username);
- String pw = new String(password);
- if (StringUtils.isEmpty(pw)) {
- // can not authenticate empty password
- return null;
- }
- // check to see if this is the federation user
-// if (canFederate()) {
-// if (usernameDecoded.equalsIgnoreCase(Constants.FEDERATION_USER)) {
-// List<String> tokens = getFederationTokens();
-// if (tokens.contains(pw)) {
-// return getFederationUser();
-// }
-// }
-// }
-
- UserModel user = userManager.authenticate(usernameDecoded, password);
-
- // try registered external authentication providers
- if (user == null) {
-// for (AuthenticationService service : authenticationServices) {
-// if (service instanceof UsernamePasswordAuthenticationService) {
-// user = service.authenticate(usernameDecoded, password);
-// if (user != null) {
-// // user authenticated
-// user.accountType = service.getAccountType();
-// return user;
-// }
-// }
-// }
- }
- return user;
- }
-
- /**
- * Sets a cookie for the specified user.
- *
- * @param response
- * @param user
- */
- @Override
- public void setCookie(HttpServletResponse response, UserModel user) {
- GitBlitWebSession session = GitBlitWebSession.get();
- boolean standardLogin = session.authenticationType.isStandard();
-
- if (userManager.supportsCookies() && standardLogin) {
- Cookie userCookie;
- if (user == null) {
- // clear cookie for logout
- userCookie = new Cookie(Constants.NAME, "");
- } else {
- // set cookie for login
- String cookie = userManager.getCookie(user);
- if (StringUtils.isEmpty(cookie)) {
- // create empty cookie
- userCookie = new Cookie(Constants.NAME, "");
- } else {
- // create real cookie
- userCookie = new Cookie(Constants.NAME, cookie);
- userCookie.setMaxAge(Integer.MAX_VALUE);
- }
- }
- userCookie.setPath("/");
- response.addCookie(userCookie);
- }
- }
-
- /**
- * Logout a user.
- *
- * @param user
- */
- @Override
- public void logout(HttpServletResponse response, UserModel user) {
- setCookie(response, null);
- userManager.logout(user);
- }
-
- /**
- * Returns true if the username represents an internal account
- *
- * @param username
- * @return true if the specified username represents an internal account
- */
- protected boolean isInternalAccount(String username) {
- return !StringUtils.isEmpty(username)
- && (username.equalsIgnoreCase(Constants.FEDERATION_USER)
- || username.equalsIgnoreCase(UserModel.ANONYMOUS.username));
- }
-
-// protected UserModel getFederationUser() {
-// // the federation user is an administrator
-// UserModel federationUser = new UserModel(Constants.FEDERATION_USER);
-// federationUser.canAdmin = true;
-// return federationUser;
-// }
-}
diff --git a/src/main/java/com/gitblit/manager/UserManager.java b/src/main/java/com/gitblit/manager/UserManager.java
index 90b9d1e2..3ca62e23 100644
--- a/src/main/java/com/gitblit/manager/UserManager.java
+++ b/src/main/java/com/gitblit/manager/UserManager.java
@@ -20,20 +20,19 @@ import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.gitblit.ConfigUserService;
-import com.gitblit.Constants;
-import com.gitblit.Constants.AccountType;
import com.gitblit.IStoredSettings;
import com.gitblit.IUserService;
import com.gitblit.Keys;
import com.gitblit.models.TeamModel;
import com.gitblit.models.UserModel;
-import com.gitblit.utils.DeepCopier;
import com.gitblit.utils.StringUtils;
/**
@@ -50,37 +49,68 @@ public class UserManager implements IUserManager {
private final IRuntimeManager runtimeManager;
+ private final Map<String, String> legacyBackingServices;
+
private IUserService userService;
public UserManager(IRuntimeManager runtimeManager) {
this.settings = runtimeManager.getSettings();
this.runtimeManager = runtimeManager;
+
+ // map of legacy realm backing user services
+ legacyBackingServices = new HashMap<String, String>();
+ legacyBackingServices.put("com.gitblit.HtpasswdUserService", "realm.htpasswd.backingUserService");
+ legacyBackingServices.put("com.gitblit.LdapUserService", "realm.ldap.backingUserService");
+ legacyBackingServices.put("com.gitblit.PAMUserService", "realm.pam.backingUserService");
+ legacyBackingServices.put("com.gitblit.RedmineUserService", "realm.redmine.backingUserService");
+ legacyBackingServices.put("com.gitblit.SalesforceUserService", "realm.salesforce.backingUserService");
+ legacyBackingServices.put("com.gitblit.WindowsUserService", "realm.windows.backingUserService");
}
/**
- * Set the user service. The user service authenticates local users and is
- * responsible for persisting and retrieving users and teams.
+ * Set the user service. The user service authenticates *local* users and is
+ * responsible for persisting and retrieving all users and all teams.
*
* @param userService
*/
public void setUserService(IUserService userService) {
- logger.info("UserService: " + userService.toString());
+ logger.info(userService.toString());
this.userService = userService;
this.userService.setup(runtimeManager);
}
@Override
+ public void setup(IRuntimeManager runtimeManager) {
+ // NOOP
+ }
+
+ @Override
public UserManager start() {
if (this.userService == null) {
- String realm = settings.getString(Keys.realm.userService, "${baseFolder}/users.properties");
+ String realm = settings.getString(Keys.realm.userService, "${baseFolder}/users.conf");
IUserService service = null;
- try {
- // check to see if this "file" is a login service class
- Class<?> realmClass = Class.forName(realm);
- service = (IUserService) realmClass.newInstance();
- } catch (Throwable t) {
- File realmFile = runtimeManager.getFileOrFolder(Keys.realm.userService, "${baseFolder}/users.conf");
+ if (legacyBackingServices.containsKey(realm)) {
+ // create the user service from the legacy config
+ String realmKey = legacyBackingServices.get(realm);
+ logger.warn("");
+ logger.warn("#################################################################");
+ logger.warn(" Key '{}' is obsolete!", realmKey);
+ logger.warn(" Please set '{}={}'", Keys.realm.userService, settings.getString(realmKey, "${baseFolder}/users.conf"));
+ logger.warn("#################################################################");
+ logger.warn("");
+ File realmFile = runtimeManager.getFileOrFolder(realmKey, "${baseFolder}/users.conf");
service = createUserService(realmFile);
+ } else {
+ // either a file path OR a custom user service
+ try {
+ // check to see if this "file" is a custom user service class
+ Class<?> realmClass = Class.forName(realm);
+ service = (IUserService) realmClass.newInstance();
+ } catch (Throwable t) {
+ // typical file path configuration
+ File realmFile = runtimeManager.getFileOrFolder(Keys.realm.userService, "${baseFolder}/users.conf");
+ service = createUserService(realmFile);
+ }
}
setUserService(service);
}
@@ -90,7 +120,7 @@ public class UserManager implements IUserManager {
protected IUserService createUserService(File realmFile) {
IUserService service = null;
if (realmFile.getName().toLowerCase().endsWith(".conf")) {
- // v0.8.0+ config-based realm file
+ // config-based realm file
service = new ConfigUserService(realmFile);
}
@@ -118,74 +148,6 @@ public class UserManager implements IUserManager {
return this;
}
- @Override
- public boolean supportsAddUser() {
- return supportsCredentialChanges(new UserModel(""));
- }
-
- /**
- * Returns true if the user's credentials can be changed.
- *
- * @param user
- * @return true if the user service supports credential changes
- */
- @Override
- public boolean supportsCredentialChanges(UserModel user) {
- if (user == null) {
- return false;
- } else if (AccountType.LOCAL.equals(user.accountType)) {
- // local account, we can change credentials
- return true;
- } else {
- // external account, ask user service
- return userService.supportsCredentialChanges();
- }
- }
-
- /**
- * Returns true if the user's display name can be changed.
- *
- * @param user
- * @return true if the user service supports display name changes
- */
- @Override
- public boolean supportsDisplayNameChanges(UserModel user) {
- return (user != null && user.isLocalAccount()) || userService.supportsDisplayNameChanges();
- }
-
- /**
- * Returns true if the user's email address can be changed.
- *
- * @param user
- * @return true if the user service supports email address changes
- */
- @Override
- public boolean supportsEmailAddressChanges(UserModel user) {
- return (user != null && user.isLocalAccount()) || userService.supportsEmailAddressChanges();
- }
-
- /**
- * Returns true if the user's team memberships can be changed.
- *
- * @param user
- * @return true if the user service supports team membership changes
- */
- @Override
- public boolean supportsTeamMembershipChanges(UserModel user) {
- return (user != null && user.isLocalAccount()) || userService.supportsTeamMembershipChanges();
- }
-
- /**
- * Allow to understand if GitBlit supports and is configured to allow
- * cookie-based authentication.
- *
- * @return status of Cookie authentication enablement.
- */
- @Override
- public boolean supportsCookies() {
- return settings.getBoolean(Keys.web.allowCookieAuthentication, true) && userService.supportsCookies();
- }
-
/**
* Returns the cookie value for the specified user.
*
@@ -198,47 +160,18 @@ public class UserManager implements IUserManager {
}
/**
- * Authenticate a user based on a username and password.
- *
- * @param username
- * @param password
- * @return a user object or null
- */
-
- @Override
- public UserModel authenticate(String username, char[] password) {
- UserModel user = userService.authenticate(username, password);
- setAccountType(user);
- return user;
- }
-
- /**
- * Authenticate a user based on their cookie.
+ * Retrieve the user object for the specified cookie.
*
* @param cookie
* @return a user object or null
*/
@Override
- public UserModel authenticate(char[] cookie) {
- UserModel user = userService.authenticate(cookie);
- setAccountType(user);
+ public UserModel getUserModel(char[] cookie) {
+ UserModel user = userService.getUserModel(cookie);
return user;
}
/**
- * Logout a user.
- *
- * @param user
- */
- @Override
- public void logout(UserModel user) {
- if (userService == null) {
- return;
- }
- userService.logout(user);
- }
-
- /**
* Retrieve the user object for the specified username.
*
* @param username
@@ -251,7 +184,6 @@ public class UserManager implements IUserManager {
}
String usernameDecoded = StringUtils.decodeUsername(username);
UserModel user = userService.getUserModel(usernameDecoded);
- setAccountType(user);
return user;
}
@@ -290,32 +222,7 @@ public class UserManager implements IUserManager {
*/
@Override
public boolean updateUserModel(String username, UserModel model) {
- if (model.isLocalAccount() || userService.supportsCredentialChanges()) {
- if (!model.isLocalAccount() && !userService.supportsTeamMembershipChanges()) {
- // teams are externally controlled - copy from original model
- UserModel existingModel = getUserModel(username);
-
- model = DeepCopier.copy(model);
- model.teams.clear();
- model.teams.addAll(existingModel.teams);
- }
- return userService.updateUserModel(username, model);
- }
- if (model.username.equals(username)) {
- // passwords are not persisted by the backing user service
- model.password = null;
- if (!model.isLocalAccount() && !userService.supportsTeamMembershipChanges()) {
- // teams are externally controlled- copy from original model
- UserModel existingModel = getUserModel(username);
-
- model = DeepCopier.copy(model);
- model.teams.clear();
- model.teams.addAll(existingModel.teams);
- }
- return userService.updateUserModel(username, model);
- }
- logger.error("Users can not be renamed!");
- return false;
+ return userService.updateUserModel(username, model);
}
/**
@@ -364,9 +271,6 @@ public class UserManager implements IUserManager {
@Override
public List<UserModel> getAllUsers() {
List<UserModel> users = userService.getAllUsers();
- for (UserModel user : users) {
- setAccountType(user);
- }
return users;
}
@@ -378,7 +282,8 @@ public class UserManager implements IUserManager {
*/
@Override
public List<String> getAllTeamNames() {
- return userService.getAllTeamNames();
+ List<String> teams = userService.getAllTeamNames();
+ return teams;
}
/**
@@ -404,7 +309,8 @@ public class UserManager implements IUserManager {
*/
@Override
public List<String> getTeamNamesForRepositoryRole(String role) {
- return userService.getTeamNamesForRepositoryRole(role);
+ List<String> teams = userService.getTeamNamesForRepositoryRole(role);
+ return teams;
}
/**
@@ -416,7 +322,8 @@ public class UserManager implements IUserManager {
*/
@Override
public TeamModel getTeamModel(String teamname) {
- return userService.getTeamModel(teamname);
+ TeamModel team = userService.getTeamModel(teamname);
+ return team;
}
/**
@@ -456,14 +363,6 @@ public class UserManager implements IUserManager {
*/
@Override
public boolean updateTeamModel(String teamname, TeamModel model) {
- if (!userService.supportsTeamMembershipChanges()) {
- // teams are externally controlled - copy from original model
- TeamModel existingModel = getTeamModel(teamname);
-
- model = DeepCopier.copy(model);
- model.users.clear();
- model.users.addAll(existingModel.users);
- }
return userService.updateTeamModel(teamname, model);
}
@@ -527,16 +426,4 @@ public class UserManager implements IUserManager {
public boolean deleteRepositoryRole(String role) {
return userService.deleteRepositoryRole(role);
}
-
- protected void setAccountType(UserModel user) {
- if (user != null) {
- if (!StringUtils.isEmpty(user.password)
- && !Constants.EXTERNAL_ACCOUNT.equalsIgnoreCase(user.password)
- && !"StoredInLDAP".equalsIgnoreCase(user.password)) {
- user.accountType = AccountType.LOCAL;
- } else {
- user.accountType = userService.getAccountType();
- }
- }
- }
}
diff --git a/src/main/java/com/gitblit/models/ServerSettings.java b/src/main/java/com/gitblit/models/ServerSettings.java
index 92d5c311..07e703b0 100644
--- a/src/main/java/com/gitblit/models/ServerSettings.java
+++ b/src/main/java/com/gitblit/models/ServerSettings.java
@@ -37,14 +37,6 @@ public class ServerSettings implements Serializable {
public List<String> pushScripts;
- public boolean supportsCredentialChanges;
-
- public boolean supportsDisplayNameChanges;
-
- public boolean supportsEmailAddressChanges;
-
- public boolean supportsTeamMembershipChanges;
-
public ServerSettings() {
settings = new TreeMap<String, SettingModel>();
}
diff --git a/src/main/java/com/gitblit/models/TeamModel.java b/src/main/java/com/gitblit/models/TeamModel.java
index a1928283..aaa3d54a 100644
--- a/src/main/java/com/gitblit/models/TeamModel.java
+++ b/src/main/java/com/gitblit/models/TeamModel.java
@@ -27,6 +27,7 @@ import java.util.Set;
import com.gitblit.Constants.AccessPermission;
import com.gitblit.Constants.AccessRestrictionType;
+import com.gitblit.Constants.AccountType;
import com.gitblit.Constants.PermissionType;
import com.gitblit.Constants.RegistrantType;
import com.gitblit.Constants.Unused;
@@ -48,6 +49,7 @@ public class TeamModel implements Serializable, Comparable<TeamModel> {
public boolean canAdmin;
public boolean canFork;
public boolean canCreate;
+ public AccountType accountType;
public final Set<String> users = new HashSet<String>();
// retained for backwards-compatibility with RPC clients
@Deprecated
@@ -59,6 +61,7 @@ public class TeamModel implements Serializable, Comparable<TeamModel> {
public TeamModel(String name) {
this.name = name;
+ this.accountType = AccountType.LOCAL;
}
/**
@@ -358,6 +361,10 @@ public class TeamModel implements Serializable, Comparable<TeamModel> {
}
}
+ public boolean isLocalTeam() {
+ return accountType.isLocal();
+ }
+
@Override
public String toString() {
return name;
diff --git a/src/main/java/com/gitblit/servlet/AccessRestrictionFilter.java b/src/main/java/com/gitblit/servlet/AccessRestrictionFilter.java
index d5ded33c..d6acdbb6 100644
--- a/src/main/java/com/gitblit/servlet/AccessRestrictionFilter.java
+++ b/src/main/java/com/gitblit/servlet/AccessRestrictionFilter.java
@@ -27,7 +27,7 @@ import javax.servlet.http.HttpServletResponse;
import com.gitblit.manager.IRepositoryManager;
import com.gitblit.manager.IRuntimeManager;
-import com.gitblit.manager.ISessionManager;
+import com.gitblit.manager.IAuthenticationManager;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.UserModel;
import com.gitblit.utils.StringUtils;
@@ -54,9 +54,9 @@ public abstract class AccessRestrictionFilter extends AuthenticationFilter {
protected AccessRestrictionFilter(
IRuntimeManager runtimeManager,
- ISessionManager sessionManager,
+ IAuthenticationManager authenticationManager,
IRepositoryManager repositoryManager) {
- super(sessionManager);
+ super(authenticationManager);
this.runtimeManager = runtimeManager;
this.repositoryManager = repositoryManager;
}
diff --git a/src/main/java/com/gitblit/servlet/AuthenticationFilter.java b/src/main/java/com/gitblit/servlet/AuthenticationFilter.java
index 214f2042..54c70141 100644
--- a/src/main/java/com/gitblit/servlet/AuthenticationFilter.java
+++ b/src/main/java/com/gitblit/servlet/AuthenticationFilter.java
@@ -36,7 +36,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.gitblit.Constants;
-import com.gitblit.manager.ISessionManager;
+import com.gitblit.manager.IAuthenticationManager;
import com.gitblit.models.UserModel;
import com.gitblit.utils.DeepCopier;
import com.gitblit.utils.StringUtils;
@@ -58,10 +58,10 @@ public abstract class AuthenticationFilter implements Filter {
protected transient Logger logger = LoggerFactory.getLogger(getClass());
- protected final ISessionManager sessionManager;
+ protected final IAuthenticationManager authenticationManager;
- protected AuthenticationFilter(ISessionManager sessionManager) {
- this.sessionManager = sessionManager;
+ protected AuthenticationFilter(IAuthenticationManager authenticationManager) {
+ this.authenticationManager = authenticationManager;
}
/**
@@ -108,7 +108,7 @@ public abstract class AuthenticationFilter implements Filter {
* @return user
*/
protected UserModel getUser(HttpServletRequest httpRequest) {
- UserModel user = sessionManager.authenticate(httpRequest, requiresClientCertificate());
+ UserModel user = authenticationManager.authenticate(httpRequest, requiresClientCertificate());
return user;
}
diff --git a/src/main/java/com/gitblit/servlet/DownloadZipFilter.java b/src/main/java/com/gitblit/servlet/DownloadZipFilter.java
index f2064e3a..398121d3 100644
--- a/src/main/java/com/gitblit/servlet/DownloadZipFilter.java
+++ b/src/main/java/com/gitblit/servlet/DownloadZipFilter.java
@@ -21,7 +21,7 @@ import javax.inject.Singleton;
import com.gitblit.Constants.AccessRestrictionType;
import com.gitblit.manager.IRepositoryManager;
import com.gitblit.manager.IRuntimeManager;
-import com.gitblit.manager.ISessionManager;
+import com.gitblit.manager.IAuthenticationManager;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.UserModel;
@@ -39,10 +39,10 @@ public class DownloadZipFilter extends AccessRestrictionFilter {
@Inject
public DownloadZipFilter(
IRuntimeManager runtimeManager,
- ISessionManager sessionManager,
+ IAuthenticationManager authenticationManager,
IRepositoryManager repositoryManager) {
- super(runtimeManager, sessionManager, repositoryManager);
+ super(runtimeManager, authenticationManager, repositoryManager);
}
/**
diff --git a/src/main/java/com/gitblit/servlet/EnforceAuthenticationFilter.java b/src/main/java/com/gitblit/servlet/EnforceAuthenticationFilter.java
index d690fd2c..6655c6e1 100644
--- a/src/main/java/com/gitblit/servlet/EnforceAuthenticationFilter.java
+++ b/src/main/java/com/gitblit/servlet/EnforceAuthenticationFilter.java
@@ -36,7 +36,7 @@ import com.gitblit.IStoredSettings;
import com.gitblit.Keys;
import com.gitblit.Keys.web;
import com.gitblit.manager.IRuntimeManager;
-import com.gitblit.manager.ISessionManager;
+import com.gitblit.manager.IAuthenticationManager;
import com.gitblit.models.UserModel;
/**
@@ -54,16 +54,16 @@ public class EnforceAuthenticationFilter implements Filter {
private final IStoredSettings settings;
- private final ISessionManager sessionManager;
+ private final IAuthenticationManager authenticationManager;
@Inject
public EnforceAuthenticationFilter(
IRuntimeManager runtimeManager,
- ISessionManager sessionManager) {
+ IAuthenticationManager authenticationManager) {
super();
this.settings = runtimeManager.getSettings();
- this.sessionManager = sessionManager;
+ this.authenticationManager = authenticationManager;
}
/*
@@ -86,7 +86,7 @@ public class EnforceAuthenticationFilter implements Filter {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
- UserModel user = sessionManager.authenticate(httpRequest);
+ UserModel user = authenticationManager.authenticate(httpRequest);
if (mustForceAuth && (user == null)) {
// not authenticated, enforce now:
diff --git a/src/main/java/com/gitblit/servlet/GitFilter.java b/src/main/java/com/gitblit/servlet/GitFilter.java
index f39d68fd..c44f7efc 100644
--- a/src/main/java/com/gitblit/servlet/GitFilter.java
+++ b/src/main/java/com/gitblit/servlet/GitFilter.java
@@ -29,7 +29,7 @@ import com.gitblit.Constants.AuthorizationControl;
import com.gitblit.Keys.git;
import com.gitblit.manager.IRepositoryManager;
import com.gitblit.manager.IRuntimeManager;
-import com.gitblit.manager.ISessionManager;
+import com.gitblit.manager.IAuthenticationManager;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.UserModel;
import com.gitblit.utils.StringUtils;
@@ -57,10 +57,10 @@ public class GitFilter extends AccessRestrictionFilter {
@Inject
public GitFilter(
IRuntimeManager runtimeManager,
- ISessionManager sessionManager,
+ IAuthenticationManager authenticationManager,
IRepositoryManager repositoryManager) {
- super(runtimeManager, sessionManager, repositoryManager);
+ super(runtimeManager, authenticationManager, repositoryManager);
this.settings = runtimeManager.getSettings();
}
diff --git a/src/main/java/com/gitblit/servlet/GitblitContext.java b/src/main/java/com/gitblit/servlet/GitblitContext.java
index 73250121..3e95b4bb 100644
--- a/src/main/java/com/gitblit/servlet/GitblitContext.java
+++ b/src/main/java/com/gitblit/servlet/GitblitContext.java
@@ -49,7 +49,7 @@ import com.gitblit.manager.IProjectManager;
import com.gitblit.manager.IRepositoryManager;
import com.gitblit.manager.IRuntimeManager;
import com.gitblit.manager.IServicesManager;
-import com.gitblit.manager.ISessionManager;
+import com.gitblit.manager.IAuthenticationManager;
import com.gitblit.manager.IUserManager;
import com.gitblit.utils.ContainerUtils;
import com.gitblit.utils.StringUtils;
@@ -170,7 +170,7 @@ public class GitblitContext extends DaggerContextListener {
// start all other managers
startManager(injector, INotificationManager.class);
startManager(injector, IUserManager.class);
- startManager(injector, ISessionManager.class);
+ startManager(injector, IAuthenticationManager.class);
startManager(injector, IRepositoryManager.class);
startManager(injector, IProjectManager.class);
startManager(injector, IGitblitManager.class);
diff --git a/src/main/java/com/gitblit/servlet/PagesFilter.java b/src/main/java/com/gitblit/servlet/PagesFilter.java
index 23e7859f..42e7de75 100644
--- a/src/main/java/com/gitblit/servlet/PagesFilter.java
+++ b/src/main/java/com/gitblit/servlet/PagesFilter.java
@@ -23,7 +23,7 @@ import org.eclipse.jgit.lib.Repository;
import com.gitblit.Constants.AccessRestrictionType;
import com.gitblit.manager.IRepositoryManager;
import com.gitblit.manager.IRuntimeManager;
-import com.gitblit.manager.ISessionManager;
+import com.gitblit.manager.IAuthenticationManager;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.UserModel;
@@ -39,10 +39,10 @@ public class PagesFilter extends AccessRestrictionFilter {
@Inject
public PagesFilter(IRuntimeManager runtimeManager,
- ISessionManager sessionManager,
+ IAuthenticationManager authenticationManager,
IRepositoryManager repositoryManager) {
- super(runtimeManager, sessionManager, repositoryManager);
+ super(runtimeManager, authenticationManager, repositoryManager);
}
/**
diff --git a/src/main/java/com/gitblit/servlet/RpcFilter.java b/src/main/java/com/gitblit/servlet/RpcFilter.java
index 6163252d..f39d37d8 100644
--- a/src/main/java/com/gitblit/servlet/RpcFilter.java
+++ b/src/main/java/com/gitblit/servlet/RpcFilter.java
@@ -31,7 +31,7 @@ import com.gitblit.Constants.RpcRequest;
import com.gitblit.IStoredSettings;
import com.gitblit.Keys;
import com.gitblit.manager.IRuntimeManager;
-import com.gitblit.manager.ISessionManager;
+import com.gitblit.manager.IAuthenticationManager;
import com.gitblit.models.UserModel;
/**
@@ -57,9 +57,9 @@ public class RpcFilter extends AuthenticationFilter {
@Inject
public RpcFilter(
IRuntimeManager runtimeManager,
- ISessionManager sessionManager) {
+ IAuthenticationManager authenticationManager) {
- super(sessionManager);
+ super(authenticationManager);
this.settings = runtimeManager.getSettings();
this.runtimeManager = runtimeManager;
}
diff --git a/src/main/java/com/gitblit/servlet/SparkleShareInviteServlet.java b/src/main/java/com/gitblit/servlet/SparkleShareInviteServlet.java
index 4b8b24f4..3bef51dd 100644
--- a/src/main/java/com/gitblit/servlet/SparkleShareInviteServlet.java
+++ b/src/main/java/com/gitblit/servlet/SparkleShareInviteServlet.java
@@ -31,7 +31,7 @@ import com.gitblit.Keys;
import com.gitblit.Keys.fanout;
import com.gitblit.manager.IRepositoryManager;
import com.gitblit.manager.IRuntimeManager;
-import com.gitblit.manager.ISessionManager;
+import com.gitblit.manager.IAuthenticationManager;
import com.gitblit.manager.IUserManager;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.UserModel;
@@ -52,7 +52,7 @@ public class SparkleShareInviteServlet extends HttpServlet {
private final IUserManager userManager;
- private final ISessionManager sessionManager;
+ private final IAuthenticationManager authenticationManager;
private final IRepositoryManager repositoryManager;
@@ -60,13 +60,13 @@ public class SparkleShareInviteServlet extends HttpServlet {
public SparkleShareInviteServlet(
IRuntimeManager runtimeManager,
IUserManager userManager,
- ISessionManager sessionManager,
+ IAuthenticationManager authenticationManager,
IRepositoryManager repositoryManager) {
super();
this.settings = runtimeManager.getSettings();
this.userManager = userManager;
- this.sessionManager = sessionManager;
+ this.authenticationManager = authenticationManager;
this.repositoryManager = repositoryManager;
}
@@ -106,7 +106,7 @@ public class SparkleShareInviteServlet extends HttpServlet {
}
UserModel user;
if (StringUtils.isEmpty(username)) {
- user = sessionManager.authenticate(request);
+ user = authenticationManager.authenticate(request);
} else {
user = userManager.getUserModel(username);
}
diff --git a/src/main/java/com/gitblit/servlet/SyndicationFilter.java b/src/main/java/com/gitblit/servlet/SyndicationFilter.java
index adf9ba94..7eb8af96 100644
--- a/src/main/java/com/gitblit/servlet/SyndicationFilter.java
+++ b/src/main/java/com/gitblit/servlet/SyndicationFilter.java
@@ -31,7 +31,7 @@ import com.gitblit.Constants.AccessRestrictionType;
import com.gitblit.manager.IProjectManager;
import com.gitblit.manager.IRepositoryManager;
import com.gitblit.manager.IRuntimeManager;
-import com.gitblit.manager.ISessionManager;
+import com.gitblit.manager.IAuthenticationManager;
import com.gitblit.models.ProjectModel;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.UserModel;
@@ -54,11 +54,11 @@ public class SyndicationFilter extends AuthenticationFilter {
@Inject
public SyndicationFilter(
IRuntimeManager runtimeManager,
- ISessionManager sessionManager,
+ IAuthenticationManager authenticationManager,
IRepositoryManager repositoryManager,
IProjectManager projectManager) {
- super(sessionManager);
+ super(authenticationManager);
this.runtimeManager = runtimeManager;
this.repositoryManager = repositoryManager;
this.projectManager = projectManager;
diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
index ad13a042..1409e474 100644
--- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
+++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java
@@ -36,7 +36,7 @@ import com.gitblit.manager.INotificationManager;
import com.gitblit.manager.IProjectManager;
import com.gitblit.manager.IRepositoryManager;
import com.gitblit.manager.IRuntimeManager;
-import com.gitblit.manager.ISessionManager;
+import com.gitblit.manager.IAuthenticationManager;
import com.gitblit.manager.IUserManager;
import com.gitblit.utils.StringUtils;
import com.gitblit.wicket.pages.ActivityPage;
@@ -89,7 +89,7 @@ public class GitBlitWebApp extends WebApplication {
private final IUserManager userManager;
- private final ISessionManager sessionManager;
+ private final IAuthenticationManager authenticationManager;
private final IRepositoryManager repositoryManager;
@@ -103,7 +103,7 @@ public class GitBlitWebApp extends WebApplication {
IRuntimeManager runtimeManager,
INotificationManager notificationManager,
IUserManager userManager,
- ISessionManager sessionManager,
+ IAuthenticationManager authenticationManager,
IRepositoryManager repositoryManager,
IProjectManager projectManager,
IGitblitManager gitblitManager,
@@ -114,7 +114,7 @@ public class GitBlitWebApp extends WebApplication {
this.runtimeManager = runtimeManager;
this.notificationManager = notificationManager;
this.userManager = userManager;
- this.sessionManager = sessionManager;
+ this.authenticationManager = authenticationManager;
this.repositoryManager = repositoryManager;
this.projectManager = projectManager;
this.gitblitManager = gitblitManager;
@@ -267,8 +267,8 @@ public class GitBlitWebApp extends WebApplication {
return userManager;
}
- public ISessionManager session() {
- return sessionManager;
+ public IAuthenticationManager authentication() {
+ return authenticationManager;
}
public IRepositoryManager repositories() {
diff --git a/src/main/java/com/gitblit/wicket/pages/ChangePasswordPage.java b/src/main/java/com/gitblit/wicket/pages/ChangePasswordPage.java
index a3c1ece5..ec5fe16e 100644
--- a/src/main/java/com/gitblit/wicket/pages/ChangePasswordPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/ChangePasswordPage.java
@@ -51,7 +51,7 @@ public class ChangePasswordPage extends RootSubPage {
}
UserModel user = GitBlitWebSession.get().getUser();
- if (!app().users().supportsCredentialChanges(user)) {
+ if (!app().authentication().supportsCredentialChanges(user)) {
error(MessageFormat.format(getString("gb.userServiceDoesNotPermitPasswordChanges"),
app().settings().getString(Keys.realm.userService, "${baseFolder}/users.conf")), true);
}
@@ -100,7 +100,7 @@ public class ChangePasswordPage extends RootSubPage {
app().gitblit().updateUserModel(user.username, user, false);
if (app().settings().getBoolean(Keys.web.allowCookieAuthentication, false)) {
WebResponse response = (WebResponse) getRequestCycle().getResponse();
- app().session().setCookie(response.getHttpServletResponse(), user);
+ app().authentication().setCookie(response.getHttpServletResponse(), user);
}
} catch (GitBlitException e) {
error(e.getMessage());
diff --git a/src/main/java/com/gitblit/wicket/pages/EditTeamPage.java b/src/main/java/com/gitblit/wicket/pages/EditTeamPage.java
index 4f548d46..232dbe3b 100644
--- a/src/main/java/com/gitblit/wicket/pages/EditTeamPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/EditTeamPage.java
@@ -216,7 +216,7 @@ public class EditTeamPage extends RootSubPage {
form.add(new SimpleAttributeModifier("autocomplete", "off"));
// not all user services support manipulating team memberships
- boolean editMemberships = app().users().supportsTeamMembershipChanges(null);
+ boolean editMemberships = app().authentication().supportsTeamMembershipChanges(teamModel);
// field names reflective match TeamModel fields
form.add(new TextField<String>("name"));
diff --git a/src/main/java/com/gitblit/wicket/pages/EditUserPage.java b/src/main/java/com/gitblit/wicket/pages/EditUserPage.java
index b2d3d3b1..4e91b45a 100644
--- a/src/main/java/com/gitblit/wicket/pages/EditUserPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/EditUserPage.java
@@ -54,10 +54,6 @@ public class EditUserPage extends RootSubPage {
public EditUserPage() {
// create constructor
super();
- if (!app().users().supportsAddUser()) {
- error(MessageFormat.format(getString("gb.userServiceDoesNotPermitAddUser"),
- app().settings().getString(Keys.realm.userService, "${baseFolder}/users.conf")), true);
- }
isCreate = true;
setupPage(new UserModel(""));
setStatelessHint(false);
@@ -138,7 +134,7 @@ public class EditUserPage extends RootSubPage {
}
boolean rename = !StringUtils.isEmpty(oldName)
&& !oldName.equalsIgnoreCase(username);
- if (app().users().supportsCredentialChanges(userModel)) {
+ if (app().authentication().supportsCredentialChanges(userModel)) {
if (!userModel.password.equals(confirmPassword.getObject())) {
error(getString("gb.passwordsDoNotMatch"));
return;
@@ -214,16 +210,16 @@ public class EditUserPage extends RootSubPage {
form.add(new SimpleAttributeModifier("autocomplete", "off"));
// not all user services support manipulating username and password
- boolean editCredentials = app().users().supportsCredentialChanges(userModel);
+ boolean editCredentials = app().authentication().supportsCredentialChanges(userModel);
// not all user services support manipulating display name
- boolean editDisplayName = app().users().supportsDisplayNameChanges(userModel);
+ boolean editDisplayName = app().authentication().supportsDisplayNameChanges(userModel);
// not all user services support manipulating email address
- boolean editEmailAddress = app().users().supportsEmailAddressChanges(userModel);
+ boolean editEmailAddress = app().authentication().supportsEmailAddressChanges(userModel);
// not all user services support manipulating team memberships
- boolean editTeams = app().users().supportsTeamMembershipChanges(userModel);
+ boolean editTeams = app().authentication().supportsTeamMembershipChanges(userModel);
// field names reflective match UserModel fields
form.add(new TextField<String>("username").setEnabled(editCredentials));
diff --git a/src/main/java/com/gitblit/wicket/pages/LogoutPage.java b/src/main/java/com/gitblit/wicket/pages/LogoutPage.java
index d99c1466..27542bd0 100644
--- a/src/main/java/com/gitblit/wicket/pages/LogoutPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/LogoutPage.java
@@ -27,7 +27,7 @@ public class LogoutPage extends BasePage {
super();
GitBlitWebSession session = GitBlitWebSession.get();
UserModel user = session.getUser();
- app().session().logout(((WebResponse) getResponse()).getHttpServletResponse(), user);
+ app().authentication().logout(((WebResponse) getResponse()).getHttpServletResponse(), user);
session.invalidate();
/*
diff --git a/src/main/java/com/gitblit/wicket/pages/RootPage.java b/src/main/java/com/gitblit/wicket/pages/RootPage.java
index 1a43bf1e..9141b4e3 100644
--- a/src/main/java/com/gitblit/wicket/pages/RootPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/RootPage.java
@@ -252,7 +252,7 @@ public abstract class RootPage extends BasePage {
// Set Cookie
if (app().settings().getBoolean(Keys.web.allowCookieAuthentication, false)) {
WebResponse response = (WebResponse) getRequestCycle().getResponse();
- app().session().setCookie(response.getHttpServletResponse(), user);
+ app().authentication().setCookie(response.getHttpServletResponse(), user);
}
if (!session.continueRequest()) {
@@ -536,7 +536,7 @@ public abstract class RootPage extends BasePage {
String username = RootPage.this.username.getObject();
char[] password = RootPage.this.password.getObject().toCharArray();
- UserModel user = app().session().authenticate(username, password);
+ UserModel user = app().authentication().authenticate(username, password);
if (user == null) {
error(getString("gb.invalidUsernameOrPassword"));
} else if (user.username.equals(Constants.FEDERATION_USER)) {
@@ -572,7 +572,7 @@ public abstract class RootPage extends BasePage {
GitBlitWebSession session = GitBlitWebSession.get();
UserModel user = session.getUser();
- boolean editCredentials = app().users().supportsCredentialChanges(user);
+ boolean editCredentials = app().authentication().supportsCredentialChanges(user);
boolean standardLogin = session.authenticationType.isStandard();
if (app().settings().getBoolean(Keys.web.allowGravatar, true)) {
diff --git a/src/main/java/com/gitblit/wicket/pages/SessionPage.java b/src/main/java/com/gitblit/wicket/pages/SessionPage.java
index a10102f4..d2fcfa0d 100644
--- a/src/main/java/com/gitblit/wicket/pages/SessionPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/SessionPage.java
@@ -60,7 +60,7 @@ public abstract class SessionPage extends WebPage {
// try to authenticate by servlet request
HttpServletRequest httpRequest = ((WebRequest) getRequestCycle().getRequest())
.getHttpServletRequest();
- UserModel user = app().session().authenticate(httpRequest);
+ UserModel user = app().authentication().authenticate(httpRequest);
// Login the user
if (user != null) {
@@ -70,7 +70,7 @@ public abstract class SessionPage extends WebPage {
// Set Cookie
WebResponse response = (WebResponse) getRequestCycle().getResponse();
- app().session().setCookie(response.getHttpServletResponse(), user);
+ app().authentication().setCookie(response.getHttpServletResponse(), user);
session.continueRequest();
}
diff --git a/src/main/java/com/gitblit/wicket/panels/TeamsPanel.java b/src/main/java/com/gitblit/wicket/panels/TeamsPanel.java
index 79ddd02d..c1e1a43d 100644
--- a/src/main/java/com/gitblit/wicket/panels/TeamsPanel.java
+++ b/src/main/java/com/gitblit/wicket/panels/TeamsPanel.java
@@ -39,7 +39,7 @@ public class TeamsPanel extends BasePanel {
Fragment adminLinks = new Fragment("adminPanel", "adminLinks", this);
adminLinks.add(new BookmarkablePageLink<Void>("newTeam", EditTeamPage.class));
- add(adminLinks.setVisible(showAdmin && app().users().supportsTeamMembershipChanges(null)));
+ add(adminLinks.setVisible(showAdmin));
final List<TeamModel> teams = app().users().getAllTeams();
DataView<TeamModel> teamsView = new DataView<TeamModel>("teamRow",
diff --git a/src/main/java/com/gitblit/wicket/panels/UsersPanel.java b/src/main/java/com/gitblit/wicket/panels/UsersPanel.java
index 9c1667ff..ed990c89 100644
--- a/src/main/java/com/gitblit/wicket/panels/UsersPanel.java
+++ b/src/main/java/com/gitblit/wicket/panels/UsersPanel.java
@@ -39,8 +39,7 @@ public class UsersPanel extends BasePanel {
super(wicketId);
Fragment adminLinks = new Fragment("adminPanel", "adminLinks", this);
- adminLinks.add(new BookmarkablePageLink<Void>("newUser", EditUserPage.class)
- .setVisible(app().users().supportsAddUser()));
+ adminLinks.add(new BookmarkablePageLink<Void>("newUser", EditUserPage.class));
add(adminLinks.setVisible(showAdmin));
final List<UserModel> users = app().users().getAllUsers();