Line data Source code
1 : // Copyright (C) 2019 The Android Open Source Project 2 : // 3 : // Licensed under the Apache License, Version 2.0 (the "License"); 4 : // you may not use this file except in compliance with the License. 5 : // You may obtain a copy of the License at 6 : // 7 : // http://www.apache.org/licenses/LICENSE-2.0 8 : // 9 : // Unless required by applicable law or agreed to in writing, software 10 : // distributed under the License is distributed on an "AS IS" BASIS, 11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 : // See the License for the specific language governing permissions and 13 : // limitations under the License. 14 : 15 : package com.google.gerrit.server.permissions; 16 : 17 : import static com.google.gerrit.extensions.api.access.PluginProjectPermission.PLUGIN_PERMISSION_NAME_PATTERN_STRING; 18 : 19 : import com.google.common.collect.ImmutableMap; 20 : import com.google.common.flogger.FluentLogger; 21 : import com.google.gerrit.extensions.config.CapabilityDefinition; 22 : import com.google.gerrit.extensions.config.PluginPermissionDefinition; 23 : import com.google.gerrit.extensions.config.PluginProjectPermissionDefinition; 24 : import com.google.gerrit.extensions.registration.DynamicMap; 25 : import com.google.gerrit.extensions.registration.Extension; 26 : import com.google.inject.Inject; 27 : import com.google.inject.Singleton; 28 : import java.util.regex.Pattern; 29 : 30 : /** Utilities for plugin permissions. */ 31 : @Singleton 32 : public final class PluginPermissionsUtil { 33 151 : private static final FluentLogger logger = FluentLogger.forEnclosingClass(); 34 : 35 : private static final String PLUGIN_NAME_PATTERN_STRING = "[a-zA-Z0-9-]+"; 36 : 37 : /** 38 : * Name pattern for a plugin non-capability permission stored in the config file. 39 : * 40 : * <p>This pattern requires a plugin declared permission to have a name in the access section of 41 : * {@code ProjectConfig} with a format like "plugin-{pluginName}-{permissionName}", which makes it 42 : * easier to tell if a config name represents a plugin permission or not. Note "-" isn't clear 43 : * enough for this purpose since some core permissions, e.g. "label-", also contain "-". 44 : */ 45 151 : private static final Pattern PLUGIN_PERMISSION_NAME_IN_CONFIG_PATTERN = 46 151 : Pattern.compile( 47 : "^plugin-" 48 : + PLUGIN_NAME_PATTERN_STRING 49 : + "-" 50 : + PLUGIN_PERMISSION_NAME_PATTERN_STRING 51 : + "$"); 52 : 53 : /** Name pattern for a Gerrit plugin. */ 54 151 : private static final Pattern PLUGIN_NAME_PATTERN = 55 151 : Pattern.compile("^" + PLUGIN_NAME_PATTERN_STRING + "$"); 56 : 57 : private final DynamicMap<CapabilityDefinition> capabilityDefinitions; 58 : private final DynamicMap<PluginProjectPermissionDefinition> pluginProjectPermissionDefinitions; 59 : 60 : @Inject 61 : PluginPermissionsUtil( 62 : DynamicMap<CapabilityDefinition> capabilityDefinitions, 63 147 : DynamicMap<PluginProjectPermissionDefinition> pluginProjectPermissionDefinitions) { 64 147 : this.capabilityDefinitions = capabilityDefinitions; 65 147 : this.pluginProjectPermissionDefinitions = pluginProjectPermissionDefinitions; 66 147 : } 67 : 68 : /** 69 : * Collects all the plugin declared capabilities. 70 : * 71 : * @return a map of plugin declared capabilities with "pluginName" as its keys and 72 : * "pluginName-{permissionName}" as its values. 73 : */ 74 : public ImmutableMap<String, String> collectPluginCapabilities() { 75 5 : return collectPermissions(capabilityDefinitions, ""); 76 : } 77 : 78 : /** 79 : * Collects all the plugin declared project permissions. 80 : * 81 : * @return a map of plugin declared project permissions with "{pluginName}" as its keys and 82 : * "plugin-{pluginName}-{permissionName}" as its values. 83 : */ 84 : public ImmutableMap<String, String> collectPluginProjectPermissions() { 85 2 : return collectPermissions(pluginProjectPermissionDefinitions, "plugin-"); 86 : } 87 : 88 : private static <T extends PluginPermissionDefinition> 89 : ImmutableMap<String, String> collectPermissions(DynamicMap<T> definitions, String prefix) { 90 5 : ImmutableMap.Builder<String, String> permissionIdNames = ImmutableMap.builder(); 91 : 92 5 : for (Extension<T> extension : definitions) { 93 4 : String pluginName = extension.getPluginName(); 94 4 : if (!PLUGIN_NAME_PATTERN.matcher(pluginName).matches()) { 95 0 : logger.atWarning().log( 96 : "Plugin name '%s' must match '%s' to use permissions; rename the plugin", 97 0 : pluginName, PLUGIN_NAME_PATTERN.pattern()); 98 0 : continue; 99 : } 100 : 101 4 : String id = prefix + pluginName + "-" + extension.getExportName(); 102 4 : permissionIdNames.put(id, extension.get().getDescription()); 103 4 : } 104 : 105 5 : return permissionIdNames.build(); 106 : } 107 : 108 : /** 109 : * Checks if a given name matches the plugin declared permission name pattern for configs. 110 : * 111 : * @param name a config name which may stand for a plugin permission. 112 : * @return whether the name matches the plugin permission name pattern for configs. 113 : */ 114 : public static boolean isValidPluginPermission(String name) { 115 151 : return PLUGIN_PERMISSION_NAME_IN_CONFIG_PATTERN.matcher(name).matches(); 116 : } 117 : }