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