From ed552ba47c02779c270ffd62841d6d1048dade70 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Sun, 22 Nov 2015 14:37:16 -0500
Subject: [PATCH] Merge branch 'develop'

---
 src/main/java/com/gitblit/servlet/GitFilter.java |  104 +++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 91 insertions(+), 13 deletions(-)

diff --git a/src/main/java/com/gitblit/servlet/GitFilter.java b/src/main/java/com/gitblit/servlet/GitFilter.java
index bb3d321..27408f0 100644
--- a/src/main/java/com/gitblit/servlet/GitFilter.java
+++ b/src/main/java/com/gitblit/servlet/GitFilter.java
@@ -17,7 +17,9 @@
 
 import java.text.MessageFormat;
 
-import javax.servlet.FilterConfig;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
 import javax.servlet.http.HttpServletRequest;
 
 import com.gitblit.Constants.AccessRestrictionType;
@@ -25,12 +27,13 @@
 import com.gitblit.GitBlitException;
 import com.gitblit.IStoredSettings;
 import com.gitblit.Keys;
+import com.gitblit.manager.IAuthenticationManager;
 import com.gitblit.manager.IFederationManager;
+import com.gitblit.manager.IRepositoryManager;
+import com.gitblit.manager.IRuntimeManager;
 import com.gitblit.models.RepositoryModel;
 import com.gitblit.models.UserModel;
 import com.gitblit.utils.StringUtils;
-
-import dagger.ObjectGraph;
 
 /**
  * The GitFilter is an AccessRestrictionFilter which ensures that Git client
@@ -40,24 +43,34 @@
  * @author James Moger
  *
  */
+@Singleton
 public class GitFilter extends AccessRestrictionFilter {
 
 	protected static final String gitReceivePack = "/git-receive-pack";
 
 	protected static final String gitUploadPack = "/git-upload-pack";
-
+	
+	protected static final String gitLfs = "/info/lfs";
+	
 	protected static final String[] suffixes = { gitReceivePack, gitUploadPack, "/info/refs", "/HEAD",
-			"/objects" };
+			"/objects", gitLfs };
 
 	private IStoredSettings settings;
 
 	private IFederationManager federationManager;
 
-	@Override
-	protected void inject(ObjectGraph dagger, FilterConfig filterConfig) {
-		super.inject(dagger, filterConfig);
-		this.settings = dagger.get(IStoredSettings.class);
-		this.federationManager = dagger.get(IFederationManager.class);
+	@Inject
+	public GitFilter(
+			IStoredSettings settings,
+			IRuntimeManager runtimeManager,
+			IAuthenticationManager authenticationManager,
+			IRepositoryManager repositoryManager,
+			IFederationManager federationManager) {
+
+		super(runtimeManager, authenticationManager, repositoryManager);
+
+		this.settings = settings;
+		this.federationManager = federationManager;
 	}
 
 	/**
@@ -106,6 +119,8 @@
 				return gitReceivePack;
 			} else if (suffix.contains("?service=git-upload-pack")) {
 				return gitUploadPack;
+			} else if (suffix.startsWith(gitLfs)) {
+				return gitLfs;
 			} else {
 				return gitUploadPack;
 			}
@@ -134,7 +149,13 @@
 	 * @return true if the server allows repository creation on-push
 	 */
 	@Override
-	protected boolean isCreationAllowed() {
+	protected boolean isCreationAllowed(String action) {
+		
+		//Repository must already exist before large files can be deposited
+		if (action.equals(gitLfs)) {
+			return false;
+		}
+		
 		return settings.getBoolean(Keys.git.allowCreateOnPush, true);
 	}
 
@@ -146,9 +167,15 @@
 	 * @return true if the action may be performed
 	 */
 	@Override
-	protected boolean isActionAllowed(RepositoryModel repository, String action) {
+	protected boolean isActionAllowed(RepositoryModel repository, String action, String method) {
 		// the log here has been moved into ReceiveHook to provide clients with
 		// error messages
+		if (gitLfs.equals(action)) {
+			if (!method.matches("GET|POST|PUT|HEAD")) {
+				return false;
+			}
+		}
+		
 		return true;
 	}
 
@@ -162,16 +189,25 @@
 	 *
 	 * @param repository
 	 * @param action
+	 * @param method
 	 * @return true if authentication required
 	 */
 	@Override
-	protected boolean requiresAuthentication(RepositoryModel repository, String action) {
+	protected boolean requiresAuthentication(RepositoryModel repository, String action, String method) {
 		if (gitUploadPack.equals(action)) {
 			// send to client
 			return repository.accessRestriction.atLeast(AccessRestrictionType.CLONE);
 		} else if (gitReceivePack.equals(action)) {
 			// receive from client
 			return repository.accessRestriction.atLeast(AccessRestrictionType.PUSH);
+		} else if (gitLfs.equals(action)) {
+			
+			if (method.matches("GET|HEAD")) {
+				return repository.accessRestriction.atLeast(AccessRestrictionType.CLONE);
+			} else {
+				//NOTE: Treat POST as PUT as as without reading message type cannot determine 
+				return repository.accessRestriction.atLeast(AccessRestrictionType.PUSH);
+			}
 		}
 		return false;
 	}
@@ -220,6 +256,12 @@
 	@Override
 	protected RepositoryModel createRepository(UserModel user, String repository, String action) {
 		boolean isPush = !StringUtils.isEmpty(action) && gitReceivePack.equals(action);
+		
+		if (action.equals(gitLfs)) {
+			//Repository must already exist for any filestore actions
+			return null;
+		}
+		
 		if (isPush) {
 			if (user.canCreate(repository)) {
 				// user is pushing to a new repository
@@ -271,4 +313,40 @@
 		// repository could not be created or action was not a push
 		return null;
 	}
+	
+	/**
+	 * Git lfs action uses an alternative authentication header, 
+	 * 
+	 * @param action
+	 * @return
+	 */
+	@Override
+	protected String getAuthenticationHeader(String action) {
+
+		if (action.equals(gitLfs)) {
+			return "LFS-Authenticate";
+		}
+		
+		return super.getAuthenticationHeader(action);
+	}
+	
+	/**
+	 * Interrogates the request headers based on the action
+	 * @param action
+	 * @param request
+	 * @return
+	 */
+	@Override
+	protected boolean hasValidRequestHeader(String action,
+			HttpServletRequest request) {
+
+		if (action.equals(gitLfs) && request.getMethod().equals("POST")) {
+			if ( 	!hasContentInRequestHeader(request, "Accept", FilestoreServlet.GIT_LFS_META_MIME)
+				 || !hasContentInRequestHeader(request, "Content-Type", FilestoreServlet.GIT_LFS_META_MIME)) {
+				return false;
+			}				
+		}
+			
+		return super.hasValidRequestHeader(action, request);
+	}
 }

--
Gitblit v1.9.1