Merge "Additional AccountExternalId when creating account"
diff --git a/Documentation/dev-plugins.txt b/Documentation/dev-plugins.txt
index e61a725..01dfcc2 100644
--- a/Documentation/dev-plugins.txt
+++ b/Documentation/dev-plugins.txt
@@ -1950,6 +1950,32 @@
 No Guice bindings or modules are required. Gerrit will automatically
 discover and bind the implementation.
 
+[[accountcreation]]
+== Account Creation
+
+Plugins can hook into the
+link:rest-api-accounts.html#create-account[account creation] REST API and
+inject additional external identifiers for an account that represents a user
+in some external user store. For that, an implementation of the extension
+point `com.google.gerrit.server.api.accounts.AccountExternalIdCreator`
+must be registered.
+
+[source,java]
+----
+class MyExternalIdCreator implements AccountExternalIdCreator {
+  @Override
+  public List<AccountExternalId> create(Account.Id id, String username,
+      String email) {
+    // your code
+  }
+}
+
+bind(AccountExternalIdCreator.class)
+  .annotatedWith(UniqueAnnotations.create())
+  .to(MyExternalIdCreator.class);
+}
+----
+
 [[download-commands]]
 == Download Commands
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/CreateAccount.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/CreateAccount.java
index cf6c27e..f16c3ea 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/CreateAccount.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/CreateAccount.java
@@ -22,6 +22,7 @@
 import com.google.gerrit.common.errors.InvalidSshKeyException;
 import com.google.gerrit.extensions.annotations.RequiresCapability;
 import com.google.gerrit.extensions.common.AccountInfo;
+import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.gerrit.extensions.restapi.BadRequestException;
 import com.google.gerrit.extensions.restapi.DefaultInput;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
@@ -37,6 +38,7 @@
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.CreateAccount.Input;
+import com.google.gerrit.server.api.accounts.AccountExternalIdCreator;
 import com.google.gerrit.server.group.GroupsCollection;
 import com.google.gerrit.server.ssh.SshKeyCache;
 import com.google.gwtorm.server.OrmDuplicateKeyException;
@@ -48,6 +50,7 @@
 import org.apache.commons.validator.routines.EmailValidator;
 
 import java.util.Collections;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
 
@@ -74,6 +77,7 @@
   private final AccountCache accountCache;
   private final AccountByEmailCache byEmailCache;
   private final AccountLoader.Factory infoLoader;
+  private final DynamicSet<AccountExternalIdCreator> externalIdCreators;
   private final String username;
   private final AuditService auditService;
 
@@ -82,6 +86,7 @@
       GroupsCollection groupsCollection, SshKeyCache sshKeyCache,
       AccountCache accountCache, AccountByEmailCache byEmailCache,
       AccountLoader.Factory infoLoader,
+      DynamicSet<AccountExternalIdCreator> externalIdCreators,
       @Assisted String username, AuditService auditService) {
     this.db = db;
     this.currentUser = currentUser;
@@ -90,6 +95,7 @@
     this.accountCache = accountCache;
     this.byEmailCache = byEmailCache;
     this.infoLoader = infoLoader;
+    this.externalIdCreators = externalIdCreators;
     this.username = username;
     this.auditService = auditService;
   }
@@ -137,8 +143,14 @@
       }
     }
 
+    LinkedList<AccountExternalId> externalIds = new LinkedList<>();
+    externalIds.add(extUser);
+    for (AccountExternalIdCreator c : externalIdCreators) {
+      externalIds.addAll(c.create(id, username, input.email));
+    }
+
     try {
-      db.accountExternalIds().insert(Collections.singleton(extUser));
+      db.accountExternalIds().insert(externalIds);
     } catch (OrmDuplicateKeyException duplicateKey) {
       throw new ResourceConflictException(
           "username '" + username + "' already exists");
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountExternalIdCreator.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountExternalIdCreator.java
new file mode 100644
index 0000000..9c500b2
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountExternalIdCreator.java
@@ -0,0 +1,37 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.api.accounts;
+
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
+
+import java.util.List;
+
+public interface AccountExternalIdCreator {
+
+  /**
+   * Returns additional external identifiers to assign to a given
+   * user when creating an account.
+   *
+   * @param id the identifier of the account.
+   * @param username the name of the user.
+   * @param email an optional email address to assign to the external
+   * identifiers, or {@code null}.
+   *
+   * @return a list of external identifiers, or an empty list.
+   */
+  public List<AccountExternalId> create(Account.Id id, String username,
+      String email);
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
index ee3f9b2..ed462ad 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
@@ -69,6 +69,7 @@
 import com.google.gerrit.server.account.GroupIncludeCacheImpl;
 import com.google.gerrit.server.account.GroupInfoCacheFactory;
 import com.google.gerrit.server.account.GroupMembers;
+import com.google.gerrit.server.api.accounts.AccountExternalIdCreator;
 import com.google.gerrit.server.auth.AuthBackend;
 import com.google.gerrit.server.auth.UniversalAuthBackend;
 import com.google.gerrit.server.avatar.AvatarProvider;
@@ -303,6 +304,7 @@
     DynamicSet.setOf(binder(), ProjectWebLink.class);
     DynamicSet.setOf(binder(), BranchWebLink.class);
     DynamicMap.mapOf(binder(), OAuthLoginProvider.class);
+    DynamicSet.setOf(binder(), AccountExternalIdCreator.class);
 
     factory(UploadValidators.Factory.class);
     DynamicSet.setOf(binder(), UploadValidationListener.class);