summaryrefslogtreecommitdiffstats
path: root/java/com/google/gerrit/server/permissions/GlobalPermission.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/google/gerrit/server/permissions/GlobalPermission.java')
-rw-r--r--java/com/google/gerrit/server/permissions/GlobalPermission.java156
1 files changed, 156 insertions, 0 deletions
diff --git a/java/com/google/gerrit/server/permissions/GlobalPermission.java b/java/com/google/gerrit/server/permissions/GlobalPermission.java
new file mode 100644
index 0000000000..07c9e84e4e
--- /dev/null
+++ b/java/com/google/gerrit/server/permissions/GlobalPermission.java
@@ -0,0 +1,156 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.permissions;
+
+import static com.google.gerrit.server.permissions.DefaultPermissionMappings.globalPermission;
+
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.common.Nullable;
+import com.google.gerrit.extensions.annotations.CapabilityScope;
+import com.google.gerrit.extensions.annotations.RequiresAnyCapability;
+import com.google.gerrit.extensions.annotations.RequiresCapability;
+import com.google.gerrit.extensions.api.access.GerritPermission;
+import com.google.gerrit.extensions.api.access.GlobalOrPluginPermission;
+import com.google.gerrit.extensions.api.access.PluginPermission;
+import com.google.gerrit.extensions.registration.PluginName;
+import java.lang.annotation.Annotation;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Optional;
+import java.util.Set;
+
+/** Global server permissions built into Gerrit. */
+public enum GlobalPermission implements GlobalOrPluginPermission {
+ ACCESS_DATABASE,
+ ADMINISTRATE_SERVER,
+ CREATE_ACCOUNT,
+ CREATE_GROUP,
+ CREATE_PROJECT,
+ EMAIL_REVIEWERS,
+ FLUSH_CACHES,
+ KILL_TASK,
+ MAINTAIN_SERVER,
+ MODIFY_ACCOUNT,
+ READ_AS,
+ RUN_AS,
+ RUN_GC,
+ STREAM_EVENTS,
+ VIEW_ALL_ACCOUNTS,
+ VIEW_CACHES,
+ VIEW_CONNECTIONS,
+ VIEW_PLUGINS,
+ VIEW_QUEUE,
+ VIEW_ACCESS;
+
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ /**
+ * Extracts the {@code @RequiresCapability} or {@code @RequiresAnyCapability} annotation.
+ *
+ * @param pluginName name of the declaring plugin. May be {@code null} or {@code "gerrit"} for
+ * classes originating from the core server.
+ * @param clazz target class to extract annotation from.
+ * @return empty set if no annotations were found, or a collection of permissions, any of which
+ * are suitable to enable access.
+ * @throws PermissionBackendException the annotation could not be parsed.
+ */
+ public static Set<GlobalOrPluginPermission> fromAnnotation(
+ @Nullable String pluginName, Class<?> clazz) throws PermissionBackendException {
+ RequiresCapability rc = findAnnotation(clazz, RequiresCapability.class);
+ RequiresAnyCapability rac = findAnnotation(clazz, RequiresAnyCapability.class);
+ if (rc != null && rac != null) {
+ logger.atSevere().log(
+ "Class %s uses both @%s and @%s",
+ clazz.getName(),
+ RequiresCapability.class.getSimpleName(),
+ RequiresAnyCapability.class.getSimpleName());
+ throw new PermissionBackendException("cannot extract permission");
+ } else if (rc != null) {
+ return Collections.singleton(
+ resolve(
+ pluginName,
+ rc.value(),
+ rc.scope(),
+ rc.fallBackToAdmin(),
+ clazz,
+ RequiresCapability.class));
+ } else if (rac != null) {
+ Set<GlobalOrPluginPermission> r = new LinkedHashSet<>();
+ for (String capability : rac.value()) {
+ r.add(
+ resolve(
+ pluginName,
+ capability,
+ rac.scope(),
+ rac.fallBackToAdmin(),
+ clazz,
+ RequiresAnyCapability.class));
+ }
+ return Collections.unmodifiableSet(r);
+ } else {
+ return Collections.emptySet();
+ }
+ }
+
+ public static Set<GlobalOrPluginPermission> fromAnnotation(Class<?> clazz)
+ throws PermissionBackendException {
+ return fromAnnotation(null, clazz);
+ }
+
+ private static GlobalOrPluginPermission resolve(
+ @Nullable String pluginName,
+ String capability,
+ CapabilityScope scope,
+ boolean fallBackToAdmin,
+ Class<?> clazz,
+ Class<?> annotationClass)
+ throws PermissionBackendException {
+ if (pluginName != null
+ && !PluginName.GERRIT.equals(pluginName)
+ && (scope == CapabilityScope.PLUGIN || scope == CapabilityScope.CONTEXT)) {
+ return new PluginPermission(pluginName, capability, fallBackToAdmin);
+ }
+
+ if (scope == CapabilityScope.PLUGIN) {
+ logger.atSevere().log(
+ "Class %s uses @%s(scope=%s), but is not within a plugin",
+ clazz.getName(), annotationClass.getSimpleName(), scope.name());
+ throw new PermissionBackendException("cannot extract permission");
+ }
+
+ Optional<GlobalPermission> perm = globalPermission(capability);
+ if (!perm.isPresent()) {
+ logger.atSevere().log("Class %s requires unknown capability %s", clazz.getName(), capability);
+ throw new PermissionBackendException("cannot extract permission");
+ }
+ return perm.get();
+ }
+
+ @Nullable
+ private static <T extends Annotation> T findAnnotation(Class<?> clazz, Class<T> annotation) {
+ for (; clazz != null; clazz = clazz.getSuperclass()) {
+ T t = clazz.getAnnotation(annotation);
+ if (t != null) {
+ return t;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String describeForException() {
+ return GerritPermission.describeEnumValue(this);
+ }
+}