diff options
Diffstat (limited to 'javatests/com/google/gerrit/acceptance/rest/account/ImpersonationIT.java')
-rw-r--r-- | javatests/com/google/gerrit/acceptance/rest/account/ImpersonationIT.java | 604 |
1 files changed, 604 insertions, 0 deletions
diff --git a/javatests/com/google/gerrit/acceptance/rest/account/ImpersonationIT.java b/javatests/com/google/gerrit/acceptance/rest/account/ImpersonationIT.java new file mode 100644 index 0000000000..65c95f85f9 --- /dev/null +++ b/javatests/com/google/gerrit/acceptance/rest/account/ImpersonationIT.java @@ -0,0 +1,604 @@ +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.acceptance.rest.account; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.TruthJUnit.assume; +import static com.google.gerrit.extensions.client.ListChangesOption.MESSAGES; +import static com.google.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS; +import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import com.google.gerrit.acceptance.AbstractDaemonTest; +import com.google.gerrit.acceptance.GerritConfig; +import com.google.gerrit.acceptance.PushOneCommit; +import com.google.gerrit.acceptance.RestResponse; +import com.google.gerrit.acceptance.RestSession; +import com.google.gerrit.acceptance.TestAccount; +import com.google.gerrit.common.data.GlobalCapability; +import com.google.gerrit.common.data.LabelType; +import com.google.gerrit.common.data.Permission; +import com.google.gerrit.extensions.api.changes.DraftInput; +import com.google.gerrit.extensions.api.changes.ReviewInput; +import com.google.gerrit.extensions.api.changes.ReviewInput.CommentInput; +import com.google.gerrit.extensions.api.changes.ReviewInput.DraftHandling; +import com.google.gerrit.extensions.api.changes.ReviewInput.RobotCommentInput; +import com.google.gerrit.extensions.api.changes.RevisionApi; +import com.google.gerrit.extensions.api.changes.SubmitInput; +import com.google.gerrit.extensions.api.groups.GroupInput; +import com.google.gerrit.extensions.client.Side; +import com.google.gerrit.extensions.common.AccountInfo; +import com.google.gerrit.extensions.common.ChangeInfo; +import com.google.gerrit.extensions.common.ChangeMessageInfo; +import com.google.gerrit.extensions.common.CommentInfo; +import com.google.gerrit.extensions.common.GroupInfo; +import com.google.gerrit.extensions.restapi.AuthException; +import com.google.gerrit.extensions.restapi.BadRequestException; +import com.google.gerrit.extensions.restapi.UnprocessableEntityException; +import com.google.gerrit.reviewdb.client.AccountGroup; +import com.google.gerrit.reviewdb.client.Change; +import com.google.gerrit.reviewdb.client.ChangeMessage; +import com.google.gerrit.reviewdb.client.Comment; +import com.google.gerrit.reviewdb.client.Patch; +import com.google.gerrit.reviewdb.client.PatchSetApproval; +import com.google.gerrit.reviewdb.client.RobotComment; +import com.google.gerrit.server.ApprovalsUtil; +import com.google.gerrit.server.ChangeMessagesUtil; +import com.google.gerrit.server.CommentsUtil; +import com.google.gerrit.server.account.AccountControl; +import com.google.gerrit.server.project.testing.Util; +import com.google.gerrit.server.query.change.ChangeData; +import com.google.inject.Inject; +import org.apache.http.Header; +import org.apache.http.message.BasicHeader; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class ImpersonationIT extends AbstractDaemonTest { + @Inject private AccountControl.Factory accountControlFactory; + + @Inject private ApprovalsUtil approvalsUtil; + + @Inject private ChangeMessagesUtil cmUtil; + + @Inject private CommentsUtil commentsUtil; + + private RestSession anonRestSession; + private TestAccount admin2; + private GroupInfo newGroup; + + @Before + public void setUp() throws Exception { + anonRestSession = new RestSession(server, null); + admin2 = accountCreator.admin2(); + GroupInput gi = new GroupInput(); + gi.name = name("New-Group"); + gi.members = ImmutableList.of(user.id.toString()); + newGroup = gApi.groups().create(gi).get(); + } + + @After + public void tearDown() throws Exception { + removeRunAs(); + } + + @Test + public void voteOnBehalfOf() throws Exception { + allowCodeReviewOnBehalfOf(); + PushOneCommit.Result r = createChange(); + RevisionApi revision = gApi.changes().id(r.getChangeId()).current(); + + ReviewInput in = ReviewInput.recommend(); + in.onBehalfOf = user.id.toString(); + in.message = "Message on behalf of"; + revision.review(in); + + PatchSetApproval psa = Iterables.getOnlyElement(r.getChange().approvals().values()); + assertThat(psa.getPatchSetId().get()).isEqualTo(1); + assertThat(psa.getLabel()).isEqualTo("Code-Review"); + assertThat(psa.getAccountId()).isEqualTo(user.id); + assertThat(psa.getValue()).isEqualTo(1); + assertThat(psa.getRealAccountId()).isEqualTo(admin.id); + + ChangeData cd = r.getChange(); + ChangeMessage m = Iterables.getLast(cmUtil.byChange(db, cd.notes())); + assertThat(m.getMessage()).endsWith(in.message); + assertThat(m.getAuthor()).isEqualTo(user.id); + assertThat(m.getRealAuthor()).isEqualTo(admin.id); + } + + @Test + public void voteOnBehalfOfRequiresLabel() throws Exception { + allowCodeReviewOnBehalfOf(); + PushOneCommit.Result r = createChange(); + RevisionApi revision = gApi.changes().id(r.getChangeId()).current(); + + ReviewInput in = new ReviewInput(); + in.onBehalfOf = user.id.toString(); + in.message = "Message on behalf of"; + + exception.expect(AuthException.class); + exception.expectMessage("label required to post review on behalf of \"" + in.onBehalfOf + '"'); + revision.review(in); + } + + @Test + @GerritConfig(name = "change.strictLabels", value = "true") + public void voteOnBehalfOfInvalidLabel() throws Exception { + allowCodeReviewOnBehalfOf(); + + String changeId = createChange().getChangeId(); + ReviewInput in = new ReviewInput().label("Not-A-Label", 5); + in.onBehalfOf = user.id.toString(); + + exception.expect(BadRequestException.class); + exception.expectMessage("label \"Not-A-Label\" is not a configured label"); + gApi.changes().id(changeId).current().review(in); + } + + @Test + public void voteOnBehalfOfInvalidLabelIgnoredWithoutStrictLabels() throws Exception { + allowCodeReviewOnBehalfOf(); + + String changeId = createChange().getChangeId(); + ReviewInput in = new ReviewInput().label("Code-Review", 1).label("Not-A-Label", 5); + in.onBehalfOf = user.id.toString(); + gApi.changes().id(changeId).current().review(in); + + assertThat(gApi.changes().id(changeId).get().labels).doesNotContainKey("Not-A-Label"); + } + + @Test + public void voteOnBehalfOfLabelNotPermitted() throws Exception { + try (ProjectConfigUpdate u = updateProject(project)) { + LabelType verified = Util.verified(); + u.getConfig().getLabelSections().put(verified.getName(), verified); + u.save(); + } + + PushOneCommit.Result r = createChange(); + RevisionApi revision = gApi.changes().id(r.getChangeId()).current(); + + ReviewInput in = new ReviewInput(); + in.onBehalfOf = user.id.toString(); + in.label("Verified", 1); + + exception.expect(AuthException.class); + exception.expectMessage( + "not permitted to modify label \"Verified\" on behalf of \"" + in.onBehalfOf + '"'); + revision.review(in); + } + + @Test + public void voteOnBehalfOfWithComment() throws Exception { + testVoteOnBehalfOfWithComment(); + } + + @Test + public void voteOnBehalfOfWithCommentWritingJson() throws Exception { + assume().that(notesMigration.readChanges()).isTrue(); + testVoteOnBehalfOfWithComment(); + } + + private void testVoteOnBehalfOfWithComment() throws Exception { + allowCodeReviewOnBehalfOf(); + PushOneCommit.Result r = createChange(); + + ReviewInput in = new ReviewInput(); + in.onBehalfOf = user.id.toString(); + in.label("Code-Review", 1); + CommentInput ci = new CommentInput(); + ci.path = Patch.COMMIT_MSG; + ci.side = Side.REVISION; + ci.line = 1; + ci.message = "message"; + in.comments = ImmutableMap.of(ci.path, ImmutableList.of(ci)); + gApi.changes().id(r.getChangeId()).current().review(in); + + PatchSetApproval psa = Iterables.getOnlyElement(r.getChange().approvals().values()); + assertThat(psa.getPatchSetId().get()).isEqualTo(1); + assertThat(psa.getLabel()).isEqualTo("Code-Review"); + assertThat(psa.getAccountId()).isEqualTo(user.id); + assertThat(psa.getValue()).isEqualTo(1); + assertThat(psa.getRealAccountId()).isEqualTo(admin.id); + + ChangeData cd = r.getChange(); + Comment c = Iterables.getOnlyElement(commentsUtil.publishedByChange(db, cd.notes())); + assertThat(c.message).isEqualTo(ci.message); + assertThat(c.author.getId()).isEqualTo(user.id); + assertThat(c.getRealAuthor().getId()).isEqualTo(admin.id); + } + + @Test + public void voteOnBehalfOfWithRobotComment() throws Exception { + assume().that(notesMigration.readChanges()).isTrue(); + allowCodeReviewOnBehalfOf(); + PushOneCommit.Result r = createChange(); + + ReviewInput in = new ReviewInput(); + in.onBehalfOf = user.id.toString(); + in.label("Code-Review", 1); + RobotCommentInput ci = new RobotCommentInput(); + ci.robotId = "my-robot"; + ci.robotRunId = "abcd1234"; + ci.path = Patch.COMMIT_MSG; + ci.side = Side.REVISION; + ci.line = 1; + ci.message = "message"; + in.robotComments = ImmutableMap.of(ci.path, ImmutableList.of(ci)); + gApi.changes().id(r.getChangeId()).current().review(in); + + ChangeData cd = r.getChange(); + RobotComment c = Iterables.getOnlyElement(commentsUtil.robotCommentsByChange(cd.notes())); + assertThat(c.message).isEqualTo(ci.message); + assertThat(c.robotId).isEqualTo(ci.robotId); + assertThat(c.robotRunId).isEqualTo(ci.robotRunId); + assertThat(c.author.getId()).isEqualTo(user.id); + assertThat(c.getRealAuthor().getId()).isEqualTo(admin.id); + } + + @Test + public void voteOnBehalfOfCannotModifyDrafts() throws Exception { + allowCodeReviewOnBehalfOf(); + PushOneCommit.Result r = createChange(); + + setApiUser(user); + DraftInput di = new DraftInput(); + di.path = Patch.COMMIT_MSG; + di.side = Side.REVISION; + di.line = 1; + di.message = "message"; + gApi.changes().id(r.getChangeId()).current().createDraft(di); + + setApiUser(admin); + ReviewInput in = new ReviewInput(); + in.onBehalfOf = user.id.toString(); + in.label("Code-Review", 1); + in.drafts = DraftHandling.PUBLISH; + + exception.expect(AuthException.class); + exception.expectMessage("not allowed to modify other user's drafts"); + gApi.changes().id(r.getChangeId()).current().review(in); + } + + @Test + public void voteOnBehalfOfMissingUser() throws Exception { + allowCodeReviewOnBehalfOf(); + PushOneCommit.Result r = createChange(); + RevisionApi revision = gApi.changes().id(r.getChangeId()).current(); + + ReviewInput in = new ReviewInput(); + in.onBehalfOf = "doesnotexist"; + in.label("Code-Review", 1); + + exception.expect(UnprocessableEntityException.class); + exception.expectMessage("not found"); + exception.expectMessage("doesnotexist"); + revision.review(in); + } + + @Test + public void voteOnBehalfOfFailsWhenUserCannotSeeDestinationRef() throws Exception { + blockRead(newGroup); + + allowCodeReviewOnBehalfOf(); + PushOneCommit.Result r = createChange(); + RevisionApi revision = gApi.changes().id(r.getChangeId()).current(); + + ReviewInput in = new ReviewInput(); + in.onBehalfOf = user.id.toString(); + in.label("Code-Review", 1); + + exception.expect(UnprocessableEntityException.class); + exception.expectMessage("on_behalf_of account " + user.id + " cannot see change"); + revision.review(in); + } + + @GerritConfig(name = "accounts.visibility", value = "SAME_GROUP") + @Test + public void voteOnBehalfOfInvisibleUserNotAllowed() throws Exception { + allowCodeReviewOnBehalfOf(); + setApiUser(accountCreator.user2()); + assertThat(accountControlFactory.get().canSee(user.id)).isFalse(); + + PushOneCommit.Result r = createChange(); + RevisionApi revision = gApi.changes().id(r.getChangeId()).current(); + + ReviewInput in = new ReviewInput(); + in.onBehalfOf = user.id.toString(); + in.label("Code-Review", 1); + + exception.expect(UnprocessableEntityException.class); + exception.expectMessage("not found"); + exception.expectMessage(in.onBehalfOf); + revision.review(in); + } + + @Test + public void submitOnBehalfOf() throws Exception { + allowSubmitOnBehalfOf(); + PushOneCommit.Result r = createChange(); + String changeId = project.get() + "~master~" + r.getChangeId(); + gApi.changes().id(changeId).current().review(ReviewInput.approve()); + SubmitInput in = new SubmitInput(); + in.onBehalfOf = admin2.email; + gApi.changes().id(changeId).current().submit(in); + + ChangeData cd = r.getChange(); + assertThat(cd.change().getStatus()).isEqualTo(Change.Status.MERGED); + PatchSetApproval submitter = + approvalsUtil.getSubmitter(db, cd.notes(), cd.change().currentPatchSetId()); + assertThat(submitter.getAccountId()).isEqualTo(admin2.id); + assertThat(submitter.getRealAccountId()).isEqualTo(admin.id); + } + + @Test + public void submitOnBehalfOfInvalidUser() throws Exception { + allowSubmitOnBehalfOf(); + PushOneCommit.Result r = createChange(); + String changeId = project.get() + "~master~" + r.getChangeId(); + gApi.changes().id(changeId).current().review(ReviewInput.approve()); + SubmitInput in = new SubmitInput(); + in.onBehalfOf = "doesnotexist"; + exception.expect(UnprocessableEntityException.class); + exception.expectMessage("not found"); + exception.expectMessage("doesnotexist"); + gApi.changes().id(changeId).current().submit(in); + } + + @Test + public void submitOnBehalfOfNotPermitted() throws Exception { + PushOneCommit.Result r = createChange(); + gApi.changes() + .id(project.get() + "~master~" + r.getChangeId()) + .current() + .review(ReviewInput.approve()); + SubmitInput in = new SubmitInput(); + in.onBehalfOf = admin2.email; + exception.expect(AuthException.class); + exception.expectMessage("submit on behalf of other users not permitted"); + gApi.changes().id(project.get() + "~master~" + r.getChangeId()).current().submit(in); + } + + @Test + public void submitOnBehalfOfFailsWhenUserCannotSeeDestinationRef() throws Exception { + blockRead(newGroup); + + allowSubmitOnBehalfOf(); + PushOneCommit.Result r = createChange(); + String changeId = project.get() + "~master~" + r.getChangeId(); + gApi.changes().id(changeId).current().review(ReviewInput.approve()); + SubmitInput in = new SubmitInput(); + in.onBehalfOf = user.email; + exception.expect(UnprocessableEntityException.class); + exception.expectMessage("on_behalf_of account " + user.id + " cannot see change"); + gApi.changes().id(changeId).current().submit(in); + } + + @GerritConfig(name = "accounts.visibility", value = "SAME_GROUP") + @Test + public void submitOnBehalfOfInvisibleUserNotAllowed() throws Exception { + allowSubmitOnBehalfOf(); + setApiUser(accountCreator.user2()); + assertThat(accountControlFactory.get().canSee(user.id)).isFalse(); + + PushOneCommit.Result r = createChange(); + String changeId = project.get() + "~master~" + r.getChangeId(); + gApi.changes().id(changeId).current().review(ReviewInput.approve()); + SubmitInput in = new SubmitInput(); + in.onBehalfOf = user.email; + exception.expect(UnprocessableEntityException.class); + exception.expectMessage("not found"); + exception.expectMessage(in.onBehalfOf); + gApi.changes().id(changeId).current().submit(in); + } + + @Test + public void runAsValidUser() throws Exception { + allowRunAs(); + RestResponse res = adminRestSession.getWithHeader("/accounts/self", runAsHeader(user.id)); + res.assertOK(); + AccountInfo account = newGson().fromJson(res.getEntityContent(), AccountInfo.class); + assertThat(account._accountId).isEqualTo(user.id.get()); + } + + @GerritConfig(name = "auth.enableRunAs", value = "false") + @Test + public void runAsDisabledByConfig() throws Exception { + allowRunAs(); + RestResponse res = adminRestSession.getWithHeader("/changes/", runAsHeader(user.id)); + res.assertForbidden(); + assertThat(res.getEntityContent()) + .isEqualTo("X-Gerrit-RunAs disabled by auth.enableRunAs = false"); + } + + @Test + public void runAsNotPermitted() throws Exception { + RestResponse res = adminRestSession.getWithHeader("/changes/", runAsHeader(user.id)); + res.assertForbidden(); + assertThat(res.getEntityContent()).isEqualTo("not permitted to use X-Gerrit-RunAs"); + } + + @Test + public void runAsNeverPermittedForAnonymousUsers() throws Exception { + allowRunAs(); + RestResponse res = anonRestSession.getWithHeader("/changes/", runAsHeader(user.id)); + res.assertForbidden(); + assertThat(res.getEntityContent()).isEqualTo("not permitted to use X-Gerrit-RunAs"); + } + + @Test + public void runAsInvalidUser() throws Exception { + allowRunAs(); + RestResponse res = adminRestSession.getWithHeader("/changes/", runAsHeader("doesnotexist")); + res.assertForbidden(); + assertThat(res.getEntityContent()).isEqualTo("no account matches X-Gerrit-RunAs"); + } + + @Test + public void voteUsingRunAsAvoidsRestrictionsOfOnBehalfOf() throws Exception { + allowRunAs(); + PushOneCommit.Result r = createChange(); + + setApiUser(user); + DraftInput di = new DraftInput(); + di.path = Patch.COMMIT_MSG; + di.side = Side.REVISION; + di.line = 1; + di.message = "inline comment"; + gApi.changes().id(r.getChangeId()).current().createDraft(di); + setApiUser(admin); + + // Things that aren't allowed with on_behalf_of: + // - no labels. + // - publish other user's drafts. + ReviewInput in = new ReviewInput(); + in.message = "message"; + in.drafts = DraftHandling.PUBLISH; + RestResponse res = + adminRestSession.postWithHeader( + "/changes/" + r.getChangeId() + "/revisions/current/review", runAsHeader(user.id), in); + res.assertOK(); + + ChangeMessageInfo m = Iterables.getLast(gApi.changes().id(r.getChangeId()).get().messages); + assertThat(m.message).endsWith(in.message); + assertThat(m.author._accountId).isEqualTo(user.id.get()); + + CommentInfo c = + Iterables.getOnlyElement(gApi.changes().id(r.getChangeId()).comments().get(di.path)); + assertThat(c.author._accountId).isEqualTo(user.id.get()); + assertThat(c.message).isEqualTo(di.message); + + setApiUser(user); + assertThat(gApi.changes().id(r.getChangeId()).drafts()).isEmpty(); + } + + @Test + public void runAsWithOnBehalfOf() throws Exception { + // - Has the same restrictions as on_behalf_of (e.g. requires labels). + // - Takes the effective user from on_behalf_of (user). + // - Takes the real user from the real caller, not the intermediate + // X-Gerrit-RunAs user (user2). + allowRunAs(); + allowCodeReviewOnBehalfOf(); + TestAccount user2 = accountCreator.user2(); + + PushOneCommit.Result r = createChange(); + ReviewInput in = new ReviewInput(); + in.onBehalfOf = user.id.toString(); + in.message = "Message on behalf of"; + + String endpoint = "/changes/" + r.getChangeId() + "/revisions/current/review"; + RestResponse res = adminRestSession.postWithHeader(endpoint, runAsHeader(user2.id), in); + res.assertForbidden(); + assertThat(res.getEntityContent()) + .isEqualTo("label required to post review on behalf of \"" + in.onBehalfOf + '"'); + + in.label("Code-Review", 1); + adminRestSession.postWithHeader(endpoint, runAsHeader(user2.id), in).assertOK(); + + PatchSetApproval psa = Iterables.getOnlyElement(r.getChange().approvals().values()); + assertThat(psa.getPatchSetId().get()).isEqualTo(1); + assertThat(psa.getLabel()).isEqualTo("Code-Review"); + assertThat(psa.getAccountId()).isEqualTo(user.id); + assertThat(psa.getValue()).isEqualTo(1); + assertThat(psa.getRealAccountId()).isEqualTo(admin.id); // not user2 + + ChangeData cd = r.getChange(); + ChangeMessage m = Iterables.getLast(cmUtil.byChange(db, cd.notes())); + assertThat(m.getMessage()).endsWith(in.message); + assertThat(m.getAuthor()).isEqualTo(user.id); + assertThat(m.getRealAuthor()).isEqualTo(admin.id); // not user2 + } + + @Test + public void changeMessageCreatedOnBehalfOfHasRealUser() throws Exception { + allowCodeReviewOnBehalfOf(); + + PushOneCommit.Result r = createChange(); + ReviewInput in = new ReviewInput(); + in.onBehalfOf = user.id.toString(); + in.message = "Message on behalf of"; + in.label("Code-Review", 1); + + setApiUser(accountCreator.user2()); + gApi.changes().id(r.getChangeId()).revision(r.getPatchSetId().getId()).review(in); + + ChangeInfo info = gApi.changes().id(r.getChangeId()).get(MESSAGES); + assertThat(info.messages).hasSize(2); + + ChangeMessageInfo changeMessageInfo = Iterables.getLast(info.messages); + assertThat(changeMessageInfo.realAuthor).isNotNull(); + assertThat(changeMessageInfo.realAuthor._accountId).isEqualTo(accountCreator.user2().id.get()); + } + + private void allowCodeReviewOnBehalfOf() throws Exception { + try (ProjectConfigUpdate u = updateProject(project)) { + LabelType codeReviewType = Util.codeReview(); + String forCodeReviewAs = Permission.forLabelAs(codeReviewType.getName()); + String heads = "refs/heads/*"; + AccountGroup.UUID uuid = systemGroupBackend.getGroup(REGISTERED_USERS).getUUID(); + Util.allow(u.getConfig(), forCodeReviewAs, -1, 1, uuid, heads); + u.save(); + } + } + + private void allowSubmitOnBehalfOf() throws Exception { + try (ProjectConfigUpdate u = updateProject(project)) { + String heads = "refs/heads/*"; + AccountGroup.UUID uuid = systemGroupBackend.getGroup(REGISTERED_USERS).getUUID(); + Util.allow(u.getConfig(), Permission.SUBMIT_AS, uuid, heads); + Util.allow(u.getConfig(), Permission.SUBMIT, uuid, heads); + LabelType codeReviewType = Util.codeReview(); + Util.allow(u.getConfig(), Permission.forLabel(codeReviewType.getName()), -2, 2, uuid, heads); + u.save(); + } + } + + private void blockRead(GroupInfo group) throws Exception { + try (ProjectConfigUpdate u = updateProject(project)) { + Util.block( + u.getConfig(), Permission.READ, new AccountGroup.UUID(group.id), "refs/heads/master"); + u.save(); + } + } + + private void allowRunAs() throws Exception { + try (ProjectConfigUpdate u = updateProject(allProjects)) { + Util.allow( + u.getConfig(), + GlobalCapability.RUN_AS, + systemGroupBackend.getGroup(ANONYMOUS_USERS).getUUID()); + u.save(); + } + } + + private void removeRunAs() throws Exception { + try (ProjectConfigUpdate u = updateProject(allProjects)) { + Util.remove( + u.getConfig(), + GlobalCapability.RUN_AS, + systemGroupBackend.getGroup(ANONYMOUS_USERS).getUUID()); + u.save(); + } + } + + private static Header runAsHeader(Object user) { + return new BasicHeader("X-Gerrit-RunAs", user.toString()); + } +} |