Support changing Google Account identity strings

If auth.allowGoogleAccountUpgrade is set to true we now allow the
user's OpenID identity token to change during sign-in, such as if
the server hostname was recently changed.

Change-Id: I5d88ce8d39186ef22fd47b257a3c791c2b2c12bd
Signed-off-by: Shawn O. Pearce <sop@google.com>
This commit is contained in:
Shawn O. Pearce
2009-08-31 10:53:12 -07:00
parent 640813c03d
commit 48eea077c5
2 changed files with 58 additions and 22 deletions

View File

@@ -131,24 +131,18 @@ By default this is false (no agreements are used).
auth.allowGoogleAccountUpgrade:: auth.allowGoogleAccountUpgrade::
+ +
Allow old Gerrit1 users to seamlessly upgrade from Google Accounts Allows Google Account users to automatically update their Gerrit
on Google App Engine to OpenID authentication. This should only be account when/if their Google Account OpenID identity token changes.
set to true on a Gerrit2 database that was imported from a Gerrit1 Identity tokens can change if the server changes hostnames, or
database run on Google App Engine. Having it enabled incurs an for other reasons known only to Google. The upgrade path works
extra database query when new Google Account users register with by matching users by email address if the identity is not present,
the Gerrit2 server. and then changing the identity.
+ +
Its strongly encouraged to unset this once the following query This setting also permits old Gerrit 1.x users to seamlessly upgrade
drops to 0, or close to 0: from Google Accounts on Google App Engine to OpenID authentication.
+ +
==== Having this enabled incurs an extra database query when Google
SELECT COUNT(*) FROM account_external_ids e Account users register with the Gerrit2 server.
WHERE e.external_id LIKE 'Google Account %'
AND NOT EXISTS (SELECT 1
FROM account_external_ids o
WHERE o.account_id = e.account_id
AND o.external_id LIKE '%.google.com%/id?id=%');
====
+ +
By default, unset/false. By default, unset/false.

View File

@@ -25,6 +25,7 @@ import com.google.gwtorm.client.Transaction;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@@ -175,16 +176,57 @@ public class AccountManager {
if (authConfig.isAllowGoogleAccountUpgrade() if (authConfig.isAllowGoogleAccountUpgrade()
&& who.isScheme(OpenIdUtil.URL_GOOGLE + "?") && who.isScheme(OpenIdUtil.URL_GOOGLE + "?")
&& who.getEmailAddress() != null) { && who.getEmailAddress() != null) {
final List<AccountExternalId> legacyAppEngine = final List<AccountExternalId> openId = new ArrayList<AccountExternalId>();
db.accountExternalIds().byExternal( final List<AccountExternalId> v1 = new ArrayList<AccountExternalId>();
AccountExternalId.LEGACY_GAE + who.getEmailAddress()).toList();
if (legacyAppEngine.size() == 1) { for (final AccountExternalId extId : db.accountExternalIds()
.byEmailAddress(who.getEmailAddress())) {
if (extId.isScheme(OpenIdUtil.URL_GOOGLE + "?")) {
openId.add(extId);
} else if (extId.isScheme(AccountExternalId.LEGACY_GAE)) {
v1.add(extId);
}
}
if (!openId.isEmpty()) {
// The user has already registered with an OpenID from Google, but
// Google may have changed the user's OpenID identity if this server
// name has changed. Insert a new identity for the user.
//
final Account.Id accountId = openId.get(0).getAccountId();
if (openId.size() > 1) {
// Validate all matching identities are actually the same user.
//
for (final AccountExternalId extId : openId) {
if (!accountId.equals(extId.getAccountId())) {
throw new AccountException("Multiple user accounts for "
+ who.getEmailAddress() + " using Google Accounts provider");
}
}
}
final AccountExternalId newId = createId(accountId, who);
newId.setEmailAddress(who.getEmailAddress());
newId.setLastUsedOn();
if (openId.size() == 1) {
final AccountExternalId oldId = openId.get(0);
final Transaction txn = db.beginTransaction();
db.accountExternalIds().delete(Collections.singleton(oldId), txn);
db.accountExternalIds().insert(Collections.singleton(newId), txn);
txn.commit();
} else {
db.accountExternalIds().insert(Collections.singleton(newId));
}
return new AuthResult(accountId, false);
} else if (v1.size() == 1) {
// Exactly one user was imported from Gerrit 1.x with this email // Exactly one user was imported from Gerrit 1.x with this email
// address. Upgrade their account by deleting the legacy import // address. Upgrade their account by deleting the legacy import
// identity and creating a new identity matching the token we have. // identity and creating a new identity matching the token we have.
// //
final AccountExternalId oldId = legacyAppEngine.get(0); final AccountExternalId oldId = v1.get(0);
final AccountExternalId newId = createId(oldId.getAccountId(), who); final AccountExternalId newId = createId(oldId.getAccountId(), who);
newId.setEmailAddress(who.getEmailAddress()); newId.setEmailAddress(who.getEmailAddress());
newId.setLastUsedOn(); newId.setLastUsedOn();
@@ -194,7 +236,7 @@ public class AccountManager {
txn.commit(); txn.commit();
return new AuthResult(newId.getAccountId(), false); return new AuthResult(newId.getAccountId(), false);
} else if (legacyAppEngine.size() > 1) { } else if (v1.size() > 1) {
throw new AccountException("Multiple Gerrit 1.x accounts found"); throw new AccountException("Multiple Gerrit 1.x accounts found");
} }
} }