Impersonate a privileged user when importing repos

Use the local admin user when creating a new repository for the purpose
of importing existing GitHub repositories.
Allow to import repositories without having to grant the create project
permission.

Change-Id: Id7447d9e78759d8b85153028c45c9e5be9c6072a
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubConfig.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubConfig.java
index a6646b1..5ba6d6d 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubConfig.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubConfig.java
@@ -16,6 +16,7 @@
 import com.google.common.base.MoreObjects;
 import com.google.common.collect.Maps;
 import com.google.gerrit.httpd.CanonicalWebUrl;
+import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.server.config.AllProjectsNameProvider;
 import com.google.gerrit.server.config.AuthConfig;
 import com.google.gerrit.server.config.GerritServerConfig;
@@ -44,6 +45,7 @@
   private static final String CONF_PRIVATE_BASE_PROJECT = "privateBaseProject";
   private static final String CONF_WEBHOOK_SECRET = "webhookSecret";
   private static final String CONF_WEBHOOK_USER = "webhookUser";
+  private static final String CONF_IMPORT_ACCOUNT_ID = "importAccountId";
 
   public final Path gitDir;
   public final int jobPoolLimit;
@@ -56,6 +58,7 @@
   public final String allProjectsName;
   public final String webhookSecret;
   public final String webhookUser;
+  public final Account.Id importAccountId;
 
   public static class NextPage {
     public final String uri;
@@ -103,6 +106,7 @@
     allProjectsName = allProjectsNameProvider.get().toString();
     webhookSecret = config.getString(CONF_SECTION, null, CONF_WEBHOOK_SECRET);
     webhookUser = config.getString(CONF_SECTION, null, CONF_WEBHOOK_USER);
+    importAccountId = new Account.Id(config.getInt(CONF_SECTION, CONF_IMPORT_ACCOUNT_ID, 1000000));
   }
 
   private String getSeparator(boolean redirect) {
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/CreateProjectStep.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/CreateProjectStep.java
index e67fcd4..22387b9 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/CreateProjectStep.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/CreateProjectStep.java
@@ -28,6 +28,8 @@
 import com.google.gerrit.server.git.MetaDataUpdate.User;
 import com.google.gerrit.server.git.ProjectConfig;
 import com.google.gerrit.server.project.ProjectCache;
+import com.google.gerrit.server.util.ManualRequestContext;
+import com.google.gerrit.server.util.OneOffRequestContext;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 import com.googlesource.gerrit.plugins.github.GitHubConfig;
@@ -42,6 +44,7 @@
   private static final String TAGS_REFS = "refs/tags/*";
   private static final String CODE_REVIEW_LABEL = "Code-Review";
   private static final String VERIFIED_LABEL = "Verified";
+  private final OneOffRequestContext context;
 
   private final String organisation;
   private final String repository;
@@ -70,6 +73,7 @@
       ProjectCache projectCache,
       GitHubRepository.Factory ghRepoFactory,
       GitHubConfig gitHubConfig,
+      OneOffRequestContext context,
       @Assisted("organisation") String organisation,
       @Assisted("name") String repository,
       @Assisted("description") String description,
@@ -85,6 +89,7 @@
     this.projectCache = projectCache;
     this.username = username;
     this.config = gitHubConfig;
+    this.context = context;
   }
 
   private void setProjectPermissions() {
@@ -153,7 +158,7 @@
   @Override
   public void doImport(ProgressMonitor progress) throws Exception {
     MetaDataUpdate md = null;
-    try {
+    try (ManualRequestContext requestContext = context.openAs(config.importAccountId)) {
       md = metaDataUpdateFactory.create(getProjectNameKey());
       projectConfig = ProjectConfig.read(md);
       progress.beginTask("Configure Gerrit project", 2);
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitCloneStep.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitCloneStep.java
index 5fe6017..bcfc117 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitCloneStep.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitCloneStep.java
@@ -35,6 +35,7 @@
 public class GitCloneStep extends ImportStep {
   private static final Logger LOG = LoggerFactory.getLogger(GitImporter.class);
 
+  private final GitHubConfig config;
   private final File gitDir;
   private final GerritApi gerritApi;
   private final OneOffRequestContext context;
@@ -49,30 +50,30 @@
 
   @Inject
   public GitCloneStep(
-      GitHubConfig gitConfig,
+      GitHubConfig config,
       GitHubRepository.Factory gitHubRepoFactory,
       GerritApi gerritApi,
       OneOffRequestContext context,
       @Assisted("organisation") String organisation,
       @Assisted("name") String repository)
       throws GitException {
-    super(gitConfig.gitHubUrl, organisation, repository, gitHubRepoFactory);
+    super(config.gitHubUrl, organisation, repository, gitHubRepoFactory);
     LOG.debug("GitHub Clone " + organisation + "/" + repository);
-    this.gitDir = gitConfig.gitDir.toFile();
+    this.config = config;
+    this.gitDir = config.gitDir.toFile();
 
     this.gerritApi = gerritApi;
     this.context = context;
     this.organisation = organisation;
     this.repository = repository;
-    this.destinationDirectory =
-        prepareTargetGitDirectory(gitDir, organisation, repository);
+    this.destinationDirectory = prepareTargetGitDirectory(gitDir, organisation, repository);
   }
 
   private static File prepareTargetGitDirectory(File gitDir, String organisation, String repository)
       throws GitException {
     String projectName = organisation + "/" + repository;
     File repositoryDir = new File(gitDir, projectName + ".git");
-    if(repositoryDir.exists()) {
+    if (repositoryDir.exists()) {
       throw new GitDestinationAlreadyExistsException(projectName);
     }
     return repositoryDir;
@@ -80,14 +81,15 @@
 
   private void createNewProject() throws GitException {
     String projectName = organisation + "/" + repository;
-    try (ManualRequestContext requestContext = context.open()) {
+    try (ManualRequestContext requestContext = context.openAs(config.importAccountId)) {
       gerritApi.projects().create(projectName).get();
     } catch (ResourceConflictException e) {
       throw new GitDestinationAlreadyExistsException(projectName);
     } catch (RestApiException e) {
       throw new GitException("Unable to create repository " + projectName, e);
     } catch (OrmException e) {
-      throw new GitException("Unable to create request context to create a new project " + projectName, e);
+      throw new GitException(
+          "Unable to create request context to create a new project " + projectName, e);
     }
   }