Do not check visibility of parent when creating project A project can be visible to a user but not necessarily its parent. To be consistent, a user with create-project permission should be able to create a project with a parent that exists even if the parent is not visible to the user. Here is an example when this case is happening. On a Gerrit server where All-projects is only visible to administrators and create-project permission is granted to non-administrators, when a non-administrator tries to create a project with All-Projects (which is the default when parent is not specified) as its parent, it was failing before this change with "Not found: All-Projects". Change-Id: Id93370ab108f377f643b55efdf781dfd2c66f220
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java index 37d350a..1d659cc 100644 --- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java
@@ -274,6 +274,26 @@ assertCreateFails(in, ResourceConflictException.class); } + @Test + public void testCreateProjectWithCreateProjectCapabilityAndParentNotVisible() + throws Exception { + Project parent = projectCache.get(allProjects).getProject(); + parent.setState(com.google.gerrit.extensions.client.ProjectState.HIDDEN); + allowGlobalCapabilities(SystemGroupBackend.REGISTERED_USERS, + GlobalCapability.CREATE_PROJECT); + try { + setApiUser(user); + ProjectInput in = new ProjectInput(); + in.name = name("newProject"); + ProjectInfo p = gApi.projects().create(in).get(); + assertThat(p.name).isEqualTo(in.name); + } finally { + parent.setState(com.google.gerrit.extensions.client.ProjectState.ACTIVE); + removeGlobalCapabilities(SystemGroupBackend.REGISTERED_USERS, + GlobalCapability.CREATE_PROJECT); + } + } + private AccountGroup.UUID groupUuid(String groupName) { return groupCache.get(new AccountGroup.NameKey(groupName)).getGroupUUID(); }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateProject.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateProject.java index 41bc288..c04878f 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateProject.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateProject.java
@@ -161,7 +161,8 @@ String parentName = MoreObjects.firstNonNull( Strings.emptyToNull(input.parent), allProjects.get()); - args.newParent = projectsCollection.get().parse(parentName).getControl(); + args.newParent = + projectsCollection.get().parse(parentName, false).getControl(); args.createEmptyCommit = input.createEmptyCommit; args.permissionsOnly = input.permissionsOnly; args.projectDescription = Strings.emptyToNull(input.description);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectsCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectsCollection.java index 0ffbe3e..51603fc 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectsCollection.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectsCollection.java
@@ -63,7 +63,7 @@ @Override public ProjectResource parse(TopLevelResource parent, IdString id) throws ResourceNotFoundException, IOException { - ProjectResource rsrc = _parse(id.get()); + ProjectResource rsrc = _parse(id.get(), true); if (rsrc == null) { throw new ResourceNotFoundException(id); } @@ -81,7 +81,24 @@ */ public ProjectResource parse(String id) throws UnprocessableEntityException, IOException { - ProjectResource rsrc = _parse(id); + return parse(id, true); + } + + /** + * Parses a project ID from a request body and returns the project. + * + * @param id ID of the project, can be a project name + * @param checkVisibility Whether to check or not that project is visible to + * the calling user + * @return the project + * @throws UnprocessableEntityException thrown if the project ID cannot be + * resolved or if the project is not visible to the calling user and + * checkVisibility is true. + * @throws IOException thrown when there is an error. + */ + public ProjectResource parse(String id, boolean checkVisibility) + throws UnprocessableEntityException, IOException { + ProjectResource rsrc = _parse(id, checkVisibility); if (rsrc == null) { throw new UnprocessableEntityException(String.format( "Project Not Found: %s", id)); @@ -89,7 +106,8 @@ return rsrc; } - private ProjectResource _parse(String id) throws IOException { + private ProjectResource _parse(String id, boolean checkVisibility) + throws IOException { if (id.endsWith(Constants.DOT_GIT_EXT)) { id = id.substring(0, id.length() - Constants.DOT_GIT_EXT.length()); } @@ -101,7 +119,7 @@ } catch (NoSuchProjectException e) { return null; } - if (!ctl.isVisible() && !ctl.isOwner()) { + if (checkVisibility && !ctl.isVisible() && !ctl.isOwner()) { return null; } return new ProjectResource(ctl);