HTTP Basic-Auth support for direct access to GitBlit plugin. Allow to access directly to GitBlit without going through the standard Gerrit login process interactively: username and password are retrieved using HTTP Basic-Auth from the Http Request. This is useful when using GitBlit RSS feeds that cannot authenticate using the manual Gerrit form-based authentication. Cherry-picked from 6984f3e035a663414056c21823d18007c07465b8 and adapted for Gerrit 2.5 Change-Id: Iabf3a690f67c96207390070a7d380539a03c8459 Signed-off-by: Luca Milanesio <luca.milanesio@gmail.com>
diff --git a/pom.xml b/pom.xml index 5926b67..51b2af5 100644 --- a/pom.xml +++ b/pom.xml
@@ -70,6 +70,11 @@ <scope>provided</scope> <version>3.1</version> </dependency> + <dependency> + <groupId>commons-codec</groupId> + <artifactId>commons-codec</artifactId> + <version>1.4</version> + </dependency> <dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifactId>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitblit/app/GerritGitBlit.java b/src/main/java/com/googlesource/gerrit/plugins/gitblit/app/GerritGitBlit.java index 6e1fe55..8da4164 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/gitblit/app/GerritGitBlit.java +++ b/src/main/java/com/googlesource/gerrit/plugins/gitblit/app/GerritGitBlit.java
@@ -23,6 +23,7 @@ import com.gitblit.models.UserModel; import com.google.inject.Inject; import com.google.inject.Singleton; +import com.googlesource.gerrit.plugins.gitblit.auth.GerritToGitBlitUserModel; import com.googlesource.gerrit.plugins.gitblit.auth.GerritToGitBlitUserService; @Singleton @@ -36,12 +37,17 @@ public UserModel authenticate(HttpServletRequest request) { String user = (String) request.getAttribute("gerrit-username"); String token = (String) request.getAttribute("gerrit-token"); - if (token == null) { - return null; + String password = (String) request.getAttribute("gerrit-password"); + if (token != null) { + return GitBlit.self().authenticate(user, + (GerritToGitBlitUserService.SESSIONAUTH + token).toCharArray()); + } else if(user != null && password != null){ + return GitBlit.self().authenticate(user, password.toCharArray()); + } else { + return GitBlit.self().authenticate( + GerritToGitBlitUserModel.ANONYMOUS_USER, + GerritToGitBlitUserModel.ANONYMOUS_PASSWORD); } - - return GitBlit.self().authenticate(user, - (GerritToGitBlitUserService.SESSIONAUTH + token).toCharArray()); } @Override
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitblit/auth/GerritAuthFilter.java b/src/main/java/com/googlesource/gerrit/plugins/gitblit/auth/GerritAuthFilter.java index 81ff438..e2872d7 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/gitblit/auth/GerritAuthFilter.java +++ b/src/main/java/com/googlesource/gerrit/plugins/gitblit/auth/GerritAuthFilter.java
@@ -13,8 +13,10 @@ // limitations under the License. package com.googlesource.gerrit.plugins.gitblit.auth; +import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED; + import java.io.IOException; -import java.net.HttpURLConnection; +import java.io.UnsupportedEncodingException; import javax.servlet.FilterChain; import javax.servlet.ServletException; @@ -23,12 +25,18 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.commons.codec.binary.Base64; + import com.gitblit.GitBlit; import com.gitblit.models.UserModel; +import com.google.common.base.Objects; import com.google.gerrit.httpd.WebSession; import com.google.inject.Provider; +import com.google.inject.Singleton; +@Singleton public class GerritAuthFilter { + private static final String LIT_BASIC = "Basic "; /** * Returns the user making the request, if the user has authenticated. @@ -58,20 +66,52 @@ ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; - HttpServletResponse httpResponse = (HttpServletResponse) response; - if (webSession.get().isSignedIn() - || httpRequest.getHeader("Authorization") != null) { - request.setAttribute("gerrit-username", webSession.get().getCurrentUser() - .getUserName()); - request.setAttribute("gerrit-token", webSession.get().getToken()); - return true; + String hdr = httpRequest.getHeader("Authorization"); + if (hdr != null) { + return filterBasicAuth((HttpServletRequest) request, + (HttpServletResponse) response, hdr); + } else if (webSession.get().isSignedIn()) { + return filterSessionAuth(webSession, (HttpServletRequest) request); } else { - httpResponse.setStatus(HttpURLConnection.HTTP_UNAUTHORIZED); - httpResponse.setHeader("WWW-Authenticate", - "Basic realm=\"Gerrit Code Review\""); + return true; + } + } + + public boolean filterSessionAuth(final Provider<WebSession> webSession, + HttpServletRequest request) { + request.setAttribute("gerrit-username", webSession.get().getCurrentUser() + .getUserName()); + request.setAttribute("gerrit-token", webSession.get().getToken()); + return true; + } + + public boolean filterBasicAuth(HttpServletRequest request, + HttpServletResponse response, String hdr) throws IOException, + UnsupportedEncodingException { + if (!hdr.startsWith(LIT_BASIC)) { + response.setHeader("WWW-Authenticate", "Basic realm=\"Gerrit Code Review\""); + response.sendError(SC_UNAUTHORIZED); return false; } + + final byte[] decoded = + new Base64().decode(hdr.substring(LIT_BASIC.length()).getBytes()); + String usernamePassword = + new String(decoded, Objects.firstNonNull( + request.getCharacterEncoding(), "UTF-8")); + int splitPos = usernamePassword.indexOf(':'); + if (splitPos < 1) { + response.setHeader("WWW-Authenticate", "Basic realm=\"Gerrit Code Review\""); + response.sendError(SC_UNAUTHORIZED); + return false; + } + request.setAttribute("gerrit-username", + usernamePassword.substring(0, splitPos)); + request.setAttribute("gerrit-password", + usernamePassword.substring(splitPos + 1)); + + return true; } }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitblit/auth/GerritToGitBlitUserModel.java b/src/main/java/com/googlesource/gerrit/plugins/gitblit/auth/GerritToGitBlitUserModel.java index fa5e377..30e3baa 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/gitblit/auth/GerritToGitBlitUserModel.java +++ b/src/main/java/com/googlesource/gerrit/plugins/gitblit/auth/GerritToGitBlitUserModel.java
@@ -25,9 +25,12 @@ import com.google.gerrit.reviewdb.client.Project.NameKey; import com.google.gerrit.server.project.NoSuchProjectException; import com.google.gerrit.server.project.ProjectControl; +import com.google.gerrit.server.project.ProjectControl.Factory; import com.google.gerrit.server.project.RefControl; public class GerritToGitBlitUserModel extends UserModel { + public static final String ANONYMOUS_USER = "$anonymous"; + public static final char[] ANONYMOUS_PASSWORD = ANONYMOUS_USER.toCharArray(); private static final long serialVersionUID = 1L; @@ -59,6 +62,11 @@ this.projectControlFactory = projectControlFactory; } + public GerritToGitBlitUserModel(final ProjectControl.Factory projectControlFactory) { + super(ANONYMOUS_USER); + this.projectControlFactory = projectControlFactory; + } + @Deprecated public boolean canAccessRepository(String repositoryName) { boolean result = false; @@ -212,4 +220,8 @@ public int compareTo(UserModel o) { return username.compareTo(o.username); } + + public static UserModel getAnonymous(Factory projectControl) { + return new GerritToGitBlitUserModel(ANONYMOUS_USER, projectControl); + } }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitblit/auth/GerritToGitBlitUserService.java b/src/main/java/com/googlesource/gerrit/plugins/gitblit/auth/GerritToGitBlitUserService.java index 2a3e774..8b8183e 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/gitblit/auth/GerritToGitBlitUserService.java +++ b/src/main/java/com/googlesource/gerrit/plugins/gitblit/auth/GerritToGitBlitUserService.java
@@ -59,7 +59,10 @@ public UserModel authenticate(String username, char[] password) { String passwordString = new String(password); - if (passwordString.startsWith(GerritToGitBlitUserService.SESSIONAUTH)) { + if (username.equals(GerritToGitBlitUserModel.ANONYMOUS_USER)) { + return GerritToGitBlitUserModel.getAnonymous(projectControl); + } else if (passwordString + .startsWith(GerritToGitBlitUserService.SESSIONAUTH)) { return authenticateSSO(username, passwordString.substring(GerritToGitBlitUserService.SESSIONAUTH .length()));