From 9effe1630d97039b3e01cd9b58ed07e75be1d63c Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Mon, 25 Feb 2013 08:40:30 -0500
Subject: [PATCH] Merge pull request #75 from thefake/master

---
 src/com/gitblit/SyndicationFilter.java |  128 ++++++++++++++++++++++++++++++++++++++----
 1 files changed, 114 insertions(+), 14 deletions(-)

diff --git a/src/com/gitblit/SyndicationFilter.java b/src/com/gitblit/SyndicationFilter.java
index 68f383b..61bf225 100644
--- a/src/com/gitblit/SyndicationFilter.java
+++ b/src/com/gitblit/SyndicationFilter.java
@@ -15,30 +15,130 @@
  */
 package com.gitblit;
 
+import java.io.IOException;
+import java.text.MessageFormat;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
 import com.gitblit.Constants.AccessRestrictionType;
+import com.gitblit.models.ProjectModel;
 import com.gitblit.models.RepositoryModel;
 import com.gitblit.models.UserModel;
 
-public class SyndicationFilter extends AccessRestrictionFilter {
+/**
+ * The SyndicationFilter is an AuthenticationFilter which ensures that feed
+ * requests for projects or view-restricted repositories have proper authentication
+ * credentials and are authorized for the requested feed.
+ * 
+ * @author James Moger
+ * 
+ */
+public class SyndicationFilter extends AuthenticationFilter {
 
-	@Override
-	protected String extractRepositoryName(String url) {
+	/**
+	 * Extract the repository name from the url.
+	 * 
+	 * @param url
+	 * @return repository name
+	 */
+	protected String extractRequestedName(String url) {
+		if (url.indexOf('?') > -1) {
+			return url.substring(0, url.indexOf('?'));
+		}
 		return url;
 	}
 
+	/**
+	 * doFilter does the actual work of preprocessing the request to ensure that
+	 * the user may proceed.
+	 * 
+	 * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,
+	 *      javax.servlet.ServletResponse, javax.servlet.FilterChain)
+	 */
 	@Override
-	protected String getUrlRequestType(String url) {
-		return "RESTRICTED";
-	}
+	public void doFilter(final ServletRequest request, final ServletResponse response,
+			final FilterChain chain) throws IOException, ServletException {
 
-	@Override
-	protected boolean requiresAuthentication(RepositoryModel repository) {
-		return repository.accessRestriction.atLeast(AccessRestrictionType.VIEW);
-	}
+		HttpServletRequest httpRequest = (HttpServletRequest) request;
+		HttpServletResponse httpResponse = (HttpServletResponse) response;
 
-	@Override
-	protected boolean canAccess(RepositoryModel repository, UserModel user, String restrictedURL) {
-		return user.canAccessRepository(repository.name);
-	}
+		String fullUrl = getFullUrl(httpRequest);
+		String name = extractRequestedName(fullUrl);
 
+		ProjectModel project = GitBlit.self().getProjectModel(name);
+		RepositoryModel model = null;
+		
+		if (project == null) {
+			// try loading a repository model
+			model = GitBlit.self().getRepositoryModel(name);
+			if (model == null) {
+				// repository not found. send 404.
+				logger.info(MessageFormat.format("ARF: {0} ({1})", fullUrl,
+						HttpServletResponse.SC_NOT_FOUND));
+				httpResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
+				return;
+			}
+		}
+		
+		// Wrap the HttpServletRequest with the AccessRestrictionRequest which
+		// overrides the servlet container user principal methods.
+		// JGit requires either:
+		//
+		// 1. servlet container authenticated user
+		// 2. http.receivepack = true in each repository's config
+		//
+		// Gitblit must conditionally authenticate users per-repository so just
+		// enabling http.receivepack is insufficient.
+		AuthenticatedRequest authenticatedRequest = new AuthenticatedRequest(httpRequest);
+		UserModel user = getUser(httpRequest);
+		if (user != null) {
+			authenticatedRequest.setUser(user);
+		}
+
+		// BASIC authentication challenge and response processing
+		if (model != null) {
+			if (model.accessRestriction.atLeast(AccessRestrictionType.VIEW)) {
+				if (user == null) {
+					// challenge client to provide credentials. send 401.
+					if (GitBlit.isDebugMode()) {
+						logger.info(MessageFormat.format("ARF: CHALLENGE {0}", fullUrl));
+					}
+					httpResponse.setHeader("WWW-Authenticate", CHALLENGE);
+					httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
+					return;
+				} else {
+					// check user access for request
+					if (user.canView(model)) {
+						// authenticated request permitted.
+						// pass processing to the restricted servlet.
+						newSession(authenticatedRequest, httpResponse);
+						logger.info(MessageFormat.format("ARF: {0} ({1}) authenticated", fullUrl,
+								HttpServletResponse.SC_CONTINUE));
+						chain.doFilter(authenticatedRequest, httpResponse);
+						return;
+					}
+					// valid user, but not for requested access. send 403.
+					if (GitBlit.isDebugMode()) {
+						logger.info(MessageFormat.format("ARF: {0} forbidden to access {1}",
+								user.username, fullUrl));
+					}
+					httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
+					return;
+				}
+			}
+		}
+
+		if (GitBlit.isDebugMode()) {
+			logger.info(MessageFormat.format("ARF: {0} ({1}) unauthenticated", fullUrl,
+					HttpServletResponse.SC_CONTINUE));
+		}
+		// unauthenticated request permitted.
+		// pass processing to the restricted servlet.
+		chain.doFilter(authenticatedRequest, httpResponse);
+	}
 }

--
Gitblit v1.9.1