diff --git a/java/com/google/gerrit/server/permissions/DefaultPermissionBackend.java b/java/com/google/gerrit/server/permissions/DefaultPermissionBackend.java index 2c8c951339..17ea107e4b 100644 --- a/java/com/google/gerrit/server/permissions/DefaultPermissionBackend.java +++ b/java/com/google/gerrit/server/permissions/DefaultPermissionBackend.java @@ -84,6 +84,11 @@ public class DefaultPermissionBackend extends PermissionBackend { return new WithUserImpl(identifiedUser); } + @Override + public boolean usesDefaultCapabilities() { + return true; + } + class WithUserImpl extends WithUser { private final CurrentUser user; private Boolean admin; diff --git a/java/com/google/gerrit/server/permissions/PermissionBackend.java b/java/com/google/gerrit/server/permissions/PermissionBackend.java index ed10184a8c..491769ccac 100644 --- a/java/com/google/gerrit/server/permissions/PermissionBackend.java +++ b/java/com/google/gerrit/server/permissions/PermissionBackend.java @@ -23,6 +23,7 @@ import com.google.gerrit.common.data.LabelType; import com.google.gerrit.extensions.api.access.GlobalOrPluginPermission; import com.google.gerrit.extensions.conditions.BooleanCondition; import com.google.gerrit.extensions.restapi.AuthException; +import com.google.gerrit.extensions.restapi.ResourceNotFoundException; import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Branch; import com.google.gerrit.reviewdb.client.Project; @@ -112,6 +113,29 @@ public abstract class PermissionBackend { */ public abstract WithUser absentUser(Account.Id user); + /** + * Check whether this {@code PermissionBackend} respects the same global capabilities as the + * {@link DefaultPermissionBackend}. + * + *

If true, then it makes sense for downstream callers to refer to built-in Gerrit capability + * names in user-facing error messages, for example. + * + * @return whether this is the default permission backend. + */ + public boolean usesDefaultCapabilities() { + return false; + } + + /** + * Throw {@link ResourceNotFoundException} if this backend does not use the default global + * capabilities. + */ + public void checkUsesDefaultCapabilities() throws ResourceNotFoundException { + if (!usesDefaultCapabilities()) { + throw new ResourceNotFoundException("Gerrit capabilities not used on this server"); + } + } + /** * Bulk evaluate a set of {@link PermissionBackendCondition} for view handling. * diff --git a/java/com/google/gerrit/server/restapi/account/Capabilities.java b/java/com/google/gerrit/server/restapi/account/Capabilities.java index 2dd54a505e..d18f1b25ad 100644 --- a/java/com/google/gerrit/server/restapi/account/Capabilities.java +++ b/java/com/google/gerrit/server/restapi/account/Capabilities.java @@ -60,6 +60,7 @@ class Capabilities implements ChildCollection { } @Override - public Object apply(AccountResource rsrc) throws AuthException, PermissionBackendException { + public Object apply(AccountResource rsrc) throws RestApiException, PermissionBackendException { + permissionBackend.checkUsesDefaultCapabilities(); PermissionBackend.WithUser perm = permissionBackend.currentUser(); if (self.get() != rsrc.getUser()) { perm.check(GlobalPermission.ADMINISTRATE_SERVER); @@ -158,8 +160,16 @@ class GetCapabilities implements RestReadView { @Singleton static class CheckOne implements RestReadView { + private final PermissionBackend permissionBackend; + + @Inject + CheckOne(PermissionBackend permissionBackend) { + this.permissionBackend = permissionBackend; + } + @Override - public BinaryResult apply(Capability resource) { + public BinaryResult apply(Capability resource) throws ResourceNotFoundException { + permissionBackend.checkUsesDefaultCapabilities(); return BinaryResult.create("ok\n"); } } diff --git a/java/com/google/gerrit/server/restapi/config/ListCapabilities.java b/java/com/google/gerrit/server/restapi/config/ListCapabilities.java index 853e156972..412b88dc6f 100644 --- a/java/com/google/gerrit/server/restapi/config/ListCapabilities.java +++ b/java/com/google/gerrit/server/restapi/config/ListCapabilities.java @@ -18,9 +18,11 @@ import com.google.common.collect.ImmutableMap; import com.google.gerrit.common.data.GlobalCapability; import com.google.gerrit.extensions.config.CapabilityDefinition; import com.google.gerrit.extensions.registration.DynamicMap; +import com.google.gerrit.extensions.restapi.ResourceNotFoundException; import com.google.gerrit.extensions.restapi.RestReadView; import com.google.gerrit.server.config.CapabilityConstants; import com.google.gerrit.server.config.ConfigResource; +import com.google.gerrit.server.permissions.PermissionBackend; import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.Singleton; @@ -36,16 +38,20 @@ public class ListCapabilities implements RestReadView { private static final Logger log = LoggerFactory.getLogger(ListCapabilities.class); private static final Pattern PLUGIN_NAME_PATTERN = Pattern.compile("^[a-zA-Z0-9-]+$"); + private final PermissionBackend permissionBackend; private final DynamicMap pluginCapabilities; @Inject - public ListCapabilities(DynamicMap pluginCapabilities) { + public ListCapabilities( + PermissionBackend permissionBackend, DynamicMap pluginCapabilities) { + this.permissionBackend = permissionBackend; this.pluginCapabilities = pluginCapabilities; } @Override public Map apply(ConfigResource resource) - throws IllegalAccessException, NoSuchFieldException { + throws ResourceNotFoundException, IllegalAccessException, NoSuchFieldException { + permissionBackend.checkUsesDefaultCapabilities(); return ImmutableMap.builder() .putAll(collectCoreCapabilities()) .putAll(collectPluginCapabilities()) diff --git a/javatests/com/google/gerrit/server/config/ListCapabilitiesTest.java b/javatests/com/google/gerrit/server/config/ListCapabilitiesTest.java index 577d931dc2..935dfc69af 100644 --- a/javatests/com/google/gerrit/server/config/ListCapabilitiesTest.java +++ b/javatests/com/google/gerrit/server/config/ListCapabilitiesTest.java @@ -20,11 +20,15 @@ import com.google.gerrit.common.data.GlobalCapability; import com.google.gerrit.extensions.annotations.Exports; import com.google.gerrit.extensions.config.CapabilityDefinition; import com.google.gerrit.extensions.registration.DynamicMap; +import com.google.gerrit.reviewdb.client.Account.Id; +import com.google.gerrit.server.CurrentUser; +import com.google.gerrit.server.permissions.PermissionBackend; import com.google.gerrit.server.restapi.config.ListCapabilities; import com.google.gerrit.server.restapi.config.ListCapabilities.CapabilityInfo; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; +import com.google.inject.Singleton; import java.util.Map; import org.junit.Before; import org.junit.Test; @@ -48,6 +52,7 @@ public class ListCapabilitiesTest { return "Print Hello"; } }); + bind(PermissionBackend.class).to(FakePermissionBackend.class); } }; injector = Guice.createInjector(mod); @@ -68,4 +73,27 @@ public class ListCapabilitiesTest { assertThat(m.get(pluginCapability).id).isEqualTo(pluginCapability); assertThat(m.get(pluginCapability).name).isEqualTo("Print Hello"); } + + @Singleton + private static class FakePermissionBackend extends PermissionBackend { + @Override + public WithUser currentUser() { + throw new UnsupportedOperationException(); + } + + @Override + public WithUser user(CurrentUser user) { + throw new UnsupportedOperationException(); + } + + @Override + public WithUser absentUser(Id user) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean usesDefaultCapabilities() { + return true; + } + } }