blob: 85f93d9b26136927d3603d9ff0f9433e78508718 [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 security
import (
"net"
"testing"
"v.io/v23/context"
"v.io/v23/naming"
)
func TestDefaultAuthorizer(t *testing.T) {
var (
pali = newPrincipal(t)
pbob = newPrincipal(t)
pche = newPrincipal(t)
pdis = newPrincipal(t) // third-party caveat discharger
che, _ = pche.BlessSelf("che")
ali, _ = pali.BlessSelf("ali")
bob, _ = pbob.BlessSelf("bob")
tpcav = mkThirdPartyCaveat(t, pdis.PublicKey(), "someLocation", UnconstrainedUse())
dis, _ = pdis.MintDischarge(tpcav, UnconstrainedUse())
dismap = map[string]Discharge{dis.ID(): dis}
// bless(ali, bob, "friend") will generate a blessing for ali, calling him "bob:friend".
bless = func(target, extend Blessings, extension string, caveats ...Caveat) Blessings {
var p Principal
switch extend.PublicKey() {
case ali.PublicKey():
p = pali
case bob.PublicKey():
p = pbob
case che.PublicKey():
p = pche
default:
panic(extend)
}
if len(caveats) == 0 {
caveats = []Caveat{UnconstrainedUse()}
}
ret, err := p.Bless(target.PublicKey(), extend, extension, caveats[0], caveats[1:]...)
if err != nil {
panic(err)
}
return ret
}
U = func(blessings ...Blessings) Blessings {
u, err := UnionOfBlessings(blessings...)
if err != nil {
panic(err)
}
return u
}
// Shorthands for getting blessings for Ali and Bob.
A = func(as Blessings, extension string, caveats ...Caveat) Blessings {
return bless(ali, as, extension, caveats...)
}
B = func(as Blessings, extension string, caveats ...Caveat) Blessings {
return bless(bob, as, extension, caveats...)
}
authorizer defaultAuthorizer
)
// Make ali, bob (the two ends) recognize all three blessings
for ip, p := range []Principal{pali, pbob} {
for _, b := range []Blessings{ali, bob, che} {
if err := AddToRoots(p, b); err != nil {
t.Fatalf("%d: %v - %v", ip, b, err)
}
}
}
// All tests are run as if "ali" is the local end and "bob" is the remote.
tests := []struct {
local, remote Blessings
call CallParams
authorized bool
}{
{
local: ali,
remote: ali,
authorized: true,
},
{
local: ali,
remote: bob,
authorized: false,
},
{
// ali talking to ali:friend (invalid caveat)
local: ali,
remote: B(ali, "friend", tpcav),
authorized: false,
},
{
// ali talking to ali:friend
local: ali,
remote: B(ali, "friend", tpcav),
call: CallParams{RemoteDischarges: dismap},
authorized: true,
},
{
// bob:friend talking to bob (local blessing has an invalid caveat, but it is not checked)
local: A(bob, "friend", tpcav),
remote: bob,
authorized: true,
},
{
// che:friend talking to che:family
local: A(che, "friend"),
remote: B(che, "family"),
authorized: false,
},
{
// {ali, bob:friend, che:friend} talking to {bob:friend:spouse, che:family}
local: U(ali, A(bob, "friend"), A(che, "friend")),
remote: U(B(bob, "friend:spouse", tpcav), B(che, "family")),
call: CallParams{RemoteDischarges: dismap},
authorized: true,
},
}
for _, test := range tests {
test.call.LocalPrincipal = pali
test.call.LocalBlessings = test.local
test.call.RemoteBlessings = test.remote
ctx, cancel := context.RootContext()
err := authorizer.Authorize(ctx, NewCall(&test.call))
if (err == nil) != test.authorized {
t.Errorf("call: %v. Got %v", test.call, err)
}
cancel()
}
}
func mkThirdPartyCaveat(t *testing.T, discharger PublicKey, location string, c Caveat) Caveat {
tpc, err := NewPublicKeyCaveat(discharger, location, ThirdPartyRequirements{}, c)
if err != nil {
t.Fatal(err)
}
return tpc
}
func TestAllowEveryone(t *testing.T) {
var (
pali = newPrincipal(t)
pbob = newPrincipal(t)
ali, _ = pali.BlessSelf("ali")
bob, _ = pbob.BlessSelf("bob")
ctx, cancel = context.RootContext()
)
defer cancel()
if err := AllowEveryone().Authorize(ctx, NewCall(&CallParams{
LocalPrincipal: pali,
LocalBlessings: ali,
RemoteBlessings: bob,
})); err != nil {
t.Fatal(err)
}
}
func TestPublicKeyAuthorizer(t *testing.T) {
var (
pali = newPrincipal(t)
pbob = newPrincipal(t)
ali, _ = pali.BlessSelf("ali")
bob, _ = pbob.BlessSelf("bob")
ctx, cancel = context.RootContext()
)
defer cancel()
if err := PublicKeyAuthorizer(pbob.PublicKey()).Authorize(ctx, NewCall(&CallParams{
RemoteBlessings: bob,
})); err != nil {
t.Fatal(err)
}
if err := PublicKeyAuthorizer(pbob.PublicKey()).Authorize(ctx, NewCall(&CallParams{
RemoteBlessings: ali,
})); err == nil {
t.Fatal("Expected error")
}
}
// implementation of naming.Endpoint.
// TODO(ashankar): naming.Endpoint should either not be an interface or at the
// very least have an implementation in v23.
type endpoint struct {
blessings []string
}
func (e endpoint) Network() string { return "v23" }
func (e endpoint) String() string {
var opts []naming.EndpointOpt
for _, b := range e.blessings {
opts = append(opts, naming.BlessingOpt(b))
}
return naming.FormatEndpoint("tcp", "localhost:14141", opts...)
}
func (e endpoint) Name() string { return naming.JoinAddressName(e.String(), "") }
func (e endpoint) VersionedString(int) string { return e.String() }
func (e endpoint) RoutingID() naming.RoutingID { return naming.FixedRoutingID(0xacbdef) }
func (e endpoint) Routes() []string { return nil }
func (e endpoint) Addr() net.Addr { return nil }
func (e endpoint) ServesMountTable() bool { return false }
func (e endpoint) ServesLeaf() bool { return true }
func (e endpoint) BlessingNames() []string { return e.blessings }
func TestEndpointAuthorizer(t *testing.T) {
var (
pali = newPrincipal(t)
pbob = newPrincipal(t)
ali, _ = pali.BlessSelf("ali")
alifriend, _ = pali.Bless(pbob.PublicKey(), ali, "friend", UnconstrainedUse())
tests = []struct {
ep naming.Endpoint
ok bool
}{
{endpoint{}, true},
{endpoint{blessings: []string{"foo", "bar"}}, false},
{endpoint{blessings: []string{"foo", "ali", "bar"}}, true},
}
ctx, cancel = context.RootContext()
)
defer cancel()
AddToRoots(pali, ali)
for _, test := range tests {
err := EndpointAuthorizer().Authorize(ctx, NewCall(&CallParams{
RemoteEndpoint: test.ep,
LocalPrincipal: pali,
RemoteBlessings: alifriend,
}))
if (err == nil) != test.ok {
t.Errorf("%v: Got error (%v), want error %v", test.ep, err, !test.ok)
}
}
}