blob: 4b0d9775a032ee47d9979a18556ebe429b20f963 [file] [log] [blame]
Asim Shankar6c247c42014-09-29 17:51:53 -07001package audit_test
2
3import (
4 "crypto/ecdsa"
5 "crypto/elliptic"
6 "crypto/rand"
7 "errors"
8 "reflect"
9 "strings"
10 "testing"
11 "time"
12
Jiri Simsa764efb72014-12-25 20:57:03 -080013 "v.io/core/veyron/security/audit"
14 "v.io/core/veyron2/security"
Asim Shankar6c247c42014-09-29 17:51:53 -070015)
16
17func TestAuditingPrincipal(t *testing.T) {
18 var (
19 thirdPartyCaveat, discharge = newThirdPartyCaveatAndDischarge(t)
20 wantErr = errors.New("call failed") // The error returned by call calls to mockID operations
21
22 mockP = new(mockPrincipal)
23 auditor = new(mockAuditor)
24 p = audit.NewPrincipal(mockP, auditor)
25 )
26 tests := []struct {
27 Method string
28 Args V
29 Result interface{} // Result returned by the Method call.
30 AuditResult bool // If true, Result should appear in the audit log. If false, it should not.
31 }{
32 {"BlessSelf", V{"self"}, newBlessing(t, "blessing"), true},
33 {"Bless", V{newPrincipal(t).PublicKey(), newBlessing(t, "root"), "extension", security.UnconstrainedUse()}, newBlessing(t, "root/extension"), true},
34 {"MintDischarge", V{thirdPartyCaveat, security.UnconstrainedUse()}, discharge, false},
35 {"Sign", V{make([]byte, 10)}, security.Signature{R: []byte{1}, S: []byte{1}}, false},
36 }
37 for _, test := range tests {
38 // Test1: If the underlying operation fails, the error should be returned and nothing should be audited.
39 mockP.NextError = wantErr
40 results, err := call(p, test.Method, test.Args)
41 if err != nil {
42 t.Errorf("failed to invoke p.%v(%#v): %v", test.Method, test.Args, err)
43 continue
44 }
45 if got, ok := results[len(results)-1].(error); !ok || got != wantErr {
46 t.Errorf("p.%v(%#v) returned (..., %v), want (..., %v)", test.Method, test.Args, got, wantErr)
47 }
48 if audited := auditor.Release(); !reflect.DeepEqual(audited, audit.Entry{}) {
49 t.Errorf("p.%v(%#v) resulted in [%+v] being written to the audit log, nothing should have been", test.Method, test.Args, audited)
50 }
51
52 // Test2: If the auditor fails, then the operation should fail too.
53 auditor.NextError = errors.New("auditor failed")
54 results, err = call(p, test.Method, test.Args)
55 if err != nil {
56 t.Errorf("failed to invoke p.%v(%#v): %v", test.Method, test.Args, err)
57 continue
58 }
59 if got, ok := results[len(results)-1].(error); !ok || !strings.HasSuffix(got.Error(), "auditor failed") {
60 t.Errorf("p.%v(%#v) returned %v when auditor failed, wanted (..., %v)", test.Method, test.Args, results, "... auditor failed")
61 }
62
63 // Test3: If the underlying operation succeeds, should return the same value and write to the audit log.
64 now := time.Now()
65 mockP.NextResult = test.Result
66 results, err = call(p, test.Method, test.Args)
67 audited := auditor.Release()
68 if err != nil {
69 t.Errorf("failed to invoke p.%v(%#v): %v", test.Method, test.Args, err)
70 continue
71 }
72 if got := results[len(results)-1]; got != nil {
73 t.Errorf("p.%v(%#v) returned an error: %v", test.Method, test.Args, got)
74 }
75 if got := results[0]; !reflect.DeepEqual(got, test.Result) {
76 t.Errorf("p.%v(%#v) returned %v(%T) want %v(%T)", test.Method, test.Args, got, got, test.Result, test.Result)
77 }
78 if audited.Timestamp.Before(now) || audited.Timestamp.IsZero() {
79 t.Errorf("p.%v(%#v) audited the time as %v, should have been a time after %v", test.Method, test.Args, audited.Timestamp, now)
80 }
81 if want := (audit.Entry{
82 Method: test.Method,
83 Arguments: []interface{}(test.Args),
84 Results: sliceOrNil(test.AuditResult, test.Result),
85 Timestamp: audited.Timestamp, // Hard to come up with the expected timestamp, relying on sanity check above.
86 }); !reflect.DeepEqual(audited, want) {
87 t.Errorf("p.%v(%#v) resulted in [%#v] being audited, wanted [%#v]", test.Method, test.Args, audited, want)
88 }
89 }
90}
91
92func TestUnauditedMethodsOnPrincipal(t *testing.T) {
93 var (
94 auditor = new(mockAuditor)
95 p = newPrincipal(t)
96 auditedP = audit.NewPrincipal(p, auditor)
97 )
98 blessing, err := p.BlessSelf("self")
99 if err != nil {
100 t.Fatal(err)
101 }
102 tests := []struct {
103 Method string
104 Args V
105 }{
106 {"PublicKey", V{}},
107 {"Roots", V{}},
108 {"AddToRoots", V{blessing}},
109 {"BlessingStore", V{}},
110 }
111
112 for _, test := range tests {
113 want, err := call(p, test.Method, test.Args)
114 if err != nil {
115 t.Fatalf("%v: %v", test.Method, err)
116 }
117 got, err := call(auditedP, test.Method, test.Args)
118 if err != nil {
119 t.Fatalf("%v: %v", test.Method, err)
120 }
121 if !reflect.DeepEqual(got, want) {
122 t.Errorf("Got %v, want %v", got, want)
123 }
124 if gotEntry := auditor.Release(); !reflect.DeepEqual(gotEntry, audit.Entry{}) {
125 t.Errorf("Unexpected entry in audit log: %v", gotEntry)
126 }
127 }
128}
129
130type mockPrincipal struct {
131 NextResult interface{}
132 NextError error
133}
134
135func (p *mockPrincipal) reset() {
136 p.NextError = nil
137 p.NextResult = nil
138}
139
140func (p *mockPrincipal) Bless(security.PublicKey, security.Blessings, string, security.Caveat, ...security.Caveat) (security.Blessings, error) {
141 defer p.reset()
142 b, _ := p.NextResult.(security.Blessings)
143 return b, p.NextError
144}
145
146func (p *mockPrincipal) BlessSelf(string, ...security.Caveat) (security.Blessings, error) {
147 defer p.reset()
148 b, _ := p.NextResult.(security.Blessings)
149 return b, p.NextError
150}
151
152func (p *mockPrincipal) Sign([]byte) (sig security.Signature, err error) {
153 defer p.reset()
154 sig, _ = p.NextResult.(security.Signature)
155 err = p.NextError
156 return
157}
158
159func (p *mockPrincipal) MintDischarge(security.ThirdPartyCaveat, security.Caveat, ...security.Caveat) (security.Discharge, error) {
160 defer p.reset()
161 d, _ := p.NextResult.(security.Discharge)
162 return d, p.NextError
163}
164
gauthamtf8263932014-12-16 10:59:09 -0800165func (p *mockPrincipal) BlessingsByName(name security.BlessingPattern) []security.Blessings {
166 return nil
167}
168
gauthamt8dc9a182015-01-08 18:03:18 -0800169func (p *mockPrincipal) BlessingsInfo(b security.Blessings) map[string][]security.Caveat {
gauthamtf8263932014-12-16 10:59:09 -0800170 return nil
171}
172
Asim Shankar6c247c42014-09-29 17:51:53 -0700173func (p *mockPrincipal) PublicKey() security.PublicKey { return p.NextResult.(security.PublicKey) }
174func (p *mockPrincipal) Roots() security.BlessingRoots { return nil }
175func (p *mockPrincipal) BlessingStore() security.BlessingStore { return nil }
176func (p *mockPrincipal) AddToRoots(b security.Blessings) error { return nil }
177
178type mockAuditor struct {
179 LastEntry audit.Entry
180 NextError error
181}
182
183func (a *mockAuditor) Audit(entry audit.Entry) error {
184 if a.NextError != nil {
185 err := a.NextError
186 a.NextError = nil
187 return err
188 }
189 a.LastEntry = entry
190 return nil
191}
192
193func (a *mockAuditor) Release() audit.Entry {
194 entry := a.LastEntry
195 a.LastEntry = audit.Entry{}
196 return entry
197}
198
199type V []interface{}
200
201func call(receiver interface{}, method string, args V) (results []interface{}, err interface{}) {
202 defer func() {
203 err = recover()
204 }()
205 callargs := make([]reflect.Value, len(args))
206 for idx, arg := range args {
207 callargs[idx] = reflect.ValueOf(arg)
208 }
209 callresults := reflect.ValueOf(receiver).MethodByName(method).Call(callargs)
210 results = make([]interface{}, len(callresults))
211 for idx, res := range callresults {
212 results[idx] = res.Interface()
213 }
214 return
215}
216
217func sliceOrNil(include bool, item interface{}) []interface{} {
218 if item != nil && include {
219 return []interface{}{item}
220 }
221 return nil
222}
223
224func newPrincipal(t *testing.T) security.Principal {
225 key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
226 if err != nil {
227 t.Fatal(err)
228 }
229 signer := security.NewInMemoryECDSASigner(key)
Asim Shankar48bf0e62014-10-03 16:27:05 -0700230 p, err := security.CreatePrincipal(signer, nil, nil)
Asim Shankar6c247c42014-09-29 17:51:53 -0700231 if err != nil {
232 t.Fatal(err)
233 }
234 return p
235}
236
237func newCaveat(c security.Caveat, err error) security.Caveat {
238 if err != nil {
239 panic(err)
240 }
241 return c
242}
243
244func newBlessing(t *testing.T, name string) security.Blessings {
245 b, err := newPrincipal(t).BlessSelf(name)
246 if err != nil {
247 t.Fatal(err)
248 }
249 return b
250}
251
252func newThirdPartyCaveatAndDischarge(t *testing.T) (security.ThirdPartyCaveat, security.Discharge) {
253 p := newPrincipal(t)
254 c, err := security.NewPublicKeyCaveat(p.PublicKey(), "location", security.ThirdPartyRequirements{}, newCaveat(security.MethodCaveat("method")))
255 if err != nil {
256 t.Fatal(err)
257 }
258 d, err := p.MintDischarge(c, security.UnconstrainedUse())
259 if err != nil {
260 t.Fatal(err)
261 }
262 return c, d
263}