1package vault
2
3import (
4	"context"
5	"reflect"
6	"sync"
7	"testing"
8	"time"
9
10	"github.com/hashicorp/vault/helper/namespace"
11	"github.com/hashicorp/vault/sdk/logical"
12)
13
14func TestACL_NewACL(t *testing.T) {
15	t.Run("root-ns", func(t *testing.T) {
16		t.Parallel()
17		testNewACL(t, namespace.RootNamespace)
18	})
19}
20
21func testNewACL(t *testing.T, ns *namespace.Namespace) {
22	ctx := namespace.ContextWithNamespace(context.Background(), ns)
23	policy := []*Policy{&Policy{Name: "root"}}
24	_, err := NewACL(ctx, policy)
25	switch ns.ID {
26	case namespace.RootNamespaceID:
27		if err != nil {
28			t.Fatal(err)
29		}
30	default:
31		if err == nil {
32			t.Fatal("expected an error")
33		}
34	}
35}
36
37func TestACL_MFAMethods(t *testing.T) {
38	t.Run("root-ns", func(t *testing.T) {
39		t.Parallel()
40		testACLMFAMethods(t, namespace.RootNamespace)
41	})
42}
43
44func testACLMFAMethods(t *testing.T, ns *namespace.Namespace) {
45	mfaRules := `
46path "secret/foo/*" {
47	mfa_methods = ["mfa_method_1", "mfa_method_2", "mfa_method_3"]
48}
49path "secret/exact/path" {
50	mfa_methods = ["mfa_method_4", "mfa_method_5"]
51}
52path "secret/split/definition" {
53	mfa_methods = ["mfa_method_6", "mfa_method_7"]
54}
55path "secret/split/definition" {
56	mfa_methods = ["mfa_method_7", "mfa_method_8", "mfa_method_9"]
57}
58	`
59
60	policy, err := ParseACLPolicy(ns, mfaRules)
61	if err != nil {
62		t.Fatal(err)
63	}
64
65	ctx := namespace.ContextWithNamespace(context.Background(), ns)
66	acl, err := NewACL(ctx, []*Policy{policy})
67	if err != nil {
68		t.Fatal(err)
69	}
70
71	request := &logical.Request{
72		Operation: logical.UpdateOperation,
73		Path:      "secret/foo/testing/glob/pattern",
74	}
75
76	actual := acl.AllowOperation(ctx, request, false).MFAMethods
77	expected := []string{"mfa_method_1", "mfa_method_2", "mfa_method_3"}
78
79	if !reflect.DeepEqual(expected, actual) {
80		t.Fatalf("bad: MFA methods; expected: %#v\n actual: %#v\n", expected, actual)
81	}
82
83	request.Path = "secret/exact/path"
84	actual = acl.AllowOperation(ctx, request, false).MFAMethods
85	expected = []string{"mfa_method_4", "mfa_method_5"}
86
87	if !reflect.DeepEqual(expected, actual) {
88		t.Fatalf("bad: MFA methods; expected: %#v\n actual: %#v\n", expected, actual)
89	}
90
91	request.Path = "secret/split/definition"
92	actual = acl.AllowOperation(ctx, request, false).MFAMethods
93	expected = []string{"mfa_method_6", "mfa_method_7", "mfa_method_8", "mfa_method_9"}
94
95	if !reflect.DeepEqual(expected, actual) {
96		t.Fatalf("bad: MFA methods; expected: %#v\n actual: %#v\n", expected, actual)
97	}
98}
99
100func TestACL_Capabilities(t *testing.T) {
101	t.Run("root-ns", func(t *testing.T) {
102		t.Parallel()
103		policy := []*Policy{&Policy{Name: "root"}}
104		ctx := namespace.RootContext(nil)
105		acl, err := NewACL(ctx, policy)
106		if err != nil {
107			t.Fatalf("err: %v", err)
108		}
109
110		actual := acl.Capabilities(ctx, "any/path")
111		expected := []string{"root"}
112		if !reflect.DeepEqual(actual, expected) {
113			t.Fatalf("bad: got\n%#v\nexpected\n%#v\n", actual, expected)
114		}
115		testACLCapabilities(t, namespace.RootNamespace)
116	})
117}
118
119func testACLCapabilities(t *testing.T, ns *namespace.Namespace) {
120	// Create the root policy ACL
121	ctx := namespace.ContextWithNamespace(context.Background(), ns)
122	policy, err := ParseACLPolicy(ns, aclPolicy)
123	if err != nil {
124		t.Fatalf("err: %v", err)
125	}
126
127	acl, err := NewACL(ctx, []*Policy{policy})
128	if err != nil {
129		t.Fatalf("err: %v", err)
130	}
131
132	actual := acl.Capabilities(ctx, "dev")
133	expected := []string{"deny"}
134	if !reflect.DeepEqual(actual, expected) {
135		t.Fatalf("bad: path: %s\ngot\n%#v\nexpected\n%#v\n", "deny", actual, expected)
136	}
137
138	actual = acl.Capabilities(ctx, "dev/")
139	expected = []string{"sudo", "read", "list", "update", "delete", "create"}
140	if !reflect.DeepEqual(actual, expected) {
141		t.Fatalf("bad: path: %s\ngot\n%#v\nexpected\n%#v\n", "dev/", actual, expected)
142	}
143
144	actual = acl.Capabilities(ctx, "stage/aws/test")
145	expected = []string{"sudo", "read", "list", "update"}
146	if !reflect.DeepEqual(actual, expected) {
147		t.Fatalf("bad: path: %s\ngot\n%#v\nexpected\n%#v\n", "stage/aws/test", actual, expected)
148	}
149}
150
151func TestACL_Root(t *testing.T) {
152	t.Run("root-ns", func(t *testing.T) {
153		t.Parallel()
154		testACLRoot(t, namespace.RootNamespace)
155	})
156}
157
158func testACLRoot(t *testing.T, ns *namespace.Namespace) {
159	// Create the root policy ACL. Always create on root namespace regardless of
160	// which namespace to ACL check on.
161	policy := []*Policy{&Policy{Name: "root"}}
162	acl, err := NewACL(namespace.RootContext(nil), policy)
163	if err != nil {
164		t.Fatalf("err: %v", err)
165	}
166
167	request := new(logical.Request)
168	request.Operation = logical.UpdateOperation
169	request.Path = "sys/mount/foo"
170	ctx := namespace.ContextWithNamespace(context.Background(), ns)
171
172	authResults := acl.AllowOperation(ctx, request, false)
173	if !authResults.RootPrivs {
174		t.Fatalf("expected root")
175	}
176	if !authResults.Allowed {
177		t.Fatalf("expected permissions")
178	}
179}
180
181func TestACL_Single(t *testing.T) {
182	t.Run("root-ns", func(t *testing.T) {
183		t.Parallel()
184		testACLSingle(t, namespace.RootNamespace)
185	})
186}
187
188func testACLSingle(t *testing.T, ns *namespace.Namespace) {
189	policy, err := ParseACLPolicy(ns, aclPolicy)
190	if err != nil {
191		t.Fatalf("err: %v", err)
192	}
193
194	ctx := namespace.ContextWithNamespace(context.Background(), ns)
195	acl, err := NewACL(ctx, []*Policy{policy})
196	if err != nil {
197		t.Fatalf("err: %v", err)
198	}
199
200	// Type of operation is not important here as we only care about checking
201	// sudo/root
202	ctx = namespace.ContextWithNamespace(context.Background(), ns)
203	request := new(logical.Request)
204	request.Operation = logical.ReadOperation
205	request.Path = "sys/mount/foo"
206
207	authResults := acl.AllowOperation(ctx, request, false)
208	if authResults.RootPrivs {
209		t.Fatalf("unexpected root")
210	}
211
212	type tcase struct {
213		op        logical.Operation
214		path      string
215		allowed   bool
216		rootPrivs bool
217	}
218	tcases := []tcase{
219		{logical.ReadOperation, "root", false, false},
220		{logical.HelpOperation, "root", true, false},
221
222		{logical.ReadOperation, "dev/foo", true, true},
223		{logical.UpdateOperation, "dev/foo", true, true},
224
225		{logical.DeleteOperation, "stage/foo", true, false},
226		{logical.ListOperation, "stage/aws/foo", true, true},
227		{logical.UpdateOperation, "stage/aws/foo", true, true},
228		{logical.UpdateOperation, "stage/aws/policy/foo", true, true},
229
230		{logical.DeleteOperation, "prod/foo", false, false},
231		{logical.UpdateOperation, "prod/foo", false, false},
232		{logical.ReadOperation, "prod/foo", true, false},
233		{logical.ListOperation, "prod/foo", true, false},
234		{logical.ReadOperation, "prod/aws/foo", false, false},
235
236		{logical.ReadOperation, "foo/bar", true, true},
237		{logical.ListOperation, "foo/bar", false, true},
238		{logical.UpdateOperation, "foo/bar", false, true},
239		{logical.CreateOperation, "foo/bar", true, true},
240
241		// Path segment wildcards
242		{logical.ReadOperation, "test/foo/bar/segment", false, false},
243		{logical.ReadOperation, "test/foo/segment", true, false},
244		{logical.ReadOperation, "test/bar/segment", true, false},
245		{logical.ReadOperation, "test/segment/at/frond", false, false},
246		{logical.ReadOperation, "test/segment/at/front", true, false},
247		{logical.ReadOperation, "test/segment/at/end/foo", true, false},
248		{logical.ReadOperation, "test/segment/at/end/foo/", false, false},
249		{logical.ReadOperation, "test/segment/at/end/v2/foo/", true, false},
250		{logical.ReadOperation, "test/segment/wildcard/at/foo/", true, false},
251		{logical.ReadOperation, "test/segment/wildcard/at/end", true, false},
252		{logical.ReadOperation, "test/segment/wildcard/at/end/", true, false},
253
254		// Path segment wildcards vs glob
255		{logical.ReadOperation, "1/2/3/4", false, false},
256		{logical.ReadOperation, "1/2/3", true, false},
257		{logical.UpdateOperation, "1/2/3", false, false},
258		{logical.UpdateOperation, "1/2/3/4", true, false},
259		{logical.CreateOperation, "1/2/3/4/5", true, false},
260	}
261
262	for _, tc := range tcases {
263		ctx := namespace.ContextWithNamespace(context.Background(), ns)
264		request := new(logical.Request)
265		request.Operation = tc.op
266		request.Path = tc.path
267
268		authResults := acl.AllowOperation(ctx, request, false)
269		if authResults.Allowed != tc.allowed {
270			t.Fatalf("bad: case %#v: %v, %v", tc, authResults.Allowed, authResults.RootPrivs)
271		}
272		if authResults.RootPrivs != tc.rootPrivs {
273			t.Fatalf("bad: case %#v: %v, %v", tc, authResults.Allowed, authResults.RootPrivs)
274		}
275	}
276}
277
278func TestACL_Layered(t *testing.T) {
279	t.Run("root-ns", func(t *testing.T) {
280		t.Parallel()
281		policy1, err := ParseACLPolicy(namespace.RootNamespace, aclPolicy)
282		if err != nil {
283			t.Fatalf("err: %v", err)
284		}
285
286		policy2, err := ParseACLPolicy(namespace.RootNamespace, aclPolicy2)
287		if err != nil {
288			t.Fatalf("err: %v", err)
289		}
290		acl, err := NewACL(namespace.RootContext(nil), []*Policy{policy1, policy2})
291		if err != nil {
292			t.Fatalf("err: %v", err)
293		}
294		testLayeredACL(t, acl, namespace.RootNamespace)
295	})
296}
297
298func testLayeredACL(t *testing.T, acl *ACL, ns *namespace.Namespace) {
299	// Type of operation is not important here as we only care about checking
300	// sudo/root
301	ctx := namespace.ContextWithNamespace(context.Background(), ns)
302	request := new(logical.Request)
303	request.Operation = logical.ReadOperation
304	request.Path = "sys/mount/foo"
305
306	authResults := acl.AllowOperation(ctx, request, false)
307	if authResults.RootPrivs {
308		t.Fatalf("unexpected root")
309	}
310
311	type tcase struct {
312		op        logical.Operation
313		path      string
314		allowed   bool
315		rootPrivs bool
316	}
317	tcases := []tcase{
318		{logical.ReadOperation, "root", false, false},
319		{logical.HelpOperation, "root", true, false},
320
321		{logical.ReadOperation, "dev/foo", true, true},
322		{logical.UpdateOperation, "dev/foo", true, true},
323		{logical.ReadOperation, "dev/hide/foo", false, false},
324		{logical.UpdateOperation, "dev/hide/foo", false, false},
325
326		{logical.DeleteOperation, "stage/foo", true, false},
327		{logical.ListOperation, "stage/aws/foo", true, true},
328		{logical.UpdateOperation, "stage/aws/foo", true, true},
329		{logical.UpdateOperation, "stage/aws/policy/foo", false, false},
330
331		{logical.DeleteOperation, "prod/foo", true, false},
332		{logical.UpdateOperation, "prod/foo", true, false},
333		{logical.ReadOperation, "prod/foo", true, false},
334		{logical.ListOperation, "prod/foo", true, false},
335		{logical.ReadOperation, "prod/aws/foo", false, false},
336
337		{logical.ReadOperation, "sys/status", false, false},
338		{logical.UpdateOperation, "sys/seal", true, true},
339
340		{logical.ReadOperation, "foo/bar", false, false},
341		{logical.ListOperation, "foo/bar", false, false},
342		{logical.UpdateOperation, "foo/bar", false, false},
343		{logical.CreateOperation, "foo/bar", false, false},
344	}
345
346	for _, tc := range tcases {
347		ctx := namespace.ContextWithNamespace(context.Background(), ns)
348		request := new(logical.Request)
349		request.Operation = tc.op
350		request.Path = tc.path
351
352		authResults := acl.AllowOperation(ctx, request, false)
353		if authResults.Allowed != tc.allowed {
354			t.Fatalf("bad: case %#v: %v, %v", tc, authResults.Allowed, authResults.RootPrivs)
355		}
356		if authResults.RootPrivs != tc.rootPrivs {
357			t.Fatalf("bad: case %#v: %v, %v", tc, authResults.Allowed, authResults.RootPrivs)
358		}
359	}
360}
361
362func TestACL_PolicyMerge(t *testing.T) {
363	t.Run("root-ns", func(t *testing.T) {
364		t.Parallel()
365		testACLPolicyMerge(t, namespace.RootNamespace)
366	})
367}
368
369func testACLPolicyMerge(t *testing.T, ns *namespace.Namespace) {
370	policy, err := ParseACLPolicy(ns, mergingPolicies)
371	if err != nil {
372		t.Fatalf("err: %v", err)
373	}
374	ctx := namespace.ContextWithNamespace(context.Background(), ns)
375	acl, err := NewACL(ctx, []*Policy{policy})
376	if err != nil {
377		t.Fatalf("err: %v", err)
378	}
379
380	type tcase struct {
381		path           string
382		minWrappingTTL *time.Duration
383		maxWrappingTTL *time.Duration
384		allowed        map[string][]interface{}
385		denied         map[string][]interface{}
386		required       []string
387	}
388
389	createDuration := func(seconds int) *time.Duration {
390		ret := time.Duration(seconds) * time.Second
391		return &ret
392	}
393
394	tcases := []tcase{
395		{"foo/bar", nil, nil, nil, map[string][]interface{}{"zip": []interface{}{}, "baz": []interface{}{}}, []string{"baz"}},
396		{"hello/universe", createDuration(50), createDuration(200), map[string][]interface{}{"foo": []interface{}{}, "bar": []interface{}{}}, nil, []string{"foo", "bar"}},
397		{"allow/all", nil, nil, map[string][]interface{}{"*": []interface{}{}, "test": []interface{}{}, "test1": []interface{}{"foo"}}, nil, nil},
398		{"allow/all1", nil, nil, map[string][]interface{}{"*": []interface{}{}, "test": []interface{}{}, "test1": []interface{}{"foo"}}, nil, nil},
399		{"deny/all", nil, nil, nil, map[string][]interface{}{"*": []interface{}{}, "test": []interface{}{}}, nil},
400		{"deny/all1", nil, nil, nil, map[string][]interface{}{"*": []interface{}{}, "test": []interface{}{}}, nil},
401		{"value/merge", nil, nil, map[string][]interface{}{"test": []interface{}{3, 4, 1, 2}}, map[string][]interface{}{"test": []interface{}{3, 4, 1, 2}}, nil},
402		{"value/empty", nil, nil, map[string][]interface{}{"empty": []interface{}{}}, map[string][]interface{}{"empty": []interface{}{}}, nil},
403	}
404
405	for _, tc := range tcases {
406		policyPath := ns.Path + tc.path
407		raw, ok := acl.exactRules.Get(policyPath)
408		if !ok {
409			t.Fatalf("Could not find acl entry for path %s", policyPath)
410		}
411
412		p := raw.(*ACLPermissions)
413		if !reflect.DeepEqual(tc.allowed, p.AllowedParameters) {
414			t.Fatalf("Allowed parameters did not match, Expected: %#v, Got: %#v", tc.allowed, p.AllowedParameters)
415		}
416		if !reflect.DeepEqual(tc.denied, p.DeniedParameters) {
417			t.Fatalf("Denied parameters did not match, Expected: %#v, Got: %#v", tc.denied, p.DeniedParameters)
418		}
419		if !reflect.DeepEqual(tc.required, p.RequiredParameters) {
420			t.Fatalf("Required parameters did not match, Expected: %#v, Got: %#v", tc.required, p.RequiredParameters)
421		}
422		if tc.minWrappingTTL != nil && *tc.minWrappingTTL != p.MinWrappingTTL {
423			t.Fatalf("Min wrapping TTL did not match, Expected: %#v, Got: %#v", tc.minWrappingTTL, p.MinWrappingTTL)
424		}
425		if tc.minWrappingTTL != nil && *tc.maxWrappingTTL != p.MaxWrappingTTL {
426			t.Fatalf("Max wrapping TTL did not match, Expected: %#v, Got: %#v", tc.maxWrappingTTL, p.MaxWrappingTTL)
427		}
428	}
429}
430
431func TestACL_AllowOperation(t *testing.T) {
432	t.Run("root-ns", func(t *testing.T) {
433		t.Parallel()
434		testACLAllowOperation(t, namespace.RootNamespace)
435	})
436}
437
438func testACLAllowOperation(t *testing.T, ns *namespace.Namespace) {
439	policy, err := ParseACLPolicy(ns, permissionsPolicy)
440	if err != nil {
441		t.Fatalf("err: %v", err)
442	}
443	ctx := namespace.ContextWithNamespace(context.Background(), ns)
444	acl, err := NewACL(ctx, []*Policy{policy})
445	if err != nil {
446		t.Fatalf("err: %v", err)
447	}
448	toperations := []logical.Operation{
449		logical.UpdateOperation,
450		logical.CreateOperation,
451	}
452	type tcase struct {
453		path        string
454		wrappingTTL *time.Duration
455		parameters  []string
456		allowed     bool
457	}
458
459	createDuration := func(seconds int) *time.Duration {
460		ret := time.Duration(seconds) * time.Second
461		return &ret
462	}
463
464	tcases := []tcase{
465		{"dev/ops", nil, []string{"zip"}, true},
466		{"foo/bar", nil, []string{"zap"}, false},
467		{"foo/bar", nil, []string{"zip"}, false},
468		{"foo/bar", createDuration(50), []string{"zip"}, false},
469		{"foo/bar", createDuration(450), []string{"zip"}, false},
470		{"foo/bar", createDuration(350), []string{"zip"}, true},
471		{"foo/baz", nil, []string{"hello"}, false},
472		{"foo/baz", createDuration(50), []string{"hello"}, false},
473		{"foo/baz", createDuration(450), []string{"hello"}, true},
474		{"foo/baz", nil, []string{"zap"}, false},
475		{"broken/phone", nil, []string{"steve"}, false},
476		{"working/phone", nil, []string{""}, false},
477		{"working/phone", createDuration(450), []string{""}, false},
478		{"working/phone", createDuration(350), []string{""}, true},
479		{"hello/world", nil, []string{"one"}, false},
480		{"tree/fort", nil, []string{"one"}, true},
481		{"tree/fort", nil, []string{"foo"}, false},
482		{"fruit/apple", nil, []string{"pear"}, false},
483		{"fruit/apple", nil, []string{"one"}, false},
484		{"cold/weather", nil, []string{"four"}, true},
485		{"var/aws", nil, []string{"cold", "warm", "kitty"}, false},
486		{"var/req", nil, []string{"cold", "warm", "kitty"}, false},
487		{"var/req", nil, []string{"cold", "warm", "kitty", "foo"}, true},
488	}
489
490	for _, tc := range tcases {
491		request := &logical.Request{
492			Path: tc.path,
493			Data: make(map[string]interface{}),
494		}
495
496		for _, parameter := range tc.parameters {
497			request.Data[parameter] = ""
498		}
499		if tc.wrappingTTL != nil {
500			request.WrapInfo = &logical.RequestWrapInfo{
501				TTL: *tc.wrappingTTL,
502			}
503		}
504		for _, op := range toperations {
505			request.Operation = op
506			ctx := namespace.ContextWithNamespace(context.Background(), ns)
507			authResults := acl.AllowOperation(ctx, request, false)
508			if authResults.Allowed != tc.allowed {
509				t.Fatalf("bad: case %#v: %v", tc, authResults.Allowed)
510			}
511		}
512	}
513}
514
515func TestACL_ValuePermissions(t *testing.T) {
516	t.Run("root-ns", func(t *testing.T) {
517		t.Parallel()
518		testACLValuePermissions(t, namespace.RootNamespace)
519	})
520}
521
522func testACLValuePermissions(t *testing.T, ns *namespace.Namespace) {
523	policy, err := ParseACLPolicy(ns, valuePermissionsPolicy)
524	if err != nil {
525		t.Fatalf("err: %v", err)
526	}
527
528	ctx := namespace.ContextWithNamespace(context.Background(), ns)
529	acl, err := NewACL(ctx, []*Policy{policy})
530	if err != nil {
531		t.Fatalf("err: %v", err)
532	}
533
534	toperations := []logical.Operation{
535		logical.UpdateOperation,
536		logical.CreateOperation,
537	}
538	type tcase struct {
539		path       string
540		parameters []string
541		values     []interface{}
542		allowed    bool
543	}
544
545	tcases := []tcase{
546		{"dev/ops", []string{"allow"}, []interface{}{"good"}, true},
547		{"dev/ops", []string{"allow"}, []interface{}{"bad"}, false},
548		{"foo/bar", []string{"deny"}, []interface{}{"bad"}, false},
549		{"foo/bar", []string{"deny"}, []interface{}{"bad glob"}, false},
550		{"foo/bar", []string{"deny"}, []interface{}{"good"}, true},
551		{"foo/bar", []string{"allow"}, []interface{}{"good"}, true},
552		{"foo/bar", []string{"deny"}, []interface{}{nil}, true},
553		{"foo/bar", []string{"allow"}, []interface{}{nil}, true},
554		{"foo/baz", []string{"aLLow"}, []interface{}{"good"}, true},
555		{"foo/baz", []string{"deny"}, []interface{}{"bad"}, false},
556		{"foo/baz", []string{"deny"}, []interface{}{"good"}, false},
557		{"foo/baz", []string{"allow", "deny"}, []interface{}{"good", "bad"}, false},
558		{"foo/baz", []string{"deny", "allow"}, []interface{}{"good", "bad"}, false},
559		{"foo/baz", []string{"deNy", "allow"}, []interface{}{"bad", "good"}, false},
560		{"foo/baz", []string{"aLLow"}, []interface{}{"bad"}, false},
561		{"foo/baz", []string{"Neither"}, []interface{}{"bad"}, false},
562		{"foo/baz", []string{"allow"}, []interface{}{nil}, false},
563		{"fizz/buzz", []string{"allow_multi"}, []interface{}{"good"}, true},
564		{"fizz/buzz", []string{"allow_multi"}, []interface{}{"good1"}, true},
565		{"fizz/buzz", []string{"allow_multi"}, []interface{}{"good2"}, true},
566		{"fizz/buzz", []string{"allow_multi"}, []interface{}{"glob good2"}, false},
567		{"fizz/buzz", []string{"allow_multi"}, []interface{}{"glob good3"}, true},
568		{"fizz/buzz", []string{"allow_multi"}, []interface{}{"bad"}, false},
569		{"fizz/buzz", []string{"allow_multi"}, []interface{}{"bad"}, false},
570		{"fizz/buzz", []string{"allow_multi", "allow"}, []interface{}{"good1", "good"}, true},
571		{"fizz/buzz", []string{"deny_multi"}, []interface{}{"bad2"}, false},
572		{"fizz/buzz", []string{"deny_multi", "allow_multi"}, []interface{}{"good", "good2"}, false},
573		//	{"test/types", []string{"array"}, []interface{}{[1]string{"good"}}, true},
574		{"test/types", []string{"map"}, []interface{}{map[string]interface{}{"good": "one"}}, true},
575		{"test/types", []string{"map"}, []interface{}{map[string]interface{}{"bad": "one"}}, false},
576		{"test/types", []string{"int"}, []interface{}{1}, true},
577		{"test/types", []string{"int"}, []interface{}{3}, false},
578		{"test/types", []string{"bool"}, []interface{}{false}, true},
579		{"test/types", []string{"bool"}, []interface{}{true}, false},
580		{"test/star", []string{"anything"}, []interface{}{true}, true},
581		{"test/star", []string{"foo"}, []interface{}{true}, true},
582		{"test/star", []string{"bar"}, []interface{}{false}, true},
583		{"test/star", []string{"bar"}, []interface{}{true}, false},
584	}
585
586	for _, tc := range tcases {
587		request := &logical.Request{
588			Path: tc.path,
589			Data: make(map[string]interface{}),
590		}
591		ctx := namespace.ContextWithNamespace(context.Background(), ns)
592
593		for i, parameter := range tc.parameters {
594			request.Data[parameter] = tc.values[i]
595		}
596		for _, op := range toperations {
597			request.Operation = op
598			authResults := acl.AllowOperation(ctx, request, false)
599			if authResults.Allowed != tc.allowed {
600				t.Fatalf("bad: case %#v: %v", tc, authResults.Allowed)
601			}
602		}
603	}
604}
605
606func TestACL_SegmentWildcardPriority(t *testing.T) {
607	ns := namespace.RootNamespace
608	ctx := namespace.ContextWithNamespace(context.Background(), ns)
609	type poltest struct {
610		policy string
611		path   string
612	}
613
614	// These test cases should each have a read rule and an update rule, where
615	// the update rule wins out due to being more specific.
616	poltests := []poltest{
617
618		{
619			// Verify edge conditions.  Here '*' is more specific both because
620			// of first wildcard position (0 vs -1/infinity) and #wildcards.
621			`
622path "+/*" { capabilities = ["read"] }
623path "*" { capabilities = ["update"] }
624`,
625			"foo/bar/bar/baz",
626		},
627		{
628			// Verify edge conditions.  Here '+/*' is less specific because of
629			// first wildcard position.
630			`
631path "+/*" { capabilities = ["read"] }
632path "foo/+/*" { capabilities = ["update"] }
633`,
634			"foo/bar/bar/baz",
635		},
636		{
637			// Verify that more wildcard segments is lower priority.
638			`
639path "foo/+/+/*" { capabilities = ["read"] }
640path "foo/+/bar/baz" { capabilities = ["update"] }
641`,
642			"foo/bar/bar/baz",
643		},
644		{
645			// Verify that more wildcard segments is lower priority.
646			`
647path "foo/+/+/baz" { capabilities = ["read"] }
648path "foo/+/bar/baz" { capabilities = ["update"] }
649`,
650			"foo/bar/bar/baz",
651		},
652		{
653			// Verify that first wildcard position is lower priority.
654			// '(' is used here because it is lexicographically smaller than "+"
655			`
656path "foo/+/(ar/baz" { capabilities = ["read"] }
657path "foo/(ar/+/baz" { capabilities = ["update"] }
658`,
659			"foo/(ar/(ar/baz",
660		},
661
662		{
663			// Verify that a glob has lower priority, even if the prefix is the
664			// same otherwise.
665			`
666path "foo/bar/+/baz*" { capabilities = ["read"] }
667path "foo/bar/+/baz" { capabilities = ["update"] }
668`,
669			"foo/bar/bar/baz",
670		},
671		{
672			// Verify that a shorter prefix has lower priority.
673			`
674path "foo/bar/+/b*" { capabilities = ["read"] }
675path "foo/bar/+/ba*" { capabilities = ["update"] }
676`,
677			"foo/bar/bar/baz",
678		},
679	}
680
681	for i, pt := range poltests {
682		policy, err := ParseACLPolicy(ns, pt.policy)
683		if err != nil {
684			t.Fatalf("err: %v", err)
685		}
686
687		acl, err := NewACL(ctx, []*Policy{policy})
688		if err != nil {
689			t.Fatalf("err: %v", err)
690		}
691
692		request := new(logical.Request)
693		request.Path = pt.path
694
695		request.Operation = logical.UpdateOperation
696		authResults := acl.AllowOperation(ctx, request, false)
697		if !authResults.Allowed {
698			t.Fatalf("bad: case %d %#v: %v", i, pt, authResults.Allowed)
699		}
700
701		request.Operation = logical.ReadOperation
702		authResults = acl.AllowOperation(ctx, request, false)
703		if authResults.Allowed {
704			t.Fatalf("bad: case %d %#v: %v", i, pt, authResults.Allowed)
705		}
706	}
707}
708
709func TestACL_SegmentWildcardPriority_BareMount(t *testing.T) {
710	ns := namespace.RootNamespace
711	ctx := namespace.ContextWithNamespace(context.Background(), ns)
712	type poltest struct {
713		policy    string
714		mountpath string
715		hasperms  bool
716	}
717	// These test cases should have one or more rules and a mount prefix.
718	// hasperms should be true if there are non-deny perms that apply
719	// to the mount prefix or something below it.
720	poltests := []poltest{
721		{
722			`path "+" { capabilities = ["read"] }`,
723			"foo/",
724			true,
725		},
726		{
727			`path "+/*" { capabilities = ["read"] }`,
728			"foo/",
729			true,
730		},
731		{
732			`path "foo/+/+/*" { capabilities = ["read"] }`,
733			"foo/",
734			true,
735		},
736		{
737			`path "foo/+/+/*" { capabilities = ["read"] }`,
738			"foo/bar/",
739			true,
740		},
741		{
742			`path "foo/+/+/*" { capabilities = ["read"] }`,
743			"foo/bar/bar/",
744			true,
745		},
746		{
747			`path "foo/+/+/*" { capabilities = ["read"] }`,
748			"foo/bar/bar/baz/",
749			true,
750		},
751		{
752			`path "foo/+/+/baz" { capabilities = ["read"] }`,
753			"foo/bar/bar/baz/",
754			true,
755		},
756		{
757			`path "foo/+/bar/baz" { capabilities = ["read"] }`,
758			"foo/bar/bar/baz/",
759			true,
760		},
761		{
762			`path "foo/bar/+/baz*" { capabilities = ["read"] }`,
763			"foo/bar/bar/baz/",
764			true,
765		},
766		{
767			`path "foo/bar/+/b*" { capabilities = ["read"] }`,
768			"foo/bar/bar/baz/",
769			true,
770		},
771		{
772			`path "foo/+" { capabilities = ["read"] }`,
773			"foo/",
774			true,
775		},
776	}
777
778	for i, pt := range poltests {
779		policy, err := ParseACLPolicy(ns, pt.policy)
780		if err != nil {
781			t.Fatalf("err: %v", err)
782		}
783
784		acl, err := NewACL(ctx, []*Policy{policy})
785		if err != nil {
786			t.Fatalf("err: %v", err)
787		}
788
789		hasperms := nil != acl.CheckAllowedFromNonExactPaths(pt.mountpath, true)
790		if hasperms != pt.hasperms {
791			t.Fatalf("bad: case %d: %#v", i, pt)
792		}
793
794	}
795}
796
797// NOTE: this test doesn't catch any races ATM
798func TestACL_CreationRace(t *testing.T) {
799	policy, err := ParseACLPolicy(namespace.RootNamespace, valuePermissionsPolicy)
800	if err != nil {
801		t.Fatalf("err: %v", err)
802	}
803
804	var wg sync.WaitGroup
805	stopTime := time.Now().Add(20 * time.Second)
806
807	for i := 0; i < 50; i++ {
808		wg.Add(1)
809		go func() {
810			defer wg.Done()
811			for {
812				if time.Now().After(stopTime) {
813					return
814				}
815				_, err := NewACL(namespace.RootContext(nil), []*Policy{policy})
816				if err != nil {
817					t.Fatalf("err: %v", err)
818				}
819			}
820		}()
821	}
822
823	wg.Wait()
824}
825
826var tokenCreationPolicy = `
827name = "tokenCreation"
828path "auth/token/create*" {
829	capabilities = ["update", "create", "sudo"]
830}
831`
832
833var aclPolicy = `
834name = "DeV"
835path "dev/*" {
836	policy = "sudo"
837}
838path "stage/*" {
839	policy = "write"
840}
841path "stage/aws/*" {
842	policy = "read"
843	capabilities = ["update", "sudo"]
844}
845path "stage/aws/policy/*" {
846	policy = "sudo"
847}
848path "prod/*" {
849	policy = "read"
850}
851path "prod/aws/*" {
852	policy = "deny"
853}
854path "sys/*" {
855	policy = "deny"
856}
857path "foo/bar" {
858	capabilities = ["read", "create", "sudo"]
859}
860path "test/+/segment" {
861	capabilities = ["read"]
862}
863path "+/segment/at/front" {
864	capabilities = ["read"]
865}
866path "test/segment/at/end/+" {
867	capabilities = ["read"]
868}
869path "test/segment/at/end/v2/+/" {
870	capabilities = ["read"]
871}
872path "test/+/wildcard/+/*" {
873	capabilities = ["read"]
874}
875path "test/+/wildcardglob/+/end*" {
876	capabilities = ["read"]
877}
878path "1/2/*" {
879	capabilities = ["create"]
880}
881path "1/2/+" {
882	capabilities = ["read"]
883}
884path "1/2/+/+" {
885	capabilities = ["update"]
886}
887`
888
889var aclPolicy2 = `
890name = "OpS"
891path "dev/hide/*" {
892	policy = "deny"
893}
894path "stage/aws/policy/*" {
895	policy = "deny"
896	# This should have no effect
897	capabilities = ["read", "update", "sudo"]
898}
899path "prod/*" {
900	policy = "write"
901}
902path "sys/seal" {
903	policy = "sudo"
904}
905path "foo/bar" {
906	capabilities = ["deny"]
907}
908`
909
910//test merging
911var mergingPolicies = `
912name = "ops"
913path "foo/bar" {
914	policy = "write"
915	denied_parameters = {
916		"baz" = []
917	}
918	required_parameters = ["baz"]
919}
920path "foo/bar" {
921	policy = "write"
922	denied_parameters = {
923		"zip" = []
924	}
925}
926path "hello/universe" {
927	policy = "write"
928	allowed_parameters = {
929		"foo" = []
930	}
931	required_parameters = ["foo"]
932	max_wrapping_ttl = 300
933	min_wrapping_ttl = 100
934}
935path "hello/universe" {
936	policy = "write"
937	allowed_parameters = {
938		"bar" = []
939	}
940	required_parameters = ["bar"]
941	max_wrapping_ttl = 200
942	min_wrapping_ttl = 50
943}
944path "allow/all" {
945	policy = "write"
946	allowed_parameters = {
947		"test" = []
948		"test1" = ["foo"]
949	}
950}
951path "allow/all" {
952	policy = "write"
953	allowed_parameters = {
954		"*" = []
955	}
956}
957path "allow/all1" {
958	policy = "write"
959	allowed_parameters = {
960		"*" = []
961	}
962}
963path "allow/all1" {
964	policy = "write"
965	allowed_parameters = {
966		"test" = []
967		"test1" = ["foo"]
968	}
969}
970path "deny/all" {
971	policy = "write"
972	denied_parameters = {
973		"test" = []
974	}
975}
976path "deny/all" {
977	policy = "write"
978	denied_parameters = {
979		"*" = []
980	}
981}
982path "deny/all1" {
983	policy = "write"
984	denied_parameters = {
985		"*" = []
986	}
987}
988path "deny/all1" {
989	policy = "write"
990	denied_parameters = {
991		"test" = []
992	}
993}
994path "value/merge" {
995	policy = "write"
996	allowed_parameters = {
997		"test" = [1, 2]
998	}
999	denied_parameters = {
1000		"test" = [1, 2]
1001	}
1002}
1003path "value/merge" {
1004	policy = "write"
1005	allowed_parameters = {
1006		"test" = [3, 4]
1007	}
1008	denied_parameters = {
1009		"test" = [3, 4]
1010	}
1011}
1012path "value/empty" {
1013	policy = "write"
1014	allowed_parameters = {
1015		"empty" = []
1016	}
1017	denied_parameters = {
1018		"empty" = [1]
1019	}
1020}
1021path "value/empty" {
1022	policy = "write"
1023	allowed_parameters = {
1024		"empty" = [1]
1025	}
1026	denied_parameters = {
1027		"empty" = []
1028	}
1029}
1030`
1031
1032//allow operation testing
1033var permissionsPolicy = `
1034name = "dev"
1035path "dev/*" {
1036	policy = "write"
1037
1038	allowed_parameters = {
1039		"zip" = []
1040	}
1041}
1042path "foo/bar" {
1043	policy = "write"
1044	denied_parameters = {
1045		"zap" = []
1046	}
1047	min_wrapping_ttl = 300
1048	max_wrapping_ttl = 400
1049}
1050path "foo/baz" {
1051	policy = "write"
1052	allowed_parameters = {
1053		"hello" = []
1054	}
1055	denied_parameters = {
1056		"zap" = []
1057	}
1058	min_wrapping_ttl = 300
1059}
1060path "working/phone" {
1061	policy = "write"
1062	max_wrapping_ttl = 400
1063}
1064path "broken/phone" {
1065	policy = "write"
1066	allowed_parameters = {
1067	  "steve" = []
1068	}
1069	denied_parameters = {
1070	  "steve" = []
1071	}
1072}
1073path "hello/world" {
1074	policy = "write"
1075	allowed_parameters = {
1076		"*" = []
1077	}
1078	denied_parameters = {
1079		"*" = []
1080	}
1081}
1082path "tree/fort" {
1083	policy = "write"
1084	allowed_parameters = {
1085		"*" = []
1086	}
1087	denied_parameters = {
1088		"foo" = []
1089	}
1090}
1091path "fruit/apple" {
1092	policy = "write"
1093	allowed_parameters = {
1094		"pear" = []
1095	}
1096	denied_parameters = {
1097		"*" = []
1098	}
1099}
1100path "cold/weather" {
1101	policy = "write"
1102	allowed_parameters = {}
1103	denied_parameters = {}
1104}
1105path "var/aws" {
1106	policy = "write"
1107	allowed_parameters = {
1108		"*" = []
1109	}
1110	denied_parameters = {
1111		"soft" = []
1112		"warm" = []
1113		"kitty" = []
1114	}
1115}
1116path "var/req" {
1117	policy = "write"
1118	required_parameters = ["foo"]
1119}
1120`
1121
1122//allow operation testing
1123var valuePermissionsPolicy = `
1124name = "op"
1125path "dev/*" {
1126	policy = "write"
1127
1128	allowed_parameters = {
1129		"allow" = ["good"]
1130	}
1131}
1132path "foo/bar" {
1133	policy = "write"
1134	denied_parameters = {
1135		"deny" = ["bad*"]
1136	}
1137}
1138path "foo/baz" {
1139	policy = "write"
1140	allowed_parameters = {
1141		"ALLOW" = ["good"]
1142	}
1143	denied_parameters = {
1144		"dEny" = ["bad"]
1145	}
1146}
1147path "fizz/buzz" {
1148	policy = "write"
1149	allowed_parameters = {
1150		"allow_multi" = ["good", "good1", "good2", "*good3"]
1151		"allow" = ["good"]
1152	}
1153	denied_parameters = {
1154		"deny_multi" = ["bad", "bad1", "bad2"]
1155	}
1156}
1157path "test/types" {
1158	policy = "write"
1159	allowed_parameters = {
1160		"map" = [{"good" = "one"}]
1161		"int" = [1, 2]
1162		"bool" = [false]
1163	}
1164	denied_parameters = {
1165	}
1166}
1167path "test/star" {
1168	policy = "write"
1169	allowed_parameters = {
1170		"*" = []
1171		"foo" = []
1172		"bar" = [false]
1173	}
1174	denied_parameters = {
1175	}
1176}
1177`
1178