blob: f5c88f7b577dc0e0d81aaab15a9da61b120e8fd0 [file] [log] [blame]
Asim Shankarda682852014-11-06 00:38:43 -08001package acl
2
3import (
4 "io/ioutil"
5 "reflect"
6 "testing"
Asim Shankarda682852014-11-06 00:38:43 -08007
8 vsecurity "veyron.io/veyron/veyron/security"
9 "veyron.io/veyron/veyron/security/acl/test"
Asim Shankarda682852014-11-06 00:38:43 -080010 "veyron.io/veyron/veyron2/security"
11)
12
13// TestTaggedACLAuthorizer is both a test and a demonstration of the use of the
14// TaggedACLAuthorizer and interaction with interface specification in VDL.
15func TestTaggedACLAuthorizer(t *testing.T) {
16 type P []security.BlessingPattern
17 type S []string
18 // TaggedACLMap to test against.
19 acl := TaggedACLMap{
20 "R": {
21 In: P{"..."},
22 },
23 "W": {
24 In: P{"ali/family/...", "bob/...", "che"},
25 NotIn: S{"bob/acquaintances"},
26 },
27 "X": {
28 In: P{"ali/family/boss", "superman"},
29 },
30 }
31 type testcase struct {
32 Method string
33 Client security.Blessings
34 }
35 var (
36 authorizer, _ = TaggedACLAuthorizer(acl, reflect.TypeOf(test.Read))
37 // Two principals: The "server" and the "client"
38 pserver, _ = vsecurity.NewPrincipal()
39 pclient, _ = vsecurity.NewPrincipal()
40 server, _ = pserver.BlessSelf("server")
41
42 // B generates the provided blessings for the client and ensures
43 // that the server will recognize them.
44 B = func(names ...string) security.Blessings {
45 var ret security.Blessings
46 for _, name := range names {
47 b, err := pclient.BlessSelf(name)
48 if err != nil {
49 t.Fatalf("%q: %v", name, err)
50 }
51 if err := pserver.AddToRoots(b); err != nil {
52 t.Fatalf("%q: %v", name, err)
53 }
54 if ret, err = security.UnionOfBlessings(ret, b); err != nil {
55 t.Fatal(err)
56 }
57 }
58 return ret
59 }
60
61 run = func(test testcase) error {
Asim Shankar252fe5f2014-11-06 00:59:29 -080062 ctx := security.NewContext(&security.ContextParams{
63 LocalPrincipal: pserver,
64 LocalBlessings: server,
65 RemoteBlessings: test.Client,
66 Method: test.Method,
67 MethodTags: methodTags(test.Method),
68 })
Asim Shankarda682852014-11-06 00:38:43 -080069 return authorizer.Authorize(ctx)
70 }
71 )
72
73 // Test cases where access should be granted to methods with tags on
74 // them.
75 for _, test := range []testcase{
76 {"Get", nil},
77 {"Get", B("ali")},
78 {"Get", B("bob/friend", "che/enemy")},
79
80 {"Put", B("ali")},
81 {"Put", B("ali/family/mom")},
82 {"Put", B("bob/friends")},
83 {"Put", B("bob/acquantainces/carol", "che")}, // Access granted because of "che"
84
85 {"Resolve", B("ali")},
86 {"Resolve", B("ali/family/boss")},
87
88 {"AllTags", B("ali/family/boss")},
89 } {
90 if err := run(test); err != nil {
91 t.Errorf("Access denied to method %q to %v: %v", test.Method, test.Client, err)
92 }
93 }
94 // Test cases where access should be denied.
95 for _, test := range []testcase{
96 // Nobody is denied access to "Get"
97 {"Put", B("bob/acquaintances/dave", "che/friend", "dave")},
98 {"Resolve", B("ali/family/friend")},
99 // Since there are no tags on the NoTags method, it has an
100 // empty ACL. No client will have access.
101 {"NoTags", B("ali", "ali/family/boss", "bob")},
102 // On a method with multiple tags on it, all must be satisfied.
103 {"AllTags", B("superman")}, // Only in the X ACL, not in R or W
104 {"AllTags", B("superman", "clark")}, // In X and in R, but not W
105 } {
106 if err := run(test); err == nil {
107 t.Errorf("Access to %q granted to %v", test.Method, test.Client)
108 }
109 }
110}
111
112func TestTaggedACLAuthorizerSelfRPCs(t *testing.T) {
113 var (
114 // Client and server are the same principal, though have
115 // different blessings.
116 p, _ = vsecurity.NewPrincipal()
117 client, _ = p.BlessSelf("client")
118 server, _ = p.BlessSelf("server")
119 // Authorizer with a TaggedACLMap that grants read access to
120 // anyone, write/execute access to noone.
121 typ test.MyTag
122 authorizer, _ = TaggedACLAuthorizer(TaggedACLMap{"R": {In: []security.BlessingPattern{"nobody"}}}, reflect.TypeOf(typ))
123 )
124 for _, test := range []string{"Put", "Get", "Resolve", "NoTags", "AllTags"} {
Asim Shankar252fe5f2014-11-06 00:59:29 -0800125 ctx := security.NewContext(&security.ContextParams{
126 LocalPrincipal: p,
127 LocalBlessings: server,
128 RemoteBlessings: client,
129 Method: test,
130 MethodTags: methodTags(test),
131 })
132 if err := authorizer.Authorize(ctx); err != nil {
Asim Shankarda682852014-11-06 00:38:43 -0800133 t.Errorf("Got error %v for method %q", err, test)
134 }
135 }
136}
137
138func TestTaggedACLAuthorizerWithNilACL(t *testing.T) {
139 var (
140 authorizer, _ = TaggedACLAuthorizer(nil, reflect.TypeOf(test.Read))
141 pserver, _ = vsecurity.NewPrincipal()
142 pclient, _ = vsecurity.NewPrincipal()
143 server, _ = pserver.BlessSelf("server")
144 client, _ = pclient.BlessSelf("client")
145 )
146 for _, test := range []string{"Put", "Get", "Resolve", "NoTags", "AllTags"} {
Asim Shankar252fe5f2014-11-06 00:59:29 -0800147 ctx := security.NewContext(&security.ContextParams{
148 LocalPrincipal: pserver,
149 LocalBlessings: server,
150 RemoteBlessings: client,
151 Method: test,
152 MethodTags: methodTags(test),
153 })
154 if err := authorizer.Authorize(ctx); err == nil {
Asim Shankarda682852014-11-06 00:38:43 -0800155 t.Errorf("nil TaggedACLMap authorized method %q", test)
156 }
157 }
158}
159
160func TestTaggedACLAuthorizerFromFile(t *testing.T) {
161 file, err := ioutil.TempFile("", "TestTaggedACLAuthorizerFromFile")
162 if err != nil {
163 t.Fatal(err)
164 }
165 filename := file.Name()
166 file.Close()
167
168 var (
169 authorizer, _ = TaggedACLAuthorizerFromFile(filename, reflect.TypeOf(test.Read))
170 pserver, _ = vsecurity.NewPrincipal()
171 pclient, _ = vsecurity.NewPrincipal()
172 server, _ = pserver.BlessSelf("alice")
173 alicefriend, _ = pserver.Bless(pclient.PublicKey(), server, "friend/bob", security.UnconstrainedUse())
Asim Shankar252fe5f2014-11-06 00:59:29 -0800174 ctx = security.NewContext(&security.ContextParams{
175 LocalPrincipal: pserver,
176 LocalBlessings: server,
177 RemoteBlessings: alicefriend,
178 Method: "Get",
179 MethodTags: methodTags("Get"),
180 })
Asim Shankarda682852014-11-06 00:38:43 -0800181 )
182 // Make pserver recognize itself as an authority on "alice/..." blessings.
183 if err := pserver.AddToRoots(server); err != nil {
184 t.Fatal(err)
185 }
186 // "alice/friend/bob" should not have access to test.Read methods like Get.
187 if err := authorizer.Authorize(ctx); err == nil {
Asim Shankar252fe5f2014-11-06 00:59:29 -0800188 t.Fatalf("Expected authorization error as %v is not on the ACL for Read operations", ctx.RemoteBlessings())
Asim Shankarda682852014-11-06 00:38:43 -0800189 }
190 // Rewrite the file giving access
191 if err := ioutil.WriteFile(filename, []byte(`{"R": { "In":["alice/friend/..."] }}`), 0600); err != nil {
192 t.Fatal(err)
193 }
194 // Now should have access
195 if err := authorizer.Authorize(ctx); err != nil {
196 t.Fatal(err)
197 }
198}
199
200func TestTagTypeMustBeString(t *testing.T) {
201 type I int
202 if auth, err := TaggedACLAuthorizer(TaggedACLMap{}, reflect.TypeOf(I(0))); err == nil || auth != nil {
203 t.Errorf("Got (%v, %v), wanted error since tag type is not a string", auth, err)
204 }
205 if auth, err := TaggedACLAuthorizerFromFile("does_not_matter", reflect.TypeOf(I(0))); err == nil || auth != nil {
206 t.Errorf("Got (%v, %v), wanted error since tag type is not a string", auth, err)
207 }
208}
209
Asim Shankar252fe5f2014-11-06 00:59:29 -0800210func methodTags(method string) []interface{} {
Todd Wang702385a2014-11-07 01:54:08 -0800211 server := test.MyObjectServer(nil)
Asim Shankar252fe5f2014-11-06 00:59:29 -0800212 tags, _ := server.GetMethodTags(nil, method)
Asim Shankarda682852014-11-06 00:38:43 -0800213 return tags
214}