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].
|
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]]
|
[[capability_viewCaches]]
|
||||||
=== View Caches
|
=== View Caches
|
||||||
|
|
||||||
|
@ -1137,6 +1137,9 @@ capability.
|
|||||||
|`streamEvents` |not set if `false`|Whether the user has the
|
|`streamEvents` |not set if `false`|Whether the user has the
|
||||||
link:access-control.html#capability_streamEvents[Stream Events]
|
link:access-control.html#capability_streamEvents[Stream Events]
|
||||||
capability.
|
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
|
|`viewCaches` |not set if `false`|Whether the user has the
|
||||||
link:access-control.html#capability_viewCaches[View Caches] capability.
|
link:access-control.html#capability_viewCaches[View Caches] capability.
|
||||||
|`viewConnections` |not set if `false`|Whether the user has the
|
|`viewConnections` |not set if `false`|Whether the user has the
|
||||||
|
@ -29,6 +29,7 @@ class CapabilityInfo {
|
|||||||
public boolean runAs;
|
public boolean runAs;
|
||||||
public boolean runGC;
|
public boolean runGC;
|
||||||
public boolean streamEvents;
|
public boolean streamEvents;
|
||||||
|
public boolean viewAllAccounts;
|
||||||
public boolean viewCaches;
|
public boolean viewCaches;
|
||||||
public boolean viewConnections;
|
public boolean viewConnections;
|
||||||
public boolean viewQueue;
|
public boolean viewQueue;
|
||||||
|
@ -15,31 +15,65 @@
|
|||||||
package com.google.gerrit.acceptance.rest.change;
|
package com.google.gerrit.acceptance.rest.change;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
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.AbstractDaemonTest;
|
||||||
import com.google.gerrit.acceptance.GerritConfig;
|
import com.google.gerrit.acceptance.GerritConfig;
|
||||||
import com.google.gerrit.acceptance.GerritConfigs;
|
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.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.gson.reflect.TypeToken;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class SuggestReviewersIT extends AbstractDaemonTest {
|
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
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
group("users1");
|
group1 = group("users1");
|
||||||
group("users2");
|
group("users2");
|
||||||
group("users3");
|
group("users3");
|
||||||
|
|
||||||
accounts.create("user1", "user1@example.com", "User1", "users1");
|
user1 = accounts.create("user1", "user1@example.com", "User1", "users1");
|
||||||
accounts.create("user2", "user2@example.com", "User2", "users2");
|
user2 = accounts.create("user2", "user2@example.com", "User2", "users2");
|
||||||
accounts.create("user3", "user3@example.com", "User3", "users1", "users2");
|
user3 = accounts.create("user3", "user3@example.com", "User3",
|
||||||
|
"users1", "users2");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -85,11 +119,52 @@ public class SuggestReviewersIT extends AbstractDaemonTest {
|
|||||||
assertEquals(reviewers.size(), 1);
|
assertEquals(reviewers.size(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<SuggestedReviewerInfo> suggestReviewers(String changeId,
|
@Test
|
||||||
String query, int n)
|
@GerritConfig(name = "accounts.visibility", value = "SAME_GROUP")
|
||||||
throws IOException {
|
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(
|
return newGson().fromJson(
|
||||||
adminSession.get("/changes/"
|
session.get("/changes/"
|
||||||
+ changeId
|
+ changeId
|
||||||
+ "/suggest_reviewers?q="
|
+ "/suggest_reviewers?q="
|
||||||
+ query
|
+ query
|
||||||
@ -100,7 +175,27 @@ public class SuggestReviewersIT extends AbstractDaemonTest {
|
|||||||
.getType());
|
.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void group(String name) throws IOException {
|
private List<SuggestedReviewerInfo> suggestReviewers(String changeId,
|
||||||
adminSession.put("/groups/" + name, new Object()).consume();
|
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. */
|
/** Can perform streaming of Gerrit events. */
|
||||||
public static final String STREAM_EVENTS = "streamEvents";
|
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. */
|
/** Can view the server's current cache states. */
|
||||||
public static final String VIEW_CACHES = "viewCaches";
|
public static final String VIEW_CACHES = "viewCaches";
|
||||||
|
|
||||||
@ -106,6 +109,7 @@ public class GlobalCapability {
|
|||||||
NAMES_ALL.add(RUN_AS);
|
NAMES_ALL.add(RUN_AS);
|
||||||
NAMES_ALL.add(RUN_GC);
|
NAMES_ALL.add(RUN_GC);
|
||||||
NAMES_ALL.add(STREAM_EVENTS);
|
NAMES_ALL.add(STREAM_EVENTS);
|
||||||
|
NAMES_ALL.add(VIEW_ALL_ACCOUNTS);
|
||||||
NAMES_ALL.add(VIEW_CACHES);
|
NAMES_ALL.add(VIEW_CACHES);
|
||||||
NAMES_ALL.add(VIEW_CONNECTIONS);
|
NAMES_ALL.add(VIEW_CONNECTIONS);
|
||||||
NAMES_ALL.add(VIEW_QUEUE);
|
NAMES_ALL.add(VIEW_QUEUE);
|
||||||
|
@ -104,6 +104,9 @@ public class AccountControl {
|
|||||||
&& ((IdentifiedUser) currentUser).getAccountId().equals(otherUser)) {
|
&& ((IdentifiedUser) currentUser).getAccountId().equals(otherUser)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (currentUser.getCapabilities().canViewAllAccounts()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
switch (accountVisibility) {
|
switch (accountVisibility) {
|
||||||
case ALL:
|
case ALL:
|
||||||
@ -139,7 +142,7 @@ public class AccountControl {
|
|||||||
default:
|
default:
|
||||||
throw new IllegalStateException("Bad AccountVisibility " + accountVisibility);
|
throw new IllegalStateException("Bad AccountVisibility " + accountVisibility);
|
||||||
}
|
}
|
||||||
return currentUser.getCapabilities().canAdministrateServer();
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<AccountGroup.UUID> groupsOf(Account.Id account) {
|
private Set<AccountGroup.UUID> groupsOf(Account.Id account) {
|
||||||
|
@ -110,6 +110,12 @@ public class CapabilityControl {
|
|||||||
|| canAdministrateServer();
|
|| 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. */
|
/** @return true if the user can view the server caches. */
|
||||||
public boolean canViewCaches() {
|
public boolean canViewCaches() {
|
||||||
return canPerform(GlobalCapability.VIEW_CACHES)
|
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.PRIORITY;
|
||||||
import static com.google.gerrit.common.data.GlobalCapability.RUN_GC;
|
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.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_CACHES;
|
||||||
import static com.google.gerrit.common.data.GlobalCapability.VIEW_CONNECTIONS;
|
import static com.google.gerrit.common.data.GlobalCapability.VIEW_CONNECTIONS;
|
||||||
import static com.google.gerrit.common.data.GlobalCapability.VIEW_QUEUE;
|
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_ACCOUNT, cc.canCreateAccount());
|
||||||
have.put(CREATE_GROUP, cc.canCreateGroup());
|
have.put(CREATE_GROUP, cc.canCreateGroup());
|
||||||
have.put(CREATE_PROJECT, cc.canCreateProject());
|
have.put(CREATE_PROJECT, cc.canCreateProject());
|
||||||
have.put(EMAIL_REVIEWERS, cc.canEmailReviewers());
|
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(FLUSH_CACHES, cc.canFlushCaches());
|
||||||
have.put(VIEW_CONNECTIONS, cc.canViewConnections());
|
have.put(KILL_TASK, cc.canKillTask());
|
||||||
have.put(VIEW_QUEUE, cc.canViewQueue());
|
|
||||||
have.put(RUN_GC, cc.canRunGC());
|
have.put(RUN_GC, cc.canRunGC());
|
||||||
have.put(STREAM_EVENTS, cc.canStreamEvents());
|
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();
|
QueueProvider.QueueType queue = cc.getQueueType();
|
||||||
if (queue != QueueProvider.QueueType.INTERACTIVE
|
if (queue != QueueProvider.QueueType.INTERACTIVE
|
||||||
|
@ -270,8 +270,8 @@ public class SuggestReviewers implements RestReadView<ChangeResource> {
|
|||||||
|
|
||||||
public static class SuggestedReviewerInfo implements Comparable<SuggestedReviewerInfo> {
|
public static class SuggestedReviewerInfo implements Comparable<SuggestedReviewerInfo> {
|
||||||
String kind = "gerritcodereview#suggestedreviewer";
|
String kind = "gerritcodereview#suggestedreviewer";
|
||||||
AccountInfo account;
|
public AccountInfo account;
|
||||||
GroupBaseInfo group;
|
public GroupBaseInfo group;
|
||||||
|
|
||||||
SuggestedReviewerInfo(AccountInfo a) {
|
SuggestedReviewerInfo(AccountInfo a) {
|
||||||
this.account = a;
|
this.account = a;
|
||||||
|
@ -35,6 +35,7 @@ public class CapabilityConstants extends TranslationBundle {
|
|||||||
public String runAs;
|
public String runAs;
|
||||||
public String runGC;
|
public String runGC;
|
||||||
public String streamEvents;
|
public String streamEvents;
|
||||||
|
public String viewAllAccounts;
|
||||||
public String viewCaches;
|
public String viewCaches;
|
||||||
public String viewConnections;
|
public String viewConnections;
|
||||||
public String viewQueue;
|
public String viewQueue;
|
||||||
|
@ -11,6 +11,7 @@ queryLimit = Query Limit
|
|||||||
runAs = Run As
|
runAs = Run As
|
||||||
runGC = Run Garbage Collection
|
runGC = Run Garbage Collection
|
||||||
streamEvents = Stream Events
|
streamEvents = Stream Events
|
||||||
|
viewAllAccounts = View All Accounts
|
||||||
viewCaches = View Caches
|
viewCaches = View Caches
|
||||||
viewConnections = View Connections
|
viewConnections = View Connections
|
||||||
viewQueue = View Queue
|
viewQueue = View Queue
|
||||||
|
Loading…
Reference in New Issue
Block a user