src/main/java/com/gitblit/ConfigUserService.java
@@ -35,6 +35,7 @@ import org.slf4j.LoggerFactory; import com.gitblit.Constants.AccessPermission; import com.gitblit.Constants.AccountType; import com.gitblit.manager.IRuntimeManager; import com.gitblit.models.TeamModel; import com.gitblit.models.UserModel; @@ -486,7 +487,7 @@ * @return list of all usernames that can bypass the access restriction */ @Override public synchronized List<String> getTeamnamesForRepositoryRole(String role) { public synchronized List<String> getTeamNamesForRepositoryRole(String role) { List<String> list = new ArrayList<String>(); try { read(); @@ -1111,4 +1112,9 @@ public String toString() { return getClass().getSimpleName() + "(" + realmFile.getAbsolutePath() + ")"; } @Override public AccountType getAccountType() { return AccountType.LOCAL; } } src/main/java/com/gitblit/DaggerModule.java
@@ -30,6 +30,7 @@ import com.gitblit.manager.IUserManager; import com.gitblit.manager.NotificationManager; import com.gitblit.manager.RuntimeManager; import com.gitblit.manager.UserManager; import com.gitblit.wicket.GitBlitWebApp; import com.gitblit.wicket.GitblitWicketFilter; @@ -100,8 +101,8 @@ return new NotificationManager(settings); } @Provides @Singleton IUserManager provideUserManager() { return gitblit; @Provides @Singleton IUserManager provideUserManager(IRuntimeManager runtimeManager) { return new UserManager(runtimeManager); } @Provides @Singleton ISessionManager provideSessionManager() { src/main/java/com/gitblit/GitBlit.java
@@ -80,7 +80,6 @@ import com.gitblit.Constants.AccessPermission; import com.gitblit.Constants.AccessRestrictionType; import com.gitblit.Constants.AccountType; import com.gitblit.Constants.AuthenticationType; import com.gitblit.Constants.AuthorizationControl; import com.gitblit.Constants.CommitMessageRenderer; @@ -162,8 +161,7 @@ */ @WebListener public class GitBlit extends DaggerContextListener implements IUserManager, ISessionManager, implements ISessionManager, IRepositoryManager, IProjectManager, IFederationManager, @@ -202,8 +200,6 @@ private File repositoriesFolder; private IUserService userService; private IStoredSettings settings; private LuceneExecutor luceneExecutor; @@ -221,13 +217,6 @@ public GitBlit() { this.goSettings = null; this.goBaseFolder = null; } protected GitBlit(final IUserService userService) { this.goSettings = null; this.goBaseFolder = null; this.userService = userService; gitblit = this; } public GitBlit(IStoredSettings settings, File baseFolder) { @@ -335,7 +324,7 @@ if (user == null) { user = UserModel.ANONYMOUS; } String username = encodeUsername(UserModel.ANONYMOUS.equals(user) ? "" : user.username); String username = StringUtils.encodeUsername(UserModel.ANONYMOUS.equals(user) ? "" : user.username); List<RepositoryUrl> list = new ArrayList<RepositoryUrl>(); // http/https url @@ -486,75 +475,6 @@ } /** * Set the user service. The user service authenticates all users and is * responsible for managing user permissions. * * @param userService */ public void setUserService(IUserService userService) { logger.info("Setting up user service " + userService.toString()); this.userService = userService; this.userService.setup(getManager(IRuntimeManager.class)); } @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(); } /** * Returns true if the username represents an internal account * * @param username @@ -580,7 +500,7 @@ // can not authenticate empty username return null; } String usernameDecoded = decodeUsername(username); String usernameDecoded = StringUtils.decodeUsername(username); String pw = new String(password); if (StringUtils.isEmpty(pw)) { // can not authenticate empty password @@ -598,10 +518,7 @@ } // delegate authentication to the user service if (userService == null) { return null; } return userService.authenticate(usernameDecoded, password); return getManager(IUserManager.class).authenticate(usernameDecoded, password); } /** @@ -611,15 +528,12 @@ * @return a user object or null */ protected UserModel authenticate(Cookie[] cookies) { if (userService == null) { return null; } if (userService.supportsCookies()) { if (getManager(IUserManager.class).supportsCookies()) { if (cookies != null && cookies.length > 0) { for (Cookie cookie : cookies) { if (cookie.getName().equals(Constants.NAME)) { String value = cookie.getValue(); return userService.authenticate(value.toCharArray()); return getManager(IUserManager.class).authenticate(value.toCharArray()); } } } @@ -658,7 +572,7 @@ UserModel model = HttpUtils.getUserModelFromCertificate(httpRequest, checkValidity, oids); if (model != null) { // grab real user model and preserve certificate serial number UserModel user = getUserModel(model.username); UserModel user = getManager(IUserManager.class).getUserModel(model.username); X509Metadata metadata = HttpUtils.getCertificateMetadata(httpRequest); if (user != null) { flagWicketSession(AuthenticationType.CERTIFICATE); @@ -682,7 +596,7 @@ String username = principal.getName(); if (!StringUtils.isEmpty(username)) { boolean internalAccount = isInternalAccount(username); UserModel user = getUserModel(username); UserModel user = getManager(IUserManager.class).getUserModel(username); if (user != null) { // existing user flagWicketSession(AuthenticationType.CONTAINER); @@ -695,7 +609,7 @@ user = new UserModel(username.toLowerCase()); user.displayName = username; user.password = Constants.EXTERNAL_ACCOUNT; userService.updateUserModel(user); getManager(IUserManager.class).updateUserModel(user); flagWicketSession(AuthenticationType.CONTAINER); logger.debug(MessageFormat.format("{0} authenticated and created by servlet container principal from {1}", user.username, httpRequest.getRemoteAddr())); @@ -708,7 +622,7 @@ } // try to authenticate by cookie if (supportsCookies()) { if (getManager(IUserManager.class).supportsCookies()) { UserModel user = authenticate(httpRequest.getCookies()); if (user != null) { flagWicketSession(AuthenticationType.COOKIE); @@ -774,20 +688,17 @@ */ @Override public void setCookie(HttpServletResponse response, UserModel user) { if (userService == null) { return; } GitBlitWebSession session = GitBlitWebSession.get(); boolean standardLogin = session.authenticationType.isStandard(); if (userService.supportsCookies() && standardLogin) { if (getManager(IUserManager.class).supportsCookies() && standardLogin) { Cookie userCookie; if (user == null) { // clear cookie for logout userCookie = new Cookie(Constants.NAME, ""); } else { // set cookie for login String cookie = userService.getCookie(user); String cookie = getManager(IUserManager.class).getCookie(user); if (StringUtils.isEmpty(cookie)) { // create empty cookie userCookie = new Cookie(Constants.NAME, ""); @@ -802,102 +713,12 @@ } } /** * Logout a user. * * @param user */ @Override public void logout(UserModel user) { if (userService == null) { return; } userService.logout(user); } /** * Encode the username for user in an url. * * @param name * @return the encoded name */ protected String encodeUsername(String name) { return name.replace("@", "%40").replace(" ", "%20").replace("\\", "%5C"); } /** * Decode a username from an encoded url. * * @param name * @return the decoded name */ protected String decodeUsername(String name) { return name.replace("%40", "@").replace("%20", " ").replace("%5C", "\\"); } /** * Returns the list of all users available to the login service. * * @see IUserService.getAllUsernames() * @return list of all usernames */ @Override public List<String> getAllUsernames() { List<String> names = new ArrayList<String>(userService.getAllUsernames()); return names; } /** * Returns the list of all users available to the login service. * * @see IUserService.getAllUsernames() * @return list of all usernames */ @Override public List<UserModel> getAllUsers() { List<UserModel> users = userService.getAllUsers(); return users; } /** * Delete the user object with the specified username * * @see IUserService.deleteUser(String) * @param username * @return true if successful */ @Override public boolean deleteUser(String username) { if (StringUtils.isEmpty(username)) { return false; } String usernameDecoded = decodeUsername(username); return userService.deleteUser(usernameDecoded); } @Override public UserModel getFederationUser() { // the federation user is an administrator UserModel federationUser = new UserModel(Constants.FEDERATION_USER); federationUser.canAdmin = true; return federationUser; } /** * Retrieve the user object for the specified username. * * @see IUserService.getUserModel(String) * @param username * @return a user object or null */ @Override public UserModel getUserModel(String username) { if (StringUtils.isEmpty(username)) { return null; } String usernameDecoded = decodeUsername(username); UserModel user = userService.getUserModel(usernameDecoded); return user; } /** @@ -965,7 +786,7 @@ return list; } // NAMED users and teams for (UserModel user : userService.getAllUsers()) { for (UserModel user : getManager(IUserManager.class).getAllUsers()) { RegistrantAccessPermission ap = user.getRepositoryPermission(repository); if (ap.permission.exceeds(AccessPermission.NONE)) { list.add(ap); @@ -987,12 +808,12 @@ for (RegistrantAccessPermission up : permissions) { if (up.mutable) { // only set editable defined permissions UserModel user = userService.getUserModel(up.registrant); UserModel user = getManager(IUserManager.class).getUserModel(up.registrant); user.setRepositoryPermission(repository.name, up.permission); users.add(user); } } return userService.updateUserModels(users); return getManager(IUserManager.class).updateUserModels(users); } /** @@ -1005,7 +826,7 @@ */ @Override public List<String> getRepositoryUsers(RepositoryModel repository) { return userService.getUsernamesForRepositoryRole(repository.name); return getManager(IUserManager.class).getUsernamesForRepositoryRole(repository.name); } /** @@ -1038,7 +859,7 @@ public void updateUserModel(String username, UserModel user, boolean isCreate) throws GitBlitException { if (!username.equalsIgnoreCase(user.username)) { if (userService.getUserModel(user.username) != null) { if (getManager(IUserManager.class).getUserModel(user.username) != null) { throw new GitBlitException(MessageFormat.format( "Failed to rename ''{0}'' because ''{1}'' already exists.", username, user.username)); @@ -1060,43 +881,9 @@ } } } if (!userService.updateUserModel(username, user)) { if (!getManager(IUserManager.class).updateUserModel(username, user)) { throw new GitBlitException(isCreate ? "Failed to add user!" : "Failed to update user!"); } } /** * Returns the list of available teams that a user or repository may be * assigned to. * * @return the list of teams */ public List<String> getAllTeamnames() { List<String> teams = new ArrayList<String>(userService.getAllTeamNames()); return teams; } /** * Returns the list of available teams that a user or repository may be * assigned to. * * @return the list of teams */ @Override public List<TeamModel> getAllTeams() { List<TeamModel> teams = userService.getAllTeams(); return teams; } /** * Returns the TeamModel object for the specified name. * * @param teamname * @return a TeamModel object or null */ @Override public TeamModel getTeamModel(String teamname) { return userService.getTeamModel(teamname); } /** @@ -1110,7 +897,7 @@ @Override public List<RegistrantAccessPermission> getTeamAccessPermissions(RepositoryModel repository) { List<RegistrantAccessPermission> list = new ArrayList<RegistrantAccessPermission>(); for (TeamModel team : userService.getAllTeams()) { for (TeamModel team : getManager(IUserManager.class).getAllTeams()) { RegistrantAccessPermission ap = team.getRepositoryPermission(repository); if (ap.permission.exceeds(AccessPermission.NONE)) { list.add(ap); @@ -1133,12 +920,12 @@ for (RegistrantAccessPermission tp : permissions) { if (tp.mutable) { // only set explicitly defined access permissions TeamModel team = userService.getTeamModel(tp.registrant); TeamModel team = getManager(IUserManager.class).getTeamModel(tp.registrant); team.setRepositoryPermission(repository.name, tp.permission); teams.add(team); } } return userService.updateTeamModels(teams); return getManager(IUserManager.class).updateTeamModels(teams); } /** @@ -1151,7 +938,7 @@ */ @Override public List<String> getRepositoryTeams(RepositoryModel repository) { return userService.getTeamnamesForRepositoryRole(repository.name); return getManager(IUserManager.class).getTeamNamesForRepositoryRole(repository.name); } /** @@ -1181,27 +968,15 @@ public void updateTeamModel(String teamname, TeamModel team, boolean isCreate) throws GitBlitException { if (!teamname.equalsIgnoreCase(team.name)) { if (userService.getTeamModel(team.name) != null) { if (getManager(IUserManager.class).getTeamModel(team.name) != null) { throw new GitBlitException(MessageFormat.format( "Failed to rename ''{0}'' because ''{1}'' already exists.", teamname, team.name)); } } if (!userService.updateTeamModel(teamname, team)) { if (!getManager(IUserManager.class).updateTeamModel(teamname, team)) { throw new GitBlitException(isCreate ? "Failed to add team!" : "Failed to update team!"); } } /** * Delete the team object with the specified teamname * * @see IUserService.deleteTeam(String) * @param teamname * @return true if successful */ @Override public boolean deleteTeam(String teamname) { return userService.deleteTeam(teamname); } /** @@ -1519,7 +1294,7 @@ @Override public long getStarCount(RepositoryModel repository) { long count = 0; for (UserModel user : getAllUsers()) { for (UserModel user : getManager(IUserManager.class).getAllUsers()) { if (user.getPreferences().isStarredRepository(repository.name)) { count++; } @@ -1680,7 +1455,7 @@ if (project == null) { project = new ProjectModel(name); if (ModelUtils.isPersonalRepository(name)) { UserModel user = getUserModel(ModelUtils.getUserNameFromRepoPath(name)); UserModel user = getManager(IUserManager.class).getUserModel(ModelUtils.getUserNameFromRepoPath(name)); if (user != null) { project.title = user.getDisplayName(); project.description = "personal repositories"; @@ -2297,7 +2072,7 @@ repository.name)); } // rename the roles if (!userService.renameRepositoryRole(repositoryName, repository.name)) { if (!getManager(IUserManager.class).renameRepositoryRole(repositoryName, repository.name)) { throw new GitBlitException(MessageFormat.format( "Failed to rename repository permissions ''{0}'' to ''{1}''.", repositoryName, repository.name)); @@ -2514,7 +2289,7 @@ File folder = new File(repositoriesFolder, repositoryName); if (folder.exists() && folder.isDirectory()) { FileUtils.delete(folder, FileUtils.RECURSIVE | FileUtils.RETRY); if (userService.deleteRepositoryRole(repositoryName)) { if (getManager(IUserManager.class).deleteRepositoryRole(repositoryName)) { logger.info(MessageFormat.format("Repository \"{0}\" deleted", repositoryName)); return true; } @@ -3046,8 +2821,8 @@ // Team Scripts if (repository != null) { for (String teamname : userService.getTeamnamesForRepositoryRole(repository.name)) { TeamModel team = userService.getTeamModel(teamname); for (String teamname : getManager(IUserManager.class).getTeamNamesForRepositoryRole(repository.name)) { TeamModel team = getManager(IUserManager.class).getTeamModel(teamname); if (!ArrayUtils.isEmpty(team.preReceiveScripts)) { scripts.addAll(team.preReceiveScripts); } @@ -3100,8 +2875,8 @@ } // Team Scripts if (repository != null) { for (String teamname : userService.getTeamnamesForRepositoryRole(repository.name)) { TeamModel team = userService.getTeamModel(teamname); for (String teamname : getManager(IUserManager.class).getTeamNamesForRepositoryRole(repository.name)) { TeamModel team = getManager(IUserManager.class).getTeamModel(teamname); if (!ArrayUtils.isEmpty(team.postReceiveScripts)) { scripts.addAll(team.postReceiveScripts); } @@ -3156,10 +2931,14 @@ * @return Map<String, SettingModel> */ private ServerSettings loadSettingModels(ServerSettings settingsModel) { settingsModel.supportsCredentialChanges = userService.supportsCredentialChanges(); settingsModel.supportsDisplayNameChanges = userService.supportsDisplayNameChanges(); settingsModel.supportsEmailAddressChanges = userService.supportsEmailAddressChanges(); settingsModel.supportsTeamMembershipChanges = userService.supportsTeamMembershipChanges(); // this entire "supports" concept will go away with user service refactoring UserModel externalUser = new UserModel(Constants.EXTERNAL_ACCOUNT); externalUser.password = Constants.EXTERNAL_ACCOUNT; IUserManager userManager = getManager(IUserManager.class); 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 @@ -3321,7 +3100,7 @@ Gitblit gitblit = new Gitblit( getManager(IRuntimeManager.class), getManager(INotificationManager.class), this, getManager(IUserManager.class), this, this, this, @@ -3430,6 +3209,7 @@ runtime.getStatus().servletContainer = context.getServerInfo(); startManager(injector, INotificationManager.class); startManager(injector, IUserManager.class); repositoriesFolder = getRepositoriesFolder(); @@ -3452,19 +3232,6 @@ if (runtimeSettings.getBoolean(Keys.git.cacheRepositoryList, true)) { logger.info("Identifying available repositories..."); getRepositoryList(); } if (this.userService == null) { String realm = runtimeSettings.getString(Keys.realm.userService, "${baseFolder}/users.properties"); IUserService loginService = null; try { // check to see if this "file" is a login service class Class<?> realmClass = Class.forName(realm); loginService = (IUserService) realmClass.newInstance(); } catch (Throwable t) { loginService = new GitblitUserService(); } setUserService(loginService); } loadSettingModels(runtime.getSettingsModel()); @@ -3747,7 +3514,7 @@ // add the owner of the source repository to the clone's access list if (!ArrayUtils.isEmpty(repository.owners)) { for (String owner : repository.owners) { UserModel originOwner = getUserModel(owner); UserModel originOwner = getManager(IUserManager.class).getUserModel(owner); if (originOwner != null) { originOwner.setRepositoryPermission(cloneName, AccessPermission.CLONE); updateUserModel(originOwner.username, originOwner, false); @@ -3760,7 +3527,7 @@ List<UserModel> cloneUsers = new ArrayList<UserModel>(); for (String name : users) { if (!name.equalsIgnoreCase(user.username)) { UserModel cloneUser = getUserModel(name); UserModel cloneUser = getManager(IUserManager.class).getUserModel(name); if (cloneUser.canClone(repository)) { // origin user can clone origin, grant clone access to fork cloneUser.setRepositoryPermission(cloneName, AccessPermission.CLONE); @@ -3768,116 +3535,30 @@ cloneUsers.add(cloneUser); } } userService.updateUserModels(cloneUsers); getManager(IUserManager.class).updateUserModels(cloneUsers); // grant origin's team list clone permission to fork List<String> teams = getRepositoryTeams(repository); List<TeamModel> cloneTeams = new ArrayList<TeamModel>(); for (String name : teams) { TeamModel cloneTeam = getTeamModel(name); TeamModel cloneTeam = getManager(IUserManager.class).getTeamModel(name); if (cloneTeam.canClone(repository)) { // origin team can clone origin, grant clone access to fork cloneTeam.setRepositoryPermission(cloneName, AccessPermission.CLONE); } cloneTeams.add(cloneTeam); } userService.updateTeamModels(cloneTeams); getManager(IUserManager.class).updateTeamModels(cloneTeams); // add this clone to the cached model addToCachedRepositoryList(cloneModel); return cloneModel; } /** * 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(); } @Override public String getCookie(UserModel model) { return userService.getCookie(model); } @Override public UserModel authenticate(char[] cookie) { return userService.authenticate(cookie); } @Override public boolean updateUserModel(UserModel model) { return userService.updateUserModel(model); } @Override public boolean updateUserModels(Collection<UserModel> models) { return userService.updateUserModels(models); } @Override public boolean updateUserModel(String username, UserModel model) { return userService.updateUserModel(username, model); } @Override public boolean deleteUserModel(UserModel model) { return userService.deleteUserModel(model); } @Override public List<String> getAllTeamNames() { return userService.getAllTeamNames(); } @Override public List<String> getTeamnamesForRepositoryRole(String role) { return userService.getTeamnamesForRepositoryRole(role); } @Override public boolean updateTeamModel(TeamModel model) { return userService.updateTeamModel(model); } @Override public boolean updateTeamModels(Collection<TeamModel> models) { return userService.updateTeamModels(models); } @Override public boolean updateTeamModel(String teamname, TeamModel model) { return userService.updateTeamModel(teamname, model); } @Override public boolean deleteTeamModel(TeamModel model) { return userService.deleteTeamModel(model); } @Override public List<String> getUsernamesForRepositoryRole(String role) { return userService.getUsernamesForRepositoryRole(role); } @Override public boolean renameRepositoryRole(String oldRole, String newRole) { return userService.renameRepositoryRole(oldRole, newRole); } @Override public boolean deleteRepositoryRole(String role) { return userService.deleteRepositoryRole(role); } @Override public void logout(HttpServletResponse response, UserModel user) { setCookie(response, null); userService.logout(user); getManager(IUserManager.class).logout(user); } @Override src/main/java/com/gitblit/Gitblit.java
@@ -348,8 +348,8 @@ } @Override public List<String> getTeamnamesForRepositoryRole(String role) { return userManager.getTeamnamesForRepositoryRole(role); public List<String> getTeamNamesForRepositoryRole(String role) { return userManager.getTeamNamesForRepositoryRole(role); } @Override src/main/java/com/gitblit/GitblitUserService.java
@@ -126,6 +126,12 @@ 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); @@ -226,8 +232,8 @@ } @Override public List<String> getTeamnamesForRepositoryRole(String role) { return serviceImpl.getTeamnamesForRepositoryRole(role); public List<String> getTeamNamesForRepositoryRole(String role) { return serviceImpl.getTeamNamesForRepositoryRole(role); } @Override @@ -312,7 +318,8 @@ } } protected AccountType getAccountType() { @Override public AccountType getAccountType() { return AccountType.LOCAL; } } src/main/java/com/gitblit/HtpasswdUserService.java
@@ -275,7 +275,7 @@ * @return AccountType.HTPASSWD */ @Override protected AccountType getAccountType() public AccountType getAccountType() { return AccountType.HTPASSWD; } src/main/java/com/gitblit/IUserService.java
@@ -18,6 +18,7 @@ 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; @@ -205,7 +206,7 @@ * @return list of all usernames that can bypass the access restriction * @since 0.8.0 */ List<String> getTeamnamesForRepositoryRole(String role); List<String> getTeamNamesForRepositoryRole(String role); /** * Sets the list of all teams who are allowed to bypass the access @@ -319,6 +320,14 @@ 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 */ src/main/java/com/gitblit/LdapUserService.java
@@ -262,7 +262,7 @@ } @Override protected AccountType getAccountType() { public AccountType getAccountType() { return AccountType.LDAP; } src/main/java/com/gitblit/PAMUserService.java
@@ -92,7 +92,7 @@ } @Override protected AccountType getAccountType() { public AccountType getAccountType() { return AccountType.PAM; } src/main/java/com/gitblit/RedmineUserService.java
@@ -91,7 +91,7 @@ } @Override protected AccountType getAccountType() { public AccountType getAccountType() { return AccountType.REDMINE; } src/main/java/com/gitblit/SalesforceUserService.java
@@ -22,7 +22,7 @@ private IStoredSettings settings; @Override protected AccountType getAccountType() { public AccountType getAccountType() { return AccountType.SALESFORCE; } src/main/java/com/gitblit/WindowsUserService.java
@@ -104,7 +104,7 @@ } @Override protected AccountType getAccountType() { public AccountType getAccountType() { return AccountType.WINDOWS; } src/main/java/com/gitblit/manager/IUserManager.java
@@ -21,7 +21,7 @@ import com.gitblit.models.TeamModel; import com.gitblit.models.UserModel; public interface IUserManager { public interface IUserManager extends IManager { boolean supportsAddUser(); @@ -189,7 +189,7 @@ * @return list of all usernames that can bypass the access restriction * @since 0.8.0 */ List<String> getTeamnamesForRepositoryRole(String role); List<String> getTeamNamesForRepositoryRole(String role); /** * Retrieve the team object for the specified team name. src/main/java/com/gitblit/manager/UserManager.java
New file @@ -0,0 +1,542 @@ /* * 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.io.File; import java.io.IOException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; import java.util.List; 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; /** * The user manager manages persistence and retrieval of users and teams. * * @author James Moger * */ public class UserManager implements IUserManager { private final Logger logger = LoggerFactory.getLogger(getClass()); private final IStoredSettings settings; private final IRuntimeManager runtimeManager; private IUserService userService; public UserManager(IRuntimeManager runtimeManager) { this.settings = runtimeManager.getSettings(); this.runtimeManager = runtimeManager; } /** * Set the user service. The user service authenticates local users and is * responsible for persisting and retrieving users and teams. * * @param userService */ public void setUserService(IUserService userService) { logger.info("Setting up user service " + userService.toString()); this.userService = userService; this.userService.setup(runtimeManager); } @Override public IManager setup() { if (this.userService == null) { String realm = settings.getString(Keys.realm.userService, "${baseFolder}/users.properties"); 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"); service = createUserService(realmFile); } setUserService(service); } return this; } 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 IManager stop() { 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. * * @param model * @return cookie value */ @Override public String getCookie(UserModel model) { return userService.getCookie(model); } /** * 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. * * @param cookie * @return a user object or null */ @Override public UserModel authenticate(char[] cookie) { UserModel user = userService.authenticate(cookie); setAccountType(user); 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 * @return a user object or null */ @Override public UserModel getUserModel(String username) { if (StringUtils.isEmpty(username)) { return null; } String usernameDecoded = StringUtils.decodeUsername(username); UserModel user = userService.getUserModel(usernameDecoded); setAccountType(user); return user; } /** * Updates/writes a complete user object. * * @param model * @return true if update is successful */ @Override public boolean updateUserModel(UserModel model) { return userService.updateUserModel(model); } /** * Updates/writes all specified user objects. * * @param models a list of user models * @return true if update is successful * @since 1.2.0 */ @Override public boolean updateUserModels(Collection<UserModel> models) { return userService.updateUserModels(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 */ @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; } /** * Deletes the user object from the user service. * * @param model * @return true if successful */ @Override public boolean deleteUserModel(UserModel model) { return userService.deleteUserModel(model); } /** * Delete the user object with the specified username * * @param username * @return true if successful */ @Override public boolean deleteUser(String username) { if (StringUtils.isEmpty(username)) { return false; } String usernameDecoded = StringUtils.decodeUsername(username); return userService.deleteUser(usernameDecoded); } /** * Returns the list of all users available to the login service. * * @return list of all usernames */ @Override public List<String> getAllUsernames() { List<String> names = new ArrayList<String>(userService.getAllUsernames()); return names; } /** * Returns the list of all users available to the login service. * * @return list of all users * @since 0.8.0 */ @Override public List<UserModel> getAllUsers() { List<UserModel> users = userService.getAllUsers(); for (UserModel user : users) { setAccountType(user); } return users; } /** * Returns the list of all teams available to the login service. * * @return list of all teams * @since 0.8.0 */ @Override public List<String> getAllTeamNames() { return userService.getAllTeamNames(); } /** * Returns the list of all teams available to the login service. * * @return list of all teams * @since 0.8.0 */ @Override public List<TeamModel> getAllTeams() { List<TeamModel> teams = userService.getAllTeams(); return teams; } /** * Returns the list of all teams who are allowed to bypass the access * restriction placed on the specified repository. * * @param role * the repository name * @return list of all teams that can bypass the access restriction * @since 0.8.0 */ @Override public List<String> getTeamNamesForRepositoryRole(String role) { return userService.getTeamNamesForRepositoryRole(role); } /** * Retrieve the team object for the specified team name. * * @param teamname * @return a team object or null * @since 0.8.0 */ @Override public TeamModel getTeamModel(String teamname) { return userService.getTeamModel(teamname); } /** * Updates/writes a complete team object. * * @param model * @return true if update is successful * @since 0.8.0 */ @Override public boolean updateTeamModel(TeamModel model) { return userService.updateTeamModel(model); } /** * Updates/writes all specified team objects. * * @param models a list of team models * @return true if update is successful * @since 1.2.0 */ @Override public boolean updateTeamModels(Collection<TeamModel> models) { return userService.updateTeamModels(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 */ @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); } /** * Deletes the team object from the user service. * * @param model * @return true if successful * @since 0.8.0 */ @Override public boolean deleteTeamModel(TeamModel model) { return userService.deleteTeamModel(model); } /** * Delete the team object with the specified teamname * * @param teamname * @return true if successful * @since 0.8.0 */ @Override public boolean deleteTeam(String teamname) { return userService.deleteTeam(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 */ @Override public List<String> getUsernamesForRepositoryRole(String role) { return userService.getUsernamesForRepositoryRole(role); } /** * Renames a repository role. * * @param oldRole * @param newRole * @return true if successful */ @Override public boolean renameRepositoryRole(String oldRole, String newRole) { return userService.renameRepositoryRole(oldRole, newRole); } /** * Removes a repository role from all users. * * @param role * @return true if successful */ @Override 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(); } } } } src/main/java/com/gitblit/utils/StringUtils.java
@@ -747,4 +747,25 @@ } return input.replace('\n',' ').replace('\r', ' ').trim(); } /** * Encode the username for user in an url. * * @param name * @return the encoded name */ public static String encodeUsername(String name) { return name.replace("@", "%40").replace(" ", "%20").replace("\\", "%5C"); } /** * Decode a username from an encoded url. * * @param name * @return the decoded name */ public static String decodeUsername(String name) { return name.replace("%40", "@").replace("%20", " ").replace("%5C", "\\"); } } src/test/java/de/akquinet/devops/GitBlit4UITests.java
@@ -9,7 +9,7 @@ private boolean luceneIndexingEnabled; public GitBlit4UITests(boolean luceneIndexingEnabled) { super(null); super(); this.luceneIndexingEnabled = luceneIndexingEnabled; }