blob: d8dcde5ecc09ae12f84affb2076d0fa915435533 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package io.v.v23.security.access;
import io.v.v23.context.VContext;
import io.v.v23.security.Authorizer;
import io.v.v23.security.Call;
import io.v.v23.vdl.Types;
import io.v.v23.vdl.VdlType;
import io.v.v23.verror.VException;
import java.lang.reflect.Type;
/**
* An authorizer that subscribes to an authorization policy where access is granted if
* the remote end presents blessings included in the Access Control Lists (ACLs) associated with
* the set of relevant tags.
* <p>
* The set of relevant tags is the subset of tags associated with the method
* ({@link io.v.v23.security.Call#methodTags}) that have the same type as
* the provided one.
* Currently, {@code tagType.getKind()} must be {@link io.v.v23.vdl.Types#STRING} , i.e., only tags
* that are named string types are supported.
* <p>
* If multiple tags of the provided type are associated with the method, then access is granted
* if the peer presents blessings that match the ACLs of each one of those tags. If no tags of
* the provided are associated with the method, then access is denied.
* <p>
* If the {@link Permissions} provided are {@code null}, then an authorizer that rejects all remote
* ends is returned.
* <p>
* <string>Sample usage:</strong>
* <p><ol>
* <li>Attach tags to methods in the VDL (eg. myservice.vdl)
* <p><blockquote><pre>
* package myservice
*
* type MyTag string
* const (
* ReadAccess = MyTag("R")
* WriteAccess = MyTag("W")
* )
*
* type MyService interface {
* Get() ([]string, error) {ReadAccess}
* GetIndex(int) (string, error) {ReadAccess}
*
* Set([]string) error {WriteAccess}
* SetIndex(int, string) error {WriteAccess}
*
* GetAndSet([]string) ([]string, error) {ReadAccess, WriteAccess}
* }
* </pre></blockquote><p>
* </li>
* <li>Setup the dispatcher to use the {@link PermissionsAuthorizer}:
* <p><blockquote><pre>
* public class MyDispatcher implements io.v.v23.rpc.Dispatcher {
* {@literal @}Override
* public ServiceObjectWithAuthorizer lookup(String suffix) throws VException {
* Permissions acls = new Permissions(ImmutableMap.of(
* "R", new AccessList(ImmutableList.of(new BlessingPattern("alice/friends/..."),
* new BlessingPattern("alice/family/...")),
* null),
* "W", new AccessList(ImmutableList.of(new BlessingPattern("alice/family/..."),
* new BlessingPattern("alice/colleagues/...")),
* null)));
* return new ServiceObjectWithAuthorizer(
* newInvoker(), VSecurity.newPermissionsAuthorizer(acls, MyTag.class));
* }
* </pre></blockquote><p>
* </li>
* </ol>
* With the above dispatcher, the server will grant access to a peer with the blessing
* {@code "alice/friend/bob"} access only to the {@code Get} and {@code GetIndex} methods.
* A peer presenting the blessing {@code "alice/colleague/carol"} will get access only to the
* {@code Set} and {@code SetIndex} methods. A peer presenting {@code "alice/family/mom"} will
* get access to all methods, even {@code GetAndSet} - which requires that the blessing appear
* in the ACLs for both the {@code ReadAccess} and {@code WriteAccess} tags.
*/
public class PermissionsAuthorizer implements Authorizer {
private static native PermissionsAuthorizer nativeCreate(Permissions perms, VdlType type)
throws VException;
/**
* Creates a new {@link PermissionsAuthorizer} authorizer.
*
* @param perms ACLs containing authorization rules
* @param tagType type of the method tags this authorizer checks
* @return a newly created authorizer
* @throws VException if the authorizer couldn't be created
*/
public static PermissionsAuthorizer create(Permissions perms, Type tagType) throws VException {
try {
VdlType type = Types.getVdlTypeFromReflect(tagType);
return nativeCreate(perms, type);
} catch (IllegalArgumentException e) {
throw new VException(String.format(
"Tag type %s does not have a corresponding VdlType: %s",
tagType, e.getMessage()));
}
}
private final long nativePtr;
private native void nativeAuthorize(long nativePtr, VContext ctx, Call call) throws VException;
private PermissionsAuthorizer(long nativePtr) {
this.nativePtr = nativePtr;
}
@Override
public void authorize(VContext ctx, Call call) throws VException {
nativeAuthorize(nativePtr, ctx, call);
}
}