From 2654d99368054b7f8cfaec056b599cac4cfb53d9 Mon Sep 17 00:00:00 2001 From: James Moger <james.moger@gitblit.com> Date: Tue, 30 Sep 2014 09:48:27 -0400 Subject: [PATCH] Merge branch 'ticket/196' into develop --- src/main/java/com/gitblit/manager/AuthenticationManager.java | 169 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 138 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/gitblit/manager/AuthenticationManager.java b/src/main/java/com/gitblit/manager/AuthenticationManager.java index ad4a985..e41deeb 100644 --- a/src/main/java/com/gitblit/manager/AuthenticationManager.java +++ b/src/main/java/com/gitblit/manager/AuthenticationManager.java @@ -35,6 +35,7 @@ import com.gitblit.Constants; import com.gitblit.Constants.AccountType; import com.gitblit.Constants.AuthenticationType; +import com.gitblit.Constants.Role; import com.gitblit.IStoredSettings; import com.gitblit.Keys; import com.gitblit.auth.AuthenticationProvider; @@ -47,11 +48,14 @@ import com.gitblit.auth.WindowsAuthProvider; import com.gitblit.models.TeamModel; import com.gitblit.models.UserModel; +import com.gitblit.transport.ssh.SshKey; 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; +import com.google.inject.Inject; +import com.google.inject.Singleton; /** * The authentication manager handles user login & logout. @@ -59,6 +63,7 @@ * @author James Moger * */ +@Singleton public class AuthenticationManager implements IAuthenticationManager { private final Logger logger = LoggerFactory.getLogger(getClass()); @@ -75,6 +80,7 @@ private final Map<String, String> legacyRedirects; + @Inject public AuthenticationManager( IRuntimeManager runtimeManager, IUserManager userManager) { @@ -158,6 +164,10 @@ } } return this; + } + + public void addAuthenticationProvider(AuthenticationProvider prov) { + authenticationProviders.add(prov); } /** @@ -286,6 +296,37 @@ } /** + * Authenticate a user based on a public key. + * + * This implementation assumes that the authentication has already take place + * (e.g. SSHDaemon) and that this is a validation/verification of the user. + * + * @param username + * @param key + * @return a user object or null + */ + @Override + public UserModel authenticate(String username, SshKey key) { + if (username != null) { + if (!StringUtils.isEmpty(username)) { + UserModel user = userManager.getUserModel(username); + if (user != null) { + // existing user + logger.debug(MessageFormat.format("{0} authenticated by {1} public key", + user.username, key.getAlgorithm())); + return validateAuthentication(user, AuthenticationType.PUBLIC_KEY); + } + logger.warn(MessageFormat.format("Failed to find UserModel for {0} during public key authentication", + username)); + } + } else { + logger.warn("Empty user passed to AuthenticationManager.authenticate!"); + } + return null; + } + + + /** * This method allows the authentication manager to reject authentication * attempts. It is called after the username/secret have been verified to * ensure that the authentication technique has been logged. @@ -341,41 +382,52 @@ // try local authentication if (user != null && user.isLocalAccount()) { - 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 validateAuthentication(returnedUser, AuthenticationType.CREDENTIALS); + return authenticateLocal(user, password); } // 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 validateAuthentication(user, AuthenticationType.CREDENTIALS); - } + for (AuthenticationProvider provider : authenticationProviders) { + if (provider instanceof UsernamePasswordAuthenticationProvider) { + UserModel returnedUser = provider.authenticate(usernameDecoded, password); + if (returnedUser != null) { + // user authenticated + returnedUser.accountType = provider.getAccountType(); + return validateAuthentication(returnedUser, AuthenticationType.CREDENTIALS); } } } - return validateAuthentication(user, AuthenticationType.CREDENTIALS); + + // could not authenticate locally or with a provider + return null; + } + + /** + * Returns a UserModel if local authentication succeeds. + * + * @param user + * @param password + * @return a UserModel if local authentication succeeds, null otherwise + */ + protected UserModel authenticateLocal(UserModel user, char [] password) { + 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(user.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 validateAuthentication(returnedUser, AuthenticationType.CREDENTIALS); } /** @@ -407,7 +459,20 @@ * @param user */ @Override + @Deprecated public void setCookie(HttpServletResponse response, UserModel user) { + setCookie(null, response, user); + } + + /** + * Sets a cookie for the specified user. + * + * @param request + * @param response + * @param user + */ + @Override + public void setCookie(HttpServletRequest request, HttpServletResponse response, UserModel user) { if (settings.getBoolean(Keys.web.allowCookieAuthentication, true)) { GitBlitWebSession session = GitBlitWebSession.get(); boolean standardLogin = session.authenticationType.isStandard(); @@ -430,7 +495,13 @@ userCookie.setMaxAge((int) TimeUnit.DAYS.toSeconds(7)); } } - userCookie.setPath("/"); + String path = "/"; + if (request != null) { + if (!StringUtils.isEmpty(request.getContextPath())) { + path = request.getContextPath(); + } + } + userCookie.setPath(path); response.addCookie(userCookie); } } @@ -439,11 +510,25 @@ /** * Logout a user. * + * @param response * @param user */ @Override + @Deprecated public void logout(HttpServletResponse response, UserModel user) { - setCookie(response, null); + setCookie(null, response, null); + } + + /** + * Logout a user. + * + * @param request + * @param response + * @param user + */ + @Override + public void logout(HttpServletRequest request, HttpServletResponse response, UserModel user) { + setCookie(request, response, null); } /** @@ -501,6 +586,28 @@ return (team != null && team.isLocalTeam()) || findProvider(team).supportsTeamMembershipChanges(); } + /** + * Returns true if the user's role can be changed. + * + * @param user + * @return true if the user's role can be changed + */ + @Override + public boolean supportsRoleChanges(UserModel user, Role role) { + return (user != null && user.isLocalAccount()) || findProvider(user).supportsRoleChanges(user, role); + } + + /** + * Returns true if the team's role can be changed. + * + * @param user + * @return true if the team's role can be changed + */ + @Override + public boolean supportsRoleChanges(TeamModel team, Role role) { + return (team != null && team.isLocalTeam()) || findProvider(team).supportsRoleChanges(team, role); + } + protected AuthenticationProvider findProvider(UserModel user) { for (AuthenticationProvider provider : authenticationProviders) { if (provider.getAccountType().equals(user.accountType)) { -- Gitblit v1.9.1