Ryan Brown | fed691e | 2014-09-15 13:09:40 -0700 | [diff] [blame] | 1 | package agent_test |
| 2 | |
| 3 | import ( |
| 4 | "crypto/ecdsa" |
| 5 | "crypto/elliptic" |
| 6 | "crypto/rand" |
Ryan Brown | fed691e | 2014-09-15 13:09:40 -0700 | [diff] [blame] | 7 | "reflect" |
| 8 | "testing" |
Cosmos Nicolaou | f889c73 | 2014-10-16 20:46:54 -0700 | [diff] [blame] | 9 | |
Ankur | f416ac5 | 2015-01-29 13:58:24 -0800 | [diff] [blame] | 10 | "v.io/core/veyron/lib/testutil" |
Jiri Simsa | 764efb7 | 2014-12-25 20:57:03 -0800 | [diff] [blame] | 11 | _ "v.io/core/veyron/profiles" |
| 12 | "v.io/core/veyron/security/agent" |
| 13 | "v.io/core/veyron/security/agent/server" |
Suharsh Sivakumar | 8a7fba4 | 2014-10-27 12:40:48 -0700 | [diff] [blame] | 14 | |
Matt Rosencrantz | 99cc06e | 2015-01-16 10:25:11 -0800 | [diff] [blame] | 15 | "v.io/core/veyron2" |
Matt Rosencrantz | 6edab56 | 2015-01-12 11:07:55 -0800 | [diff] [blame] | 16 | "v.io/core/veyron2/context" |
Jiri Simsa | 764efb7 | 2014-12-25 20:57:03 -0800 | [diff] [blame] | 17 | "v.io/core/veyron2/security" |
| 18 | "v.io/core/veyron2/verror2" |
Ryan Brown | fed691e | 2014-09-15 13:09:40 -0700 | [diff] [blame] | 19 | ) |
| 20 | |
Matt Rosencrantz | 6edab56 | 2015-01-12 11:07:55 -0800 | [diff] [blame] | 21 | func setupAgent(t *testing.T, ctx *context.T, p security.Principal) security.Principal { |
| 22 | sock, err := server.RunAnonymousAgent(ctx, p) |
Ryan Brown | fed691e | 2014-09-15 13:09:40 -0700 | [diff] [blame] | 23 | if err != nil { |
Suharsh Sivakumar | 8a7fba4 | 2014-10-27 12:40:48 -0700 | [diff] [blame] | 24 | t.Fatal(err) |
Ryan Brown | fed691e | 2014-09-15 13:09:40 -0700 | [diff] [blame] | 25 | } |
| 26 | defer sock.Close() |
Matt Rosencrantz | 6edab56 | 2015-01-12 11:07:55 -0800 | [diff] [blame] | 27 | |
Suharsh Sivakumar | 8a7fba4 | 2014-10-27 12:40:48 -0700 | [diff] [blame] | 28 | var agentP security.Principal |
Matt Rosencrantz | 99cc06e | 2015-01-16 10:25:11 -0800 | [diff] [blame] | 29 | if agentP, err = agent.NewAgentPrincipal(ctx, int(sock.Fd()), veyron2.GetClient(ctx)); err != nil { |
Suharsh Sivakumar | 8a7fba4 | 2014-10-27 12:40:48 -0700 | [diff] [blame] | 30 | t.Fatal(err) |
| 31 | } |
| 32 | return agentP |
| 33 | } |
| 34 | |
| 35 | type testInfo struct { |
| 36 | Method string |
| 37 | Args V |
| 38 | Result interface{} // Result returned by the Method call. |
Todd Wang | 34ed4c6 | 2014-11-26 15:15:52 -0800 | [diff] [blame] | 39 | Error verror2.E // If Error is not nil will be compared to the last result. |
Suharsh Sivakumar | 8a7fba4 | 2014-10-27 12:40:48 -0700 | [diff] [blame] | 40 | } |
| 41 | |
Jiri Simsa | 764efb7 | 2014-12-25 20:57:03 -0800 | [diff] [blame] | 42 | const pkgPath = "v.io/core/veyron/security/agent/" |
Todd Wang | 34ed4c6 | 2014-11-26 15:15:52 -0800 | [diff] [blame] | 43 | |
| 44 | var ( |
| 45 | addToRootsErr = verror2.Register(pkgPath+".addToRoots", verror2.NoRetry, "") |
| 46 | storeSetDefaultErr = verror2.Register(pkgPath+".storeSetDefault", verror2.NoRetry, "") |
| 47 | rootsAddErr = verror2.Register(pkgPath+".rootsAdd", verror2.NoRetry, "") |
| 48 | rootsRecognizedErr = verror2.Register(pkgPath+".rootsRecognized", verror2.NoRetry, "") |
| 49 | ) |
Suharsh Sivakumar | 8a7fba4 | 2014-10-27 12:40:48 -0700 | [diff] [blame] | 50 | |
| 51 | func TestAgent(t *testing.T) { |
Ankur | f416ac5 | 2015-01-29 13:58:24 -0800 | [diff] [blame] | 52 | ctx, shutdown := testutil.InitForTest() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 53 | defer shutdown() |
Matt Rosencrantz | 0610a23 | 2014-12-04 10:26:39 -0800 | [diff] [blame] | 54 | |
Suharsh Sivakumar | 8a7fba4 | 2014-10-27 12:40:48 -0700 | [diff] [blame] | 55 | var ( |
| 56 | thirdPartyCaveat, discharge = newThirdPartyCaveatAndDischarge(t) |
| 57 | mockP = newMockPrincipal() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 58 | agent = setupAgent(t, ctx, mockP) |
Suharsh Sivakumar | 8a7fba4 | 2014-10-27 12:40:48 -0700 | [diff] [blame] | 59 | ) |
| 60 | tests := []testInfo{ |
| 61 | {"BlessSelf", V{"self"}, newBlessing(t, "blessing"), nil}, |
| 62 | {"Bless", V{newPrincipal(t).PublicKey(), newBlessing(t, "root"), "extension", security.UnconstrainedUse()}, newBlessing(t, "root/extension"), nil}, |
Robin Thellend | 3709c16 | 2014-12-10 15:37:59 -0800 | [diff] [blame] | 63 | {"Sign", V{make([]byte, 10)}, security.Signature{Purpose: []byte{}, R: []byte{1}, S: []byte{1}}, nil}, |
Suharsh Sivakumar | 8a7fba4 | 2014-10-27 12:40:48 -0700 | [diff] [blame] | 64 | {"MintDischarge", V{thirdPartyCaveat, security.UnconstrainedUse()}, discharge, nil}, |
| 65 | {"PublicKey", V{}, mockP.PublicKey(), nil}, |
gauthamt | f826393 | 2014-12-16 10:59:09 -0800 | [diff] [blame] | 66 | {"BlessingsByName", V{security.BlessingPattern("self")}, []security.Blessings{newBlessing(t, "blessing")}, nil}, |
gauthamt | 8dc9a18 | 2015-01-08 18:03:18 -0800 | [diff] [blame] | 67 | {"BlessingsInfo", V{newBlessing(t, "blessing")}, map[string][]security.Caveat{"blessing": nil}, nil}, |
Todd Wang | 34ed4c6 | 2014-11-26 15:15:52 -0800 | [diff] [blame] | 68 | {"AddToRoots", V{newBlessing(t, "blessing")}, nil, verror2.Make(addToRootsErr, nil)}, |
Suharsh Sivakumar | 8a7fba4 | 2014-10-27 12:40:48 -0700 | [diff] [blame] | 69 | } |
| 70 | for _, test := range tests { |
| 71 | mockP.NextResult = test.Result |
| 72 | mockP.NextError = test.Error |
| 73 | runTest(t, agent, test) |
| 74 | } |
| 75 | |
| 76 | store := agent.BlessingStore() |
| 77 | storeTests := []testInfo{ |
| 78 | {"Set", V{newBlessing(t, "blessing"), security.BlessingPattern("test")}, newBlessing(t, "root/extension"), nil}, |
| 79 | {"ForPeer", V{"test", "oink"}, newBlessing(t, "for/peer"), nil}, |
Todd Wang | 34ed4c6 | 2014-11-26 15:15:52 -0800 | [diff] [blame] | 80 | {"SetDefault", V{newBlessing(t, "blessing")}, nil, verror2.Make(storeSetDefaultErr, nil)}, |
Suharsh Sivakumar | 8a7fba4 | 2014-10-27 12:40:48 -0700 | [diff] [blame] | 81 | {"Default", V{}, newBlessing(t, "root/extension"), nil}, |
| 82 | {"PublicKey", V{}, mockP.PublicKey(), nil}, |
gauthamt | f826393 | 2014-12-16 10:59:09 -0800 | [diff] [blame] | 83 | {"PeerBlessings", V{}, map[security.BlessingPattern]security.Blessings{"test": newBlessing(t, "root/extension")}, nil}, |
Suharsh Sivakumar | 8a7fba4 | 2014-10-27 12:40:48 -0700 | [diff] [blame] | 84 | {"DebugString", V{}, "StoreString", nil}, |
| 85 | } |
| 86 | for _, test := range storeTests { |
| 87 | mockP.MockStore.NextResult = test.Result |
| 88 | mockP.MockStore.NextError = test.Error |
| 89 | runTest(t, store, test) |
| 90 | } |
| 91 | |
| 92 | roots := agent.Roots() |
| 93 | rootTests := []testInfo{ |
Todd Wang | 34ed4c6 | 2014-11-26 15:15:52 -0800 | [diff] [blame] | 94 | {"Add", V{newPrincipal(t).PublicKey(), security.BlessingPattern("test")}, nil, verror2.Make(rootsAddErr, nil)}, |
| 95 | {"Recognized", V{newPrincipal(t).PublicKey(), "blessing"}, nil, verror2.Make(rootsRecognizedErr, nil)}, |
Suharsh Sivakumar | 8a7fba4 | 2014-10-27 12:40:48 -0700 | [diff] [blame] | 96 | {"DebugString", V{}, "RootsString", nil}, |
| 97 | } |
| 98 | for _, test := range rootTests { |
| 99 | mockP.MockRoots.NextResult = test.Result |
| 100 | mockP.MockRoots.NextError = test.Error |
| 101 | runTest(t, roots, test) |
Ryan Brown | fed691e | 2014-09-15 13:09:40 -0700 | [diff] [blame] | 102 | } |
| 103 | } |
| 104 | |
Suharsh Sivakumar | 8a7fba4 | 2014-10-27 12:40:48 -0700 | [diff] [blame] | 105 | func runTest(t *testing.T, receiver interface{}, test testInfo) { |
| 106 | results, err := call(receiver, test.Method, test.Args) |
Ryan Brown | fed691e | 2014-09-15 13:09:40 -0700 | [diff] [blame] | 107 | if err != nil { |
Suharsh Sivakumar | 8a7fba4 | 2014-10-27 12:40:48 -0700 | [diff] [blame] | 108 | t.Errorf("failed to invoke p.%v(%#v): %v", test.Method, test.Args, err) |
| 109 | return |
Ryan Brown | fed691e | 2014-09-15 13:09:40 -0700 | [diff] [blame] | 110 | } |
Suharsh Sivakumar | 8a7fba4 | 2014-10-27 12:40:48 -0700 | [diff] [blame] | 111 | // We only set the error value when error is the only output to ensure the real function gets called. |
| 112 | if test.Error != nil { |
Todd Wang | 34ed4c6 | 2014-11-26 15:15:52 -0800 | [diff] [blame] | 113 | if got := results[len(results)-1]; got == nil || !verror2.Is(got.(error), test.Error.ErrorID()) { |
Suharsh Sivakumar | 8a7fba4 | 2014-10-27 12:40:48 -0700 | [diff] [blame] | 114 | t.Errorf("p.%v(%#v) returned an incorrect error: %v, expected %v", test.Method, test.Args, got, test.Error) |
| 115 | } |
| 116 | if len(results) == 1 { |
| 117 | return |
| 118 | } |
| 119 | } |
| 120 | if got := results[0]; !reflect.DeepEqual(got, test.Result) { |
Todd Wang | 34ed4c6 | 2014-11-26 15:15:52 -0800 | [diff] [blame] | 121 | t.Errorf("p.%v(%#v) returned %#v want %#v", test.Method, test.Args, got, test.Result) |
Ryan Brown | fed691e | 2014-09-15 13:09:40 -0700 | [diff] [blame] | 122 | } |
| 123 | } |
| 124 | |
Suharsh Sivakumar | 8a7fba4 | 2014-10-27 12:40:48 -0700 | [diff] [blame] | 125 | func newMockPrincipal() *mockPrincipal { |
Ryan Brown | fed691e | 2014-09-15 13:09:40 -0700 | [diff] [blame] | 126 | key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) |
| 127 | if err != nil { |
| 128 | panic(err) |
| 129 | } |
Suharsh Sivakumar | 8a7fba4 | 2014-10-27 12:40:48 -0700 | [diff] [blame] | 130 | pkey := security.NewECDSAPublicKey(&key.PublicKey) |
| 131 | return &mockPrincipal{ |
| 132 | Key: pkey, |
| 133 | MockStore: &mockBlessingStore{Key: pkey}, |
| 134 | MockRoots: &mockBlessingRoots{}, |
| 135 | } |
Ryan Brown | fed691e | 2014-09-15 13:09:40 -0700 | [diff] [blame] | 136 | } |
| 137 | |
Suharsh Sivakumar | 8a7fba4 | 2014-10-27 12:40:48 -0700 | [diff] [blame] | 138 | type mockPrincipal struct { |
| 139 | NextError error |
| 140 | NextResult interface{} |
| 141 | Key security.PublicKey |
| 142 | MockStore *mockBlessingStore |
| 143 | MockRoots *mockBlessingRoots |
Ryan Brown | fed691e | 2014-09-15 13:09:40 -0700 | [diff] [blame] | 144 | } |
| 145 | |
Suharsh Sivakumar | 8a7fba4 | 2014-10-27 12:40:48 -0700 | [diff] [blame] | 146 | func (p *mockPrincipal) reset() { |
| 147 | p.NextError = nil |
| 148 | p.NextResult = nil |
| 149 | } |
| 150 | |
| 151 | func (p *mockPrincipal) Bless(security.PublicKey, security.Blessings, string, security.Caveat, ...security.Caveat) (security.Blessings, error) { |
| 152 | defer p.reset() |
| 153 | b, _ := p.NextResult.(security.Blessings) |
| 154 | return b, p.NextError |
| 155 | } |
| 156 | |
| 157 | func (p *mockPrincipal) BlessSelf(string, ...security.Caveat) (security.Blessings, error) { |
| 158 | defer p.reset() |
| 159 | b, _ := p.NextResult.(security.Blessings) |
| 160 | return b, p.NextError |
| 161 | } |
| 162 | |
| 163 | func (p *mockPrincipal) Sign([]byte) (sig security.Signature, err error) { |
| 164 | defer p.reset() |
| 165 | sig, _ = p.NextResult.(security.Signature) |
| 166 | err = p.NextError |
| 167 | return |
| 168 | } |
| 169 | |
| 170 | func (p *mockPrincipal) MintDischarge(security.ThirdPartyCaveat, security.Caveat, ...security.Caveat) (security.Discharge, error) { |
| 171 | defer p.reset() |
| 172 | d, _ := p.NextResult.(security.Discharge) |
| 173 | return d, p.NextError |
| 174 | } |
| 175 | |
gauthamt | f826393 | 2014-12-16 10:59:09 -0800 | [diff] [blame] | 176 | func (p *mockPrincipal) BlessingsByName(name security.BlessingPattern) []security.Blessings { |
| 177 | defer p.reset() |
| 178 | b, _ := p.NextResult.([]security.Blessings) |
| 179 | return b |
| 180 | } |
| 181 | |
gauthamt | 8dc9a18 | 2015-01-08 18:03:18 -0800 | [diff] [blame] | 182 | func (p *mockPrincipal) BlessingsInfo(blessings security.Blessings) map[string][]security.Caveat { |
gauthamt | f826393 | 2014-12-16 10:59:09 -0800 | [diff] [blame] | 183 | defer p.reset() |
gauthamt | 8dc9a18 | 2015-01-08 18:03:18 -0800 | [diff] [blame] | 184 | s, _ := p.NextResult.(map[string][]security.Caveat) |
gauthamt | f826393 | 2014-12-16 10:59:09 -0800 | [diff] [blame] | 185 | return s |
| 186 | } |
| 187 | |
Suharsh Sivakumar | 8a7fba4 | 2014-10-27 12:40:48 -0700 | [diff] [blame] | 188 | func (p *mockPrincipal) PublicKey() security.PublicKey { return p.Key } |
| 189 | func (p *mockPrincipal) Roots() security.BlessingRoots { return p.MockRoots } |
| 190 | func (p *mockPrincipal) BlessingStore() security.BlessingStore { return p.MockStore } |
| 191 | func (p *mockPrincipal) AddToRoots(b security.Blessings) error { |
| 192 | defer p.reset() |
| 193 | return p.NextError |
| 194 | } |
| 195 | |
| 196 | type mockBlessingStore struct { |
| 197 | NextError error |
| 198 | NextResult interface{} |
| 199 | Key security.PublicKey |
| 200 | } |
| 201 | |
| 202 | func (s *mockBlessingStore) reset() { |
| 203 | s.NextError = nil |
| 204 | s.NextResult = nil |
| 205 | } |
| 206 | |
| 207 | func (s *mockBlessingStore) Set(security.Blessings, security.BlessingPattern) (security.Blessings, error) { |
| 208 | defer s.reset() |
| 209 | b, _ := s.NextResult.(security.Blessings) |
| 210 | return b, s.NextError |
| 211 | } |
| 212 | |
| 213 | func (s *mockBlessingStore) ForPeer(...string) security.Blessings { |
| 214 | defer s.reset() |
| 215 | b, _ := s.NextResult.(security.Blessings) |
| 216 | return b |
| 217 | } |
| 218 | |
| 219 | func (s *mockBlessingStore) SetDefault(security.Blessings) error { |
| 220 | defer s.reset() |
| 221 | return s.NextError |
| 222 | } |
| 223 | |
| 224 | func (s *mockBlessingStore) Default() security.Blessings { |
| 225 | defer s.reset() |
| 226 | b, _ := s.NextResult.(security.Blessings) |
| 227 | return b |
| 228 | } |
| 229 | |
| 230 | func (s *mockBlessingStore) PublicKey() security.PublicKey { return s.Key } |
| 231 | |
gauthamt | f826393 | 2014-12-16 10:59:09 -0800 | [diff] [blame] | 232 | func (s *mockBlessingStore) PeerBlessings() map[security.BlessingPattern]security.Blessings { |
| 233 | defer s.reset() |
| 234 | m, _ := s.NextResult.(map[security.BlessingPattern]security.Blessings) |
| 235 | return m |
| 236 | } |
| 237 | |
Suharsh Sivakumar | 8a7fba4 | 2014-10-27 12:40:48 -0700 | [diff] [blame] | 238 | func (s *mockBlessingStore) DebugString() string { |
| 239 | defer s.reset() |
| 240 | return s.NextResult.(string) |
| 241 | } |
| 242 | |
| 243 | type mockBlessingRoots struct { |
| 244 | NextError error |
| 245 | NextResult interface{} |
| 246 | } |
| 247 | |
| 248 | func (r *mockBlessingRoots) reset() { |
| 249 | r.NextError = nil |
| 250 | r.NextResult = nil |
| 251 | } |
| 252 | |
| 253 | func (r *mockBlessingRoots) Add(security.PublicKey, security.BlessingPattern) error { |
| 254 | defer r.reset() |
| 255 | return r.NextError |
| 256 | } |
| 257 | |
| 258 | func (r *mockBlessingRoots) Recognized(security.PublicKey, string) error { |
| 259 | defer r.reset() |
| 260 | return r.NextError |
| 261 | } |
| 262 | |
| 263 | func (r *mockBlessingRoots) DebugString() string { |
| 264 | defer r.reset() |
| 265 | return r.NextResult.(string) |
| 266 | } |
| 267 | |
| 268 | type V []interface{} |
| 269 | |
| 270 | func call(receiver interface{}, method string, args V) (results []interface{}, err interface{}) { |
| 271 | defer func() { |
| 272 | err = recover() |
| 273 | }() |
| 274 | callargs := make([]reflect.Value, len(args)) |
| 275 | for idx, arg := range args { |
| 276 | callargs[idx] = reflect.ValueOf(arg) |
| 277 | } |
| 278 | callresults := reflect.ValueOf(receiver).MethodByName(method).Call(callargs) |
| 279 | results = make([]interface{}, len(callresults)) |
| 280 | for idx, res := range callresults { |
| 281 | results[idx] = res.Interface() |
| 282 | } |
| 283 | return |
| 284 | } |
| 285 | |
| 286 | func newPrincipal(t *testing.T) security.Principal { |
| 287 | key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) |
| 288 | if err != nil { |
| 289 | t.Fatal(err) |
| 290 | } |
| 291 | signer := security.NewInMemoryECDSASigner(key) |
| 292 | p, err := security.CreatePrincipal(signer, nil, nil) |
| 293 | if err != nil { |
| 294 | t.Fatal(err) |
| 295 | } |
| 296 | return p |
| 297 | } |
| 298 | |
| 299 | func newCaveat(c security.Caveat, err error) security.Caveat { |
| 300 | if err != nil { |
| 301 | panic(err) |
| 302 | } |
| 303 | return c |
| 304 | } |
| 305 | |
| 306 | func newBlessing(t *testing.T, name string) security.Blessings { |
| 307 | b, err := newPrincipal(t).BlessSelf(name) |
| 308 | if err != nil { |
| 309 | t.Fatal(err) |
| 310 | } |
| 311 | return b |
| 312 | } |
| 313 | |
| 314 | func newThirdPartyCaveatAndDischarge(t *testing.T) (security.ThirdPartyCaveat, security.Discharge) { |
| 315 | p := newPrincipal(t) |
| 316 | c, err := security.NewPublicKeyCaveat(p.PublicKey(), "location", security.ThirdPartyRequirements{}, newCaveat(security.MethodCaveat("method"))) |
| 317 | if err != nil { |
| 318 | t.Fatal(err) |
| 319 | } |
| 320 | d, err := p.MintDischarge(c, security.UnconstrainedUse()) |
| 321 | if err != nil { |
| 322 | t.Fatal(err) |
| 323 | } |
| 324 | return c, d |
Ryan Brown | fed691e | 2014-09-15 13:09:40 -0700 | [diff] [blame] | 325 | } |