Allow getting displayName/e-mail with auth.type=HTTP

When using HTTP-based authentication, the SSO can be
delegated to check not only the user credentials
but also to fetch the full user-profile (e.g. SiteMinder does).

With the config properties auth.httpDisplaynameHeader
and auth.httpEmailHeader it is possible to configure
the name of the headers used for propagating this
extra information and enforce them on the user profile
during login and beyond. This allows the company to
take full control of the user profile through a unique
entry point using HTTP authentication.

This is particularly useful if we consider all the
existing authentication mechanisms available with
an HTTP front-end reverse proxy:
- Kerberos
- Radius
- Generic SQL Database
- SiteMinder
- OAuth

Change-Id: I12f9cc0386acd11c03eeaa7475e4e9e8ab94a555
This commit is contained in:
Luca Milanesio
2013-07-30 09:10:07 +01:00
parent 09471488f0
commit 384ed6c298
6 changed files with 74 additions and 3 deletions

View File

@@ -255,6 +255,24 @@ The "Sign In" link will send users directly to this URL.
HTTP header to trust the username from, or unset to select HTTP basic
or digest authentication. Only used if `auth.type` is set to `HTTP`.
[[auth.httpDisplaynameHeader]]auth.httpDisplaynameHeader::
+
HTTP header to retrieve the user's display name from. Only used if `auth.type`
is set to `HTTP`.
+
If set, Gerrit trusts and enforces the user's full name using the HTTP header
and disables the ability to manually modify the user's full name
from the contact information page.
[[auth.httpEmailHeader]]auth.httpEmailHeader::
+
HTTP header to retrieve the user's e-mail from. Only used if `auth.type`
is set to `HTTP`.
+
If set, Gerrit trusts and enforces the user's e-mail using the HTTP header
and disables the ability to manually modify or register other e-mails
from the contact information page.
[[auth.loginUrl]]auth.loginUrl::
+
URL to redirect a browser to after the end-user has clicked on the

View File

@@ -137,7 +137,8 @@ class GerritConfigProvider implements Provider<GerritConfig> {
fields.add(n);
}
}
if (emailSender != null && emailSender.isEnabled()) {
if (emailSender != null && emailSender.isEnabled()
&& realm.allowsEdit(Account.FieldName.REGISTER_NEW_EMAIL)) {
fields.add(Account.FieldName.REGISTER_NEW_EMAIL);
}
config.setEditableAccountFields(fields);

View File

@@ -61,6 +61,8 @@ class HttpAuthFilter implements Filter {
private final byte[] signInRaw;
private final byte[] signInGzip;
private final String loginHeader;
private final String displaynameHeader;
private final String emailHeader;
@Inject
HttpAuthFilter(final Provider<WebSession> webSession,
@@ -78,6 +80,8 @@ class HttpAuthFilter implements Filter {
loginHeader = firstNonNull(
emptyToNull(authConfig.getLoginHttpHeader()),
AUTHORIZATION);
displaynameHeader = emptyToNull(authConfig.getHttpDisplaynameHeader());
emailHeader = emptyToNull(authConfig.getHttpEmailHeader());
}
@Override
@@ -174,6 +178,22 @@ class HttpAuthFilter implements Filter {
}
}
String getRemoteDisplayname(HttpServletRequest req) {
if (displaynameHeader != null) {
return emptyToNull(req.getHeader(displaynameHeader));
} else {
return null;
}
}
String getRemoteEmail(HttpServletRequest req) {
if (emailHeader != null) {
return emptyToNull(req.getHeader(emailHeader));
} else {
return null;
}
}
String getLoginHeader() {
return loginHeader;
}

View File

@@ -110,6 +110,8 @@ class HttpLoginServlet extends HttpServlet {
}
final AuthRequest areq = AuthRequest.forUser(user);
areq.setDisplayName(authFilter.getRemoteDisplayname(req));
areq.setEmailAddress(authFilter.getRemoteEmail(req));
final AuthResult arsp;
try {
arsp = accountManager.authenticate(areq);

View File

@@ -14,8 +14,11 @@
package com.google.gerrit.server.account;
import com.google.common.base.Strings;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AuthType;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.config.AuthConfig;
import com.google.inject.Inject;
import java.util.Set;
@@ -23,17 +26,32 @@ import java.util.Set;
public class DefaultRealm implements Realm {
private final EmailExpander emailExpander;
private final AccountByEmailCache byEmail;
private final AuthConfig authConfig;
@Inject
DefaultRealm(final EmailExpander emailExpander,
final AccountByEmailCache byEmail) {
final AccountByEmailCache byEmail, final AuthConfig authConfig) {
this.emailExpander = emailExpander;
this.byEmail = byEmail;
this.authConfig = authConfig;
}
@Override
public boolean allowsEdit(final Account.FieldName field) {
return true;
if (authConfig.getAuthType() == AuthType.HTTP) {
switch (field) {
case USER_NAME:
return false;
case FULL_NAME:
return Strings.emptyToNull(authConfig.getHttpDisplaynameHeader()) == null;
case REGISTER_NEW_EMAIL:
return Strings.emptyToNull(authConfig.getHttpEmailHeader()) == null;
default:
return true;
}
} else {
return true;
}
}
@Override

View File

@@ -36,6 +36,8 @@ import java.util.concurrent.TimeUnit;
public class AuthConfig {
private final AuthType authType;
private final String httpHeader;
private final String httpDisplaynameHeader;
private final String httpEmailHeader;
private final boolean trustContainerAuth;
private final boolean enableRunAs;
private final boolean userNameToLowerCase;
@@ -58,6 +60,8 @@ public class AuthConfig {
throws XsrfException {
authType = toType(cfg);
httpHeader = cfg.getString("auth", null, "httpheader");
httpDisplaynameHeader = cfg.getString("auth", null, "httpdisplaynameheader");
httpEmailHeader = cfg.getString("auth", null, "httpemailheader");
loginUrl = cfg.getString("auth", null, "loginurl");
logoutUrl = cfg.getString("auth", null, "logouturl");
openIdSsoUrl = cfg.getString("auth", null, "openidssourl");
@@ -126,6 +130,14 @@ public class AuthConfig {
return httpHeader;
}
public String getHttpDisplaynameHeader() {
return httpDisplaynameHeader;
}
public String getHttpEmailHeader() {
return httpEmailHeader;
}
public String getLoginUrl() {
return loginUrl;
}