Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: tokenserver/appengine/delegation/config_test.go

Issue 2413683004: token-server: Delegation config import, validation and evaluation. (Closed)
Patch Set: also check validity_duration Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file.
4
5 package delegation
6
7 import (
8 "testing"
9 "time"
10
11 "github.com/golang/protobuf/proto"
12 "golang.org/x/net/context"
13
14 "github.com/luci/gae/service/datastore"
15 "github.com/luci/luci-go/appengine/gaetesting"
16 "github.com/luci/luci-go/common/clock/testclock"
17 "github.com/luci/luci-go/server/auth"
18 "github.com/luci/luci-go/server/auth/authtest"
19 "github.com/luci/luci-go/server/auth/identity"
20 admin "github.com/luci/luci-go/tokenserver/api/admin/v1"
21 "github.com/luci/luci-go/tokenserver/appengine/utils/identityset"
22
23 . "github.com/luci/luci-go/common/testing/assertions"
24 . "github.com/smartystreets/goconvey/convey"
25 )
26
27 func TestDelegationConfigLoader(t *testing.T) {
28 Convey("DelegationConfigLoader works", t, func() {
29 ctx := gaetesting.TestingContext()
30 ctx, tc := testclock.UseTime(ctx, testclock.TestTimeUTC)
31
32 loader := DelegationConfigLoader()
33
34 // Put the initial copy into the datastore.
35 cfg, err := loadConfig(`
36 rules {
37 name: "rule 1"
38 requestor: "user:some-user@example.com"
39 target_service: "service:some-service"
40 allowed_to_impersonate: "group:some-group"
41 allowed_audience: "REQUESTOR"
42 max_validity_duration: 86400
43 }`)
44 So(err, ShouldBeNil)
45 cfg.Revision = "1"
46 So(datastore.Put(ctx, cfg), ShouldBeNil)
47
48 // Loader fetches it.
49 fetched1, err := loader(ctx)
50 So(err, ShouldBeNil)
51 So(fetched1.ParsedConfig.Rules[0].Name, ShouldEqual, "rule 1")
52
53 // Config is updated.
54 cfg, err = loadConfig(`
55 rules {
56 name: "rule 2"
57 requestor: "user:some-user@example.com"
58 target_service: "service:some-service"
59 allowed_to_impersonate: "group:some-group"
60 allowed_audience: "REQUESTOR"
61 max_validity_duration: 86400
62 }`)
63 So(err, ShouldBeNil)
64 cfg.Revision = "2"
65 So(datastore.Put(ctx, cfg), ShouldBeNil)
66
67 // Loader still returns old cached copy.
68 fetched2, err := loader(ctx)
69 So(err, ShouldBeNil)
70 So(fetched2, ShouldEqual, fetched1)
71
72 // Advance time to expire the cache. The new copy is fetched.
73 tc.Add(procCacheExpiration + time.Second)
74 fetched3, err := loader(ctx)
75 So(err, ShouldBeNil)
76 So(fetched3.ParsedConfig.Rules[0].Name, ShouldEqual, "rule 2")
77
78 // Advance time again, but do not change the config. Loader reus es existing
79 // object.
80 tc.Add(procCacheExpiration + time.Second)
81 fetched4, err := loader(ctx)
82 So(err, ShouldBeNil)
83 So(fetched4, ShouldEqual, fetched3)
84 })
85 }
86
87 func TestIsAuthorizedRequestor(t *testing.T) {
88 Convey("IsAuthorizedRequestor works", t, func() {
89 cfg, err := loadConfig(`
90 rules {
91 name: "rule 1"
92 requestor: "user:some-user@example.com"
93
94 target_service: "service:some-service"
95 allowed_to_impersonate: "group:some-group"
96 allowed_audience: "REQUESTOR"
97 max_validity_duration: 86400
98 }
99
100 rules {
101 name: "rule 2"
102 requestor: "user:some-another-user@example.com"
103 requestor: "group:some-group"
104
105 target_service: "service:some-service"
106 allowed_to_impersonate: "group:some-group"
107 allowed_audience: "REQUESTOR"
108 max_validity_duration: 86400
109 }
110 `)
111 So(err, ShouldBeNil)
112 So(cfg, ShouldNotBeNil)
113
114 ctx := auth.WithState(context.Background(), &authtest.FakeState{
115 Identity: "user:some-user@example.com",
116 })
117 res, err := cfg.IsAuthorizedRequestor(ctx, identity.Identity("us er:some-user@example.com"))
118 So(err, ShouldBeNil)
119 So(res, ShouldBeTrue)
120
121 ctx = auth.WithState(context.Background(), &authtest.FakeState{
122 Identity: "user:some-another-user@example.com",
123 })
124 res, err = cfg.IsAuthorizedRequestor(ctx, identity.Identity("use r:some-another-user@example.com"))
125 So(err, ShouldBeNil)
126 So(res, ShouldBeTrue)
127
128 ctx = auth.WithState(context.Background(), &authtest.FakeState{
129 Identity: "user:unknown-user@example.com",
130 })
131 res, err = cfg.IsAuthorizedRequestor(ctx, identity.Identity("use r:unknown-user@example.com"))
132 So(err, ShouldBeNil)
133 So(res, ShouldBeFalse)
134
135 ctx = auth.WithState(context.Background(), &authtest.FakeState{
136 Identity: "user:via-group@example.com",
137 IdentityGroups: []string{"some-group"},
138 })
139 res, err = cfg.IsAuthorizedRequestor(ctx, identity.Identity("use r:via-group@example.com"))
140 So(err, ShouldBeNil)
141 So(res, ShouldBeTrue)
142 })
143 }
144
145 func TestFindMatchingRule(t *testing.T) {
146 Convey("with example config", t, func() {
147 cfg, err := loadConfig(`
148 rules {
149 name: "rule 1"
150 requestor: "user:requestor@example.com"
151 target_service: "service:some-service"
152 allowed_to_impersonate: "user:allowed-to-imperso nate@example.com"
153 allowed_audience: "user:allowed-audience@example .com"
154 max_validity_duration: 86400
155 }
156
157 rules {
158 name: "rule 2"
159 requestor: "group:requestor-group"
160 target_service: "service:some-service"
161 allowed_to_impersonate: "group:delegatees-group"
162 allowed_audience: "group:audience-group"
163 max_validity_duration: 86400
164 }
165
166 rules {
167 name: "rule 3"
168 requestor: "group:requestor-group"
169 target_service: "service:some-service"
170 allowed_to_impersonate: "REQUESTOR"
171 allowed_audience: "REQUESTOR"
172 max_validity_duration: 86400
173 }
174
175 rules {
176 name: "rule 4"
177 requestor: "user:some-requestor@example.com"
178 requestor: "user:conflicts-with-rule-5@example.c om"
179 target_service: "*"
180 allowed_to_impersonate: "REQUESTOR"
181 allowed_audience: "*"
182 max_validity_duration: 86400
183 }
184
185 rules {
186 name: "rule 5"
187 requestor: "user:conflicts-with-rule-5@example.c om"
188 target_service: "*"
189 allowed_to_impersonate: "REQUESTOR"
190 allowed_audience: "*"
191 max_validity_duration: 86400
192 }
193 `)
194 So(err, ShouldBeNil)
195 So(cfg, ShouldNotBeNil)
196
197 ctx := auth.WithState(context.Background(), &authtest.FakeState{
198 Identity: "user:requestor@example.com",
199 FakeDB: authtest.FakeDB{
200 "user:requestor-group-member@example.com": []st ring{"requestor-group"},
201 "user:delegatees-group-member@example.com": []st ring{"delegatees-group"},
202 "user:audience-group-member@example.com": []st ring{"audience-group"},
203 },
204 })
205
206 Convey("Direct matches and misses", func() {
207 // Match.
208 res, err := cfg.FindMatchingRule(ctx, &RulesQuery{
209 Requestor: "user:requestor@example.com",
210 Delegatee: "user:allowed-to-impersonate@example. com",
211 Audience: makeSet("user:allowed-audience@exampl e.com"),
212 Services: makeSet("service:some-service"),
213 })
214 So(err, ShouldBeNil)
215 So(res, ShouldNotBeNil)
216 So(res.Name, ShouldEqual, "rule 1")
217
218 // Unknown requestor.
219 res, err = cfg.FindMatchingRule(ctx, &RulesQuery{
220 Requestor: "user:unknown-requestor@example.com",
221 Delegatee: "user:allowed-to-impersonate@example. com",
222 Audience: makeSet("user:allowed-audience@exampl e.com"),
223 Services: makeSet("service:some-service"),
224 })
225 So(err, ShouldErrLike, "no matching delegation rules in the config")
226 So(res, ShouldBeNil)
227
228 // Unknown delegatee.
229 res, err = cfg.FindMatchingRule(ctx, &RulesQuery{
230 Requestor: "user:requestor@example.com",
231 Delegatee: "user:unknown-allowed-to-impersonate@ example.com",
232 Audience: makeSet("user:allowed-audience@exampl e.com"),
233 Services: makeSet("service:some-service"),
234 })
235 So(err, ShouldErrLike, "no matching delegation rules in the config")
236 So(res, ShouldBeNil)
237
238 // Unknown audience.
239 res, err = cfg.FindMatchingRule(ctx, &RulesQuery{
240 Requestor: "user:requestor@example.com",
241 Delegatee: "user:allowed-to-impersonate@example. com",
242 Audience: makeSet("user:unknown-allowed-audienc e@example.com"),
243 Services: makeSet("service:some-service"),
244 })
245 So(err, ShouldErrLike, "no matching delegation rules in the config")
246 So(res, ShouldBeNil)
247
248 // Unknown target service.
249 res, err = cfg.FindMatchingRule(ctx, &RulesQuery{
250 Requestor: "user:requestor@example.com",
251 Delegatee: "user:allowed-to-impersonate@example. com",
252 Audience: makeSet("user:allowed-audience@exampl e.com"),
253 Services: makeSet("service:unknown-some-service "),
254 })
255 So(err, ShouldErrLike, "no matching delegation rules in the config")
256 So(res, ShouldBeNil)
257 })
258
259 Convey("Matches via groups", func() {
260 res, err := cfg.FindMatchingRule(ctx, &RulesQuery{
261 Requestor: "user:requestor-group-member@example. com",
262 Delegatee: "user:delegatees-group-member@example .com",
263 Audience: makeSet("group:audience-group"),
264 Services: makeSet("service:some-service"),
265 })
266 So(err, ShouldBeNil)
267 So(res, ShouldNotBeNil)
268 So(res.Name, ShouldEqual, "rule 2")
269
270 // Doesn't do group lookup when checking audience!
271 res, err = cfg.FindMatchingRule(ctx, &RulesQuery{
272 Requestor: "user:requestor-group-member@example. com",
273 Delegatee: "user:delegatees-group-member@example .com",
274 Audience: makeSet("user:audience-group-member@e xample.com"),
275 Services: makeSet("service:some-service"),
276 })
277 So(err, ShouldErrLike, "no matching delegation rules in the config")
278 So(res, ShouldBeNil)
279 })
280
281 Convey("REQUESTOR rules work", func() {
282 res, err := cfg.FindMatchingRule(ctx, &RulesQuery{
283 Requestor: "user:requestor-group-member@example. com",
284 Delegatee: "user:requestor-group-member@example. com",
285 Audience: makeSet("user:requestor-group-member@ example.com"),
286 Services: makeSet("service:some-service"),
287 })
288 So(err, ShouldBeNil)
289 So(res, ShouldNotBeNil)
290 So(res.Name, ShouldEqual, "rule 3")
291 })
292
293 Convey("'*' rules work", func() {
294 res, err := cfg.FindMatchingRule(ctx, &RulesQuery{
295 Requestor: "user:some-requestor@example.com",
296 Delegatee: "user:some-requestor@example.com",
297 Audience: makeSet("group:abc", "user:def@exampl e.com"),
298 Services: makeSet("service:unknown"),
299 })
300 So(err, ShouldBeNil)
301 So(res, ShouldNotBeNil)
302 So(res.Name, ShouldEqual, "rule 4")
303 })
304
305 Convey("a conflict is handled", func() {
306 res, err := cfg.FindMatchingRule(ctx, &RulesQuery{
307 Requestor: "user:conflicts-with-rule-5@example.c om",
308 Delegatee: "user:conflicts-with-rule-5@example.c om",
309 Audience: makeSet("group:abc", "user:def@exampl e.com"),
310 Services: makeSet("service:unknown"),
311 })
312 So(err, ShouldErrLike, `ambiguous request, multiple dele gation rules match ("rule 4", "rule 5")`)
313 So(res, ShouldBeNil)
314 })
315 })
316 }
317
318 func loadConfig(text string) (*DelegationConfig, error) {
319 cfg := &admin.DelegationPermissions{}
320 err := proto.UnmarshalText(text, cfg)
321 if err != nil {
322 return nil, err
323 }
324 blob, err := proto.Marshal(cfg)
325 if err != nil {
326 return nil, err
327 }
328 c := &DelegationConfig{Config: blob}
329 if err := c.Initialize(); err != nil {
330 return nil, err
331 }
332 return c, nil
333 }
334
335 func makeSet(ident ...string) *identityset.Set {
336 s, err := identityset.FromStrings(ident, nil)
337 if err != nil {
338 panic(err)
339 }
340 return s
341 }
OLDNEW
« no previous file with comments | « tokenserver/appengine/delegation/config.go ('k') | tokenserver/appengine/delegation/rpc_import_delegation_configs.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698