Paul Martin
2015-12-25 46f33f87750573713509fbdbd0fc2ae51dc12044
src/main/java/com/gitblit/servlet/AccessRestrictionFilter.java
@@ -17,6 +17,8 @@
import java.io.IOException;
import java.text.MessageFormat;
import java.util.Collections;
import java.util.Iterator;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
@@ -84,16 +86,17 @@
    *
    * @return true if the filter allows repository creation
    */
   protected abstract boolean isCreationAllowed();
   protected abstract boolean isCreationAllowed(String action);
   /**
    * Determine if the action may be executed on the repository.
    *
    * @param repository
    * @param action
    * @param method
    * @return true if the action may be performed
    */
   protected abstract boolean isActionAllowed(RepositoryModel repository, String action);
   protected abstract boolean isActionAllowed(RepositoryModel repository, String action, String method);
   /**
    * Determine if the repository requires authentication.
@@ -102,7 +105,7 @@
    * @param action
    * @return true if authentication required
    */
   protected abstract boolean requiresAuthentication(RepositoryModel repository, String action);
   protected abstract boolean requiresAuthentication(RepositoryModel repository, String action, String method);
   /**
    * Determine if the user can access the repository and perform the specified
@@ -126,7 +129,27 @@
   protected RepositoryModel createRepository(UserModel user, String repository, String action) {
      return null;
   }
   /**
    * Allows authentication header to be altered based on the action requested
    * Default is WWW-Authenticate
    * @param httpRequest
    * @param action
    * @return authentication type header
    */
   protected String getAuthenticationHeader(HttpServletRequest httpRequest, String action) {
      return "WWW-Authenticate";
   }
   /**
    * Allows request headers to be used as part of filtering
    * @param request
    * @return true (default) if headers are valid, false otherwise
    */
   protected boolean hasValidRequestHeader(String action, HttpServletRequest request) {
      return true;
   }
   /**
    * doFilter does the actual work of preprocessing the request to ensure that
    * the user may proceed.
@@ -143,6 +166,10 @@
      String fullUrl = getFullUrl(httpRequest);
      String repository = extractRepositoryName(fullUrl);
      if (StringUtils.isEmpty(repository)) {
         httpResponse.setStatus(HttpServletResponse.SC_BAD_REQUEST);
         return;
      }
      if (repositoryManager.isCollectingGarbage(repository)) {
         logger.info(MessageFormat.format("ARF: Rejecting request for {0}, busy collecting garbage!", repository));
@@ -159,13 +186,14 @@
      // Load the repository model
      RepositoryModel model = repositoryManager.getRepositoryModel(repository);
      if (model == null) {
         if (isCreationAllowed()) {
         if (isCreationAllowed(urlRequestType)) {
            if (user == null) {
               // challenge client to provide credentials for creation. send 401.
               if (runtimeManager.isDebugMode()) {
                  logger.info(MessageFormat.format("ARF: CREATE CHALLENGE {0}", fullUrl));
               }
               httpResponse.setHeader("WWW-Authenticate", CHALLENGE);
               httpResponse.setHeader(getAuthenticationHeader(httpRequest, urlRequestType), CHALLENGE);
               httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
               return;
            } else {
@@ -184,7 +212,7 @@
      }
      // Confirm that the action may be executed on the repository
      if (!isActionAllowed(model, urlRequestType)) {
      if (!isActionAllowed(model, urlRequestType, httpRequest.getMethod())) {
         logger.info(MessageFormat.format("ARF: action {0} on {1} forbidden ({2})",
               urlRequestType, model, HttpServletResponse.SC_FORBIDDEN));
         httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
@@ -206,13 +234,13 @@
      }
      // BASIC authentication challenge and response processing
      if (!StringUtils.isEmpty(urlRequestType) && requiresAuthentication(model, urlRequestType)) {
      if (!StringUtils.isEmpty(urlRequestType) && requiresAuthentication(model, urlRequestType,  httpRequest.getMethod())) {
         if (user == null) {
            // challenge client to provide credentials. send 401.
            if (runtimeManager.isDebugMode()) {
               logger.info(MessageFormat.format("ARF: CHALLENGE {0}", fullUrl));
            }
            httpResponse.setHeader("WWW-Authenticate", CHALLENGE);
            httpResponse.setHeader(getAuthenticationHeader(httpRequest, urlRequestType), CHALLENGE);
            httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
            return;
         } else {
@@ -221,8 +249,8 @@
               // authenticated request permitted.
               // pass processing to the restricted servlet.
               newSession(authenticatedRequest, httpResponse);
               logger.info(MessageFormat.format("ARF: {0} ({1}) authenticated", fullUrl,
                     HttpServletResponse.SC_CONTINUE));
               logger.info(MessageFormat.format("ARF: authenticated {0} to {1} ({2})", user.username,
                     fullUrl, HttpServletResponse.SC_CONTINUE));
               chain.doFilter(authenticatedRequest, httpResponse);
               return;
            }
@@ -244,4 +272,17 @@
      // pass processing to the restricted servlet.
      chain.doFilter(authenticatedRequest, httpResponse);
   }
   public static boolean hasContentInRequestHeader(HttpServletRequest request, String headerName, String content)
   {
      Iterator<String> headerItr = Collections.list(request.getHeaders(headerName)).iterator();
      while (headerItr.hasNext()) {
         if (headerItr.next().contains(content)) {
            return true;
         }
      }
      return false;
   }
}