blob: 4b86e24eb09554cc3abb5bafbde76dae3eb994ee [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 com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import io.v.v23.V;
import io.v.v23.context.VContext;
import io.v.v23.security.BlessingPattern;
import io.v.v23.security.BlessingRoots;
import io.v.v23.security.Blessings;
import io.v.v23.security.Call;
import io.v.v23.security.CallParams;
import io.v.v23.security.Constants;
import io.v.v23.security.VPrincipal;
import io.v.v23.security.VSecurity;
import io.v.v23.security.VSigner;
import io.v.v23.security.access.internal.MyObjectServerWrapper;
import io.v.v23.security.access.internal.MyTag;
import io.v.v23.vdl.VdlValue;
import io.v.v23.verror.VException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.security.interfaces.ECPublicKey;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import static org.junit.Assert.fail;
/**
* Tests the implementation of {@code PermissionsAuthorizer}.
*/
@RunWith(Parameterized.class)
public class PermissionsAuthorizerTest {
private static final VContext CONTEXT;
private static final PermissionsAuthorizer AUTHORIZER;
private static final VPrincipal CLIENT_PRINCIPAL;
private static final VPrincipal SERVER_PRINCIPAL;
private static final Blessings SERVER_BLESSINGS;
static {
CONTEXT = V.init();
Permissions perms = new Permissions(ImmutableMap.of(
"R", new AccessList(
ImmutableList.of(Constants.ALL_PRINCIPALS),
null),
"W", new AccessList(
ImmutableList.of(
new BlessingPattern("ali:family"),
new BlessingPattern("bob"),
new BlessingPattern("che:$")),
ImmutableList.of(
"bob:acquaintances")),
"X", new AccessList(
ImmutableList.of(
new BlessingPattern("ali:family:boss:$"),
new BlessingPattern("superman:$")),
null)
));
try {
AUTHORIZER = PermissionsAuthorizer.create(perms, MyTag.class);
CLIENT_PRINCIPAL = newPrincipal();
SERVER_PRINCIPAL = newPrincipal();
SERVER_BLESSINGS = SERVER_PRINCIPAL.blessSelf("server");
} catch (VException e) {
throw new RuntimeException(e);
}
}
private static VPrincipal newPrincipal() throws VException {
VSigner signer = VSecurity.newInMemorySigner();
return VSecurity.newPrincipal(signer, null, new TrustAllRoots());
}
private static VdlValue[] getMethodTags(String method) throws VException {
MyObjectServerWrapper s = new MyObjectServerWrapper(null);
return s.getMethodTags(method);
}
private final String methodName;
private final Blessings clientBlessings;
private final boolean shouldAccept;
private final VdlValue[] methodTags;
@Parameterized.Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
{"get", ImmutableList.of(), true},
{"get", ImmutableList.of("ali"), true},
{"get", ImmutableList.of("bob:friend", "che:enemy"), true},
{"put", ImmutableList.of("ali:family:mom"), true},
{"put", ImmutableList.of("bob:friends"), true},
// granted because of "che"
{"put", ImmutableList.of("bob:acquantainces:carol", "che"), true},
{"resolve", ImmutableList.of("superman"), true},
{"resolve", ImmutableList.of("ali:family:boss"), true},
{"put", ImmutableList.of("ali", "bob:acquaintances", "bob:acquaintances:dave",
"che:friend", "dave"), false},
{"resolve", ImmutableList.of("ali", "ali:friend", "ali:family", "ali:family:friend",
"alice:family:boss:friend", "superman:friend"), false},
// Since there are no tags on the noTags method, it has an
// empty ACL. No client will have access.
{"noTags", ImmutableList.of(
"ali", "ali:family:boss", "bob", "che", "superman"), false}
});
}
public PermissionsAuthorizerTest(String methodName, List<String> clientBlessingNames,
boolean isAccepted) throws VException {
this.methodName = methodName;
this.methodTags = new MyObjectServerWrapper(null).getMethodTags(methodName);
this.clientBlessings = VSecurity.unionOfBlessings(Lists.transform(
clientBlessingNames, new Function<String, Blessings>() {
@Override
public Blessings apply(String name) {
try {
return CLIENT_PRINCIPAL.blessSelf(name);
} catch (VException e) {
throw new RuntimeException(e);
}
}
}).toArray(new Blessings[0]));
this.shouldAccept = isAccepted;
}
@Test
public void testAuthorize() {
Call call = VSecurity.newCall(new CallParams()
.withLocalPrincipal(SERVER_PRINCIPAL)
.withLocalBlessings(SERVER_BLESSINGS)
.withRemoteBlessings(clientBlessings)
.withMethod(methodName)
.withMethodTags(methodTags));
try {
AUTHORIZER.authorize(CONTEXT, call);
if (!shouldAccept) {
fail(String.format(
"Access granted for method %s to %s", methodName, clientBlessings));
}
} catch (VException e) {
if (shouldAccept) {
fail(String.format(
"Access denied for method %s to %s", methodName, clientBlessings));
}
}
}
private static class TrustAllRoots implements BlessingRoots {
@Override
public void add(ECPublicKey root, BlessingPattern pattern) throws VException {}
@Override
public void recognized(ECPublicKey root, String blessing) throws VException {}
@Override
public String debugString() { return TrustAllRoots.class.toString(); }
@Override
public Multimap<BlessingPattern, ECPublicKey> dump() {
return ImmutableMultimap.of();
}
}
}