Allow container-based authentication for git over http

Gerrit was insisting on DIGEST authentication when doing git over http.
This change allows to configure gerrit to trust the container to do
the authentication. A new boolean configuration parameter
auth.trustContainerAuth was introduced.

Change-Id: Ie527ed2c9e73c4f7136b271c66ee8b621fc4c79a
Signed-off-by: Christian Halstrick <christian.halstrick@sap.com>
Signed-off-by: Stefan Lay <stefan.lay@sap.com>
Signed-off-by: Jens Baumgart <jens.baumgart@sap.com>
This commit is contained in:
Christian Halstrick
2011-08-31 09:21:41 +02:00
parent 2ad3f98e21
commit a3d88a5e55
5 changed files with 131 additions and 6 deletions

View File

@@ -287,6 +287,17 @@ Account users register with the Gerrit server.
+
By default, unset/false.
[[auth.trustContainerAuth]]auth.trustContainerAuth::
+
If true then it is the responsibility of the container hosting
Gerrit to authenticate users. In this case Gerrit will blindly trust
the container.
+
This parameter only affects git over http traffic. If set to false
then Gerrit will do the authentication (using DIGEST authentication).
+
By default this is set to false.
[[cache]]Section cache
~~~~~~~~~~~~~~~~~~~~~~

View File

@@ -0,0 +1,96 @@
// Copyright (C) 2011 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.httpd;
import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.config.AuthConfig;
import com.google.gwtjsonrpc.server.XsrfException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
/**
* Trust the authentication which is done by the container.
* <p>
* Check whether the container has already authenticated the user. If yes, then
* lookup the account and set the account ID in our current session.
* <p>
* This filter should only be configured to run, when authentication is
* configured to trust container authentication. This filter is intended only to
* protect the {@link ProjectServlet} and its handled URLs, which provide remote
* repository access over HTTP.
*/
@Singleton
class ContainerAuthFilter implements Filter {
public static final String REALM_NAME = "Gerrit Code Review";
private final Provider<WebSession> session;
private final AccountCache accountCache;
@Inject
ContainerAuthFilter(Provider<WebSession> session, AccountCache accountCache)
throws XsrfException {
this.session = session;
this.accountCache = accountCache;
}
@Override
public void init(FilterConfig config) {
}
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponseWrapper rsp =
new HttpServletResponseWrapper((HttpServletResponse) response);
if (verify(req, rsp)) {
chain.doFilter(req, response);
}
}
private boolean verify(HttpServletRequest req, HttpServletResponseWrapper rsp)
throws IOException {
final String username = req.getRemoteUser();
final AccountState who =
(username == null) ? null : accountCache.getByUsername(username);
if (who == null || !who.getAccount().isActive()) {
rsp.sendError(SC_UNAUTHORIZED);
return false;
}
session.get().setUserAccountId(who.getAccount().getId());
return true;
}
}

View File

@@ -24,6 +24,7 @@ import com.google.gerrit.httpd.raw.SshInfoServlet;
import com.google.gerrit.httpd.raw.StaticServlet;
import com.google.gerrit.httpd.raw.ToolServlet;
import com.google.gerrit.reviewdb.Change;
import com.google.gerrit.server.config.AuthConfig;
import com.google.gwtexpui.server.CacheControlFilter;
import com.google.inject.Key;
import com.google.inject.Provider;
@@ -37,6 +38,12 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
class UrlModule extends ServletModule {
private final AuthConfig authConfig;
public UrlModule(AuthConfig authConfig) {
this.authConfig = authConfig;
}
@Override
protected void configureServlets() {
filter("/*").through(Key.get(CacheControlFilter.class));
@@ -54,7 +61,11 @@ class UrlModule extends ServletModule {
serve("/tools/*").with(ToolServlet.class);
filter("/p/*").through(ProjectAccessPathFilter.class);
filter("/p/*").through(ProjectDigestFilter.class);
if (authConfig.isTrustContainerAuth()) {
filter("/p/*").through(ContainerAuthFilter.class);
} else {
filter("/p/*").through(ProjectDigestFilter.class);
}
serve("/p/*").with(ProjectServlet.class);
serve("/Main.class").with(notFound());

View File

@@ -55,7 +55,7 @@ import javax.annotation.Nullable;
public class WebModule extends FactoryModule {
private final Provider<SshInfo> sshInfoProvider;
private final Provider<SshKeyCache> sshKeyCacheProvider;
private final AuthType authType;
private final AuthConfig authConfig;
private final boolean wantSSL;
private final GitWebConfig gitWebConfig;
@@ -67,7 +67,7 @@ public class WebModule extends FactoryModule {
final Injector creatingInjector) {
this.sshInfoProvider = sshInfoProvider;
this.sshKeyCacheProvider = sshKeyCacheProvider;
this.authType = authConfig.getAuthType();
this.authConfig = authConfig;
this.wantSSL = canonicalUrl != null && canonicalUrl.startsWith("https:");
this.gitWebConfig =
@@ -92,7 +92,7 @@ public class WebModule extends FactoryModule {
install(new RequireSslFilter.Module());
}
switch (authType) {
switch (authConfig.getAuthType()) {
case OPENID:
install(new OpenIdModule());
break;
@@ -121,10 +121,10 @@ public class WebModule extends FactoryModule {
break;
default:
throw new ProvisionException("Unsupported loginType: " + authType);
throw new ProvisionException("Unsupported loginType: " + authConfig.getAuthType());
}
install(new UrlModule());
install(new UrlModule(authConfig));
install(new UiRpcModule());
install(new GerritRequestModule());
install(new ProjectServlet.Module());

View File

@@ -35,6 +35,7 @@ import java.util.concurrent.TimeUnit;
public class AuthConfig {
private final AuthType authType;
private final String httpHeader;
private final boolean trustContainerAuth;
private final String logoutUrl;
private final List<OpenIdProviderPattern> trustedOpenIDs;
private final List<OpenIdProviderPattern> allowedOpenIDs;
@@ -54,6 +55,7 @@ public class AuthConfig {
allowedOpenIDs = toPatterns(cfg, "allowedOpenID");
cookiePath = cfg.getString("auth", null, "cookiepath");
cookieSecure = cfg.getBoolean("auth", "cookiesecure", false);
trustContainerAuth = cfg.getBoolean("auth", "trustContainerAuth", false);
String key = cfg.getString("auth", null, "registerEmailPrivateKey");
if (key != null && !key.isEmpty()) {
@@ -125,6 +127,11 @@ public class AuthConfig {
return allowedOpenIDs;
}
/** Whether git-over-http should trust authentication done by container. */
public boolean isTrustContainerAuth() {
return trustContainerAuth;
}
public boolean isIdentityTrustable(final Collection<AccountExternalId> ids) {
switch (getAuthType()) {
case DEVELOPMENT_BECOME_ANY_ACCOUNT: