blob: d94964b2e5c2c1d81a085b2b5d1860b1da6c7d53 [file] [log] [blame]
Tilak Sharma3ed30242014-08-11 11:45:55 -07001package security
2
3import (
4 "io/ioutil"
5 "os"
6 "runtime"
7 "testing"
Tilak Sharma3ed30242014-08-11 11:45:55 -07008
Jiri Simsa519c5072014-09-17 21:37:57 -07009 "veyron.io/veyron/veyron2/naming"
10 "veyron.io/veyron/veyron2/security"
Tilak Sharma3ed30242014-08-11 11:45:55 -070011)
12
Asim Shankarbf6263f2014-10-01 12:32:30 -070013// context implements security.Context.
Tilak Sharma3ed30242014-08-11 11:45:55 -070014type context struct {
Asim Shankarbf6263f2014-10-01 12:32:30 -070015 localPrincipal security.Principal
16 localBlessings, remoteBlessings security.Blessings
17 method string
18 label security.Label
Tilak Sharma3ed30242014-08-11 11:45:55 -070019}
20
Ankurf044a8d2014-09-05 17:05:24 -070021func (c *context) Method() string { return c.method }
Asim Shankarbf6263f2014-10-01 12:32:30 -070022func (c *context) Name() string { return "" }
23func (c *context) Suffix() string { return "" }
Ankurf044a8d2014-09-05 17:05:24 -070024func (c *context) Label() security.Label { return c.label }
Asim Shankarbf6263f2014-10-01 12:32:30 -070025func (c *context) Discharges() map[string]security.Discharge { return nil }
26func (c *context) LocalID() security.PublicID { return nil }
27func (c *context) RemoteID() security.PublicID { return nil }
28func (c *context) LocalPrincipal() security.Principal { return c.localPrincipal }
29func (c *context) LocalBlessings() security.Blessings { return c.localBlessings }
30func (c *context) RemoteBlessings() security.Blessings { return c.remoteBlessings }
Ankurf044a8d2014-09-05 17:05:24 -070031func (c *context) LocalEndpoint() naming.Endpoint { return nil }
32func (c *context) RemoteEndpoint() naming.Endpoint { return nil }
Tilak Sharma3ed30242014-08-11 11:45:55 -070033
34func saveACLToTempFile(acl security.ACL) string {
35 f, err := ioutil.TempFile("", "saved_acl")
36 if err != nil {
37 panic(err)
38 }
39 defer f.Close()
Tilak Sharmad6ade0e2014-08-20 16:28:32 -070040 if err := SaveACL(f, acl); err != nil {
Tilak Sharma3ed30242014-08-11 11:45:55 -070041 defer os.Remove(f.Name())
42 panic(err)
43 }
44 return f.Name()
45}
46
47func updateACLInFile(fileName string, acl security.ACL) {
48 f, err := os.OpenFile(fileName, os.O_WRONLY, 0600)
49 if err != nil {
50 panic(err)
51 }
52 defer f.Close()
Tilak Sharmad6ade0e2014-08-20 16:28:32 -070053 if err := SaveACL(f, acl); err != nil {
Tilak Sharma3ed30242014-08-11 11:45:55 -070054 panic(err)
55 }
56}
57
Tilak Sharma3ed30242014-08-11 11:45:55 -070058func testSelfRPCs(t *testing.T, authorizer security.Authorizer) {
59 _, file, line, _ := runtime.Caller(1)
60 var (
Asim Shankarbf6263f2014-10-01 12:32:30 -070061 pserver, server = newPrincipal("server")
62 _, imposter = newPrincipal("server")
63 palice, alice = newPrincipal("alice")
Tilak Sharma3ed30242014-08-11 11:45:55 -070064
Asim Shankarbf6263f2014-10-01 12:32:30 -070065 serverAlice = bless(pserver, palice, server, "alice")
66 aliceServer = bless(palice, pserver, alice, "server")
67
68 ctx = &context{
69 localPrincipal: pserver,
70 localBlessings: server,
71 }
72
73 tests = []struct {
74 remote security.Blessings
75 isAuthorized bool
76 }{
77 {server, true},
78 {imposter, false},
79 {serverAlice, false},
80 // A principal talking to itself (even if with a different blessing) is authorized.
81 // TODO(ashankar,ataly): Is this a desired property?
82 {aliceServer, true},
83 }
84 )
85 for _, test := range tests {
86 ctx.remoteBlessings = test.remote
87 if got, want := authorizer.Authorize(ctx), test.isAuthorized; (got == nil) != want {
88 t.Errorf("%s:%d: %+v.Authorize(&context{local: %v, remote: %v}) returned error: %v, want error: %v", file, line, authorizer, ctx.localBlessings, ctx.remoteBlessings, got, !want)
Tilak Sharma3ed30242014-08-11 11:45:55 -070089 }
90 }
91}
92
93func testNothingPermitted(t *testing.T, authorizer security.Authorizer) {
94 _, file, line, _ := runtime.Caller(1)
95 var (
Asim Shankarbf6263f2014-10-01 12:32:30 -070096 pserver, server = newPrincipal("server")
97 palice, alice = newPrincipal("alice")
98 pbob, bob = newPrincipal("random")
Tilak Sharma3ed30242014-08-11 11:45:55 -070099
Asim Shankarbf6263f2014-10-01 12:32:30 -0700100 serverAlice = bless(pserver, palice, server, "alice")
101 serverAliceFriend = bless(palice, pbob, serverAlice, "friend")
102 serverBob = bless(pserver, pbob, server, "bob")
103
104 users = []security.Blessings{
105 // blessings not recognized by "server" (since they are rooted at public
106 // keys not recognized as roots by pserver)
107 alice,
108 bob,
109 // blessings recognized by "server" (since they are its delegates)
110 serverAlice,
111 serverAliceFriend,
112 serverBob,
113 }
114
115 invalidLabel = security.Label(3)
116 )
117 // No principal (other than the server itself - self-RPCs are allowed) should have access to any
118 // valid or invalid label.
Tilak Sharma3ed30242014-08-11 11:45:55 -0700119 for _, u := range users {
120 for _, l := range security.ValidLabels {
Asim Shankarbf6263f2014-10-01 12:32:30 -0700121 ctx := &context{localPrincipal: pserver, localBlessings: server, remoteBlessings: u, label: l}
Tilak Sharma3ed30242014-08-11 11:45:55 -0700122 if got := authorizer.Authorize(ctx); got == nil {
123 t.Errorf("%s:%d: %+v.Authorize(%v) returns nil, want error", file, line, authorizer, ctx)
124 }
125 }
Asim Shankarbf6263f2014-10-01 12:32:30 -0700126
127 ctx := &context{localPrincipal: pserver, localBlessings: server, remoteBlessings: u, label: invalidLabel}
Tilak Sharma3ed30242014-08-11 11:45:55 -0700128 if got := authorizer.Authorize(ctx); got == nil {
129 t.Errorf("%s:%d: %+v.Authorize(%v) returns nil, want error", file, line, authorizer, ctx)
130 }
131 }
132}
133
134func TestACLAuthorizer(t *testing.T) {
135 const (
136 // Shorthands
137 R = security.ReadLabel
138 W = security.WriteLabel
139 A = security.AdminLabel
140 D = security.DebugLabel
141 M = security.MonitoringLabel
Asim Shankarbf6263f2014-10-01 12:32:30 -0700142 X = security.ResolveLabel
Tilak Sharma3ed30242014-08-11 11:45:55 -0700143 )
Asim Shankarbf6263f2014-10-01 12:32:30 -0700144 type Expectations map[security.Blessings]security.LabelSet
Tilak Sharma3ed30242014-08-11 11:45:55 -0700145 // Principals to test
146 var (
Asim Shankarbf6263f2014-10-01 12:32:30 -0700147 // Principals
148 pserver, server = newPrincipal("server")
149 palice, alice = newPrincipal("alice")
150 pbob, bob = newPrincipal("bob")
151 pche, che = newPrincipal("che")
Tilak Sharma3ed30242014-08-11 11:45:55 -0700152
Asim Shankarbf6263f2014-10-01 12:32:30 -0700153 // Blessings from the server
154 serverAlice = bless(pserver, palice, server, "alice")
155 serverBob = bless(pserver, pbob, server, "bob")
156 serverChe = bless(pserver, pche, server, "che")
157 serverAliceFriend = bless(palice, pbob, serverAlice, "friend")
158 serverCheFriend = bless(pche, pbob, serverChe, "friend")
159
160 authorizer security.Authorizer // the authorizer to test.
161
162 runTests = func(expectations Expectations) {
163 _, file, line, _ := runtime.Caller(1)
164 for user, labels := range expectations {
165 for _, l := range security.ValidLabels {
166 ctx := &context{remoteBlessings: user, localBlessings: server, localPrincipal: pserver, label: l}
167 if got, want := authorizer.Authorize(ctx), labels.HasLabel(l); (got == nil) != want {
168 t.Errorf("%s:%d: %+v.Authorize(&context{remoteBlessings: %v, label: %v}) returned error: %v, want error: %v", file, line, authorizer, user, l, got, !want)
169 }
170 }
171 }
172 }
Tilak Sharma3ed30242014-08-11 11:45:55 -0700173 )
174 // Convenience function for combining Labels into a LabelSet.
175 LS := func(labels ...security.Label) security.LabelSet {
176 var ret security.LabelSet
177 for _, l := range labels {
178 ret = ret | security.LabelSet(l)
179 }
180 return ret
181 }
182
183 // ACL for testing
Asim Shankarbf6263f2014-10-01 12:32:30 -0700184 acl := security.ACL{
185 In: map[security.BlessingPattern]security.LabelSet{
186 "...": LS(R),
187 "server/alice/...": LS(W, R),
188 "server/alice": LS(A, D, M),
189 "server/bob": LS(D, M),
190 "server/che/...": LS(W, R),
191 "server/che": LS(W, R),
192 },
193 NotIn: map[string]security.LabelSet{
194 "server/che/friend": LS(W),
195 },
Tilak Sharma3ed30242014-08-11 11:45:55 -0700196 }
197
198 // Authorizations for the above ACL.
Asim Shankarbf6263f2014-10-01 12:32:30 -0700199 expectations := Expectations{
200 alice: LS(R), // "..." ACL entry.
201 bob: LS(R), // "..." ACL entry.
202 che: LS(R), // "..." ACL entry.
203 server: security.AllLabels, // self RPC
204 serverAlice: LS(R, W, A, D, M), // "server/alice/..." ACL entry
205 serverBob: LS(R, D, M), // "..." and "server/bob" ACL entries
206 serverAliceFriend: LS(W, R), // "server/alice/..." ACL entry.
207 serverChe: LS(W, R), // "server/che" ACL entry.
208 serverCheFriend: LS(R), // "server/che/..." ACL entry, with the "server/che/friend" NotIn exception.
209 nil: LS(R), // No blessings presented, same authorizations as "..." ACL entry.
Tilak Sharma3ed30242014-08-11 11:45:55 -0700210 }
211 // Create an aclAuthorizer based on the ACL and verify the authorizations.
Asim Shankarbf6263f2014-10-01 12:32:30 -0700212 authorizer = NewACLAuthorizer(acl)
213 runTests(expectations)
Tilak Sharma3ed30242014-08-11 11:45:55 -0700214 testSelfRPCs(t, authorizer)
215
216 // Create a fileACLAuthorizer by saving the ACL in a file, and verify the
217 // authorizations.
218 fileName := saveACLToTempFile(acl)
219 defer os.Remove(fileName)
Asim Shankarbf6263f2014-10-01 12:32:30 -0700220 authorizer = NewFileACLAuthorizer(fileName)
221 runTests(expectations)
222 testSelfRPCs(t, authorizer)
Tilak Sharma3ed30242014-08-11 11:45:55 -0700223
224 // Modify the ACL stored in the file and verify that the authorizations appropriately
225 // change for the fileACLAuthorizer.
Asim Shankarbf6263f2014-10-01 12:32:30 -0700226 acl.In["server/bob"] = LS(R, W, A, D, M)
227 expectations[serverBob] = LS(R, W, A, D, M)
Tilak Sharma3ed30242014-08-11 11:45:55 -0700228 updateACLInFile(fileName, acl)
Asim Shankarbf6263f2014-10-01 12:32:30 -0700229 runTests(expectations)
230 testSelfRPCs(t, authorizer)
Tilak Sharma3ed30242014-08-11 11:45:55 -0700231
232 // Update the ACL file with invalid contents and verify that no requests are
233 // authorized.
234 f, err := os.OpenFile(fileName, os.O_WRONLY, 0600)
235 if err != nil {
236 panic(err)
237 }
238 f.Write([]byte("invalid ACL"))
239 f.Close()
Asim Shankarbf6263f2014-10-01 12:32:30 -0700240 testNothingPermitted(t, authorizer)
241}
Tilak Sharma3ed30242014-08-11 11:45:55 -0700242
Asim Shankarbf6263f2014-10-01 12:32:30 -0700243func TestFileACLAuthorizerOnNonExistentFile(t *testing.T) {
244 testNothingPermitted(t, NewFileACLAuthorizer("fileDoesNotExist"))
Tilak Sharma3ed30242014-08-11 11:45:55 -0700245}
246
247func TestNilACLAuthorizer(t *testing.T) {
Tilak Sharmab88a1112014-08-15 17:17:12 -0700248 authorizer := NewACLAuthorizer(nullACL)
Tilak Sharma3ed30242014-08-11 11:45:55 -0700249 testNothingPermitted(t, authorizer)
250 testSelfRPCs(t, authorizer)
251}