blob: 1d04e8948dd691d445ed7b7349ea026d554e1293 [file] [log] [blame]
Tilak Sharma3ed30242014-08-11 11:45:55 -07001package security
2
3import (
4 "io/ioutil"
5 "os"
6 "runtime"
7 "testing"
8 "time"
9
10 "veyron2/naming"
11 "veyron2/security"
12)
13
14type authMap map[security.PublicID]security.LabelSet
15
16// context implements Context.
17type context struct {
18 localID, remoteID security.PublicID
19 discharges security.CaveatDischargeMap
20 method, name, suffix string
21 label security.Label
22}
23
24func (c *context) Method() string { return c.method }
25func (c *context) Name() string { return c.name }
26func (c *context) Suffix() string { return c.suffix }
27func (c *context) Label() security.Label { return c.label }
28func (c *context) CaveatDischarges() security.CaveatDischargeMap { return c.discharges }
29func (c *context) LocalID() security.PublicID { return c.localID }
30func (c *context) RemoteID() security.PublicID { return c.remoteID }
31func (c *context) LocalEndpoint() naming.Endpoint { return nil }
32func (c *context) RemoteEndpoint() naming.Endpoint { return nil }
33
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
58func bless(blessee security.PublicID, blesser security.PrivateID, name string) security.PublicID {
59 blessed, err := blesser.Bless(blessee, name, 5*time.Minute, nil)
60 if err != nil {
61 panic(err)
62 }
63 return blessed
64}
65
66func derive(pub security.PublicID, priv security.PrivateID) security.PrivateID {
67 d, err := priv.Derive(pub)
68 if err != nil {
69 panic(err)
70 }
71 return d
72}
73
74func testSelfRPCs(t *testing.T, authorizer security.Authorizer) {
75 _, file, line, _ := runtime.Caller(1)
76 var (
77 veyron = security.FakePrivateID("veyron")
78 alice = security.FakePrivateID("alice")
79 veyronAlice = bless(alice.PublicID(), veyron, "alice")
80 )
81 testData := []struct {
82 localID, remoteID security.PublicID
83 isAuthorized bool
84 }{
85 {alice.PublicID(), alice.PublicID(), true},
86 {veyron.PublicID(), veyron.PublicID(), true},
87 {veyron.PublicID(), alice.PublicID(), false},
88 {veyronAlice, veyronAlice, true},
89 {veyronAlice, alice.PublicID(), false},
90 {veyronAlice, veyron.PublicID(), false},
91 }
92 for _, d := range testData {
93 ctx := &context{localID: d.localID, remoteID: d.remoteID}
94 if got, want := authorizer.Authorize(ctx), d.isAuthorized; (got == nil) != want {
95 t.Errorf("%s:%d: %+v.Authorize(&context{localID: %v, remoteID: %v}) returned error: %v, want error: %v", file, line, authorizer, d.localID, d.remoteID, got, !want)
96 }
97 }
98}
99
100func testAuthorizations(t *testing.T, authorizer security.Authorizer, authorizations authMap) {
101 _, file, line, _ := runtime.Caller(1)
102 for user, labels := range authorizations {
103 for _, l := range security.ValidLabels {
104 ctx := &context{remoteID: user, label: l}
105 if got, want := authorizer.Authorize(ctx), labels.HasLabel(l); (got == nil) != want {
106 t.Errorf("%s:%d: %+v.Authorize(&context{remoteID: %v, label: %v}) returned error: %v, want error: %v", file, line, authorizer, user, l, got, !want)
107 }
108 }
109 }
110}
111
112func testNothingPermitted(t *testing.T, authorizer security.Authorizer) {
113 _, file, line, _ := runtime.Caller(1)
114 var (
115 veyronPrivateID = security.FakePrivateID("veyron")
116 alicePrivateID = security.FakePrivateID("alice")
117 randomPrivateID = security.FakePrivateID("random")
118 veyron = veyronPrivateID.PublicID()
119 alice = alicePrivateID.PublicID()
120 random = randomPrivateID.PublicID()
121 veyronAlice = bless(alice, veyronPrivateID, "alice")
122 veyronAliceFriend = bless(random, derive(veyronAlice, alicePrivateID), "friend")
123 veyronBob = bless(random, veyronPrivateID, "bob")
124 )
125 users := []security.PublicID{
126 veyron,
127 random,
128 alice,
129
130 // Blessed principals
131 veyronAlice,
132 veyronAliceFriend,
133 veyronBob,
134 }
135 // No principal (whether the identity provider is trusted or not)
136 // should have access to any valid or invalid label.
137 for _, u := range users {
138 for _, l := range security.ValidLabels {
139 ctx := &context{remoteID: u, label: l}
140 if got := authorizer.Authorize(ctx); got == nil {
141 t.Errorf("%s:%d: %+v.Authorize(%v) returns nil, want error", file, line, authorizer, ctx)
142 }
143 }
144 invalidLabel := security.Label(3)
145 ctx := &context{remoteID: u, label: invalidLabel}
146 if got := authorizer.Authorize(ctx); got == nil {
147 t.Errorf("%s:%d: %+v.Authorize(%v) returns nil, want error", file, line, authorizer, ctx)
148 }
149 }
150}
151
152func TestACLAuthorizer(t *testing.T) {
153 const (
154 // Shorthands
155 R = security.ReadLabel
156 W = security.WriteLabel
157 A = security.AdminLabel
158 D = security.DebugLabel
159 M = security.MonitoringLabel
160 )
161 // Principals to test
162 var (
163 veyronPrivateID = security.FakePrivateID("veyron")
164 alicePrivateID = security.FakePrivateID("alice")
Tilak Sharmab88a1112014-08-15 17:17:12 -0700165 bobPrivateID = security.FakePrivateID("bob")
166 chePrivateID = security.FakePrivateID("che")
Tilak Sharma3ed30242014-08-11 11:45:55 -0700167 veyron = veyronPrivateID.PublicID()
168 alice = alicePrivateID.PublicID()
Tilak Sharmab88a1112014-08-15 17:17:12 -0700169 bob = bobPrivateID.PublicID()
170 che = chePrivateID.PublicID()
Tilak Sharma3ed30242014-08-11 11:45:55 -0700171
172 // Blessed principals
173 veyronAlice = bless(alice, veyronPrivateID, "alice")
174 veyronBob = bless(bob, veyronPrivateID, "bob")
Tilak Sharmab88a1112014-08-15 17:17:12 -0700175 veyronChe = bless(che, veyronPrivateID, "che")
Tilak Sharma3ed30242014-08-11 11:45:55 -0700176 veyronAliceFriend = bless(bob, derive(veyronAlice, alicePrivateID), "friend")
Tilak Sharmab88a1112014-08-15 17:17:12 -0700177 veyronCheFriend = bless(che, derive(veyronChe, chePrivateID), "friend")
Tilak Sharma3ed30242014-08-11 11:45:55 -0700178 )
179 // Convenience function for combining Labels into a LabelSet.
180 LS := func(labels ...security.Label) security.LabelSet {
181 var ret security.LabelSet
182 for _, l := range labels {
183 ret = ret | security.LabelSet(l)
184 }
185 return ret
186 }
187
188 // ACL for testing
Tilak Sharmab88a1112014-08-15 17:17:12 -0700189 acl := security.ACL{}
Asim Shankar9f6db082014-08-27 16:44:03 -0700190 acl.In = map[security.BlessingPattern]security.LabelSet{
191 "...": LS(R),
192 "fake/veyron/alice/...": LS(W, R),
193 "fake/veyron/alice": LS(A, D, M),
194 "fake/veyron/bob": LS(D, M),
195 "fake/veyron/che/...": LS(W, R),
196 "fake/veyron/che": LS(W, R),
Tilak Sharmab88a1112014-08-15 17:17:12 -0700197 }
Asim Shankar9f6db082014-08-27 16:44:03 -0700198 acl.NotIn = map[string]security.LabelSet{
Tilak Sharmab88a1112014-08-15 17:17:12 -0700199 "fake/veyron/che/friend": LS(W),
Tilak Sharma3ed30242014-08-11 11:45:55 -0700200 }
201
202 // Authorizations for the above ACL.
203 authorizations := authMap{
Asim Shankar9f6db082014-08-27 16:44:03 -0700204 // alice and bob have only what "..." has.
Tilak Sharma3ed30242014-08-11 11:45:55 -0700205 alice: LS(R),
206 bob: LS(R),
Tilak Sharmab88a1112014-08-15 17:17:12 -0700207 che: LS(R),
Tilak Sharma3ed30242014-08-11 11:45:55 -0700208 // veyron and veyronAlice have R, W, A, D, M from the "veyron/alice" and
Asim Shankar9f6db082014-08-27 16:44:03 -0700209 // "veyron/alice/..." ACL entries.
Tilak Sharma3ed30242014-08-11 11:45:55 -0700210 veyron: LS(R, W, A, D, M),
211 veyronAlice: LS(R, W, A, D, M),
Asim Shankar9f6db082014-08-27 16:44:03 -0700212 // veyronBob has R, D, M from "..." and "veyron/bob" ACL entries.
Tilak Sharma3ed30242014-08-11 11:45:55 -0700213 veyronBob: LS(R, D, M),
Asim Shankar9f6db082014-08-27 16:44:03 -0700214 // veyronAliceFriend has W, R from the "veyron/alice/..." ACL entry.
Tilak Sharma3ed30242014-08-11 11:45:55 -0700215 veyronAliceFriend: LS(W, R),
Tilak Sharmab88a1112014-08-15 17:17:12 -0700216 // veyronChe has W, R from the "veyron/che" entry.
217 veyronChe: LS(W, R),
Asim Shankar9f6db082014-08-27 16:44:03 -0700218 // veyronCheFriend has W, R from the "veyron/che/..." entry, but loses W
Tilak Sharmab88a1112014-08-15 17:17:12 -0700219 // from the blacklist entry "veyron/che/friend".
220 veyronCheFriend: LS(R),
Tilak Sharma3ed30242014-08-11 11:45:55 -0700221 // nil PublicIDs are not authorized.
222 nil: LS(),
223 }
224 // Create an aclAuthorizer based on the ACL and verify the authorizations.
225 authorizer := NewACLAuthorizer(acl)
226 testAuthorizations(t, authorizer, authorizations)
227 testSelfRPCs(t, authorizer)
228
229 // Create a fileACLAuthorizer by saving the ACL in a file, and verify the
230 // authorizations.
231 fileName := saveACLToTempFile(acl)
232 defer os.Remove(fileName)
233 fileAuthorizer := NewFileACLAuthorizer(fileName)
234 testAuthorizations(t, fileAuthorizer, authorizations)
235 testSelfRPCs(t, fileAuthorizer)
236
237 // Modify the ACL stored in the file and verify that the authorizations appropriately
238 // change for the fileACLAuthorizer.
Asim Shankar9f6db082014-08-27 16:44:03 -0700239 acl.In["fake/veyron/bob"] = LS(R, W, A, D, M)
Tilak Sharma3ed30242014-08-11 11:45:55 -0700240 updateACLInFile(fileName, acl)
241
242 authorizations[veyronBob] = LS(R, W, A, D, M)
243 testAuthorizations(t, fileAuthorizer, authorizations)
244 testSelfRPCs(t, fileAuthorizer)
245
246 // Update the ACL file with invalid contents and verify that no requests are
247 // authorized.
248 f, err := os.OpenFile(fileName, os.O_WRONLY, 0600)
249 if err != nil {
250 panic(err)
251 }
252 f.Write([]byte("invalid ACL"))
253 f.Close()
254 testNothingPermitted(t, fileAuthorizer)
255
256 // Verify that a fileACLAuthorizer based on a nonexistent file does not authorize any
257 // requests.
258 fileAuthorizer = NewFileACLAuthorizer("fileDoesNotExist")
259 testNothingPermitted(t, fileAuthorizer)
260}
261
262func TestNilACLAuthorizer(t *testing.T) {
Tilak Sharmab88a1112014-08-15 17:17:12 -0700263 authorizer := NewACLAuthorizer(nullACL)
Tilak Sharma3ed30242014-08-11 11:45:55 -0700264 testNothingPermitted(t, authorizer)
265 testSelfRPCs(t, authorizer)
266}