8
jc "github.com/juju/testing/checkers"
11
"gopkg.in/macaroon.v1"
13
"gopkg.in/macaroon-bakery.v1/bakery"
14
"gopkg.in/macaroon-bakery.v1/bakery/checkers"
17
type CheckersSuite struct{}
19
var _ = gc.Suite(&CheckersSuite{})
21
// Freeze time for the tests.
22
var now = func() time.Time {
23
now, err := time.Parse(time.RFC3339Nano, "2006-01-02T15:04:05.123Z")
27
*checkers.TimeNow = func() time.Time {
33
type checkTest struct {
36
expectCause func(err error) bool
39
var isCaveatNotRecognized = errgo.Is(checkers.ErrCaveatNotRecognized)
41
var checkerTests = []struct {
43
checker bakery.FirstPartyChecker
46
about: "empty MultiChecker",
47
checker: checkers.New(),
50
expectError: `caveat "something" not satisfied: caveat not recognized`,
51
expectCause: isCaveatNotRecognized,
54
expectError: `cannot parse caveat "": empty caveat`,
55
expectCause: isCaveatNotRecognized,
58
expectError: `cannot parse caveat " hello": caveat starts with space character`,
59
expectCause: isCaveatNotRecognized,
62
about: "MultiChecker with some values",
63
checker: checkers.New(
64
argChecker("a", "aval"),
65
argChecker("b", "bval"),
73
expectError: `caveat "a wrong" not satisfied: wrong arg`,
74
expectCause: errgo.Is(errWrongArg),
77
about: "MultiChecker with several of the same condition",
78
checker: checkers.New(
79
argChecker("a", "aval"),
80
argChecker("a", "bval"),
84
expectError: `caveat "a aval" not satisfied: wrong arg`,
85
expectCause: errgo.Is(errWrongArg),
88
expectError: `caveat "a bval" not satisfied: wrong arg`,
89
expectCause: errgo.Is(errWrongArg),
92
about: "nested MultiChecker",
93
checker: checkers.New(
94
argChecker("a", "aval"),
95
argChecker("b", "bval"),
97
argChecker("c", "cval"),
99
argChecker("d", "dval"),
101
argChecker("e", "eval"),
104
checks: []checkTest{{
116
expectError: `caveat "a wrong" not satisfied: wrong arg`,
117
expectCause: errgo.Is(errWrongArg),
120
expectError: `caveat "c wrong" not satisfied: wrong arg`,
121
expectCause: errgo.Is(errWrongArg),
124
expectError: `caveat "d wrong" not satisfied: wrong arg`,
125
expectCause: errgo.Is(errWrongArg),
127
caveat: "f something",
128
expectError: `caveat "f something" not satisfied: caveat not recognized`,
129
expectCause: isCaveatNotRecognized,
132
about: "Map with no items",
133
checker: checkers.New(
136
checks: []checkTest{{
138
expectError: `caveat "a aval" not satisfied: caveat not recognized`,
139
expectCause: isCaveatNotRecognized,
142
about: "Map with some values",
143
checker: checkers.New(
145
"a": argChecker("a", "aval").Check,
146
"b": argChecker("b", "bval").Check,
149
checks: []checkTest{{
155
expectError: `caveat "a wrong" not satisfied: wrong arg`,
156
expectCause: errgo.Is(errWrongArg),
159
expectError: `caveat "b wrong" not satisfied: wrong arg`,
160
expectCause: errgo.Is(errWrongArg),
163
about: "time within limit",
164
checker: checkers.New(
167
checks: []checkTest{{
168
caveat: checkers.TimeBeforeCaveat(now.Add(1)).Condition,
170
caveat: checkers.TimeBeforeCaveat(now).Condition,
171
expectError: `caveat "time-before 2006-01-02T15:04:05.123Z" not satisfied: macaroon has expired`,
173
caveat: checkers.TimeBeforeCaveat(now.Add(-1)).Condition,
174
expectError: `caveat "time-before 2006-01-02T15:04:05.122999999Z" not satisfied: macaroon has expired`,
176
caveat: `time-before bad-date`,
177
expectError: `caveat "time-before bad-date" not satisfied: parsing time "bad-date" as "2006-01-02T15:04:05.999999999Z07:00": cannot parse "bad-date" as "2006"`,
179
caveat: checkers.TimeBeforeCaveat(now).Condition + " ",
180
expectError: `caveat "time-before 2006-01-02T15:04:05.123Z " not satisfied: parsing time "2006-01-02T15:04:05.123Z ": extra text: `,
183
about: "declared, no entries",
184
checker: checkers.New(checkers.Declared{}),
185
checks: []checkTest{{
186
caveat: checkers.DeclaredCaveat("a", "aval").Condition,
187
expectError: `caveat "declared a aval" not satisfied: got a=null, expected "aval"`,
189
caveat: checkers.CondDeclared,
190
expectError: `caveat "declared" not satisfied: declared caveat has no value`,
193
about: "declared, some entries",
194
checker: checkers.New(checkers.Declared{
199
checks: []checkTest{{
200
caveat: checkers.DeclaredCaveat("a", "aval").Condition,
202
caveat: checkers.DeclaredCaveat("b", "bval").Condition,
204
caveat: checkers.DeclaredCaveat("spc", " a b").Condition,
206
caveat: checkers.DeclaredCaveat("a", "bval").Condition,
207
expectError: `caveat "declared a bval" not satisfied: got a="aval", expected "bval"`,
209
caveat: checkers.DeclaredCaveat("a", " aval").Condition,
210
expectError: `caveat "declared a aval" not satisfied: got a="aval", expected " aval"`,
212
caveat: checkers.DeclaredCaveat("spc", "a b").Condition,
213
expectError: `caveat "declared spc a b" not satisfied: got spc=" a b", expected "a b"`,
215
caveat: checkers.DeclaredCaveat("", "a b").Condition,
216
expectError: `caveat "error invalid caveat 'declared' key \\"\\"" not satisfied: bad caveat`,
218
caveat: checkers.DeclaredCaveat("a b", "a b").Condition,
219
expectError: `caveat "error invalid caveat 'declared' key \\"a b\\"" not satisfied: bad caveat`,
222
about: "error caveat",
223
checker: checkers.New(),
224
checks: []checkTest{{
225
caveat: checkers.ErrorCaveatf("").Condition,
226
expectError: `caveat "error " not satisfied: bad caveat`,
228
caveat: checkers.ErrorCaveatf("something %d", 134).Condition,
229
expectError: `caveat "error something 134" not satisfied: bad caveat`,
232
about: "error caveat overrides other",
233
checker: checkers.New(argChecker("error", "something")),
234
checks: []checkTest{{
235
caveat: checkers.ErrorCaveatf("something").Condition,
236
expectError: `caveat "error something" not satisfied: bad caveat`,
240
var errWrongArg = errgo.New("wrong arg")
242
func argChecker(expectCond, checkArg string) checkers.Checker {
243
return checkers.CheckerFunc{
244
Condition_: expectCond,
245
Check_: func(cond, arg string) error {
246
if cond != expectCond {
247
panic(fmt.Errorf("got condition %q want %q", cond, expectCond))
257
func (s *CheckersSuite) TestCheckers(c *gc.C) {
258
for i, test := range checkerTests {
259
c.Logf("test %d: %s", i, test.about)
260
for j, check := range test.checks {
261
c.Logf("\tcheck %d", j)
262
err := test.checker.CheckFirstPartyCaveat(check.caveat)
263
if check.expectError != "" {
264
c.Assert(err, gc.ErrorMatches, check.expectError)
265
if check.expectCause == nil {
266
check.expectCause = errgo.Any
268
c.Assert(check.expectCause(errgo.Cause(err)), gc.Equals, true)
270
c.Assert(err, gc.IsNil)
276
func (s *CheckersSuite) TestClientIPAddrCaveat(c *gc.C) {
277
cav := checkers.ClientIPAddrCaveat(net.IP{127, 0, 0, 1})
278
c.Assert(cav, gc.Equals, checkers.Caveat{
279
Condition: "client-ip-addr 127.0.0.1",
281
cav = checkers.ClientIPAddrCaveat(net.ParseIP("2001:4860:0:2001::68"))
282
c.Assert(cav, gc.Equals, checkers.Caveat{
283
Condition: "client-ip-addr 2001:4860:0:2001::68",
285
cav = checkers.ClientIPAddrCaveat(nil)
286
c.Assert(cav, gc.Equals, checkers.Caveat{
287
Condition: "error bad IP address []",
289
cav = checkers.ClientIPAddrCaveat(net.IP{123, 3})
290
c.Assert(cav, gc.Equals, checkers.Caveat{
291
Condition: "error bad IP address [123 3]",
295
func (s *CheckersSuite) TestClientOriginCaveat(c *gc.C) {
296
cav := checkers.ClientOriginCaveat("")
297
c.Assert(cav, gc.Equals, checkers.Caveat{
298
Condition: "origin ",
300
cav = checkers.ClientOriginCaveat("somewhere")
301
c.Assert(cav, gc.Equals, checkers.Caveat{
302
Condition: "origin somewhere",
306
var inferDeclaredTests = []struct {
308
caveats [][]checkers.Caveat
309
expect checkers.Declared
311
about: "no macaroons",
312
expect: checkers.Declared{},
314
about: "single macaroon with one declaration",
315
caveats: [][]checkers.Caveat{{{
316
Condition: "declared foo bar",
318
expect: checkers.Declared{
322
about: "only one argument to declared",
323
caveats: [][]checkers.Caveat{{{
324
Condition: "declared foo",
326
expect: checkers.Declared{},
328
about: "spaces in value",
329
caveats: [][]checkers.Caveat{{{
330
Condition: "declared foo bar bloggs",
332
expect: checkers.Declared{
336
about: "attribute with declared prefix",
337
caveats: [][]checkers.Caveat{{{
338
Condition: "declaredccf foo",
340
expect: checkers.Declared{},
342
about: "several macaroons with different declares",
343
caveats: [][]checkers.Caveat{{
344
checkers.DeclaredCaveat("a", "aval"),
345
checkers.DeclaredCaveat("b", "bval"),
347
checkers.DeclaredCaveat("c", "cval"),
348
checkers.DeclaredCaveat("d", "dval"),
350
expect: checkers.Declared{
357
about: "duplicate values",
358
caveats: [][]checkers.Caveat{{
359
checkers.DeclaredCaveat("a", "aval"),
360
checkers.DeclaredCaveat("a", "aval"),
361
checkers.DeclaredCaveat("b", "bval"),
363
checkers.DeclaredCaveat("a", "aval"),
364
checkers.DeclaredCaveat("b", "bval"),
365
checkers.DeclaredCaveat("c", "cval"),
366
checkers.DeclaredCaveat("d", "dval"),
368
expect: checkers.Declared{
375
about: "conflicting values",
376
caveats: [][]checkers.Caveat{{
377
checkers.DeclaredCaveat("a", "aval"),
378
checkers.DeclaredCaveat("a", "conflict"),
379
checkers.DeclaredCaveat("b", "bval"),
381
checkers.DeclaredCaveat("a", "conflict"),
382
checkers.DeclaredCaveat("b", "another conflict"),
383
checkers.DeclaredCaveat("c", "cval"),
384
checkers.DeclaredCaveat("d", "dval"),
386
expect: checkers.Declared{
391
about: "third party caveats ignored",
392
caveats: [][]checkers.Caveat{{{
393
Condition: "declared a no conflict",
394
Location: "location",
396
checkers.DeclaredCaveat("a", "aval"),
398
expect: checkers.Declared{
402
about: "unparseable caveats ignored",
403
caveats: [][]checkers.Caveat{{{
406
checkers.DeclaredCaveat("a", "aval"),
408
expect: checkers.Declared{
413
func (*CheckersSuite) TestInferDeclared(c *gc.C) {
414
for i, test := range inferDeclaredTests {
415
c.Logf("test %d: %s", i, test.about)
416
ms := make(macaroon.Slice, len(test.caveats))
417
for i, caveats := range test.caveats {
418
m, err := macaroon.New(nil, fmt.Sprint(i), "")
419
c.Assert(err, gc.IsNil)
420
for _, cav := range caveats {
421
if cav.Location == "" {
422
m.AddFirstPartyCaveat(cav.Condition)
424
m.AddThirdPartyCaveat(nil, cav.Condition, cav.Location)
429
c.Assert(checkers.InferDeclared(ms), jc.DeepEquals, test.expect)
433
var operationCheckerTests = []struct {
435
caveat checkers.Caveat
436
oc checkers.OperationChecker
439
about: "allowed operation",
440
caveat: checkers.AllowCaveat("op1", "op2", "op3"),
441
oc: checkers.OperationChecker("op1"),
443
about: "not denied oc",
444
caveat: checkers.DenyCaveat("op1", "op2", "op3"),
445
oc: checkers.OperationChecker("op4"),
447
about: "not allowed oc",
448
caveat: checkers.AllowCaveat("op1", "op2", "op3"),
449
oc: checkers.OperationChecker("op4"),
450
expectError: "op4 not allowed",
453
caveat: checkers.DenyCaveat("op1", "op2", "op3"),
454
oc: checkers.OperationChecker("op1"),
455
expectError: "op1 not allowed",
457
about: "unrecognised caveat",
458
caveat: checkers.ErrorCaveatf("unrecognized"),
459
oc: checkers.OperationChecker("op1"),
460
expectError: "caveat not recognized",
462
about: "empty deny caveat",
463
caveat: checkers.DenyCaveat(),
464
oc: checkers.OperationChecker("op1"),
467
func (*CheckersSuite) TestOperationChecker(c *gc.C) {
468
for i, test := range operationCheckerTests {
469
c.Logf("%d: %s", i, test.about)
470
cond, arg, err := checkers.ParseCaveat(test.caveat.Condition)
471
c.Assert(err, gc.IsNil)
472
c.Assert(test.oc.Condition(), gc.Equals, "")
473
err = test.oc.Check(cond, arg)
474
if test.expectError == "" {
475
c.Assert(err, gc.IsNil)
478
c.Assert(err, gc.ErrorMatches, test.expectError)
482
var operationsCheckerTests = []struct {
484
caveat checkers.Caveat
485
oc checkers.OperationsChecker
488
about: "all allowed",
489
caveat: checkers.AllowCaveat("op1", "op2", "op4", "op3"),
490
oc: checkers.OperationsChecker{"op1", "op3", "op2"},
492
about: "none denied",
493
caveat: checkers.DenyCaveat("op1", "op2"),
494
oc: checkers.OperationsChecker{"op3", "op4"},
496
about: "one not allowed",
497
caveat: checkers.AllowCaveat("op1", "op2"),
498
oc: checkers.OperationsChecker{"op1", "op3"},
499
expectError: `op3 not allowed`,
502
caveat: checkers.DenyCaveat("op1", "op2"),
503
oc: checkers.OperationsChecker{"op4", "op5", "op2"},
504
expectError: `op2 not allowed`,
506
about: "no operations, allow caveat",
507
caveat: checkers.AllowCaveat("op1"),
508
oc: checkers.OperationsChecker{},
509
expectError: `op1 not allowed`,
511
about: "no operations, deny caveat",
512
caveat: checkers.DenyCaveat("op1"),
513
oc: checkers.OperationsChecker{},
515
about: "no operations, empty allow caveat",
516
caveat: checkers.Caveat{
517
Condition: checkers.CondAllow,
519
oc: checkers.OperationsChecker{},
520
expectError: `no operations allowed`,
523
func (*CheckersSuite) TestOperationsChecker(c *gc.C) {
524
for i, test := range operationsCheckerTests {
525
c.Logf("%d: %s", i, test.about)
526
cond, arg, err := checkers.ParseCaveat(test.caveat.Condition)
527
c.Assert(err, gc.IsNil)
528
c.Assert(test.oc.Condition(), gc.Equals, "")
529
err = test.oc.Check(cond, arg)
530
if test.expectError == "" {
531
c.Assert(err, gc.IsNil)
534
c.Assert(err, gc.ErrorMatches, test.expectError)
538
var operationErrorCaveatTests = []struct {
540
caveat checkers.Caveat
541
expectCondition string
543
about: "empty allow",
544
caveat: checkers.AllowCaveat(),
545
expectCondition: "error no operations allowed",
547
about: "allow: invalid operation name",
548
caveat: checkers.AllowCaveat("op1", "operation number 2"),
549
expectCondition: `error invalid operation name "operation number 2"`,
551
about: "deny: invalid operation name",
552
caveat: checkers.DenyCaveat("op1", "operation number 2"),
553
expectCondition: `error invalid operation name "operation number 2"`,
556
func (*CheckersSuite) TestOperationErrorCaveatTest(c *gc.C) {
557
for i, test := range operationErrorCaveatTests {
558
c.Logf("%d: %s", i, test.about)
559
c.Assert(test.caveat.Condition, gc.Matches, test.expectCondition)