Merge "Allow container-based authentication for git over http"
This commit is contained in:
commit
e59ad34e04
@ -287,6 +287,17 @@ Account users register with the Gerrit server.
|
|||||||
+
|
+
|
||||||
By default, unset/false.
|
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
|
[[cache]]Section cache
|
||||||
~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -24,6 +24,7 @@ import com.google.gerrit.httpd.raw.SshInfoServlet;
|
|||||||
import com.google.gerrit.httpd.raw.StaticServlet;
|
import com.google.gerrit.httpd.raw.StaticServlet;
|
||||||
import com.google.gerrit.httpd.raw.ToolServlet;
|
import com.google.gerrit.httpd.raw.ToolServlet;
|
||||||
import com.google.gerrit.reviewdb.Change;
|
import com.google.gerrit.reviewdb.Change;
|
||||||
|
import com.google.gerrit.server.config.AuthConfig;
|
||||||
import com.google.gwtexpui.server.CacheControlFilter;
|
import com.google.gwtexpui.server.CacheControlFilter;
|
||||||
import com.google.inject.Key;
|
import com.google.inject.Key;
|
||||||
import com.google.inject.Provider;
|
import com.google.inject.Provider;
|
||||||
@ -37,6 +38,12 @@ import javax.servlet.http.HttpServletRequest;
|
|||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
class UrlModule extends ServletModule {
|
class UrlModule extends ServletModule {
|
||||||
|
private final AuthConfig authConfig;
|
||||||
|
|
||||||
|
public UrlModule(AuthConfig authConfig) {
|
||||||
|
this.authConfig = authConfig;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void configureServlets() {
|
protected void configureServlets() {
|
||||||
filter("/*").through(Key.get(CacheControlFilter.class));
|
filter("/*").through(Key.get(CacheControlFilter.class));
|
||||||
@ -54,7 +61,11 @@ class UrlModule extends ServletModule {
|
|||||||
serve("/tools/*").with(ToolServlet.class);
|
serve("/tools/*").with(ToolServlet.class);
|
||||||
|
|
||||||
filter("/p/*").through(ProjectAccessPathFilter.class);
|
filter("/p/*").through(ProjectAccessPathFilter.class);
|
||||||
|
if (authConfig.isTrustContainerAuth()) {
|
||||||
|
filter("/p/*").through(ContainerAuthFilter.class);
|
||||||
|
} else {
|
||||||
filter("/p/*").through(ProjectDigestFilter.class);
|
filter("/p/*").through(ProjectDigestFilter.class);
|
||||||
|
}
|
||||||
serve("/p/*").with(ProjectServlet.class);
|
serve("/p/*").with(ProjectServlet.class);
|
||||||
|
|
||||||
serve("/Main.class").with(notFound());
|
serve("/Main.class").with(notFound());
|
||||||
|
@ -55,7 +55,7 @@ import javax.annotation.Nullable;
|
|||||||
public class WebModule extends FactoryModule {
|
public class WebModule extends FactoryModule {
|
||||||
private final Provider<SshInfo> sshInfoProvider;
|
private final Provider<SshInfo> sshInfoProvider;
|
||||||
private final Provider<SshKeyCache> sshKeyCacheProvider;
|
private final Provider<SshKeyCache> sshKeyCacheProvider;
|
||||||
private final AuthType authType;
|
private final AuthConfig authConfig;
|
||||||
private final boolean wantSSL;
|
private final boolean wantSSL;
|
||||||
private final GitWebConfig gitWebConfig;
|
private final GitWebConfig gitWebConfig;
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ public class WebModule extends FactoryModule {
|
|||||||
final Injector creatingInjector) {
|
final Injector creatingInjector) {
|
||||||
this.sshInfoProvider = sshInfoProvider;
|
this.sshInfoProvider = sshInfoProvider;
|
||||||
this.sshKeyCacheProvider = sshKeyCacheProvider;
|
this.sshKeyCacheProvider = sshKeyCacheProvider;
|
||||||
this.authType = authConfig.getAuthType();
|
this.authConfig = authConfig;
|
||||||
this.wantSSL = canonicalUrl != null && canonicalUrl.startsWith("https:");
|
this.wantSSL = canonicalUrl != null && canonicalUrl.startsWith("https:");
|
||||||
|
|
||||||
this.gitWebConfig =
|
this.gitWebConfig =
|
||||||
@ -92,7 +92,7 @@ public class WebModule extends FactoryModule {
|
|||||||
install(new RequireSslFilter.Module());
|
install(new RequireSslFilter.Module());
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (authType) {
|
switch (authConfig.getAuthType()) {
|
||||||
case OPENID:
|
case OPENID:
|
||||||
install(new OpenIdModule());
|
install(new OpenIdModule());
|
||||||
break;
|
break;
|
||||||
@ -121,10 +121,10 @@ public class WebModule extends FactoryModule {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
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 UiRpcModule());
|
||||||
install(new GerritRequestModule());
|
install(new GerritRequestModule());
|
||||||
install(new ProjectServlet.Module());
|
install(new ProjectServlet.Module());
|
||||||
|
@ -35,6 +35,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
public class AuthConfig {
|
public class AuthConfig {
|
||||||
private final AuthType authType;
|
private final AuthType authType;
|
||||||
private final String httpHeader;
|
private final String httpHeader;
|
||||||
|
private final boolean trustContainerAuth;
|
||||||
private final String logoutUrl;
|
private final String logoutUrl;
|
||||||
private final List<OpenIdProviderPattern> trustedOpenIDs;
|
private final List<OpenIdProviderPattern> trustedOpenIDs;
|
||||||
private final List<OpenIdProviderPattern> allowedOpenIDs;
|
private final List<OpenIdProviderPattern> allowedOpenIDs;
|
||||||
@ -54,6 +55,7 @@ public class AuthConfig {
|
|||||||
allowedOpenIDs = toPatterns(cfg, "allowedOpenID");
|
allowedOpenIDs = toPatterns(cfg, "allowedOpenID");
|
||||||
cookiePath = cfg.getString("auth", null, "cookiepath");
|
cookiePath = cfg.getString("auth", null, "cookiepath");
|
||||||
cookieSecure = cfg.getBoolean("auth", "cookiesecure", false);
|
cookieSecure = cfg.getBoolean("auth", "cookiesecure", false);
|
||||||
|
trustContainerAuth = cfg.getBoolean("auth", "trustContainerAuth", false);
|
||||||
|
|
||||||
String key = cfg.getString("auth", null, "registerEmailPrivateKey");
|
String key = cfg.getString("auth", null, "registerEmailPrivateKey");
|
||||||
if (key != null && !key.isEmpty()) {
|
if (key != null && !key.isEmpty()) {
|
||||||
@ -125,6 +127,11 @@ public class AuthConfig {
|
|||||||
return allowedOpenIDs;
|
return allowedOpenIDs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Whether git-over-http should trust authentication done by container. */
|
||||||
|
public boolean isTrustContainerAuth() {
|
||||||
|
return trustContainerAuth;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isIdentityTrustable(final Collection<AccountExternalId> ids) {
|
public boolean isIdentityTrustable(final Collection<AccountExternalId> ids) {
|
||||||
switch (getAuthType()) {
|
switch (getAuthType()) {
|
||||||
case DEVELOPMENT_BECOME_ANY_ACCOUNT:
|
case DEVELOPMENT_BECOME_ANY_ACCOUNT:
|
||||||
|
Loading…
Reference in New Issue
Block a user