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:
@@ -14,35 +14,51 @@
|
|||||||
|
|
||||||
package com.google.gerrit.server.account;
|
package com.google.gerrit.server.account;
|
||||||
|
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.gerrit.extensions.registration.DynamicMap;
|
import com.google.gerrit.extensions.registration.DynamicMap;
|
||||||
import com.google.gerrit.extensions.restapi.AuthException;
|
import com.google.gerrit.extensions.restapi.AuthException;
|
||||||
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
||||||
import com.google.gerrit.extensions.restapi.RestCollection;
|
import com.google.gerrit.extensions.restapi.RestCollection;
|
||||||
import com.google.gerrit.extensions.restapi.RestView;
|
import com.google.gerrit.extensions.restapi.RestView;
|
||||||
import com.google.gerrit.extensions.restapi.TopLevelResource;
|
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.AnonymousUser;
|
||||||
import com.google.gerrit.server.CurrentUser;
|
import com.google.gerrit.server.CurrentUser;
|
||||||
import com.google.gerrit.server.IdentifiedUser;
|
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.Inject;
|
||||||
import com.google.inject.Provider;
|
import com.google.inject.Provider;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class AccountsCollection implements
|
public class AccountsCollection implements
|
||||||
RestCollection<TopLevelResource, AccountResource> {
|
RestCollection<TopLevelResource, AccountResource> {
|
||||||
private final Provider<CurrentUser> self;
|
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;
|
private final DynamicMap<RestView<AccountResource>> views;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
AccountsCollection(Provider<CurrentUser> self,
|
AccountsCollection(Provider<CurrentUser> self,
|
||||||
|
AccountResolver resolver,
|
||||||
|
AccountControl.Factory accountControlFactory,
|
||||||
|
IdentifiedUser.GenericFactory userFactory,
|
||||||
DynamicMap<RestView<AccountResource>> views) {
|
DynamicMap<RestView<AccountResource>> views) {
|
||||||
this.self = self;
|
this.self = self;
|
||||||
|
this.resolver = resolver;
|
||||||
|
this.accountControlFactory = accountControlFactory;
|
||||||
|
this.userFactory = userFactory;
|
||||||
this.views = views;
|
this.views = views;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AccountResource parse(TopLevelResource root, String id)
|
public AccountResource parse(TopLevelResource root, String id)
|
||||||
throws ResourceNotFoundException, AuthException {
|
throws ResourceNotFoundException, AuthException, OrmException {
|
||||||
|
CurrentUser user = self.get();
|
||||||
|
|
||||||
if ("self".equals(id)) {
|
if ("self".equals(id)) {
|
||||||
CurrentUser user = self.get();
|
|
||||||
if (user instanceof IdentifiedUser) {
|
if (user instanceof IdentifiedUser) {
|
||||||
return new AccountResource((IdentifiedUser) user);
|
return new AccountResource((IdentifiedUser) user);
|
||||||
} else if (user instanceof AnonymousUser) {
|
} else if (user instanceof AnonymousUser) {
|
||||||
@@ -50,6 +66,17 @@ public class AccountsCollection implements
|
|||||||
} else {
|
} else {
|
||||||
throw new ResourceNotFoundException(id);
|
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 {
|
} else {
|
||||||
throw new ResourceNotFoundException(id);
|
throw new ResourceNotFoundException(id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,22 +16,27 @@ package com.google.gerrit.server.account;
|
|||||||
|
|
||||||
import com.google.gerrit.common.data.GlobalCapability;
|
import com.google.gerrit.common.data.GlobalCapability;
|
||||||
import com.google.gerrit.extensions.registration.DynamicMap;
|
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.ChildCollection;
|
||||||
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
||||||
import com.google.gerrit.extensions.restapi.RestView;
|
import com.google.gerrit.extensions.restapi.RestView;
|
||||||
|
import com.google.gerrit.server.CurrentUser;
|
||||||
import com.google.gerrit.server.account.AccountResource.Capability;
|
import com.google.gerrit.server.account.AccountResource.Capability;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Provider;
|
import com.google.inject.Provider;
|
||||||
|
|
||||||
class Capabilities implements
|
class Capabilities implements
|
||||||
ChildCollection<AccountResource, AccountResource.Capability> {
|
ChildCollection<AccountResource, AccountResource.Capability> {
|
||||||
|
private final Provider<CurrentUser> self;
|
||||||
private final DynamicMap<RestView<AccountResource.Capability>> views;
|
private final DynamicMap<RestView<AccountResource.Capability>> views;
|
||||||
private final Provider<GetCapabilities> get;
|
private final Provider<GetCapabilities> get;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
Capabilities(
|
Capabilities(
|
||||||
|
Provider<CurrentUser> self,
|
||||||
DynamicMap<RestView<AccountResource.Capability>> views,
|
DynamicMap<RestView<AccountResource.Capability>> views,
|
||||||
Provider<GetCapabilities> get) {
|
Provider<GetCapabilities> get) {
|
||||||
|
this.self = self;
|
||||||
this.views = views;
|
this.views = views;
|
||||||
this.get = get;
|
this.get = get;
|
||||||
}
|
}
|
||||||
@@ -43,7 +48,12 @@ class Capabilities implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Capability parse(AccountResource parent, String id)
|
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();
|
CapabilityControl cap = parent.getUser().getCapabilities();
|
||||||
if (cap.canPerform(id)
|
if (cap.canPerform(id)
|
||||||
|| (cap.canAdministrateServer() && GlobalCapability.isCapability(id))) {
|
|| (cap.canAdministrateServer() && GlobalCapability.isCapability(id))) {
|
||||||
|
|||||||
@@ -32,13 +32,17 @@ import com.google.common.collect.Maps;
|
|||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.google.gerrit.common.data.GlobalCapability;
|
import com.google.gerrit.common.data.GlobalCapability;
|
||||||
import com.google.gerrit.common.data.PermissionRange;
|
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.BadRequestException;
|
||||||
import com.google.gerrit.extensions.restapi.BinaryResult;
|
import com.google.gerrit.extensions.restapi.BinaryResult;
|
||||||
import com.google.gerrit.extensions.restapi.RestReadView;
|
import com.google.gerrit.extensions.restapi.RestReadView;
|
||||||
|
import com.google.gerrit.server.CurrentUser;
|
||||||
import com.google.gerrit.server.OutputFormat;
|
import com.google.gerrit.server.OutputFormat;
|
||||||
import com.google.gerrit.server.account.AccountResource.Capability;
|
import com.google.gerrit.server.account.AccountResource.Capability;
|
||||||
import com.google.gerrit.server.git.QueueProvider;
|
import com.google.gerrit.server.git.QueueProvider;
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Provider;
|
||||||
|
|
||||||
import org.kohsuke.args4j.Option;
|
import org.kohsuke.args4j.Option;
|
||||||
|
|
||||||
@@ -67,9 +71,21 @@ class GetCapabilities implements RestReadView<AccountResource> {
|
|||||||
}
|
}
|
||||||
private Set<String> query;
|
private Set<String> query;
|
||||||
|
|
||||||
|
private final Provider<CurrentUser> self;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
GetCapabilities(Provider<CurrentUser> self) {
|
||||||
|
this.self = self;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object apply(AccountResource resource)
|
public Object apply(AccountResource resource)
|
||||||
throws BadRequestException, Exception {
|
throws BadRequestException, Exception {
|
||||||
|
if (self.get() != resource.getUser()
|
||||||
|
&& !self.get().getCapabilities().canAdministrateServer()) {
|
||||||
|
throw new AuthException("restricted to administrator");
|
||||||
|
}
|
||||||
|
|
||||||
CapabilityControl cc = resource.getUser().getCapabilities();
|
CapabilityControl cc = resource.getUser().getCapabilities();
|
||||||
Map<String, Object> have = Maps.newLinkedHashMap();
|
Map<String, Object> have = Maps.newLinkedHashMap();
|
||||||
for (String name : GlobalCapability.getAllNames()) {
|
for (String name : GlobalCapability.getAllNames()) {
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import com.google.gerrit.server.InternalUser;
|
|||||||
import com.google.gerrit.server.MimeUtilFileTypeRegistry;
|
import com.google.gerrit.server.MimeUtilFileTypeRegistry;
|
||||||
import com.google.gerrit.server.account.AccountByEmailCacheImpl;
|
import com.google.gerrit.server.account.AccountByEmailCacheImpl;
|
||||||
import com.google.gerrit.server.account.AccountCacheImpl;
|
import com.google.gerrit.server.account.AccountCacheImpl;
|
||||||
|
import com.google.gerrit.server.account.AccountControl;
|
||||||
import com.google.gerrit.server.account.AccountInfoCacheFactory;
|
import com.google.gerrit.server.account.AccountInfoCacheFactory;
|
||||||
import com.google.gerrit.server.account.AccountResolver;
|
import com.google.gerrit.server.account.AccountResolver;
|
||||||
import com.google.gerrit.server.account.AccountVisibility;
|
import com.google.gerrit.server.account.AccountVisibility;
|
||||||
@@ -196,6 +197,7 @@ public class GerritGlobalModule extends FactoryModule {
|
|||||||
bind(IdentifiedUser.GenericFactory.class).in(SINGLETON);
|
bind(IdentifiedUser.GenericFactory.class).in(SINGLETON);
|
||||||
bind(ChangeControl.GenericFactory.class);
|
bind(ChangeControl.GenericFactory.class);
|
||||||
bind(ProjectControl.GenericFactory.class);
|
bind(ProjectControl.GenericFactory.class);
|
||||||
|
bind(AccountControl.Factory.class);
|
||||||
factory(FunctionState.Factory.class);
|
factory(FunctionState.Factory.class);
|
||||||
|
|
||||||
install(new AuditModule());
|
install(new AuditModule());
|
||||||
|
|||||||
@@ -60,7 +60,6 @@ public class GerritRequestModule extends FactoryModule {
|
|||||||
bind(PerRequestProjectControlCache.class).in(RequestScoped.class);
|
bind(PerRequestProjectControlCache.class).in(RequestScoped.class);
|
||||||
bind(ChangeControl.Factory.class).in(SINGLETON);
|
bind(ChangeControl.Factory.class).in(SINGLETON);
|
||||||
bind(ProjectControl.Factory.class).in(SINGLETON);
|
bind(ProjectControl.Factory.class).in(SINGLETON);
|
||||||
bind(AccountControl.Factory.class).in(SINGLETON);
|
|
||||||
|
|
||||||
factory(SubmoduleOp.Factory.class);
|
factory(SubmoduleOp.Factory.class);
|
||||||
factory(MergeOp.Factory.class);
|
factory(MergeOp.Factory.class);
|
||||||
|
|||||||
Reference in New Issue
Block a user