/** * 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 org.apache.aurora.scheduler.spi; import com.google.common.base.Optional; import org.apache.aurora.scheduler.storage.entities.IJobKey; import org.apache.shiro.authz.Permission; import org.apache.shiro.authz.permission.WildcardPermission; import static java.util.Objects.requireNonNull; import static com.google.common.base.MoreObjects.toStringHelper; /** * Utilities for Aurora-specific Shiro permissions. */ public final class Permissions { private Permissions() { // Utility class. } /** * A permission representing an intended invocation of an RPC exposed by the Aurora scheduler API. * * Drop-in implementations of {@link org.apache.shiro.realm.Realm} that construct standard Shiro * {@link org.apache.shiro.authz.permission.WildcardPermission}s will work fine, but realms that * want to authorize or account access using type-safe Aurora-specific information can inspect * permission checks and add additional information if they are instances of this or its * public subclasses in the SPI. */ public interface AuroraRpcPermission extends Permission { /** * The domain of the RPC permitted to be invoked. */ Domain getDomain(); /** * The name of the RPC permitted to be invoked. */ String getRpc(); } /** * Domain of a permitted RPC (the first part of a {@link WildcardPermission}). */ public enum Domain { /** * RPCs on the {@link org.apache.aurora.gen.AuroraSchedulerManager} service. */ THRIFT_AURORA_SCHEDULER_MANAGER("thrift.AuroraSchedulerManager"), /** * RPCs on the {@link org.apache.aurora.gen.AuroraAdmin} service. */ THRIFT_AURORA_ADMIN("thrift.AuroraAdmin"); private final String permissionPart; Domain(String permissionPart) { this.permissionPart = permissionPart; } /** * The String form of the permission part represented by this domain. */ @Override public String toString() { return permissionPart; } /** * Get the {@link Domain} associated with a given permission part. Inverse of {@link #toString}. * * @param permissionPart The permission part representing the domain. * @return The domain represented by it, if one exists. */ public static Optional<Domain> fromString(String permissionPart) { for (Domain domain : Domain.values()) { if (domain.permissionPart.equals(permissionPart)) { return Optional.of(domain); } } return Optional.absent(); } } /** * A permission to invoke an RPC with any arguments. */ public static final class UnscopedRpcPermission extends WildcardPermission implements AuroraRpcPermission { private final Domain domain; private final String rpc; UnscopedRpcPermission(Domain domain, String rpc) { this.domain = requireNonNull(domain); this.rpc = requireNonNull(rpc); setParts(String.format("%s:%s", domain, rpc)); } @Override public Domain getDomain() { return domain; } @Override public String getRpc() { return rpc; } @Override public String toString() { return toStringHelper(this).add("domain", domain).add("rpc", rpc).toString(); } } /** * Permission to invoke an RPC only with arguments scoped to a single job. */ public static final class JobScopedRpcPermission extends WildcardPermission implements AuroraRpcPermission { private static final Domain DOMAIN = Domain.THRIFT_AURORA_SCHEDULER_MANAGER; private final String rpc; private final IJobKey permittedJob; JobScopedRpcPermission(String rpc, IJobKey permittedJob) { this.rpc = requireNonNull(rpc); this.permittedJob = requireNonNull(permittedJob); setParts( String.format("%s:%s:%s:%s:%s", DOMAIN, rpc, permittedJob.getRole(), permittedJob.getEnvironment(), permittedJob.getName())); } /** * The job permitted as an argument to the permitted RPC. */ public IJobKey getPermittedJob() { return permittedJob; } @Override public Domain getDomain() { return DOMAIN; } @Override public String getRpc() { return rpc; } @Override public String toString() { return toStringHelper(this).add("rpc", rpc).add("permittedJob", permittedJob).toString(); } } /** * Creates a permission permitting the given RPC to operate on a single given job. * * @param rpc The RPC permitted to be called. * @param targetJob The job permitted to be operated upon. * @return A permission permitting the given RPC to operate on the given job. */ public static JobScopedRpcPermission createJobScopedPermission(String rpc, IJobKey targetJob) { return new JobScopedRpcPermission(rpc, targetJob); } /** * Creates a permission permitting invocation of the given RPC with any possible argument. * * @param domain The domain of the RPC. * @param rpc The RPC permitted to be called. * @return A permission permitting invocation of the given RPC for all arguments. */ public static UnscopedRpcPermission createUnscopedPermission(Domain domain, String rpc) { return new UnscopedRpcPermission(domain, rpc); } }