Dissolve gerrit-server top-level directory
Change-Id: I538512dfe0f1bea774c01fdd45fa410a45634011
This commit is contained in:
committed by
Dave Borowitz
parent
472396c797
commit
376a7bbb64
182
java/com/google/gerrit/server/permissions/GlobalPermission.java
Normal file
182
java/com/google/gerrit/server/permissions/GlobalPermission.java
Normal file
@@ -0,0 +1,182 @@
|
||||
// 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 com.google.common.collect.ImmutableMap;
|
||||
import com.google.gerrit.common.Nullable;
|
||||
import com.google.gerrit.common.data.GlobalCapability;
|
||||
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.GlobalOrPluginPermission;
|
||||
import com.google.gerrit.extensions.api.access.PluginPermission;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/** Global server permissions built into Gerrit. */
|
||||
public enum GlobalPermission implements GlobalOrPluginPermission {
|
||||
ACCESS_DATABASE(GlobalCapability.ACCESS_DATABASE),
|
||||
ADMINISTRATE_SERVER(GlobalCapability.ADMINISTRATE_SERVER),
|
||||
CREATE_ACCOUNT(GlobalCapability.CREATE_ACCOUNT),
|
||||
CREATE_GROUP(GlobalCapability.CREATE_GROUP),
|
||||
CREATE_PROJECT(GlobalCapability.CREATE_PROJECT),
|
||||
EMAIL_REVIEWERS(GlobalCapability.EMAIL_REVIEWERS),
|
||||
FLUSH_CACHES(GlobalCapability.FLUSH_CACHES),
|
||||
KILL_TASK(GlobalCapability.KILL_TASK),
|
||||
MAINTAIN_SERVER(GlobalCapability.MAINTAIN_SERVER),
|
||||
MODIFY_ACCOUNT(GlobalCapability.MODIFY_ACCOUNT),
|
||||
RUN_AS(GlobalCapability.RUN_AS),
|
||||
RUN_GC(GlobalCapability.RUN_GC),
|
||||
STREAM_EVENTS(GlobalCapability.STREAM_EVENTS),
|
||||
VIEW_ALL_ACCOUNTS(GlobalCapability.VIEW_ALL_ACCOUNTS),
|
||||
VIEW_CACHES(GlobalCapability.VIEW_CACHES),
|
||||
VIEW_CONNECTIONS(GlobalCapability.VIEW_CONNECTIONS),
|
||||
VIEW_PLUGINS(GlobalCapability.VIEW_PLUGINS),
|
||||
VIEW_QUEUE(GlobalCapability.VIEW_QUEUE);
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(GlobalPermission.class);
|
||||
private static final ImmutableMap<String, GlobalPermission> BY_NAME;
|
||||
|
||||
static {
|
||||
ImmutableMap.Builder<String, GlobalPermission> m = ImmutableMap.builder();
|
||||
for (GlobalPermission p : values()) {
|
||||
m.put(p.permissionName(), p);
|
||||
}
|
||||
BY_NAME = m.build();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static GlobalPermission byName(String name) {
|
||||
return BY_NAME.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
log.error(
|
||||
String.format(
|
||||
"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 final String name;
|
||||
|
||||
GlobalPermission(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/** @return name used in {@code project.config} permissions. */
|
||||
@Override
|
||||
public String permissionName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String describeForException() {
|
||||
return toString().toLowerCase(Locale.US).replace('_', ' ');
|
||||
}
|
||||
|
||||
private static GlobalOrPluginPermission resolve(
|
||||
@Nullable String pluginName,
|
||||
String capability,
|
||||
CapabilityScope scope,
|
||||
boolean fallBackToAdmin,
|
||||
Class<?> clazz,
|
||||
Class<?> annotationClass)
|
||||
throws PermissionBackendException {
|
||||
if (pluginName != null
|
||||
&& !"gerrit".equals(pluginName)
|
||||
&& (scope == CapabilityScope.PLUGIN || scope == CapabilityScope.CONTEXT)) {
|
||||
return new PluginPermission(pluginName, capability, fallBackToAdmin);
|
||||
}
|
||||
|
||||
if (scope == CapabilityScope.PLUGIN) {
|
||||
log.error(
|
||||
String.format(
|
||||
"Class %s uses @%s(scope=%s), but is not within a plugin",
|
||||
clazz.getName(), annotationClass.getSimpleName(), scope.name()));
|
||||
throw new PermissionBackendException("cannot extract permission");
|
||||
}
|
||||
|
||||
GlobalPermission perm = byName(capability);
|
||||
if (perm == null) {
|
||||
log.error(
|
||||
String.format("Class %s requires unknown capability %s", clazz.getName(), capability));
|
||||
throw new PermissionBackendException("cannot extract permission");
|
||||
}
|
||||
return perm;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user