From 0a8969410f2f76e39e45529c142e58a41a08d944 Mon Sep 17 00:00:00 2001 From: Shawn Pearce Date: Wed, 16 Jan 2013 20:09:46 -0800 Subject: [PATCH] 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 --- .../server/account/AccountsCollection.java | 31 +++++++++++++++++-- .../gerrit/server/account/Capabilities.java | 12 ++++++- .../server/account/GetCapabilities.java | 16 ++++++++++ .../server/config/GerritGlobalModule.java | 2 ++ .../server/config/GerritRequestModule.java | 1 - 5 files changed, 58 insertions(+), 4 deletions(-) diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountsCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountsCollection.java index 77a2504695..c69371eac6 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountsCollection.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountsCollection.java @@ -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 { private final Provider self; + private final AccountResolver resolver; + private final AccountControl.Factory accountControlFactory; + private final IdentifiedUser.GenericFactory userFactory; private final DynamicMap> views; @Inject AccountsCollection(Provider self, + AccountResolver resolver, + AccountControl.Factory accountControlFactory, + IdentifiedUser.GenericFactory userFactory, DynamicMap> 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 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); } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/Capabilities.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/Capabilities.java index 5ba5ca3eee..aa8dfcfe69 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/account/Capabilities.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/Capabilities.java @@ -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 { + private final Provider self; private final DynamicMap> views; private final Provider get; @Inject Capabilities( + Provider self, DynamicMap> views, Provider 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))) { diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetCapabilities.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetCapabilities.java index fe875ea5a6..1868bd7e6e 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetCapabilities.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetCapabilities.java @@ -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 { } private Set query; + private final Provider self; + + @Inject + GetCapabilities(Provider 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 have = Maps.newLinkedHashMap(); for (String name : GlobalCapability.getAllNames()) { diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java index 120c843a1f..48be6124e0 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java @@ -34,6 +34,7 @@ import com.google.gerrit.server.InternalUser; import com.google.gerrit.server.MimeUtilFileTypeRegistry; import com.google.gerrit.server.account.AccountByEmailCacheImpl; 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.AccountResolver; import com.google.gerrit.server.account.AccountVisibility; @@ -196,6 +197,7 @@ public class GerritGlobalModule extends FactoryModule { bind(IdentifiedUser.GenericFactory.class).in(SINGLETON); bind(ChangeControl.GenericFactory.class); bind(ProjectControl.GenericFactory.class); + bind(AccountControl.Factory.class); factory(FunctionState.Factory.class); install(new AuditModule()); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritRequestModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritRequestModule.java index b7360ff4c2..9c1eeac8af 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritRequestModule.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritRequestModule.java @@ -60,7 +60,6 @@ public class GerritRequestModule extends FactoryModule { bind(PerRequestProjectControlCache.class).in(RequestScoped.class); bind(ChangeControl.Factory.class).in(SINGLETON); bind(ProjectControl.Factory.class).in(SINGLETON); - bind(AccountControl.Factory.class).in(SINGLETON); factory(SubmoduleOp.Factory.class); factory(MergeOp.Factory.class);