Allow project creation only when CREATE_PROJECT capability is set

Currently, the CREATE_PROJECT capability is not checked when creating
projects on primaries and replicas.

Bug: Issue 15279
Change-Id: Ifd0cfe78a8a3084ca250da4a795a4e66294f10fe
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/ProjectInitializationAction.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/ProjectInitializationAction.java
index b7749da..01635e6 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/ProjectInitializationAction.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/ProjectInitializationAction.java
@@ -21,8 +21,12 @@
 import com.google.common.flogger.FluentLogger;
 import com.google.gerrit.entities.Project;
 import com.google.gerrit.entities.RefNames;
+import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.Url;
 import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.permissions.GlobalPermission;
+import com.google.gerrit.server.permissions.PermissionBackend;
+import com.google.gerrit.server.permissions.PermissionBackendException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
@@ -45,11 +49,16 @@
 
   private final GerritConfigOps gerritConfigOps;
   private final Provider<CurrentUser> userProvider;
+  private final PermissionBackend permissionBackend;
 
   @Inject
-  ProjectInitializationAction(GerritConfigOps gerritConfigOps, Provider<CurrentUser> userProvider) {
+  ProjectInitializationAction(
+      GerritConfigOps gerritConfigOps,
+      Provider<CurrentUser> userProvider,
+      PermissionBackend permissionBackend) {
     this.gerritConfigOps = gerritConfigOps;
     this.userProvider = userProvider;
+    this.permissionBackend = permissionBackend;
   }
 
   @Override
@@ -72,11 +81,19 @@
     String path = httpServletRequest.getRequestURI();
     String projectName = Url.decode(path.substring(path.lastIndexOf('/') + 1));
 
-    if (initProject(projectName)) {
+    try {
+      if (initProject(projectName)) {
+        setResponse(
+            httpServletResponse,
+            HttpServletResponse.SC_CREATED,
+            "Project " + projectName + " initialized");
+        return;
+      }
+    } catch (AuthException | PermissionBackendException e) {
       setResponse(
           httpServletResponse,
-          HttpServletResponse.SC_CREATED,
-          "Project " + projectName + " initialized");
+          HttpServletResponse.SC_FORBIDDEN,
+          "User not authorized to create project " + projectName);
       return;
     }
 
@@ -86,7 +103,10 @@
         "Cannot initialize project " + projectName);
   }
 
