| // 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 ( |
| "fmt" |
| "reflect" |
| "testing" |
| |
| "v.io/v23/security" |
| ) |
| |
| func TestFixedBlessingStore(t *testing.T) { |
| p, b1 := newPrincipal("self") |
| b2, _ := p.BlessSelf("other") |
| tpcav := mkCaveat(security.NewPublicKeyCaveat(p.PublicKey(), "location", security.ThirdPartyRequirements{}, security.UnconstrainedUse())) |
| d := mkDischarge(p.MintDischarge(tpcav, security.UnconstrainedUse())) |
| s1 := newInMemoryBlessingStore(p.PublicKey()) |
| s2 := FixedBlessingsStore(b1, s1) |
| |
| // Set and SetDefault should fail, other than that, s2 should behave |
| // identically to s1 after setting s1 up |
| s1.Set(b1, security.AllPrincipals) |
| s1.SetDefault(b1) |
| |
| if _, err := s2.Set(b2, security.AllPrincipals); err == nil { |
| t.Fatal("%T.Set should fail", s2) |
| } |
| if err := s2.SetDefault(b2); err == nil { |
| t.Fatal("%T.SetDefault should fail", s2) |
| } |
| for idx, c := range []call{ |
| {"ForPeer", []interface{}{"foobar"}}, |
| {"PublicKey", nil}, |
| {"PeerBlessings", nil}, |
| {"CacheDischarge", []interface{}{d, tpcav, security.DischargeImpetus{}}}, |
| {"Discharge", []interface{}{tpcav, security.DischargeImpetus{}}}, |
| {"ClearDischarges", []interface{}{d}}, |
| {"Discharge", []interface{}{tpcav, security.DischargeImpetus{}}}, |
| } { |
| if err := c.Compare(s1, s2); err != nil { |
| t.Errorf("#%d: %v", idx, err) |
| } |
| } |
| // Check call to Default separately since both the stores should return |
| // the same blessing but possibly different channels. |
| def1, _ := s1.Default() |
| def2, _ := s2.Default() |
| if !reflect.DeepEqual(def1, def2) { |
| t.Errorf("Default: Got %v, want %v", def1, def2) |
| } |
| } |
| |
| func TestImmutableBlessingStore(t *testing.T) { |
| p, b1 := newPrincipal("self") |
| b2, _ := p.BlessSelf("othername") |
| bdef, _ := p.BlessSelf("default") |
| tpcav := mkCaveat(security.NewPublicKeyCaveat(p.PublicKey(), "location", security.ThirdPartyRequirements{}, security.UnconstrainedUse())) |
| d := mkDischarge(p.MintDischarge(tpcav, security.UnconstrainedUse())) |
| s1 := newInMemoryBlessingStore(p.PublicKey()) |
| s2 := ImmutableBlessingStore(s1) |
| |
| // Set and SetDefault called on s1 should affect s2 |
| if _, err := s1.Set(b1, security.AllPrincipals); err != nil { |
| t.Fatal(err) |
| } |
| if err := s1.SetDefault(bdef); err != nil { |
| t.Fatal(err) |
| } |
| // But Set and SetDefault on s2 should fail |
| if _, err := s2.Set(b2, security.AllPrincipals); err == nil { |
| t.Fatalf("%T.Set should fail", s2) |
| } |
| if err := s2.SetDefault(b2); err == nil { |
| t.Fatalf("%T.SetDefault should fail", s2) |
| } |
| // All other method calls should defer to s1 |
| for idx, c := range []call{ |
| {"ForPeer", []interface{}{"foobar"}}, |
| {"Default", nil}, |
| {"PublicKey", nil}, |
| {"PeerBlessings", nil}, |
| {"CacheDischarge", []interface{}{d, tpcav, security.DischargeImpetus{}}}, |
| {"Discharge", []interface{}{tpcav, security.DischargeImpetus{}}}, |
| {"DebugString", nil}, |
| {"ClearDischarges", []interface{}{d}}, |
| {"Discharge", []interface{}{tpcav, security.DischargeImpetus{}}}, |
| } { |
| if err := c.Compare(s1, s2); err != nil { |
| t.Errorf("#%d: %v", idx, err) |
| } |
| } |
| } |
| |
| func TestImmutableBlessingRoots(t *testing.T) { |
| pubkey, _, _ := NewPrincipalKey() |
| pk, _ := pubkey.MarshalBinary() |
| r1 := newInMemoryBlessingRoots() |
| r2 := ImmutableBlessingRoots(r1) |
| pat := "pattern1" |
| |
| // Adding to r1 should affect r2 |
| if err := r1.Add(pk, security.BlessingPattern(pat)); err != nil { |
| t.Fatal(err) |
| } |
| // But Add on r2 should fail |
| if err := r2.Add(pk, "otherpattern"); err == nil { |
| t.Errorf("%T.Add should fail", r2) |
| } |
| // All other methods should be the same |
| for _, c := range []call{ |
| {"Recognized", []interface{}{pk, pat}}, |
| {"Dump", nil}, |
| {"DebugString", nil}, |
| } { |
| if err := c.Compare(r1, r2); err != nil { |
| t.Error(err) |
| } |
| } |
| } |
| |
| type call struct { |
| Method string |
| Args []interface{} |
| } |
| |
| // Run executes c.Method on object with c.Args and returns the results. |
| func (c *call) Call(object interface{}) []interface{} { |
| args := make([]reflect.Value, len(c.Args)) |
| for i, a := range c.Args { |
| args[i] = reflect.ValueOf(a) |
| } |
| results := reflect.ValueOf(object).MethodByName(c.Method).Call(args) |
| ret := make([]interface{}, len(results)) |
| for i, r := range results { |
| ret[i] = r.Interface() |
| } |
| return ret |
| } |
| |
| // Compare calls Run on o1 and o2 and returns an error if the results do not match. |
| func (c *call) Compare(o1, o2 interface{}) error { |
| r1 := c.Call(o1) |
| r2 := c.Call(o2) |
| if !reflect.DeepEqual(r1, r2) { |
| return fmt.Errorf("%v(%v): Got %v, want %v", c.Method, c.Args, r2, r1) |
| } |
| return nil |
| } |