PutReviewers: Add validation of input.reviewer

Check that the given reviewer matches a known account name or group
name, and throw 404 if it doesn't.

Change-Id: I098acf7164c7448454dcffe8d55c0760f2f7f07d
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewers/PutReviewers.java b/src/main/java/com/googlesource/gerrit/plugins/reviewers/PutReviewers.java
index 39f9d1a..92d8001 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewers/PutReviewers.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewers/PutReviewers.java
@@ -21,14 +21,19 @@
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
 import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.extensions.restapi.RestModifyView;
+import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
+import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.Branch;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.client.RefNames;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.account.AccountResolver;
 import com.google.gerrit.server.git.MetaDataUpdate;
+import com.google.gerrit.server.group.GroupsCollection;
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.server.project.ProjectResource;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
@@ -38,12 +43,17 @@
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
 import org.eclipse.jgit.lib.ObjectId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.util.List;
 
 @Singleton
 class PutReviewers implements RestModifyView<ProjectResource, Input> {
+  private static final Logger log = LoggerFactory
+      .getLogger(PutReviewers.class);
+
   public static class Input {
     public Action action;
     public String filter;
@@ -56,6 +66,8 @@
   private final ProjectCache projectCache;
   private final Provider<CurrentUser> currentUser;
   private final ChangeHooks hooks;
+  private final AccountResolver accountResolver;
+  private final Provider<GroupsCollection> groupsCollection;
 
   @Inject
   PutReviewers(@PluginName String pluginName,
@@ -63,13 +75,17 @@
       Provider<MetaDataUpdate.User> metaDataUpdateFactory,
       ProjectCache projectCache,
       ChangeHooks hooks,
-      Provider<CurrentUser> currentUser) {
+      Provider<CurrentUser> currentUser,
+      AccountResolver accountResolver,
+      Provider<GroupsCollection> groupsCollection) {
     this.pluginName = pluginName;
     this.configFactory = configFactory;
     this.metaDataUpdateFactory = metaDataUpdateFactory;
     this.projectCache = projectCache;
     this.hooks = hooks;
     this.currentUser = currentUser;
+    this.accountResolver = accountResolver;
+    this.groupsCollection = groupsCollection;
   }
 
   @Override
@@ -91,6 +107,7 @@
       throw new ResourceNotFoundException(
           "Project" + projectName.get() + " not found", e);
     }
+    validateReviewer(input.reviewer);
     try {
       StringBuilder message = new StringBuilder(pluginName)
           .append(" plugin: ");
@@ -140,4 +157,20 @@
     }
     return cfg.getReviewerFilterSections();
   }
+
+  private void validateReviewer(String reviewer) throws RestApiException {
+    try {
+      Account account = accountResolver.find(reviewer);
+      if (account == null) {
+        try {
+          groupsCollection.get().parse(reviewer);
+        } catch (UnprocessableEntityException e) {
+          throw new ResourceNotFoundException(
+              "Account or group " + reviewer + " not found");
+        }
+      }
+    } catch (OrmException e) {
+      log.error("Failed to resolve account " + reviewer);
+    }
+  }
 }