Dariusz Bywalec
2016-01-04 db09ef1033ce4942ac1eb3cb684f232bf7e5e231
src/main/java/com/gitblit/manager/AuthenticationManager.java
@@ -41,6 +41,7 @@
import com.gitblit.auth.AuthenticationProvider;
import com.gitblit.auth.AuthenticationProvider.UsernamePasswordAuthenticationProvider;
import com.gitblit.auth.HtpasswdAuthProvider;
import com.gitblit.auth.HttpHeaderAuthProvider;
import com.gitblit.auth.LdapAuthProvider;
import com.gitblit.auth.PAMAuthProvider;
import com.gitblit.auth.RedmineAuthProvider;
@@ -92,6 +93,7 @@
      // map of shortcut provider names
      providerNames = new HashMap<String, Class<? extends AuthenticationProvider>>();
      providerNames.put("htpasswd", HtpasswdAuthProvider.class);
      providerNames.put("httpheader", HttpHeaderAuthProvider.class);
      providerNames.put("ldap", LdapAuthProvider.class);
      providerNames.put("pam", PAMAuthProvider.class);
      providerNames.put("redmine", RedmineAuthProvider.class);
@@ -170,7 +172,11 @@
   }
   /**
    * Authenticate a user based on HTTP request parameters.
    * Used to handle authentication for page requests.
    *
    * This allows authentication to occur based on the contents of the request
    * itself. If no configured @{AuthenticationProvider}s authenticate succesffully,
    * a request for login will be shown.
    *
    * Authentication by X509Certificate is tried first and then by cookie.
    *
@@ -185,7 +191,7 @@
   /**
    * Authenticate a user based on HTTP request parameters.
    *
    * Authentication by servlet container principal, X509Certificate, cookie,
    * Authentication by custom HTTP header, servlet container principal, X509Certificate, cookie,
    * and finally BASIC header.
    *
    * @param httpRequest
@@ -194,6 +200,14 @@
    */
   @Override
   public UserModel authenticate(HttpServletRequest httpRequest, boolean requiresCertificate) {
      // Check if this request has already been authenticated, and trust that instead of re-processing
      String reqAuthUser = (String) httpRequest.getAttribute(Constants.ATTRIB_AUTHUSER);
      if (!StringUtils.isEmpty(reqAuthUser)) {
         logger.debug("Called servlet authenticate when request is already authenticated.");
         return userManager.getUserModel(reqAuthUser);
      }
      // try to authenticate by servlet container principal
      if (!requiresCertificate) {
         Principal principal = httpRequest.getUserPrincipal();
@@ -204,7 +218,7 @@
               UserModel user = userManager.getUserModel(username);
               if (user != null) {
                  // existing user
                  flagSession(httpRequest, AuthenticationType.CONTAINER);
                  flagRequest(httpRequest, AuthenticationType.CONTAINER, user.username);
                  logger.debug(MessageFormat.format("{0} authenticated by servlet container principal from {1}",
                        user.username, httpRequest.getRemoteAddr()));
                  return validateAuthentication(user, AuthenticationType.CONTAINER);
@@ -239,7 +253,7 @@
                  }
                  
                  userManager.updateUserModel(user);
                  flagSession(httpRequest, AuthenticationType.CONTAINER);
                  flagRequest(httpRequest, AuthenticationType.CONTAINER, user.username);
                  logger.debug(MessageFormat.format("{0} authenticated and created by servlet container principal from {1}",
                        user.username, httpRequest.getRemoteAddr()));
                  return validateAuthentication(user, AuthenticationType.CONTAINER);
@@ -260,7 +274,7 @@
         UserModel user = userManager.getUserModel(model.username);
         X509Metadata metadata = HttpUtils.getCertificateMetadata(httpRequest);
         if (user != null) {
            flagSession(httpRequest, AuthenticationType.CERTIFICATE);
            flagRequest(httpRequest, AuthenticationType.CERTIFICATE, user.username);
            logger.debug(MessageFormat.format("{0} authenticated by client certificate {1} from {2}",
                  user.username, metadata.serialNumber, httpRequest.getRemoteAddr()));
            return validateAuthentication(user, AuthenticationType.CERTIFICATE);
@@ -282,7 +296,7 @@
      if (!StringUtils.isEmpty(cookie)) {
         user = userManager.getUserModel(cookie.toCharArray());
         if (user != null) {
            flagSession(httpRequest, AuthenticationType.COOKIE);
            flagRequest(httpRequest, AuthenticationType.COOKIE, user.username);
            logger.debug(MessageFormat.format("{0} authenticated by cookie from {1}",
               user.username, httpRequest.getRemoteAddr()));
            return validateAuthentication(user, AuthenticationType.COOKIE);
@@ -302,16 +316,25 @@
         if (values.length == 2) {
            String username = values[0];
            char[] password = values[1].toCharArray();
            user = authenticate(username, password);
            user = authenticate(username, password, httpRequest.getRemoteAddr());
            if (user != null) {
               flagSession(httpRequest, AuthenticationType.CREDENTIALS);
               flagRequest(httpRequest, AuthenticationType.CREDENTIALS, user.username);
               logger.debug(MessageFormat.format("{0} authenticated by BASIC request header from {1}",
                     user.username, httpRequest.getRemoteAddr()));
               return validateAuthentication(user, AuthenticationType.CREDENTIALS);
            } else {
               logger.warn(MessageFormat.format("Failed login attempt for {0}, invalid credentials from {1}",
                     username, httpRequest.getRemoteAddr()));
            }
         }
      }
      // Check each configured AuthenticationProvider
      for (AuthenticationProvider ap : authenticationProviders) {
         UserModel authedUser = ap.authenticate(httpRequest);
         if (null != authedUser) {
            flagRequest(httpRequest, ap.getAuthenticationType(), authedUser.username);
            logger.debug(MessageFormat.format("{0} authenticated by {1} from {2} for {3}",
                  authedUser.username, ap.getServiceName(), httpRequest.getRemoteAddr(),
                  httpRequest.getPathInfo()));
            return validateAuthentication(authedUser, ap.getAuthenticationType());
         }
      }
      return null;
@@ -374,6 +397,35 @@
   /**
    * Return the UserModel for already authenticated user.
    *
    * 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
    * @return a user object or null
    */
   @Override
   public UserModel authenticate(String username) {
      if (username != null) {
         if (!StringUtils.isEmpty(username)) {
            UserModel user = userManager.getUserModel(username);
            if (user != null) {
               // existing user
               logger.debug(MessageFormat.format("{0} authenticated externally", user.username));
               return validateAuthentication(user, AuthenticationType.CONTAINER);
            }
            logger.warn(MessageFormat.format("Failed to find UserModel for {0} during external 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.
@@ -394,8 +446,9 @@
      return user;
   }
   protected void flagSession(HttpServletRequest httpRequest, AuthenticationType authenticationType) {
      httpRequest.getSession().setAttribute(Constants.AUTHENTICATION_TYPE, authenticationType);
   protected void flagRequest(HttpServletRequest httpRequest, AuthenticationType authenticationType, String authedUsername) {
      httpRequest.setAttribute(Constants.ATTRIB_AUTHUSER,  authedUsername);
      httpRequest.setAttribute(Constants.ATTRIB_AUTHTYPE,  authenticationType);
   }
   /**
@@ -407,7 +460,7 @@
    * @return a user object or null
    */
   @Override
   public UserModel authenticate(String username, char[] password) {
   public UserModel authenticate(String username, char[] password, String remoteIP) {
      if (StringUtils.isEmpty(username)) {
         // can not authenticate empty username
         return null;
@@ -424,22 +477,29 @@
      // try local authentication
      if (user != null && user.isLocalAccount()) {
         return authenticateLocal(user, password);
      }
      // try registered external authentication providers
      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);
         UserModel returnedUser = authenticateLocal(user, password);
         if (returnedUser != null) {
            // user authenticated
            return returnedUser;
         }
      } else {
         // try registered external authentication providers
         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
      logger.warn(MessageFormat.format("Failed login attempt for {0}, invalid credentials from {1}", username,
            remoteIP != null ? remoteIP : "unknown"));
      return null;
   }
@@ -516,9 +576,15 @@
   @Override
   public void setCookie(HttpServletRequest request, HttpServletResponse response, UserModel user) {
      if (settings.getBoolean(Keys.web.allowCookieAuthentication, true)) {
         HttpSession session = request.getSession();
         AuthenticationType authenticationType = (AuthenticationType) session.getAttribute(Constants.AUTHENTICATION_TYPE);
         boolean standardLogin = authenticationType.isStandard();
         boolean standardLogin = true;
         if (null != request) {
            // Pull the auth type from the request, it is set there if container managed
            AuthenticationType authenticationType = (AuthenticationType) request.getAttribute(Constants.ATTRIB_AUTHTYPE);
            if (null != authenticationType)
               standardLogin = authenticationType.isStandard();
         }
         if (standardLogin) {
            Cookie userCookie;