diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java index 3ff18e210e..7442aa8620 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/GitPermissionFilter.java @@ -73,6 +73,8 @@ public class GitPermissionFilter extends ProviderPermissionFilter /** Field description */ public static final String URI_REF_INFO = "/info/refs"; + + public static final String METHOD_LFS_UPLOAD = "PUT"; //~--- constructors --------------------------------------------------------- @@ -129,21 +131,23 @@ public class GitPermissionFilter extends ProviderPermissionFilter */ @Override protected boolean isWriteRequest(HttpServletRequest request) { - - String uri = request.getRequestURI(); - - return uri.endsWith(URI_RECEIVE_PACK) || - (uri.endsWith(URI_REF_INFO) && PARAMETER_VALUE_RECEIVE.equals(request.getParameter(PARAMETER_SERVICE))) || - isLfsFileUpload(request); - + return isReceivePackRequest(request) || + isReceiveServiceRequest(request) || + isLfsFileUpload(request); + } + + private boolean isReceivePackRequest(HttpServletRequest request) { + return request.getRequestURI().endsWith(URI_RECEIVE_PACK); + } + + private boolean isReceiveServiceRequest(HttpServletRequest request) { + return request.getRequestURI().endsWith(URI_REF_INFO) + && PARAMETER_VALUE_RECEIVE.equals(request.getParameter(PARAMETER_SERVICE)); } @VisibleForTesting - static boolean isLfsFileUpload(HttpServletRequest request) { - String regex = String.format("^%s%s/.+(\\.git)?/info/lfs/objects/[a-z0-9]{64}$", request.getContextPath(), GitServletModule.GIT_PATH); - return request.getRequestURI().matches(regex) && "PUT".equals(request.getMethod()); - + private static boolean isLfsFileUpload(HttpServletRequest request) { + return METHOD_LFS_UPLOAD.equalsIgnoreCase(request.getMethod()); } - } diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/GitPermissionFilterTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/GitPermissionFilterTest.java index a107f35816..69fc72fcc7 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/GitPermissionFilterTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/web/GitPermissionFilterTest.java @@ -1,48 +1,125 @@ package sonia.scm.web; +import com.google.common.base.Charsets; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import javax.servlet.ServletOutputStream; import org.junit.Test; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import static org.mockito.Mockito.*; +import org.mockito.runners.MockitoJUnitRunner; +import sonia.scm.config.ScmConfiguration; +import sonia.scm.repository.RepositoryProvider; /** + * Unit tests for {@link GitPermissionFilter}. + * * Created by omilke on 19.05.2017. */ +@RunWith(MockitoJUnitRunner.class) public class GitPermissionFilterTest { + @Mock + private RepositoryProvider repositoryProvider; + + private final GitPermissionFilter permissionFilter = new GitPermissionFilter( + new ScmConfiguration(), repositoryProvider + ); + + @Mock + private HttpServletResponse response; + @Test - public void isLfsFileUpload() throws Exception { - - HttpServletRequest mockedRequest = getRequestWithMethodAndPathInfo("PUT", - "/scm/git/git-lfs-demo.git/info/lfs/objects/8fcebeb5698230685f92028e560f8f1683ebc15ec82a620ffad5c12a3c19bdec"); - assertThat((GitPermissionFilter.isLfsFileUpload(mockedRequest)), is(true)); - - mockedRequest = getRequestWithMethodAndPathInfo("GET", - "/scm/git/git-lfs-demo.git/info/lfs/objects/8fcebeb5698230685f92028e560f8f1683ebc15ec82a620ffad5c12a3c19bdec"); - assertThat((GitPermissionFilter.isLfsFileUpload(mockedRequest)), is(false)); - - mockedRequest = getRequestWithMethodAndPathInfo("POST", - "/scm/git/git-lfs-demo.git/info/lfs/objects/8fcebeb5698230685f92028e560f8f1683ebc15ec82a620ffad5c12a3c19bdec"); - assertThat((GitPermissionFilter.isLfsFileUpload(mockedRequest)), is(false)); - - mockedRequest = getRequestWithMethodAndPathInfo("POST", - "/scm/git/git-lfs-demo.git/info/lfs/objects/batch"); - assertThat((GitPermissionFilter.isLfsFileUpload(mockedRequest)), is(false)); + public void testIsWriteRequest() { + HttpServletRequest request = mockRequestWithMethodAndRequestURI("POST", "/scm/git/fanzy-project/git-receive-pack"); + assertThat(permissionFilter.isWriteRequest(request), is(true)); + + request = mockRequestWithMethodAndRequestURI("GET", "/scm/git/fanzy-project/info/refs?service=git-receive-pack"); + assertThat(permissionFilter.isWriteRequest(request), is(true)); + + request = mockRequestWithMethodAndRequestURI("GET", "/scm/git/fanzy-project/info/refs?service=some-other-service"); + assertThat(permissionFilter.isWriteRequest(request), is(false)); + + request = mockRequestWithMethodAndRequestURI( + "PUT", + "/scm/git/git-lfs-demo.git/info/lfs/objects/8fcebeb5698230685f92028e560f8f1683ebc15ec82a620ffad5c12a3c19bdec" + ); + assertThat(permissionFilter.isWriteRequest(request), is(true)); + + request = mockRequestWithMethodAndRequestURI( + "GET", + "/scm/git/git-lfs-demo.git/info/lfs/objects/8fcebeb5698230685f92028e560f8f1683ebc15ec82a620ffad5c12a3c19bdec" + ); + assertThat(permissionFilter.isWriteRequest(request), is(false)); + + request = mockRequestWithMethodAndRequestURI("POST", "/scm/git/git-lfs-demo.git/info/lfs/objects/batch"); + assertThat(permissionFilter.isWriteRequest(request), is(false)); } - private HttpServletRequest getRequestWithMethodAndPathInfo(String method, String pathInfo) { - + private HttpServletRequest mockRequestWithMethodAndRequestURI(String method, String requestURI) { HttpServletRequest mock = mock(HttpServletRequest.class); when(mock.getMethod()).thenReturn(method); - when(mock.getRequestURI()).thenReturn(pathInfo); + when(mock.getRequestURI()).thenReturn(requestURI); when(mock.getContextPath()).thenReturn("/scm"); return mock; } + @Test + public void testSendNotEnoughPrivilegesErrorAsBrowser() throws IOException { + HttpServletRequest request = mockGitReceivePackServiceRequest(); + + permissionFilter.sendNotEnoughPrivilegesError(request, response); + + verify(response).sendError(HttpServletResponse.SC_FORBIDDEN); + } + + @Test + public void testSendNotEnoughPrivilegesErrorAsGitClient() throws IOException { + HttpServletRequest request = mockGitReceivePackServiceRequest(); + when(request.getHeader("User-Agent")).thenReturn("git/2.9.3"); + + CapturingServletOutputStream stream = new CapturingServletOutputStream(); + when(response.getOutputStream()).thenReturn(stream); + + permissionFilter.sendNotEnoughPrivilegesError(request, response); + + verify(response).setStatus(HttpServletResponse.SC_OK); + assertThat(stream.toString(), containsString("privileges")); + } + + private HttpServletRequest mockGitReceivePackServiceRequest() { + HttpServletRequest request = mockRequestWithMethodAndRequestURI("GET", "/git/info/refs"); + when(request.getParameter("service")).thenReturn("git-receive-pack"); + return request; + } + + private static class CapturingServletOutputStream extends ServletOutputStream { + + private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + @Override + public void write(int b) throws IOException { + baos.write(b); + } + + @Override + public void close() throws IOException { + baos.close(); + } + + @Override + public String toString() { + return baos.toString(); + } + } + }