CreateChange: add a visibility check for the target branch
Currently, it's possible for a user to create a change on a branch they can't see. When this happens, the created change is not accessible by the user (WAI) but this gives the user a way to probe whether a branch exists or not. This commit fixes this issue by adding a "READ" permisssion check for the input branch and verifies that if the user doesn't have permission to see the target branch, we always return 404 no matter the branch exists or not. BTW, the existing #createChangeOnInvisibleBranchFails test failed to catch up this because the 404 it verifies is thrown by the java API ChangesImpl#create when it tries to create a ChangeInfo for the created change. Change-Id: I5c8e3334e37b7215c86c08c5172a8e3b4a69d0c6
This commit is contained in:
@@ -30,6 +30,7 @@ import com.google.gerrit.extensions.restapi.AuthException;
|
||||
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||
import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
|
||||
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
||||
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
||||
import com.google.gerrit.extensions.restapi.Response;
|
||||
import com.google.gerrit.extensions.restapi.RestApiException;
|
||||
import com.google.gerrit.extensions.restapi.TopLevelResource;
|
||||
@@ -196,6 +197,12 @@ public class CreateChange
|
||||
|
||||
Project.NameKey project = rsrc.getNameKey();
|
||||
String refName = RefNames.fullName(input.branch);
|
||||
try {
|
||||
permissionBackend.currentUser().project(project).ref(refName).check(RefPermission.READ);
|
||||
} catch (AuthException e) {
|
||||
throw new ResourceNotFoundException(String.format("ref %s not found", refName));
|
||||
}
|
||||
|
||||
permissionBackend
|
||||
.currentUser()
|
||||
.project(project)
|
||||
|
@@ -267,16 +267,6 @@ public class CreateChangeIT extends AbstractDaemonTest {
|
||||
in, UnprocessableEntityException.class, "Base change not found: " + in.baseChange);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createChangeOnInvisibleBranchFails() throws Exception {
|
||||
changeInTwoBranches("invisible-branch", "a.txt", "branchB", "b.txt");
|
||||
block(project, "refs/heads/invisible-branch", READ, REGISTERED_USERS);
|
||||
|
||||
ChangeInput in = newChangeInput(ChangeStatus.NEW);
|
||||
in.branch = "invisible-branch";
|
||||
assertCreateFails(in, ResourceNotFoundException.class, "");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noteDbCommit() throws Exception {
|
||||
ChangeInfo c = assertCreateSucceeds(newChangeInput(ChangeStatus.NEW));
|
||||
@@ -456,6 +446,30 @@ public class CreateChangeIT extends AbstractDaemonTest {
|
||||
assertThat(revInfo.commit.message).isEqualTo(input.message + "\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createChangeOnExistingBranchNotPermitted() throws Exception {
|
||||
createBranch(new Branch.NameKey(project, "foo"));
|
||||
blockRead("refs/heads/*");
|
||||
requestScopeOperations.setApiUser(user.id);
|
||||
ChangeInput input = newChangeInput(ChangeStatus.NEW);
|
||||
input.branch = "foo";
|
||||
|
||||
assertCreateFails(input, ResourceNotFoundException.class, "ref refs/heads/foo not found");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createChangeOnNonExistingBranchNotPermitted() throws Exception {
|
||||
blockRead("refs/heads/*");
|
||||
requestScopeOperations.setApiUser(user.id);
|
||||
ChangeInput input = newChangeInput(ChangeStatus.NEW);
|
||||
input.branch = "foo";
|
||||
// sets this option to be true to make sure permission check happened before this option could
|
||||
// be considered.
|
||||
input.newBranch = true;
|
||||
|
||||
assertCreateFails(input, ResourceNotFoundException.class, "ref refs/heads/foo not found");
|
||||
}
|
||||
|
||||
private ChangeInput newChangeInput(ChangeStatus status) {
|
||||
ChangeInput in = new ChangeInput();
|
||||
in.project = project.get();
|
||||
|
Reference in New Issue
Block a user