Line data Source code
1 : // Copyright (C) 2012 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.restapi.account; 16 : 17 : import static com.google.gerrit.common.data.GlobalCapability.PRIORITY; 18 : import static com.google.gerrit.server.permissions.DefaultPermissionMappings.globalOrPluginPermissionName; 19 : import static com.google.gerrit.server.permissions.DefaultPermissionMappings.globalPermissionName; 20 : import static com.google.gerrit.server.permissions.DefaultPermissionMappings.pluginCapabilityName; 21 : 22 : import com.google.common.collect.Iterables; 23 : import com.google.gerrit.common.data.GlobalCapability; 24 : import com.google.gerrit.entities.PermissionRange; 25 : import com.google.gerrit.extensions.api.access.GlobalOrPluginPermission; 26 : import com.google.gerrit.extensions.api.access.PluginPermission; 27 : import com.google.gerrit.extensions.config.CapabilityDefinition; 28 : import com.google.gerrit.extensions.registration.DynamicMap; 29 : import com.google.gerrit.extensions.restapi.BinaryResult; 30 : import com.google.gerrit.extensions.restapi.ResourceNotFoundException; 31 : import com.google.gerrit.extensions.restapi.Response; 32 : import com.google.gerrit.extensions.restapi.RestApiException; 33 : import com.google.gerrit.extensions.restapi.RestReadView; 34 : import com.google.gerrit.server.CurrentUser; 35 : import com.google.gerrit.server.OptionUtil; 36 : import com.google.gerrit.server.account.AccountLimits; 37 : import com.google.gerrit.server.account.AccountResource; 38 : import com.google.gerrit.server.account.AccountResource.Capability; 39 : import com.google.gerrit.server.git.QueueProvider; 40 : import com.google.gerrit.server.permissions.GlobalPermission; 41 : import com.google.gerrit.server.permissions.PermissionBackend; 42 : import com.google.gerrit.server.permissions.PermissionBackendException; 43 : import com.google.inject.Inject; 44 : import com.google.inject.Provider; 45 : import com.google.inject.Singleton; 46 : import java.util.HashSet; 47 : import java.util.LinkedHashMap; 48 : import java.util.Map; 49 : import java.util.Set; 50 : import org.kohsuke.args4j.Option; 51 : 52 : /** 53 : * REST endpoint to list the global capabilities that are assigned to an account. 54 : * 55 : * <p>This REST endpoint handles {@code GET /accounts/<account-identifier>/capabilities/} requests. 56 : */ 57 : public class GetCapabilities implements RestReadView<AccountResource> { 58 : @Option(name = "-q", metaVar = "CAP", usage = "Capability to inspect") 59 : void addQuery(String name) { 60 0 : if (query == null) { 61 0 : query = new HashSet<>(); 62 : } 63 0 : Iterables.addAll(query, OptionUtil.splitOptionValue(name)); 64 0 : } 65 : 66 : private Set<String> query; 67 : 68 : private final PermissionBackend permissionBackend; 69 : private final AccountLimits.Factory limitsFactory; 70 : private final Provider<CurrentUser> self; 71 : private final DynamicMap<CapabilityDefinition> pluginCapabilities; 72 : 73 : @Inject 74 : GetCapabilities( 75 : PermissionBackend permissionBackend, 76 : AccountLimits.Factory limitsFactory, 77 : Provider<CurrentUser> self, 78 2 : DynamicMap<CapabilityDefinition> pluginCapabilities) { 79 2 : this.permissionBackend = permissionBackend; 80 2 : this.limitsFactory = limitsFactory; 81 2 : this.self = self; 82 2 : this.pluginCapabilities = pluginCapabilities; 83 2 : } 84 : 85 : @Override 86 : public Response<Map<String, Object>> apply(AccountResource resource) 87 : throws RestApiException, PermissionBackendException { 88 2 : permissionBackend.checkUsesDefaultCapabilities(); 89 2 : PermissionBackend.WithUser perm = permissionBackend.currentUser(); 90 2 : if (!self.get().hasSameAccountId(resource.getUser())) { 91 0 : perm.check(GlobalPermission.ADMINISTRATE_SERVER); 92 0 : perm = permissionBackend.absentUser(resource.getUser().getAccountId()); 93 : } 94 : 95 2 : Map<String, Object> have = new LinkedHashMap<>(); 96 2 : for (GlobalOrPluginPermission p : perm.test(permissionsToTest())) { 97 2 : have.put(globalOrPluginPermissionName(p), true); 98 2 : } 99 : 100 2 : AccountLimits limits = limitsFactory.create(resource.getUser()); 101 2 : addRanges(have, limits); 102 2 : addPriority(have, limits); 103 : 104 2 : return Response.ok(have); 105 : } 106 : 107 : private Set<GlobalOrPluginPermission> permissionsToTest() { 108 2 : Set<GlobalOrPluginPermission> toTest = new HashSet<>(); 109 2 : for (GlobalPermission p : GlobalPermission.values()) { 110 2 : if (want(globalPermissionName(p))) { 111 2 : toTest.add(p); 112 : } 113 : } 114 : 115 2 : for (String pluginName : pluginCapabilities.plugins()) { 116 0 : for (String capability : pluginCapabilities.byPlugin(pluginName).keySet()) { 117 0 : PluginPermission p = new PluginPermission(pluginName, capability); 118 0 : if (want(pluginCapabilityName(p))) { 119 0 : toTest.add(p); 120 : } 121 0 : } 122 0 : } 123 2 : return toTest; 124 : } 125 : 126 : private boolean want(String name) { 127 2 : return query == null || query.contains(name.toLowerCase()); 128 : } 129 : 130 : private void addRanges(Map<String, Object> have, AccountLimits limits) { 131 2 : for (String name : GlobalCapability.getRangeNames()) { 132 2 : if (want(name) && limits.hasExplicitRange(name)) { 133 2 : have.put(name, new Range(limits.getRange(name))); 134 : } 135 2 : } 136 2 : } 137 : 138 : private void addPriority(Map<String, Object> have, AccountLimits limits) { 139 2 : QueueProvider.QueueType queue = limits.getQueueType(); 140 2 : if (queue != QueueProvider.QueueType.INTERACTIVE 141 0 : || (query != null && query.contains(PRIORITY))) { 142 0 : have.put(PRIORITY, queue); 143 : } 144 2 : } 145 : 146 : private static class Range { 147 : private transient PermissionRange range; 148 : 149 : @SuppressWarnings("unused") 150 : private int min; 151 : 152 : @SuppressWarnings("unused") 153 : private int max; 154 : 155 2 : Range(PermissionRange r) { 156 2 : range = r; 157 2 : min = r.getMin(); 158 2 : max = r.getMax(); 159 2 : } 160 : 161 : @Override 162 : public String toString() { 163 0 : return range.toString(); 164 : } 165 : } 166 : 167 : /** 168 : * REST endpoint to check if a global capability is assigned to an account. 169 : * 170 : * <p>This REST endpoint handles {@code GET 171 : * /accounts/<account-identifier>/capabilities/<capability-identifier>} requests. 172 : */ 173 : @Singleton 174 : public static class CheckOne implements RestReadView<AccountResource.Capability> { 175 : private final PermissionBackend permissionBackend; 176 : 177 : @Inject 178 138 : CheckOne(PermissionBackend permissionBackend) { 179 138 : this.permissionBackend = permissionBackend; 180 138 : } 181 : 182 : @Override 183 : public Response<BinaryResult> apply(Capability resource) throws ResourceNotFoundException { 184 0 : permissionBackend.checkUsesDefaultCapabilities(); 185 0 : return Response.ok(BinaryResult.create("ok\n")); 186 : } 187 : } 188 : }