Add a global capability for viewing all accounts
Users with this capability can auto-complete all accounts regardless of the global accounts.visibility setting. The use case is a core group of committers that should be able to view all accounts, where the rest of the contributors are all in small, non-overlapping accounts that should not be able to view one another. For small numbers of groups it is sufficient to add the committer groups to each of the contributor groups, but this approach becomes a maintenance headache as the number of contributor groups grows to the 10-100 range. Change-Id: Ib31d642484459afa0c129524bc0bc52348dd7416
This commit is contained in:
parent
d4d01dcc1b
commit
f3548a9e90
@ -1268,6 +1268,14 @@ allows the granted group to
|
||||
link:cmd-stream-events.html[stream Gerrit events via ssh].
|
||||
|
||||
|
||||
[[capability_viewAllAccounts]]
|
||||
=== View All Accounts
|
||||
|
||||
Allow viewing all accounts for purposes of auto-completion, regardless
|
||||
of link:config-gerrit.html#accounts.visibility[accounts.visibility]
|
||||
setting.
|
||||
|
||||
|
||||
[[capability_viewCaches]]
|
||||
=== View Caches
|
||||
|
||||
|
@ -1137,6 +1137,9 @@ capability.
|
||||
|`streamEvents` |not set if `false`|Whether the user has the
|
||||
link:access-control.html#capability_streamEvents[Stream Events]
|
||||
capability.
|
||||
|`viewAllAccounts` |not set if `false`|Whether the user has the
|
||||
link:access-control.html#capability_viewAllAccounts[View All Accounts]
|
||||
capability.
|
||||
|`viewCaches` |not set if `false`|Whether the user has the
|
||||
link:access-control.html#capability_viewCaches[View Caches] capability.
|
||||
|`viewConnections` |not set if `false`|Whether the user has the
|
||||
|
@ -29,6 +29,7 @@ class CapabilityInfo {
|
||||
public boolean runAs;
|
||||
public boolean runGC;
|
||||
public boolean streamEvents;
|
||||
public boolean viewAllAccounts;
|
||||
public boolean viewCaches;
|
||||
public boolean viewConnections;
|
||||
public boolean viewQueue;
|
||||
|
@ -15,31 +15,65 @@
|
||||
package com.google.gerrit.acceptance.rest.change;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.gerrit.acceptance.AbstractDaemonTest;
|
||||
import com.google.gerrit.acceptance.GerritConfig;
|
||||
import com.google.gerrit.acceptance.GerritConfigs;
|
||||
import com.google.gerrit.acceptance.RestSession;
|
||||
import com.google.gerrit.acceptance.TestAccount;
|
||||
import com.google.gerrit.common.data.AccessSection;
|
||||
import com.google.gerrit.common.data.GlobalCapability;
|
||||
import com.google.gerrit.common.data.Permission;
|
||||
import com.google.gerrit.common.data.PermissionRule;
|
||||
import com.google.gerrit.reviewdb.client.AccountGroup;
|
||||
import com.google.gerrit.server.account.CreateGroupArgs;
|
||||
import com.google.gerrit.server.account.PerformCreateGroup;
|
||||
import com.google.gerrit.server.change.SuggestReviewers.SuggestedReviewerInfo;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.git.MetaDataUpdate;
|
||||
import com.google.gerrit.server.git.ProjectConfig;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class SuggestReviewersIT extends AbstractDaemonTest {
|
||||
@Inject
|
||||
private PerformCreateGroup.Factory createGroupFactory;
|
||||
|
||||
@Inject
|
||||
private MetaDataUpdate.Server metaDataUpdateFactory;
|
||||
|
||||
@Inject
|
||||
private AllProjectsName allProjects;
|
||||
|
||||
@Inject
|
||||
private ProjectCache projectCache;
|
||||
|
||||
private AccountGroup group1;
|
||||
private TestAccount user1;
|
||||
private TestAccount user2;
|
||||
private TestAccount user3;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
group("users1");
|
||||
group1 = group("users1");
|
||||
group("users2");
|
||||
group("users3");
|
||||
|
||||
accounts.create("user1", "user1@example.com", "User1", "users1");
|
||||
accounts.create("user2", "user2@example.com", "User2", "users2");
|
||||
accounts.create("user3", "user3@example.com", "User3", "users1", "users2");
|
||||
user1 = accounts.create("user1", "user1@example.com", "User1", "users1");
|
||||
user2 = accounts.create("user2", "user2@example.com", "User2", "users2");
|
||||
user3 = accounts.create("user3", "user3@example.com", "User3",
|
||||
"users1", "users2");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -85,11 +119,52 @@ public class SuggestReviewersIT extends AbstractDaemonTest {
|
||||
assertEquals(reviewers.size(), 1);
|
||||
}
|
||||
|
||||
private List<SuggestedReviewerInfo> suggestReviewers(String changeId,
|
||||
String query, int n)
|
||||
throws IOException {
|
||||
@Test
|
||||
@GerritConfig(name = "accounts.visibility", value = "SAME_GROUP")
|
||||
public void suggestReviewersSameGroupVisibility() throws Exception {
|
||||
String changeId = createChange().getChangeId();
|
||||
List<SuggestedReviewerInfo> reviewers;
|
||||
|
||||
reviewers = suggestReviewers(changeId, "user2", 2);
|
||||
assertEquals(1, reviewers.size());
|
||||
assertEquals("User2", Iterables.getOnlyElement(reviewers).account.name);
|
||||
|
||||
reviewers = suggestReviewers(new RestSession(server, user1),
|
||||
changeId, "user2", 2);
|
||||
assertTrue(reviewers.isEmpty());
|
||||
|
||||
reviewers = suggestReviewers(new RestSession(server, user2),
|
||||
changeId, "user2", 2);
|
||||
assertEquals(1, reviewers.size());
|
||||
assertEquals("User2", Iterables.getOnlyElement(reviewers).account.name);
|
||||
|
||||
reviewers = suggestReviewers(new RestSession(server, user3),
|
||||
changeId, "user2", 2);
|
||||
assertEquals(1, reviewers.size());
|
||||
assertEquals("User2", Iterables.getOnlyElement(reviewers).account.name);
|
||||
}
|
||||
|
||||
@Test
|
||||
@GerritConfig(name = "accounts.visibility", value = "SAME_GROUP")
|
||||
public void suggestReviewersViewAllAccounts() throws Exception {
|
||||
String changeId = createChange().getChangeId();
|
||||
List<SuggestedReviewerInfo> reviewers;
|
||||
|
||||
reviewers = suggestReviewers(new RestSession(server, user1),
|
||||
changeId, "user2", 2);
|
||||
assertTrue(reviewers.isEmpty());
|
||||
|
||||
grantCapability(GlobalCapability.VIEW_ALL_ACCOUNTS, group1);
|
||||
reviewers = suggestReviewers(new RestSession(server, user1),
|
||||
changeId, "user2", 2);
|
||||
assertEquals(1, reviewers.size());
|
||||
assertEquals("User2", Iterables.getOnlyElement(reviewers).account.name);
|
||||
}
|
||||
|
||||
private List<SuggestedReviewerInfo> suggestReviewers(RestSession session,
|
||||
String changeId, String query, int n) throws IOException {
|
||||
return newGson().fromJson(
|
||||
adminSession.get("/changes/"
|
||||
session.get("/changes/"
|
||||
+ changeId
|
||||
+ "/suggest_reviewers?q="
|
||||
+ query
|
||||
@ -100,7 +175,27 @@ public class SuggestReviewersIT extends AbstractDaemonTest {
|
||||
.getType());
|
||||
}
|
||||
|
||||
private void group(String name) throws IOException {
|
||||
adminSession.put("/groups/" + name, new Object()).consume();
|
||||
private List<SuggestedReviewerInfo> suggestReviewers(String changeId,
|
||||
String query, int n) throws IOException {
|
||||
return suggestReviewers(adminSession, changeId, query, n);
|
||||
}
|
||||
|
||||
private AccountGroup group(String name) throws Exception {
|
||||
CreateGroupArgs args = new CreateGroupArgs();
|
||||
args.setGroupName(name);
|
||||
args.initialMembers = Collections.singleton(admin.getId());
|
||||
return createGroupFactory.create(args).createGroup();
|
||||
}
|
||||
|
||||
private void grantCapability(String name, AccountGroup group)
|
||||
throws Exception {
|
||||
MetaDataUpdate md = metaDataUpdateFactory.create(allProjects);
|
||||
ProjectConfig config = ProjectConfig.read(md);
|
||||
AccessSection s = config.getAccessSection(
|
||||
AccessSection.GLOBAL_CAPABILITIES);
|
||||
Permission p = s.getPermission(name, true);
|
||||
p.add(new PermissionRule(config.resolve(group)));
|
||||
config.commit(md);
|
||||
projectCache.evict(config.getProject());
|
||||
}
|
||||
}
|
||||
|
@ -79,6 +79,9 @@ public class GlobalCapability {
|
||||
/** Can perform streaming of Gerrit events. */
|
||||
public static final String STREAM_EVENTS = "streamEvents";
|
||||
|
||||
/** Can view all accounts, regardless of {@code accounts.visibility}. */
|
||||
public static final String VIEW_ALL_ACCOUNTS = "viewAllAccounts";
|
||||
|
||||
/** Can view the server's current cache states. */
|
||||
public static final String VIEW_CACHES = "viewCaches";
|
||||
|
||||
@ -106,6 +109,7 @@ public class GlobalCapability {
|
||||
NAMES_ALL.add(RUN_AS);
|
||||
NAMES_ALL.add(RUN_GC);
|
||||
NAMES_ALL.add(STREAM_EVENTS);
|
||||
NAMES_ALL.add(VIEW_ALL_ACCOUNTS);
|
||||
NAMES_ALL.add(VIEW_CACHES);
|
||||
NAMES_ALL.add(VIEW_CONNECTIONS);
|
||||
NAMES_ALL.add(VIEW_QUEUE);
|
||||
|
@ -104,6 +104,9 @@ public class AccountControl {
|
||||
&& ((IdentifiedUser) currentUser).getAccountId().equals(otherUser)) {
|
||||
return true;
|
||||
}
|
||||
if (currentUser.getCapabilities().canViewAllAccounts()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (accountVisibility) {
|
||||
case ALL:
|
||||
@ -139,7 +142,7 @@ public class AccountControl {
|
||||
default:
|
||||
throw new IllegalStateException("Bad AccountVisibility " + accountVisibility);
|
||||
}
|
||||
return currentUser.getCapabilities().canAdministrateServer();
|
||||
return false;
|
||||
}
|
||||
|
||||
private Set<AccountGroup.UUID> groupsOf(Account.Id account) {
|
||||
|
@ -110,6 +110,12 @@ public class CapabilityControl {
|
||||
|| canAdministrateServer();
|
||||
}
|
||||
|
||||
/** @return true if the user can view all accounts. */
|
||||
public boolean canViewAllAccounts() {
|
||||
return canPerform(GlobalCapability.VIEW_ALL_ACCOUNTS)
|
||||
|| canAdministrateServer();
|
||||
}
|
||||
|
||||
/** @return true if the user can view the server caches. */
|
||||
public boolean canViewCaches() {
|
||||
return canPerform(GlobalCapability.VIEW_CACHES)
|
||||
|
@ -24,6 +24,7 @@ import static com.google.gerrit.common.data.GlobalCapability.KILL_TASK;
|
||||
import static com.google.gerrit.common.data.GlobalCapability.PRIORITY;
|
||||
import static com.google.gerrit.common.data.GlobalCapability.RUN_GC;
|
||||
import static com.google.gerrit.common.data.GlobalCapability.STREAM_EVENTS;
|
||||
import static com.google.gerrit.common.data.GlobalCapability.VIEW_ALL_ACCOUNTS;
|
||||
import static com.google.gerrit.common.data.GlobalCapability.VIEW_CACHES;
|
||||
import static com.google.gerrit.common.data.GlobalCapability.VIEW_CONNECTIONS;
|
||||
import static com.google.gerrit.common.data.GlobalCapability.VIEW_QUEUE;
|
||||
@ -104,18 +105,19 @@ class GetCapabilities implements RestReadView<AccountResource> {
|
||||
}
|
||||
}
|
||||
|
||||
have.put(ACCESS_DATABASE, cc.canAccessDatabase());
|
||||
have.put(CREATE_ACCOUNT, cc.canCreateAccount());
|
||||
have.put(CREATE_GROUP, cc.canCreateGroup());
|
||||
have.put(CREATE_PROJECT, cc.canCreateProject());
|
||||
have.put(EMAIL_REVIEWERS, cc.canEmailReviewers());
|
||||
have.put(KILL_TASK, cc.canKillTask());
|
||||
have.put(VIEW_CACHES, cc.canViewCaches());
|
||||
have.put(FLUSH_CACHES, cc.canFlushCaches());
|
||||
have.put(VIEW_CONNECTIONS, cc.canViewConnections());
|
||||
have.put(VIEW_QUEUE, cc.canViewQueue());
|
||||
have.put(KILL_TASK, cc.canKillTask());
|
||||
have.put(RUN_GC, cc.canRunGC());
|
||||
have.put(STREAM_EVENTS, cc.canStreamEvents());
|
||||
have.put(ACCESS_DATABASE, cc.canAccessDatabase());
|
||||
have.put(VIEW_ALL_ACCOUNTS, cc.canViewAllAccounts());
|
||||
have.put(VIEW_CACHES, cc.canViewCaches());
|
||||
have.put(VIEW_CONNECTIONS, cc.canViewConnections());
|
||||
have.put(VIEW_QUEUE, cc.canViewQueue());
|
||||
|
||||
QueueProvider.QueueType queue = cc.getQueueType();
|
||||
if (queue != QueueProvider.QueueType.INTERACTIVE
|
||||
|
@ -270,8 +270,8 @@ public class SuggestReviewers implements RestReadView<ChangeResource> {
|
||||
|
||||
public static class SuggestedReviewerInfo implements Comparable<SuggestedReviewerInfo> {
|
||||
String kind = "gerritcodereview#suggestedreviewer";
|
||||
AccountInfo account;
|
||||
GroupBaseInfo group;
|
||||
public AccountInfo account;
|
||||
public GroupBaseInfo group;
|
||||
|
||||
SuggestedReviewerInfo(AccountInfo a) {
|
||||
this.account = a;
|
||||
|
@ -35,6 +35,7 @@ public class CapabilityConstants extends TranslationBundle {
|
||||
public String runAs;
|
||||
public String runGC;
|
||||
public String streamEvents;
|
||||
public String viewAllAccounts;
|
||||
public String viewCaches;
|
||||
public String viewConnections;
|
||||
public String viewQueue;
|
||||
|
@ -11,6 +11,7 @@ queryLimit = Query Limit
|
||||
runAs = Run As
|
||||
runGC = Run Garbage Collection
|
||||
streamEvents = Stream Events
|
||||
viewAllAccounts = View All Accounts
|
||||
viewCaches = View Caches
|
||||
viewConnections = View Connections
|
||||
viewQueue = View Queue
|
||||
|
Loading…
Reference in New Issue
Block a user