-  protected boolean initProject(String projectName) {
+  protected boolean initProject(String projectName)
+      throws AuthException, PermissionBackendException {
+    permissionBackend.user(userProvider.get()).check(GlobalPermission.CREATE_PROJECT);
+
     Optional<URIish> maybeUri = gerritConfigOps.getGitRepositoryURI(projectName);
     if (!maybeUri.isPresent()) {
       logger.atSevere().log("Cannot initialize project '{}'", projectName);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/PullReplicationFilter.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/PullReplicationFilter.java
index 9831704..a4ea953 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/PullReplicationFilter.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/PullReplicationFilter.java
@@ -163,7 +163,7 @@
   }
 
   private void doInitProject(HttpServletRequest httpRequest, HttpServletResponse httpResponse)
-      throws RestApiException, IOException {
+      throws RestApiException, IOException, PermissionBackendException {
 
     String path = httpRequest.getRequestURI();
     String projectName = Url.decode(path.substring(path.lastIndexOf('/') + 1));
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ProjectInitializationActionIT.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ProjectInitializationActionIT.java
index 4035fb8..ca4fa31 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ProjectInitializationActionIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ProjectInitializationActionIT.java
@@ -14,11 +14,16 @@
 
 package com.googlesource.gerrit.plugins.replication.pull.api;
 
+import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allowCapability;
 import static com.googlesource.gerrit.plugins.replication.pull.api.ProjectInitializationAction.getProjectInitializationUrl;
 
 import com.google.common.net.MediaType;
 import com.google.gerrit.acceptance.config.GerritConfig;
+import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
+import com.google.gerrit.common.data.GlobalCapability;
 import com.google.gerrit.extensions.restapi.Url;
+import com.google.gerrit.server.group.SystemGroupBackend;
+import com.google.inject.Inject;
 import javax.servlet.http.HttpServletResponse;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpPut;
@@ -27,6 +32,7 @@
 
 public class ProjectInitializationActionIT extends ActionITBase {
   public static final String INVALID_TEST_PROJECT_NAME = "\0";
+  @Inject private ProjectOperations projectOperations;
 
   @Test
   public void shouldReturnUnauthorizedForUserWithoutPermissions() throws Exception {
@@ -68,6 +74,43 @@
   }
 
   @Test
+  public void shouldCreateRepositoryWhenUserHasProjectCreationCapabilities() throws Exception {
+    String newProjectName = "new/newProjectForUserWithCapabilities";
+    url = getURL(newProjectName);
+    httpClientFactory
+        .create(source)
+        .execute(
+            createPutRequestWithHeaders(),
+            assertHttpResponseCode(HttpServletResponse.SC_FORBIDDEN),
+            getUserContext());
+
+    projectOperations
+        .project(allProjects)
+        .forUpdate()
+        .add(
+            allowCapability(GlobalCapability.CREATE_PROJECT)
+                .group(SystemGroupBackend.REGISTERED_USERS))
+        .update();
+
+    httpClientFactory
+        .create(source)
+        .execute(
+            createPutRequestWithHeaders(),
+            assertHttpResponseCode(HttpServletResponse.SC_CREATED),
+            getUserContext());
+  }
+
+  @Test
+  public void shouldReturnForbiddenIfUserNotAuthorized() throws Exception {
+    httpClientFactory
+        .create(source)
+        .execute(
+            createPutRequestWithHeaders(),
+            assertHttpResponseCode(HttpServletResponse.SC_FORBIDDEN),
+            getUserContext());
+  }
+
+  @Test
   @GerritConfig(name = "container.replica", value = "true")
   public void shouldCreateRepositoryWhenNodeIsAReplica() throws Exception {
     String newProjectName = "new/newProjectForReplica";
@@ -82,6 +125,46 @@
 
   @Test
   @GerritConfig(name = "container.replica", value = "true")
+  public void shouldReturnForbiddenIfUserNotAuthorizedAndNodeIsAReplica() throws Exception {
+    httpClientFactory
+        .create(source)
+        .execute(
+            createPutRequestWithHeaders(),
+            assertHttpResponseCode(HttpServletResponse.SC_FORBIDDEN),
+            getUserContext());
+  }
+
+  @Test
+  @GerritConfig(name = "container.replica", value = "true")
+  public void shouldCreateRepositoryWhenUserHasProjectCreationCapabilitiesAndNodeIsAReplica()
+      throws Exception {
+    String newProjectName = "new/newProjectForUserWithCapabilitiesReplica";
+    url = getURL(newProjectName);
+    httpClientFactory
+        .create(source)
+        .execute(
+            createPutRequestWithHeaders(),
+            assertHttpResponseCode(HttpServletResponse.SC_FORBIDDEN),
+            getUserContext());
+
+    projectOperations
+        .project(allProjects)
+        .forUpdate()
+        .add(
+            allowCapability(GlobalCapability.CREATE_PROJECT)
+                .group(SystemGroupBackend.REGISTERED_USERS))
+        .update();
+
+    httpClientFactory
+        .create(source)
+        .execute(
+            createPutRequestWithHeaders(),
+            assertHttpResponseCode(HttpServletResponse.SC_CREATED),
+            getUserContext());
+  }
+
+  @Test
+  @GerritConfig(name = "container.replica", value = "true")
   public void shouldReturnInternalServerErrorIfProjectCannotBeCreatedWhenNodeIsAReplica()
       throws Exception {
     url = getURL(INVALID_TEST_PROJECT_NAME);