From f76fee63ed9cb3a30d3c0c092d860b1cb93a481b Mon Sep 17 00:00:00 2001
From: Gerard Smyth <gerard.smyth@gmail.com>
Date: Thu, 08 May 2014 13:09:30 -0400
Subject: [PATCH] Updated the SyndicationServlet to provide an additional option to return details of the tags in the repository instead of the commits. This uses a new 'ot' request parameter to indicate the object type of the content to return, which can be ither TAG or COMMIT. If this is not provided, then COMMIT is assumed to maintain backwards compatability. If tags are returned, then the paging parameters, 'l' and 'pg' are still supported, but searching options are currently ignored.
---
src/main/java/com/gitblit/manager/AuthenticationManager.java | 189 ++++++++++++++++++++++++++++++++++-------------
1 files changed, 137 insertions(+), 52 deletions(-)
diff --git a/src/main/java/com/gitblit/manager/AuthenticationManager.java b/src/main/java/com/gitblit/manager/AuthenticationManager.java
index 8c66ce5..d1b1af0 100644
--- a/src/main/java/com/gitblit/manager/AuthenticationManager.java
+++ b/src/main/java/com/gitblit/manager/AuthenticationManager.java
@@ -22,6 +22,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.TimeUnit;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
@@ -46,6 +47,7 @@
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;
@@ -108,10 +110,10 @@
String realm = settings.getString(Keys.realm.userService, "${baseFolder}/users.conf");
if (legacyRedirects.containsKey(realm)) {
logger.warn("");
- logger.warn("#################################################################");
+ logger.warn(Constants.BORDER2);
logger.warn(" IUserService '{}' is obsolete!", realm);
logger.warn(" Please set '{}={}'", "realm.authenticationProviders", legacyRedirects.get(realm));
- logger.warn("#################################################################");
+ logger.warn(Constants.BORDER2);
logger.warn("");
// conditionally override specified authentication providers
@@ -149,7 +151,18 @@
@Override
public AuthenticationManager stop() {
+ for (AuthenticationProvider provider : authenticationProviders) {
+ try {
+ provider.stop();
+ } catch (Exception e) {
+ logger.error("Failed to stop " + provider.getClass().getSimpleName(), e);
+ }
+ }
return this;
+ }
+
+ public void addAuthenticationProvider(AuthenticationProvider prov) {
+ authenticationProviders.add(prov);
}
/**
@@ -190,7 +203,7 @@
flagWicketSession(AuthenticationType.CONTAINER);
logger.debug(MessageFormat.format("{0} authenticated by servlet container principal from {1}",
user.username, httpRequest.getRemoteAddr()));
- return user;
+ return validateAuthentication(user, AuthenticationType.CONTAINER);
} else if (settings.getBoolean(Keys.realm.container.autoCreateAccounts, false)
&& !internalAccount) {
// auto-create user from an authenticated container principal
@@ -202,7 +215,7 @@
flagWicketSession(AuthenticationType.CONTAINER);
logger.debug(MessageFormat.format("{0} authenticated and created by servlet container principal from {1}",
user.username, httpRequest.getRemoteAddr()));
- return user;
+ return validateAuthentication(user, AuthenticationType.CONTAINER);
} else if (!internalAccount) {
logger.warn(MessageFormat.format("Failed to find UserModel for {0}, attempted servlet container authentication from {1}",
principal.getName(), httpRequest.getRemoteAddr()));
@@ -223,7 +236,7 @@
flagWicketSession(AuthenticationType.CERTIFICATE);
logger.debug(MessageFormat.format("{0} authenticated by client certificate {1} from {2}",
user.username, metadata.serialNumber, httpRequest.getRemoteAddr()));
- return user;
+ return validateAuthentication(user, AuthenticationType.CERTIFICATE);
} else {
logger.warn(MessageFormat.format("Failed to find UserModel for {0}, attempted client certificate ({1}) authentication from {2}",
model.username, metadata.serialNumber, httpRequest.getRemoteAddr()));
@@ -235,13 +248,18 @@
return null;
}
+ UserModel user = 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}",
+ String cookie = getCookie(httpRequest);
+ if (!StringUtils.isEmpty(cookie)) {
+ user = userManager.getUserModel(cookie.toCharArray());
+ if (user != null) {
+ flagWicketSession(AuthenticationType.COOKIE);
+ logger.debug(MessageFormat.format("{0} authenticated by cookie from {1}",
user.username, httpRequest.getRemoteAddr()));
- return user;
+ return validateAuthentication(user, AuthenticationType.COOKIE);
+ }
}
// try to authenticate by BASIC
@@ -262,7 +280,7 @@
flagWicketSession(AuthenticationType.CREDENTIALS);
logger.debug(MessageFormat.format("{0} authenticated by BASIC request header from {1}",
user.username, httpRequest.getRemoteAddr()));
- return user;
+ return validateAuthentication(user, AuthenticationType.CREDENTIALS);
} else {
logger.warn(MessageFormat.format("Failed login attempt for {0}, invalid credentials from {1}",
username, httpRequest.getRemoteAddr()));
@@ -273,23 +291,55 @@
}
/**
- * Authenticate a user based on their cookie.
+ * Authenticate a user based on a public key.
*
- * @param cookies
+ * 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
*/
- 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());
- }
+ @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.
+ *
+ * @param user
+ * @return
+ */
+ protected UserModel validateAuthentication(UserModel user, AuthenticationType type) {
+ if (user == null) {
+ return null;
+ }
+ if (user.disabled) {
+ // user has been disabled
+ logger.warn("Rejected {} authentication attempt by disabled account \"{}\"",
+ type, user.username);
+ return null;
+ }
+ return user;
}
protected void flagWicketSession(AuthenticationType authenticationType) {
@@ -323,44 +373,78 @@
return null;
}
- // 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 local authentication
+ if (user != null && user.isLocalAccount()) {
+ 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 user;
+ 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);
+ }
+ }
+ }
+
+ // 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);
+ }
+
+ /**
+ * Returns the Gitlbit cookie in the request.
+ *
+ * @param request
+ * @return the Gitblit cookie for the request or null if not found
+ */
+ @Override
+ public String getCookie(HttpServletRequest request) {
+ if (settings.getBoolean(Keys.web.allowCookieAuthentication, true)) {
+ Cookie[] cookies = request.getCookies();
+ if (cookies != null && cookies.length > 0) {
+ for (Cookie cookie : cookies) {
+ if (cookie.getName().equals(Constants.NAME)) {
+ String value = cookie.getValue();
+ return value;
}
}
}
}
- return user;
+ return null;
}
/**
@@ -389,7 +473,8 @@
} else {
// create real cookie
userCookie = new Cookie(Constants.NAME, cookie);
- userCookie.setMaxAge(Integer.MAX_VALUE);
+ // expire the cookie in 7 days
+ userCookie.setMaxAge((int) TimeUnit.DAYS.toSeconds(7));
}
}
userCookie.setPath("/");
--
Gitblit v1.9.1