summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn O. Pearce <sop@google.com>2009-08-31 10:53:12 -0700
committerShawn O. Pearce <sop@google.com>2009-08-31 10:56:05 -0700
commit48eea077c5bcae20449afe65f98ad50901cc1180 (patch)
treee65bd138cee1c141b09f461619b82c0d4a9c063b
parent640813c03d3358fb7b2466c1d5ff9194fe2160a0 (diff)
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>
-rw-r--r--Documentation/config-gerrit.txt30
-rw-r--r--src/main/java/com/google/gerrit/server/account/AccountManager.java54
2 files changed, 60 insertions, 24 deletions
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 80f5191117..3b90fcc1ef 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -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.
-+
-Its strongly encouraged to unset this once the following query
-drops to 0, or close to 0:
-+
-====
- 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=%');
-====
+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.
++
+This setting also permits old Gerrit 1.x users to seamlessly upgrade
+from Google Accounts on Google App Engine to OpenID authentication.
++
+Having this enabled incurs an extra database query when Google
+Account users register with the Gerrit2 server.
+
By default, unset/false.
diff --git a/src/main/java/com/google/gerrit/server/account/AccountManager.java b/src/main/java/com/google/gerrit/server/account/AccountManager.java
index d45110e85c..0e957a24bd 100644
--- a/src/main/java/com/google/gerrit/server/account/AccountManager.java
+++ b/src/main/java/com/google/gerrit/server/account/AccountManager.java
@@ -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");
}
}