diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt index 3d391877a8..96472949e8 100644 --- a/Documentation/config-gerrit.txt +++ b/Documentation/config-gerrit.txt @@ -443,7 +443,7 @@ By default this is set to false. [[auth.gitBasicAuth]]auth.gitBasicAuth:: + If true then Git over HTTP and HTTP/S traffic is authenticated using -standard BasicAuth. Depending on the configured `auth.type` credentials +standard BasicAuth. Depending on the configured `auth.type`, credentials are validated against the randomly generated HTTP password, against LDAP (`auth.type = LDAP`) or against an OAuth 2 provider (`auth.type = OAUTH`). + @@ -452,8 +452,14 @@ API. If set to false then Gerrit will authenticate through DIGEST authentication and the randomly generated HTTP password in the Gerrit database. + -When `auth.type` is `LDAP`, service users that only exist in the Gerrit -database are still authenticated by their HTTP passwords. +When `auth.type` is `LDAP`, users should authenticate using their LDAP passwords. +However, if link:#auth.gitBasicAuthPolicy[`auth.gitBasicAuthPolicy`] is set to `HTTP`, +the randomly generated HTTP password is used exclusively. In the other hand, +if link:#auth.gitBasicAuthPolicy[`auth.gitBasicAuthPolicy`] is set to `HTTP_LDAP`, +the password in the request is first checked against the HTTP password and, if +it does not match, it is then validated against the LDAP password. +Service users that only exist in the Gerrit database are authenticated by their +HTTP passwords. + When `auth.type` is `OAUTH`, Git clients may send OAuth 2 access tokens instead of passwords in the Basic authentication header. Note that provider @@ -463,6 +469,31 @@ selected as default with the `auth.gitOAuthProvider` option. + By default this is set to false. +[[auth.gitBasicAuthPolicy]]auth.gitBasicAuthPolicy:: ++ +When `auth.type` is `LDAP` and BasicAuth (i.e., link:#auth.gitBasicAuth[`auth.gitBasicAuth`] +is set to true), it allows using either the generated HTTP password, the LDAP +password or both to authenticate Git over HTTP and REST API requests. The +supported values are: ++ +*`HTTP` ++ +Only the randomly generated HTTP password is accepted when doing Git over HTTP +and REST API requests. ++ +*`LDAP` ++ +Only the `LDAP` password is allowed when doing Git over HTTP and REST API +requests. ++ +*`HTTP_LDAP` ++ +The password in the request is first checked against the HTTP password and, if +it does not match, it is then validated against the `LDAP` password. ++ +By default this is set to `LDAP` when link:#auth.type[`auth.type`] is `LDAP`. +Otherwise, the default value is `HTTP`. + [[auth.gitOAuthProvider]]auth.gitOAuthProvider:: + Selects the OAuth 2 provider to authenticate git over HTTP traffic with. diff --git a/Documentation/rest-api-config.txt b/Documentation/rest-api-config.txt index de2103480e..7246786e08 100644 --- a/Documentation/rest-api-config.txt +++ b/Documentation/rest-api-config.txt @@ -1275,6 +1275,12 @@ Whether link:config-gerrit.html#auth.gitBasicAuth[basic authentication is used for Git over HTTP/HTTPS]. Only set if link:config-gerrit.html#auth.type[authentication type] is is `LDAP` or `LDAP_BIND`. +|`git_basic_auth_policy` |optional| +The link:config-gerrit.html#auth.gitBasicAuthPolicy[policy] to authenticate +Git over HTTP and REST API requests when +link:config-gerrit.html#auth.type[authentication type] is `LDAP` and +link:config-gerrit.html#auth.gitBasicAuth[basic authentication] is set to true. +Can be `HTTP`, `LDAP` or `HTTP_LDAP`. |========================================== [[cache-info]] diff --git a/Documentation/user-upload.txt b/Documentation/user-upload.txt index 546f13f3bc..a0803d6f5b 100644 --- a/Documentation/user-upload.txt +++ b/Documentation/user-upload.txt @@ -19,11 +19,17 @@ On Gerrit installations that do not support SSH authentication, the user must authenticate via HTTP/HTTPS. When link:config-gerrit.html#auth.gitBasicAuth[gitBasicAuth] is enabled, -the user is authenticated using standard BasicAuth and credentials validated -using the randomly generated HTTP password on the `HTTP Password` tab -in the user settings page or against LDAP when configured for the Gerrit Web UI. +the user is authenticated using standard BasicAuth. Depending on the value of +link:#auth.gitBasicAuthPolicy[auth.gitBasicAuthPolicy], credentials are +validated using: -When gitBasicAuth is not configured, the user's HTTP credentials can be +* The randomly generated HTTP password on the `HTTP Password` tab + in the user settings page if `gitBasicAuthPolicy` is `HTTP`. +* The LDAP password if `gitBasicAuthPolicy` is `LDAP` +* Both, the HTTP and the LDAP passwords (in this order) if `gitBasicAuthPolicy` + is `HTTP_LDAP`. + +When gitBasicAuthPolicy is not `LDAP`, the user's HTTP credentials can be accessed within Gerrit by going to `Settings`, and then accessing the `HTTP Password` tab. diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/GitBasicAuthPolicy.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/GitBasicAuthPolicy.java new file mode 100644 index 0000000000..6450b0dc15 --- /dev/null +++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/client/GitBasicAuthPolicy.java @@ -0,0 +1,21 @@ +// Copyright (C) 2016 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.extensions.client; + +public enum GitBasicAuthPolicy { + HTTP, + LDAP, + HTTP_LDAP +} diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/AuthInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/AuthInfo.java index 1000e9cf03..0a066c6706 100644 --- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/AuthInfo.java +++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/AuthInfo.java @@ -16,6 +16,7 @@ package com.google.gerrit.extensions.common; import com.google.gerrit.extensions.client.AccountFieldName; import com.google.gerrit.extensions.client.AuthType; +import com.google.gerrit.extensions.client.GitBasicAuthPolicy; import java.util.List; @@ -32,4 +33,5 @@ public class AuthInfo { public String editFullNameUrl; public String httpPasswordUrl; public Boolean isGitBasicAuth; + public GitBasicAuthPolicy gitBasicAuthPolicy; } \ No newline at end of file diff --git a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/AuthInfo.java b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/AuthInfo.java index 8669dd507c..ca3912cbf7 100644 --- a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/AuthInfo.java +++ b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/info/AuthInfo.java @@ -17,6 +17,7 @@ package com.google.gerrit.client.info; import com.google.gerrit.client.rpc.Natives; import com.google.gerrit.extensions.client.AccountFieldName; import com.google.gerrit.extensions.client.AuthType; +import com.google.gerrit.extensions.client.GitBasicAuthPolicy; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.JsArray; import com.google.gwt.core.client.JsArrayString; @@ -82,12 +83,16 @@ public class AuthInfo extends JavaScriptObject { } public final boolean isHttpPasswordSettingsEnabled() { - if (isLdap() && isGitBasicAuth()) { + if (isGitBasicAuth() && gitBasicAuthPolicy() == GitBasicAuthPolicy.LDAP) { return false; } return true; } + public final GitBasicAuthPolicy gitBasicAuthPolicy() { + return GitBasicAuthPolicy.valueOf(gitBasicAuthPolicyRaw()); + } + public final native boolean useContributorAgreements() /*-{ return this.use_contributor_agreements || false; }-*/; public final native String loginUrl() /*-{ return this.login_url; }-*/; @@ -98,6 +103,8 @@ public class AuthInfo extends JavaScriptObject { public final native String editFullNameUrl() /*-{ return this.edit_full_name_url; }-*/; public final native String httpPasswordUrl() /*-{ return this.http_password_url; }-*/; public final native boolean isGitBasicAuth() /*-{ return this.is_git_basic_auth || false; }-*/; + private native String gitBasicAuthPolicyRaw() + /*-{ return this.git_basic_auth_policy; }-*/; private native String authTypeRaw() /*-{ return this.auth_type; }-*/; private native JsArrayString _editableAccountFields() /*-{ return this.editable_account_fields; }-*/; diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java index b06f3701b5..fab0aeb716 100644 --- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java +++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java @@ -19,6 +19,7 @@ import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED; import com.google.common.base.MoreObjects; import com.google.common.base.Strings; +import com.google.gerrit.extensions.client.GitBasicAuthPolicy; import com.google.gerrit.extensions.registration.DynamicItem; import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.server.AccessPath; @@ -141,12 +142,16 @@ class ProjectBasicAuthFilter implements Filter { return false; } - if (!authConfig.isLdapAuthType() - && !passwordMatchesTheUserGeneratedOne(who, username, password)) { - log.warn("Authentication failed for " + username - + ": password does not match the one stored in Gerrit"); - rsp.sendError(SC_UNAUTHORIZED); - return false; + GitBasicAuthPolicy gitBasicAuthPolicy = authConfig.getGitBasicAuthPolicy(); + if (gitBasicAuthPolicy == GitBasicAuthPolicy.HTTP + || gitBasicAuthPolicy == GitBasicAuthPolicy.HTTP_LDAP) { + if (passwordMatchesTheUserGeneratedOne(who, username, password)) { + return succeedAuthentication(who); + } + } + + if (gitBasicAuthPolicy == GitBasicAuthPolicy.HTTP) { + return failAuthentication(rsp, username); } AuthRequest whoAuth = AuthRequest.forUser(username); @@ -158,8 +163,7 @@ class ProjectBasicAuthFilter implements Filter { return true; } catch (NoSuchUserException e) { if (password.equals(who.getPassword(who.getUserName()))) { - setUserIdentified(who.getAccount().getId()); - return true; + return succeedAuthentication(who); } log.warn("Authentication failed for " + username, e); rsp.sendError(SC_UNAUTHORIZED); @@ -175,6 +179,19 @@ class ProjectBasicAuthFilter implements Filter { } } + private boolean succeedAuthentication(final AccountState who) { + setUserIdentified(who.getAccount().getId()); + return true; + } + + private boolean failAuthentication(Response rsp, String username) + throws IOException { + log.warn("Authentication failed for {}: password does not match the one" + + " stored in Gerrit", username); + rsp.sendError(SC_UNAUTHORIZED); + return false; + } + private void setUserIdentified(Account.Id id) { WebSession ws = session.get(); ws.setUserAccountId(id); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfig.java index 5a40a31743..11a34f7de4 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfig.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfig.java @@ -15,6 +15,7 @@ package com.google.gerrit.server.config; import com.google.gerrit.extensions.client.AuthType; +import com.google.gerrit.extensions.client.GitBasicAuthPolicy; import com.google.gerrit.reviewdb.client.AccountExternalId; import com.google.gerrit.server.auth.openid.OpenIdProviderPattern; import com.google.gwtjsonrpc.server.SignedToken; @@ -62,6 +63,7 @@ public class AuthConfig { private final boolean cookieSecure; private final SignedToken emailReg; private final boolean allowRegisterNewEmail; + private GitBasicAuthPolicy gitBasicAuthPolicy; @Inject AuthConfig(@GerritServerConfig final Config cfg) @@ -90,6 +92,7 @@ public class AuthConfig { trustContainerAuth = cfg.getBoolean("auth", "trustContainerAuth", false); enableRunAs = cfg.getBoolean("auth", null, "enableRunAs", true); gitBasicAuth = cfg.getBoolean("auth", "gitBasicAuth", false); + gitBasicAuthPolicy = getBasicAuthPolicy(cfg); useContributorAgreements = cfg.getBoolean("auth", "contributoragreements", false); userNameToLowerCase = cfg.getBoolean("auth", "userNameToLowerCase", false); @@ -124,6 +127,12 @@ public class AuthConfig { return cfg.getEnum("auth", null, "type", AuthType.OPENID); } + private GitBasicAuthPolicy getBasicAuthPolicy(Config cfg) { + GitBasicAuthPolicy defaultAuthPolicy = + isLdapAuthType() ? GitBasicAuthPolicy.LDAP : GitBasicAuthPolicy.HTTP; + return cfg.getEnum("auth", null, "gitBasicAuthPolicy", defaultAuthPolicy); + } + /** Type of user authentication used by this Gerrit server. */ public AuthType getAuthType() { return authType; @@ -218,6 +227,10 @@ public class AuthConfig { return gitBasicAuth; } + public GitBasicAuthPolicy getGitBasicAuthPolicy() { + return gitBasicAuthPolicy; + } + /** Whether contributor agreements are used. */ public boolean isUseContributorAgreements() { return useContributorAgreements; diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GetServerInfo.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GetServerInfo.java index 1d9117a16c..00e9c6c3a2 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GetServerInfo.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GetServerInfo.java @@ -160,6 +160,7 @@ public class GetServerInfo implements RestReadView { info.editableAccountFields = new ArrayList<>(realm.getEditableFields()); info.switchAccountUrl = cfg.getSwitchAccountUrl(); info.isGitBasicAuth = toBoolean(cfg.isGitBasicAuth()); + info.gitBasicAuthPolicy = cfg.getGitBasicAuthPolicy(); if (info.useContributorAgreements != null) { Collection agreements =