Allow anonymous clones when pull-replication plugin is enabled. When the command `git clone` is executed over http, behind the scenes it does a request: `/info/refs?service=git-upload-pack`. Currently `BearerAuthenticationFilter.java` filters ALL the `upload pack` requests and therefore it checks the Bearer token header. This feature was added to allow Bearer Token Authentication when `git fetch over http` is executed from other Gerrit instances. The fix allows to discriminate the `upload pack` requests, therefore Bearer token header checking will be done just in the case of `git fetch over http` from other Gerrit instances. Bug: Issue 16548 Change-Id: I9873d92c88b8eb00c895a8e1cce18cae94199ac9
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/BearerAuthenticationFilter.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/BearerAuthenticationFilter.java index 8147149..be71946 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/BearerAuthenticationFilter.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/BearerAuthenticationFilter.java
@@ -44,6 +44,7 @@ public class BearerAuthenticationFilter extends AllRequestFilter { private static final String BEARER_TOKEN = "BearerToken"; + private static final String BEARER_TOKEN_PREFIX = "Bearer"; private final DynamicItem<WebSession> session; private final String pluginName; private final PullReplicationInternalUser pluginUser; @@ -79,13 +80,14 @@ HttpServletRequest httpRequest = (HttpServletRequest) servletRequest; HttpServletResponse httpResponse = (HttpServletResponse) servletResponse; String requestURI = httpRequest.getRequestURI(); + Optional<String> authorizationHeader = + Optional.ofNullable(httpRequest.getHeader("Authorization")); if (isBasicAuthenticationRequest(requestURI)) { filterChain.doFilter(servletRequest, servletResponse); - } else if (isPullReplicationApiRequest(requestURI) || isGitUploadPackRequest(httpRequest)) { - Optional<String> authorizationHeader = - Optional.ofNullable(httpRequest.getHeader("Authorization")); - + } else if (isPullReplicationApiRequest(requestURI) + || (isGitUploadPackRequest(httpRequest) + && isAuthenticationHeaderWithBearerToken(authorizationHeader))) { if (isBearerTokenAuthenticated(authorizationHeader, bearerToken)) try (ManualRequestContext ctx = new ManualRequestContext(pluginUser, threadLocalRequestContext.get())) { @@ -137,4 +139,8 @@ } return Optional.empty(); } + + private boolean isAuthenticationHeaderWithBearerToken(Optional<String> authorizationHeader) { + return authorizationHeader.map(h -> h.startsWith(BEARER_TOKEN_PREFIX)).orElse(false); + } }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/BearerAuthenticationFilterTest.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/BearerAuthenticationFilterTest.java index 824496a..ca69f06 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/BearerAuthenticationFilterTest.java +++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/BearerAuthenticationFilterTest.java
@@ -16,7 +16,6 @@ import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED; import static org.mockito.Mockito.atMost; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -108,17 +107,53 @@ } @Test - public void shouldAuthenticateWhenGitUploadPacket() throws ServletException, IOException { + public void shouldAuthenticateWhenGitUploadPack() throws ServletException, IOException { authenticateAndFilter("any-prefix/git-upload-pack", NO_QUERY_PARAMETERS); } @Test - public void shouldAuthenticateWhenGitUploadPacketInQueryParameter() + public void shouldAuthenticateWhenGitUploadPackInQueryParameter() throws ServletException, IOException { authenticateAndFilter("any-prefix", GIT_UPLOAD_PACK_QUERY_PARAMETER); } @Test + public void shouldGoNextInChainWhenGitUploadPackWithoutAuthenticationHeader() + throws ServletException, IOException { + when(httpServletRequest.getRequestURI()).thenReturn("any-prefix/git-upload-pack"); + + final BearerAuthenticationFilter filter = + new BearerAuthenticationFilter( + session, + pluginName, + pluginUser, + threadLocalRequestContextProvider, + "some-bearer-token"); + filter.doFilter(httpServletRequest, httpServletResponse, filterChain); + + verify(httpServletRequest).getHeader("Authorization"); + verify(filterChain).doFilter(httpServletRequest, httpServletResponse); + } + + @Test + public void shouldGoNextInChainWhenGitUploadPackWithAuthenticationHeaderDifferentThanBearer() + throws ServletException, IOException { + when(httpServletRequest.getRequestURI()).thenReturn("any-prefix/git-upload-pack"); + when(httpServletRequest.getHeader("Authorization")).thenReturn("some-authorization"); + final BearerAuthenticationFilter filter = + new BearerAuthenticationFilter( + session, + pluginName, + pluginUser, + threadLocalRequestContextProvider, + "some-bearer-token"); + filter.doFilter(httpServletRequest, httpServletResponse, filterChain); + + verify(httpServletRequest).getHeader("Authorization"); + verify(filterChain).doFilter(httpServletRequest, httpServletResponse); + } + + @Test public void shouldBe401WhenBearerTokenDoesNotMatch() throws ServletException, IOException { when(httpServletRequest.getRequestURI()).thenReturn("any-prefix/pull-replication~fetch"); when(httpServletRequest.getHeader("Authorization")) @@ -171,6 +206,7 @@ filter.doFilter(httpServletRequest, httpServletResponse, filterChain); verify(httpServletRequest).getRequestURI(); + verify(httpServletRequest).getHeader("Authorization"); verify(httpServletResponse).sendError(SC_UNAUTHORIZED); } @@ -187,7 +223,7 @@ "some-bearer-token"); filter.doFilter(httpServletRequest, httpServletResponse, filterChain); - verify(httpServletRequest, times(2)).getRequestURI(); + verify(httpServletRequest).getHeader("Authorization"); verify(filterChain).doFilter(httpServletRequest, httpServletResponse); } @@ -206,7 +242,7 @@ "some-bearer-token"); filter.doFilter(httpServletRequest, httpServletResponse, filterChain); - verify(httpServletRequest).getRequestURI(); + verify(httpServletRequest).getHeader("Authorization"); verify(filterChain).doFilter(httpServletRequest, httpServletResponse); } }