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::
+
Allow old Gerrit1 users to seamlessly upgrade from Google Accounts
on Google App Engine to OpenID authentication. This should only be
set to true on a Gerrit2 database that was imported from a Gerrit1
database run on Google App Engine. Having it enabled incurs an
extra database query when new Google Account users register with
the Gerrit2 server.
Allows Google Account users to automatically update their Gerrit
account when/if their Google Account OpenID identity token changes.
Identity tokens can change if the server changes hostnames, or
for other reasons known only to Google. The upgrade path works
by matching users by email address if the identity is not present,
and then changing the identity.
+
Its strongly encouraged to unset this once the following query
drops to 0, or close to 0:
This setting also permits old Gerrit 1.x users to seamlessly upgrade
from Google Accounts on Google App Engine to OpenID authentication.
+
====
SELECT COUNT(*) FROM account_external_ids e
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=%');
====
Having this enabled incurs an extra database query when Google
Account users register with the Gerrit2 server.
+
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.Singleton;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -175,16 +176,57 @@ public class AccountManager {
if (authConfig.isAllowGoogleAccountUpgrade()
&& who.isScheme(OpenIdUtil.URL_GOOGLE + "?")
&& who.getEmailAddress() != null) {
final List<AccountExternalId> legacyAppEngine =
db.accountExternalIds().byExternal(
AccountExternalId.LEGACY_GAE + who.getEmailAddress()).toList();
final List<AccountExternalId> openId = new ArrayList<AccountExternalId>();
final List<AccountExternalId> v1 = new ArrayList<AccountExternalId>();
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
// address. Upgrade their account by deleting the legacy import
// 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);
newId.setEmailAddress(who.getEmailAddress());
newId.setLastUsedOn();
@@ -194,7 +236,7 @@ public class AccountManager {
txn.commit();
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");
}
}