Prevent updates to refs/meta/group-names through push and submit

Change-Id: Iea92c2b120a96439b3fb1240af0ab484bf02a858
This commit is contained in:
Patrick Hiesel
2017-11-15 11:14:17 +01:00
parent 4485711ffe
commit 83f09cb6bc
4 changed files with 66 additions and 24 deletions

View File

@@ -778,7 +778,7 @@ public class CommitValidators {
} }
} }
/** Rejects updates to group branches. */ /** Rejects updates to group branches (refs/groups/* and refs/meta/group-names). */
public static class GroupCommitValidator implements CommitValidationListener { public static class GroupCommitValidator implements CommitValidationListener {
private final AllUsersName allUsers; private final AllUsersName allUsers;
@@ -790,6 +790,7 @@ public class CommitValidators {
public List<CommitValidationMessage> onCommitReceived(CommitReceivedEvent receiveEvent) public List<CommitValidationMessage> onCommitReceived(CommitReceivedEvent receiveEvent)
throws CommitValidationException { throws CommitValidationException {
// Groups are stored inside 'refs/groups/' refs inside the 'All-Users' repository. // Groups are stored inside 'refs/groups/' refs inside the 'All-Users' repository.
// Group names are stored inside 'refs/meta/group-names' refs inside the 'All-Users' repository.
if (!allUsers.equals(receiveEvent.project.getNameKey())) { if (!allUsers.equals(receiveEvent.project.getNameKey())) {
return Collections.emptyList(); return Collections.emptyList();
} }
@@ -800,7 +801,8 @@ public class CommitValidators {
return Collections.emptyList(); return Collections.emptyList();
} }
if (receiveEvent.command.getRefName().startsWith(RefNames.REFS_GROUPS)) { if (receiveEvent.command.getRefName().startsWith(RefNames.REFS_GROUPS)
|| receiveEvent.command.getRefName().equals(RefNames.REFS_GROUPNAMES)) {
throw new CommitValidationException("group update not allowed"); throw new CommitValidationException("group update not allowed");
} }
return Collections.emptyList(); return Collections.emptyList();

View File

@@ -319,8 +319,10 @@ public class MergeValidators {
IdentifiedUser caller) IdentifiedUser caller)
throws MergeValidationException { throws MergeValidationException {
// Groups are stored inside 'refs/groups/' refs inside the 'All-Users' repository. // Groups are stored inside 'refs/groups/' refs inside the 'All-Users' repository.
// Group names are stored inside 'refs/meta/group-names' inside the 'All-Users' repository.
if (!allUsersName.equals(destProject.getNameKey()) if (!allUsersName.equals(destProject.getNameKey())
|| !destBranch.get().startsWith(RefNames.REFS_GROUPS)) { || (!destBranch.get().startsWith(RefNames.REFS_GROUPS)
&& !destBranch.get().equals(RefNames.REFS_GROUPNAMES))) {
return; return;
} }

View File

@@ -49,7 +49,7 @@ import org.eclipse.jgit.revwalk.RevSort;
// TODO(aliceks): Add Javadoc descriptions to this file. // TODO(aliceks): Add Javadoc descriptions to this file.
public class GroupConfig extends VersionedMetaData { public class GroupConfig extends VersionedMetaData {
private static final String GROUP_CONFIG_FILE = "group.config"; public static final String GROUP_CONFIG_FILE = "group.config";
private static final String MEMBERS_FILE = "members"; private static final String MEMBERS_FILE = "members";
private static final String SUBGROUPS_FILE = "subgroups"; private static final String SUBGROUPS_FILE = "subgroups";
private static final Pattern LINE_SEPARATOR_PATTERN = Pattern.compile("\\R"); private static final Pattern LINE_SEPARATOR_PATTERN = Pattern.compile("\\R");

View File

@@ -35,6 +35,7 @@ import com.google.gerrit.acceptance.Sandboxed;
import com.google.gerrit.acceptance.TestAccount; import com.google.gerrit.acceptance.TestAccount;
import com.google.gerrit.common.TimeUtil; import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.common.data.AccessSection; import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.common.data.GroupDescription; import com.google.gerrit.common.data.GroupDescription;
import com.google.gerrit.common.data.GroupReference; import com.google.gerrit.common.data.GroupReference;
import com.google.gerrit.common.data.Permission; import com.google.gerrit.common.data.Permission;
@@ -66,6 +67,7 @@ import com.google.gerrit.server.account.GroupIncludeCache;
import com.google.gerrit.server.git.ProjectConfig; import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.group.InternalGroup; import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.group.SystemGroupBackend; import com.google.gerrit.server.group.SystemGroupBackend;
import com.google.gerrit.server.group.db.GroupConfig;
import com.google.gerrit.server.group.db.Groups; import com.google.gerrit.server.group.db.Groups;
import com.google.gerrit.server.index.group.StalenessChecker; import com.google.gerrit.server.index.group.StalenessChecker;
import com.google.gerrit.server.util.MagicBranch; import com.google.gerrit.server.util.MagicBranch;
@@ -832,44 +834,57 @@ public class GroupsIT extends AbstractDaemonTest {
@Test @Test
public void pushToGroupBranchIsRejectedForAllUsersRepo() throws Exception { public void pushToGroupBranchIsRejectedForAllUsersRepo() throws Exception {
pushToGroupBranch(allUsers, "Not allowed to create group branch.", "group update not allowed"); String groupRef =
RefNames.refsGroups(new AccountGroup.UUID(gApi.groups().create(name("fo")).get().id));
assertPushToGroupBranch(allUsers, groupRef, !groupsInNoteDb(), "group update not allowed");
} }
@Test @Test
public void pushToGroupBranchForNonAllUsersRepo() throws Exception { public void pushToGroupNamesBranchIsRejectedForAllUsersRepo() throws Exception {
pushToGroupBranch(project, null, null); assume().that(groupsInNoteDb()).isTrue(); // branch only exists when groups are in NoteDb
// refs/meta/group-names isn't usually available for fetch, so grant ACCESS_DATABASE
allowGlobalCapabilities(REGISTERED_USERS, GlobalCapability.ACCESS_DATABASE);
assertPushToGroupBranch(allUsers, RefNames.REFS_GROUPNAMES, false, "group update not allowed");
} }
private void pushToGroupBranch( @Test
Project.NameKey project, String expectedErrorOnCreate, String expectedErrorOnUpdate) public void pushToGroupsBranchForNonAllUsersRepo() throws Exception {
assertCreateGroupBranch(project, null);
String groupRef =
RefNames.refsGroups(new AccountGroup.UUID(gApi.groups().create(name("fo")).get().id));
assertPushToGroupBranch(project, groupRef, true, null);
}
@Test
public void pushToGroupNamesBranchForNonAllUsersRepo() throws Exception {
assertPushToGroupBranch(project, RefNames.REFS_GROUPNAMES, true, null);
}
private void assertPushToGroupBranch(
Project.NameKey project, String groupRefName, boolean createRef, String expectedErrorOnUpdate)
throws Exception { throws Exception {
grant(project, RefNames.REFS_GROUPS + "*", Permission.CREATE, false, REGISTERED_USERS); grant(project, RefNames.REFS_GROUPS + "*", Permission.CREATE, false, REGISTERED_USERS);
grant(project, RefNames.REFS_GROUPS + "*", Permission.PUSH, false, REGISTERED_USERS); grant(project, RefNames.REFS_GROUPS + "*", Permission.PUSH, false, REGISTERED_USERS);
grant(project, RefNames.REFS_GROUPNAMES, Permission.PUSH, false, REGISTERED_USERS);
TestRepository<InMemoryRepository> repo = cloneProject(project); TestRepository<InMemoryRepository> repo = cloneProject(project);
// create new branch if (createRef) {
PushOneCommit.Result r = createGroupBranch(project, groupRefName);
pushFactory
.create(
db, admin.getIdent(), repo, "Update group config", "group.config", "some content")
.setParents(ImmutableList.of())
.to(RefNames.REFS_GROUPS + name("foo"));
if (expectedErrorOnCreate != null) {
r.assertErrorStatus(expectedErrorOnCreate);
} else {
r.assertOkStatus();
} }
// update existing branch // update existing branch
String groupRefName = RefNames.REFS_GROUPS + name("bar");
createGroupBranch(project, groupRefName);
fetch(repo, groupRefName + ":groupRef"); fetch(repo, groupRefName + ":groupRef");
repo.reset("groupRef"); repo.reset("groupRef");
r = PushOneCommit.Result r =
pushFactory pushFactory
.create( .create(
db, admin.getIdent(), repo, "Update group config", "group.config", "some content") db,
admin.getIdent(),
repo,
"Update group config",
GroupConfig.GROUP_CONFIG_FILE,
"some content")
.to(groupRefName); .to(groupRefName);
if (expectedErrorOnUpdate != null) { if (expectedErrorOnUpdate != null) {
r.assertErrorStatus(expectedErrorOnUpdate); r.assertErrorStatus(expectedErrorOnUpdate);
@@ -878,6 +893,29 @@ public class GroupsIT extends AbstractDaemonTest {
} }
} }
private void assertCreateGroupBranch(Project.NameKey project, String expectedErrorOnCreate)
throws Exception {
grant(project, RefNames.REFS_GROUPS + "*", Permission.CREATE, false, REGISTERED_USERS);
grant(project, RefNames.REFS_GROUPS + "*", Permission.PUSH, false, REGISTERED_USERS);
TestRepository<InMemoryRepository> repo = cloneProject(project);
PushOneCommit.Result r =
pushFactory
.create(
db,
admin.getIdent(),
repo,
"Update group config",
GroupConfig.GROUP_CONFIG_FILE,
"some content")
.setParents(ImmutableList.of())
.to(RefNames.REFS_GROUPS + name("bar"));
if (expectedErrorOnCreate != null) {
r.assertErrorStatus(expectedErrorOnCreate);
} else {
r.assertOkStatus();
}
}
@Test @Test
public void pushToGroupBranchForReviewForAllUsersRepoIsRejectedOnSubmit() throws Exception { public void pushToGroupBranchForReviewForAllUsersRepoIsRejectedOnSubmit() throws Exception {
pushToGroupBranchForReviewAndSubmit(allUsers, "group update not allowed"); pushToGroupBranchForReviewAndSubmit(allUsers, "group update not allowed");