Allow administrators to see other user capabilities

Expand /accounts/{id}/capabilities to permit an administrator
to inspect another user's effective capabilities by identifying
the user with anything AccountResolver understands.

This is a stepping stone to making more data available about
other accounts.

Change-Id: I81c786825f6531844b36f6178e5ed7324ccebd3a
This commit is contained in:
Shawn Pearce
2013-01-16 20:09:46 -08:00
parent d18ef139f3
commit 0a8969410f
5 changed files with 58 additions and 4 deletions

View File

@@ -14,35 +14,51 @@
package com.google.gerrit.server.account;
import com.google.common.collect.Iterables;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestCollection;
import com.google.gerrit.extensions.restapi.RestView;
import com.google.gerrit.extensions.restapi.TopLevelResource;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.server.AnonymousUser;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.util.Url;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.util.Set;
public class AccountsCollection implements
RestCollection<TopLevelResource, AccountResource> {
private final Provider<CurrentUser> self;
private final AccountResolver resolver;
private final AccountControl.Factory accountControlFactory;
private final IdentifiedUser.GenericFactory userFactory;
private final DynamicMap<RestView<AccountResource>> views;
@Inject
AccountsCollection(Provider<CurrentUser> self,
AccountResolver resolver,
AccountControl.Factory accountControlFactory,
IdentifiedUser.GenericFactory userFactory,
DynamicMap<RestView<AccountResource>> views) {
this.self = self;
this.resolver = resolver;
this.accountControlFactory = accountControlFactory;
this.userFactory = userFactory;
this.views = views;
}
@Override
public AccountResource parse(TopLevelResource root, String id)
throws ResourceNotFoundException, AuthException {
throws ResourceNotFoundException, AuthException, OrmException {
CurrentUser user = self.get();
if ("self".equals(id)) {
CurrentUser user = self.get();
if (user instanceof IdentifiedUser) {
return new AccountResource((IdentifiedUser) user);
} else if (user instanceof AnonymousUser) {
@@ -50,6 +66,17 @@ public class AccountsCollection implements
} else {
throw new ResourceNotFoundException(id);
}
}
Set<Account.Id> matches = resolver.findAll(Url.decode(id));
if (matches.size() != 1) {
throw new ResourceNotFoundException(id);
}
Account.Id a = Iterables.getOnlyElement(matches);
if (accountControlFactory.get().canSee(a)
|| user.getCapabilities().canAdministrateServer()) {
return new AccountResource(userFactory.create(a));
} else {
throw new ResourceNotFoundException(id);
}

View File

@@ -16,22 +16,27 @@ package com.google.gerrit.server.account;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.ChildCollection;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestView;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.account.AccountResource.Capability;
import com.google.inject.Inject;
import com.google.inject.Provider;
class Capabilities implements
ChildCollection<AccountResource, AccountResource.Capability> {
private final Provider<CurrentUser> self;
private final DynamicMap<RestView<AccountResource.Capability>> views;
private final Provider<GetCapabilities> get;
@Inject
Capabilities(
Provider<CurrentUser> self,
DynamicMap<RestView<AccountResource.Capability>> views,
Provider<GetCapabilities> get) {
this.self = self;
this.views = views;
this.get = get;
}
@@ -43,7 +48,12 @@ class Capabilities implements
@Override
public Capability parse(AccountResource parent, String id)
throws ResourceNotFoundException, Exception {
throws ResourceNotFoundException, AuthException {
if (self.get() != parent.getUser()
&& !self.get().getCapabilities().canAdministrateServer()) {
throw new AuthException("restricted to administrator");
}
CapabilityControl cap = parent.getUser().getCapabilities();
if (cap.canPerform(id)
|| (cap.canAdministrateServer() && GlobalCapability.isCapability(id))) {

View File

@@ -32,13 +32,17 @@ import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.common.data.PermissionRange;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.BinaryResult;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.OutputFormat;
import com.google.gerrit.server.account.AccountResource.Capability;
import com.google.gerrit.server.git.QueueProvider;
import com.google.gson.reflect.TypeToken;
import com.google.inject.Inject;
import com.google.inject.Provider;
import org.kohsuke.args4j.Option;
@@ -67,9 +71,21 @@ class GetCapabilities implements RestReadView<AccountResource> {
}
private Set<String> query;
private final Provider<CurrentUser> self;
@Inject
GetCapabilities(Provider<CurrentUser> self) {
this.self = self;
}
@Override
public Object apply(AccountResource resource)
throws BadRequestException, Exception {
if (self.get() != resource.getUser()
&& !self.get().getCapabilities().canAdministrateServer()) {
throw new AuthException("restricted to administrator");
}
CapabilityControl cc = resource.getUser().getCapabilities();
Map<String, Object> have = Maps.newLinkedHashMap();
for (String name : GlobalCapability.getAllNames()) {