/**
* 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);
}
}