Allow HTTP password when using LDAP and basic authentication
So far, it was not possible to use HTTP password to validate git over HTTP and REST API requests if LDAP was used along with HTTP basic authentication. There is a use case, though, where users do not want to use their LDAP password for the aforementioned requests as in, for example, automation scripts. Introduce a new configuration parameter, `gitBasicAuthPolicy`, to allow LDAP users to authenticate using either the HTTP or the LDAP passwords when doing git over HTTP and REST API requests. When this new parameter is set to LDAP, the password in the request is checked against the LDAP password only. When set to HTTP, the password is validated against the randomly generated HTTP password. Finally, when set to HTTP_LDAP, the password in the request is checked first against the HTTP password and, if it does not match, it is checked against the LDAP password. If the new parameter is not specified or if is set to LDAP, the current behavior is preserved, i.e., only LDAP password is allowed when using basic authentication. Change-Id: I8846cd89dfdb98ab2fc36ba754d8302cf40527e9
This commit is contained in:
parent
b10848ee83
commit
d0bf015308
@ -443,7 +443,7 @@ By default this is set to false.
|
|||||||
[[auth.gitBasicAuth]]auth.gitBasicAuth::
|
[[auth.gitBasicAuth]]auth.gitBasicAuth::
|
||||||
+
|
+
|
||||||
If true then Git over HTTP and HTTP/S traffic is authenticated using
|
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
|
are validated against the randomly generated HTTP password, against LDAP
|
||||||
(`auth.type = LDAP`) or against an OAuth 2 provider (`auth.type = OAUTH`).
|
(`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
|
authentication and the randomly generated HTTP password in the Gerrit
|
||||||
database.
|
database.
|
||||||
+
|
+
|
||||||
When `auth.type` is `LDAP`, service users that only exist in the Gerrit
|
When `auth.type` is `LDAP`, users should authenticate using their LDAP passwords.
|
||||||
database are still authenticated by their HTTP 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
|
When `auth.type` is `OAUTH`, Git clients may send OAuth 2 access tokens
|
||||||
instead of passwords in the Basic authentication header. Note that provider
|
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.
|
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::
|
[[auth.gitOAuthProvider]]auth.gitOAuthProvider::
|
||||||
+
|
+
|
||||||
Selects the OAuth 2 provider to authenticate git over HTTP traffic with.
|
Selects the OAuth 2 provider to authenticate git over HTTP traffic with.
|
||||||
|
@ -1261,6 +1261,12 @@ Whether link:config-gerrit.html#auth.gitBasicAuth[basic authentication
|
|||||||
is used for Git over HTTP/HTTPS]. Only set if
|
is used for Git over HTTP/HTTPS]. Only set if
|
||||||
link:config-gerrit.html#auth.type[authentication type] is is `LDAP` or
|
link:config-gerrit.html#auth.type[authentication type] is is `LDAP` or
|
||||||
`LDAP_BIND`.
|
`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]]
|
[[cache-info]]
|
||||||
|
@ -19,11 +19,17 @@ On Gerrit installations that do not support SSH authentication, the
|
|||||||
user must authenticate via HTTP/HTTPS.
|
user must authenticate via HTTP/HTTPS.
|
||||||
|
|
||||||
When link:config-gerrit.html#auth.gitBasicAuth[gitBasicAuth] is enabled,
|
When link:config-gerrit.html#auth.gitBasicAuth[gitBasicAuth] is enabled,
|
||||||
the user is authenticated using standard BasicAuth and credentials validated
|
the user is authenticated using standard BasicAuth. Depending on the value of
|
||||||
using the randomly generated HTTP password on the `HTTP Password` tab
|
link:#auth.gitBasicAuthPolicy[auth.gitBasicAuthPolicy], credentials are
|
||||||
in the user settings page or against LDAP when configured for the Gerrit Web UI.
|
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
|
accessed within Gerrit by going to `Settings`, and then accessing the `HTTP
|
||||||
Password` tab.
|
Password` tab.
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
}
|
@ -15,6 +15,7 @@
|
|||||||
package com.google.gerrit.client.info;
|
package com.google.gerrit.client.info;
|
||||||
|
|
||||||
import com.google.gerrit.client.rpc.Natives;
|
import com.google.gerrit.client.rpc.Natives;
|
||||||
|
import com.google.gerrit.extensions.client.GitBasicAuthPolicy;
|
||||||
import com.google.gerrit.reviewdb.client.Account;
|
import com.google.gerrit.reviewdb.client.Account;
|
||||||
import com.google.gerrit.reviewdb.client.Account.FieldName;
|
import com.google.gerrit.reviewdb.client.Account.FieldName;
|
||||||
import com.google.gerrit.reviewdb.client.AuthType;
|
import com.google.gerrit.reviewdb.client.AuthType;
|
||||||
@ -74,12 +75,16 @@ public class AuthInfo extends JavaScriptObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final boolean isHttpPasswordSettingsEnabled() {
|
public final boolean isHttpPasswordSettingsEnabled() {
|
||||||
if (isLdap() && isGitBasicAuth()) {
|
if (isGitBasicAuth() && gitBasicAuthPolicy() == GitBasicAuthPolicy.LDAP) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final GitBasicAuthPolicy gitBasicAuthPolicy() {
|
||||||
|
return GitBasicAuthPolicy.valueOf(gitBasicAuthPolicyRaw());
|
||||||
|
}
|
||||||
|
|
||||||
public final native boolean useContributorAgreements()
|
public final native boolean useContributorAgreements()
|
||||||
/*-{ return this.use_contributor_agreements || false; }-*/;
|
/*-{ return this.use_contributor_agreements || false; }-*/;
|
||||||
public final native String loginUrl() /*-{ return this.login_url; }-*/;
|
public final native String loginUrl() /*-{ return this.login_url; }-*/;
|
||||||
@ -90,6 +95,8 @@ public class AuthInfo extends JavaScriptObject {
|
|||||||
public final native String editFullNameUrl() /*-{ return this.edit_full_name_url; }-*/;
|
public final native String editFullNameUrl() /*-{ return this.edit_full_name_url; }-*/;
|
||||||
public final native String httpPasswordUrl() /*-{ return this.http_password_url; }-*/;
|
public final native String httpPasswordUrl() /*-{ return this.http_password_url; }-*/;
|
||||||
public final native boolean isGitBasicAuth() /*-{ return this.is_git_basic_auth || false; }-*/;
|
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 String authTypeRaw() /*-{ return this.auth_type; }-*/;
|
||||||
private native JsArrayString _editableAccountFields()
|
private native JsArrayString _editableAccountFields()
|
||||||
/*-{ return this.editable_account_fields; }-*/;
|
/*-{ return this.editable_account_fields; }-*/;
|
||||||
|
@ -19,6 +19,7 @@ import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
|
|||||||
|
|
||||||
import com.google.common.base.MoreObjects;
|
import com.google.common.base.MoreObjects;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
|
import com.google.gerrit.extensions.client.GitBasicAuthPolicy;
|
||||||
import com.google.gerrit.extensions.registration.DynamicItem;
|
import com.google.gerrit.extensions.registration.DynamicItem;
|
||||||
import com.google.gerrit.reviewdb.client.Account;
|
import com.google.gerrit.reviewdb.client.Account;
|
||||||
import com.google.gerrit.server.AccessPath;
|
import com.google.gerrit.server.AccessPath;
|
||||||
@ -141,12 +142,16 @@ class ProjectBasicAuthFilter implements Filter {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!authConfig.isLdapAuthType()
|
GitBasicAuthPolicy gitBasicAuthPolicy = authConfig.getGitBasicAuthPolicy();
|
||||||
&& !passwordMatchesTheUserGeneratedOne(who, username, password)) {
|
if (gitBasicAuthPolicy == GitBasicAuthPolicy.HTTP
|
||||||
log.warn("Authentication failed for " + username
|
|| gitBasicAuthPolicy == GitBasicAuthPolicy.HTTP_LDAP) {
|
||||||
+ ": password does not match the one stored in Gerrit");
|
if (passwordMatchesTheUserGeneratedOne(who, username, password)) {
|
||||||
rsp.sendError(SC_UNAUTHORIZED);
|
return succeedAuthentication(who);
|
||||||
return false;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gitBasicAuthPolicy == GitBasicAuthPolicy.HTTP) {
|
||||||
|
return failAuthentication(rsp, username);
|
||||||
}
|
}
|
||||||
|
|
||||||
AuthRequest whoAuth = AuthRequest.forUser(username);
|
AuthRequest whoAuth = AuthRequest.forUser(username);
|
||||||
@ -158,8 +163,7 @@ class ProjectBasicAuthFilter implements Filter {
|
|||||||
return true;
|
return true;
|
||||||
} catch (NoSuchUserException e) {
|
} catch (NoSuchUserException e) {
|
||||||
if (password.equals(who.getPassword(who.getUserName()))) {
|
if (password.equals(who.getPassword(who.getUserName()))) {
|
||||||
setUserIdentified(who.getAccount().getId());
|
return succeedAuthentication(who);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
log.warn("Authentication failed for " + username, e);
|
log.warn("Authentication failed for " + username, e);
|
||||||
rsp.sendError(SC_UNAUTHORIZED);
|
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) {
|
private void setUserIdentified(Account.Id id) {
|
||||||
WebSession ws = session.get();
|
WebSession ws = session.get();
|
||||||
ws.setUserAccountId(id);
|
ws.setUserAccountId(id);
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
package com.google.gerrit.server.config;
|
package com.google.gerrit.server.config;
|
||||||
|
|
||||||
|
import com.google.gerrit.extensions.client.GitBasicAuthPolicy;
|
||||||
import com.google.gerrit.reviewdb.client.AccountExternalId;
|
import com.google.gerrit.reviewdb.client.AccountExternalId;
|
||||||
import com.google.gerrit.reviewdb.client.AuthType;
|
import com.google.gerrit.reviewdb.client.AuthType;
|
||||||
import com.google.gerrit.server.auth.openid.OpenIdProviderPattern;
|
import com.google.gerrit.server.auth.openid.OpenIdProviderPattern;
|
||||||
@ -62,6 +63,7 @@ public class AuthConfig {
|
|||||||
private final boolean cookieSecure;
|
private final boolean cookieSecure;
|
||||||
private final SignedToken emailReg;
|
private final SignedToken emailReg;
|
||||||
private final boolean allowRegisterNewEmail;
|
private final boolean allowRegisterNewEmail;
|
||||||
|
private GitBasicAuthPolicy gitBasicAuthPolicy;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
AuthConfig(@GerritServerConfig final Config cfg)
|
AuthConfig(@GerritServerConfig final Config cfg)
|
||||||
@ -90,6 +92,7 @@ public class AuthConfig {
|
|||||||
trustContainerAuth = cfg.getBoolean("auth", "trustContainerAuth", false);
|
trustContainerAuth = cfg.getBoolean("auth", "trustContainerAuth", false);
|
||||||
enableRunAs = cfg.getBoolean("auth", null, "enableRunAs", true);
|
enableRunAs = cfg.getBoolean("auth", null, "enableRunAs", true);
|
||||||
gitBasicAuth = cfg.getBoolean("auth", "gitBasicAuth", false);
|
gitBasicAuth = cfg.getBoolean("auth", "gitBasicAuth", false);
|
||||||
|
gitBasicAuthPolicy = getBasicAuthPolicy(cfg);
|
||||||
useContributorAgreements =
|
useContributorAgreements =
|
||||||
cfg.getBoolean("auth", "contributoragreements", false);
|
cfg.getBoolean("auth", "contributoragreements", false);
|
||||||
userNameToLowerCase = cfg.getBoolean("auth", "userNameToLowerCase", false);
|
userNameToLowerCase = cfg.getBoolean("auth", "userNameToLowerCase", false);
|
||||||
@ -124,6 +127,12 @@ public class AuthConfig {
|
|||||||
return cfg.getEnum("auth", null, "type", AuthType.OPENID);
|
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. */
|
/** Type of user authentication used by this Gerrit server. */
|
||||||
public AuthType getAuthType() {
|
public AuthType getAuthType() {
|
||||||
return authType;
|
return authType;
|
||||||
@ -218,6 +227,10 @@ public class AuthConfig {
|
|||||||
return gitBasicAuth;
|
return gitBasicAuth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GitBasicAuthPolicy getGitBasicAuthPolicy() {
|
||||||
|
return gitBasicAuthPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
/** Whether contributor agreements are used. */
|
/** Whether contributor agreements are used. */
|
||||||
public boolean isUseContributorAgreements() {
|
public boolean isUseContributorAgreements() {
|
||||||
return useContributorAgreements;
|
return useContributorAgreements;
|
||||||
|
@ -20,6 +20,7 @@ import com.google.common.base.Optional;
|
|||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.gerrit.extensions.client.GitBasicAuthPolicy;
|
||||||
import com.google.gerrit.extensions.config.CloneCommand;
|
import com.google.gerrit.extensions.config.CloneCommand;
|
||||||
import com.google.gerrit.extensions.config.DownloadCommand;
|
import com.google.gerrit.extensions.config.DownloadCommand;
|
||||||
import com.google.gerrit.extensions.config.DownloadScheme;
|
import com.google.gerrit.extensions.config.DownloadScheme;
|
||||||
@ -133,6 +134,7 @@ public class GetServerInfo implements RestReadView<ConfigResource> {
|
|||||||
info.editableAccountFields = new ArrayList<>(realm.getEditableFields());
|
info.editableAccountFields = new ArrayList<>(realm.getEditableFields());
|
||||||
info.switchAccountUrl = cfg.getSwitchAccountUrl();
|
info.switchAccountUrl = cfg.getSwitchAccountUrl();
|
||||||
info.isGitBasicAuth = toBoolean(cfg.isGitBasicAuth());
|
info.isGitBasicAuth = toBoolean(cfg.isGitBasicAuth());
|
||||||
|
info.gitBasicAuthPolicy = cfg.getGitBasicAuthPolicy();
|
||||||
|
|
||||||
switch (info.authType) {
|
switch (info.authType) {
|
||||||
case LDAP:
|
case LDAP:
|
||||||
@ -349,6 +351,7 @@ public class GetServerInfo implements RestReadView<ConfigResource> {
|
|||||||
public String editFullNameUrl;
|
public String editFullNameUrl;
|
||||||
public String httpPasswordUrl;
|
public String httpPasswordUrl;
|
||||||
public Boolean isGitBasicAuth;
|
public Boolean isGitBasicAuth;
|
||||||
|
public GitBasicAuthPolicy gitBasicAuthPolicy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ChangeConfigInfo {
|
public static class ChangeConfigInfo {
|
||||||
|
Loading…
Reference in New Issue
Block a user