Use OpenID PAPE extension to force reauthentication
Site administrators relying on OpenID can now enable the PAPE extension, requiring users to reauthenticate with their provider before establishing a new session with the Gerrit server. This resolves issue 521 by allowing a site administrator to set auth.maxOpenIdSessionAge to 0. In this configuration the Google Accounts provider will always prompt for a password, which gives the user a chance to sign-out of Google's account system and sign-in as a different user before they return to the Gerrit installation. Bug: issue 521 Change-Id: I656d6fd31831a71edf15319b6d94503ac93f6f36 Signed-off-by: Shawn O. Pearce <sop@google.com>
This commit is contained in:
@@ -112,6 +112,30 @@ end with `$`) or be a simple prefix (any other string).
|
||||
By default, the list contains two values, `http://` and `https://`,
|
||||
allowing Gerrit to trust any OpenID it receives.
|
||||
|
||||
[[auth.maxOpenIdSessionAge]]auth.maxOpenIdSessionAge::
|
||||
+
|
||||
Time in seconds before an OpenID provider must force the user
|
||||
to authenticate themselves again before authentication to this
|
||||
Gerrit server. Currently this is only a polite request, and users
|
||||
coming from providers that don't support the PAPE extension will
|
||||
be accepted anyway. In the future it may be enforced, rejecting
|
||||
users coming from providers that don't honor the max session age.
|
||||
+
|
||||
If set to 0, the provider will always force the user to authenticate
|
||||
(e.g. supply their password). Values should use common unit suffixes
|
||||
to express their setting:
|
||||
+
|
||||
* s, sec, second, seconds
|
||||
* m, min, minute, minutes
|
||||
* h, hr, hour, hours
|
||||
* d, day, days
|
||||
* w, week, weeks (`1 week` is treated as `7 days`)
|
||||
* mon, month, months (`1 month` is treated as `30 days`)
|
||||
* y, year, years (`1 year` is treated as `365 days`)
|
||||
|
||||
+
|
||||
Default is -1, permitting infinite time between authentications.
|
||||
|
||||
[[auth.httpHeader]]auth.httpHeader::
|
||||
+
|
||||
HTTP header to trust the username from, or unset to select HTTP basic
|
||||
|
@@ -28,6 +28,7 @@ import com.google.gerrit.server.account.AccountManager;
|
||||
import com.google.gerrit.server.cache.Cache;
|
||||
import com.google.gerrit.server.cache.SelfPopulatingCache;
|
||||
import com.google.gerrit.server.config.CanonicalWebUrl;
|
||||
import com.google.gerrit.server.config.ConfigUtil;
|
||||
import com.google.gerrit.server.config.GerritServerConfig;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwtorm.client.KeyUtil;
|
||||
@@ -50,6 +51,9 @@ import org.openid4java.message.ParameterList;
|
||||
import org.openid4java.message.ax.AxMessage;
|
||||
import org.openid4java.message.ax.FetchRequest;
|
||||
import org.openid4java.message.ax.FetchResponse;
|
||||
import org.openid4java.message.pape.PapeMessage;
|
||||
import org.openid4java.message.pape.PapeRequest;
|
||||
import org.openid4java.message.pape.PapeResponse;
|
||||
import org.openid4java.message.sreg.SRegMessage;
|
||||
import org.openid4java.message.sreg.SRegRequest;
|
||||
import org.openid4java.message.sreg.SRegResponse;
|
||||
@@ -62,6 +66,7 @@ import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.servlet.http.Cookie;
|
||||
@@ -98,6 +103,9 @@ class OpenIdServiceImpl implements OpenIdService {
|
||||
private final ConsumerManager manager;
|
||||
private final SelfPopulatingCache<String, List> discoveryCache;
|
||||
|
||||
/** Maximum age, in seconds, before forcing re-authentication of account. */
|
||||
private final int papeMaxAuthAge;
|
||||
|
||||
@Inject
|
||||
OpenIdServiceImpl(final Provider<WebSession> cf,
|
||||
final Provider<IdentifiedUser> iu,
|
||||
@@ -135,6 +143,8 @@ class OpenIdServiceImpl implements OpenIdService {
|
||||
urlProvider = up;
|
||||
accountManager = am;
|
||||
manager = new ConsumerManager();
|
||||
papeMaxAuthAge = (int) ConfigUtil.getTimeUnit(config, //
|
||||
"auth", null, "maxOpenIdSessionAge", -1, TimeUnit.SECONDS);
|
||||
|
||||
discoveryCache = new SelfPopulatingCache<String, List>(openidCache) {
|
||||
@Override
|
||||
@@ -177,6 +187,12 @@ class OpenIdServiceImpl implements OpenIdService {
|
||||
fetch.addAttribute("Email", SCHEMA_EMAIL, true);
|
||||
aReq.addExtension(fetch);
|
||||
}
|
||||
|
||||
if (0 <= papeMaxAuthAge) {
|
||||
final PapeRequest pape = PapeRequest.createPapeRequest();
|
||||
pape.setMaxAuthAge(papeMaxAuthAge);
|
||||
aReq.addExtension(pape);
|
||||
}
|
||||
} catch (MessageException e) {
|
||||
callback.onSuccess(new DiscoveryResult(false));
|
||||
return;
|
||||
@@ -277,6 +293,28 @@ class OpenIdServiceImpl implements OpenIdService {
|
||||
SRegResponse sregRsp = null;
|
||||
FetchResponse fetchRsp = null;
|
||||
|
||||
if (0 <= papeMaxAuthAge) {
|
||||
PapeResponse ext;
|
||||
boolean unsupported = false;
|
||||
|
||||
try {
|
||||
ext = (PapeResponse) authRsp.getExtension(PapeMessage.OPENID_NS_PAPE);
|
||||
} catch (MessageException err) {
|
||||
// Far too many providers are unable to provide PAPE extensions
|
||||
// right now. Instead of blocking all of them log the error and
|
||||
// let the authentication complete anyway.
|
||||
//
|
||||
log.error("Invalid PAPE response " + openidIdentifier + ": " + err);
|
||||
unsupported = true;
|
||||
ext = null;
|
||||
}
|
||||
if (!unsupported && ext == null) {
|
||||
log.error("No PAPE extension response from " + openidIdentifier);
|
||||
cancelWithError(req, rsp, "OpenID provider does not support PAPE.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (authRsp.hasExtension(SRegMessage.OPENID_NS_SREG)) {
|
||||
final MessageExtension ext =
|
||||
authRsp.getExtension(SRegMessage.OPENID_NS_SREG);
|
||||
|
Reference in New Issue
Block a user