open-vault/vault/acl_test.go

937 lines
24 KiB
Go
Raw Normal View History

2015-03-18 01:31:20 +00:00
package vault
import (
2018-09-18 03:03:00 +00:00
"context"
2016-03-05 05:03:55 +00:00
"reflect"
"sync"
2015-03-18 01:31:20 +00:00
"testing"
"time"
2015-03-18 01:31:20 +00:00
2018-09-18 03:03:00 +00:00
"github.com/hashicorp/vault/helper/namespace"
2015-03-18 01:31:20 +00:00
"github.com/hashicorp/vault/logical"
)
2018-09-18 03:03:00 +00:00
func TestACL_NewACL(t *testing.T) {
t.Run("root-ns", func(t *testing.T) {
t.Parallel()
testNewACL(t, namespace.RootNamespace)
})
}
func testNewACL(t *testing.T, ns *namespace.Namespace) {
ctx := namespace.ContextWithNamespace(context.Background(), ns)
2016-03-05 05:03:55 +00:00
policy := []*Policy{&Policy{Name: "root"}}
2018-09-18 03:03:00 +00:00
_, err := NewACL(ctx, policy)
switch ns.ID {
case namespace.RootNamespaceID:
if err != nil {
t.Fatal(err)
}
default:
if err == nil {
t.Fatal("expected an error")
}
}
}
func TestACL_MFAMethods(t *testing.T) {
t.Run("root-ns", func(t *testing.T) {
t.Parallel()
testACLMFAMethods(t, namespace.RootNamespace)
})
}
func testACLMFAMethods(t *testing.T, ns *namespace.Namespace) {
mfaRules := `
path "secret/foo/*" {
mfa_methods = ["mfa_method_1", "mfa_method_2", "mfa_method_3"]
}
path "secret/exact/path" {
mfa_methods = ["mfa_method_4", "mfa_method_5"]
}
path "secret/split/definition" {
mfa_methods = ["mfa_method_6", "mfa_method_7"]
}
path "secret/split/definition" {
mfa_methods = ["mfa_method_7", "mfa_method_8", "mfa_method_9"]
}
`
policy, err := ParseACLPolicy(ns, mfaRules)
2016-03-05 05:03:55 +00:00
if err != nil {
2018-09-18 03:03:00 +00:00
t.Fatal(err)
2016-03-05 05:03:55 +00:00
}
2018-09-18 03:03:00 +00:00
ctx := namespace.ContextWithNamespace(context.Background(), ns)
acl, err := NewACL(ctx, []*Policy{policy})
if err != nil {
t.Fatal(err)
}
request := &logical.Request{
Operation: logical.UpdateOperation,
Path: "secret/foo/testing/glob/pattern",
}
actual := acl.AllowOperation(ctx, request, false).MFAMethods
expected := []string{"mfa_method_1", "mfa_method_2", "mfa_method_3"}
if !reflect.DeepEqual(expected, actual) {
t.Fatalf("bad: MFA methods; expected: %#v\n actual: %#v\n", expected, actual)
}
request.Path = "secret/exact/path"
actual = acl.AllowOperation(ctx, request, false).MFAMethods
expected = []string{"mfa_method_4", "mfa_method_5"}
if !reflect.DeepEqual(expected, actual) {
t.Fatalf("bad: MFA methods; expected: %#v\n actual: %#v\n", expected, actual)
2016-03-05 05:03:55 +00:00
}
2018-09-18 03:03:00 +00:00
request.Path = "secret/split/definition"
actual = acl.AllowOperation(ctx, request, false).MFAMethods
expected = []string{"mfa_method_6", "mfa_method_7", "mfa_method_8", "mfa_method_9"}
if !reflect.DeepEqual(expected, actual) {
t.Fatalf("bad: MFA methods; expected: %#v\n actual: %#v\n", expected, actual)
}
}
func TestACL_Capabilities(t *testing.T) {
t.Run("root-ns", func(t *testing.T) {
t.Parallel()
policy := []*Policy{&Policy{Name: "root"}}
ctx := namespace.RootContext(nil)
acl, err := NewACL(ctx, policy)
if err != nil {
t.Fatalf("err: %v", err)
}
actual := acl.Capabilities(ctx, "any/path")
expected := []string{"root"}
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: got\n%#v\nexpected\n%#v\n", actual, expected)
}
testACLCapabilities(t, namespace.RootNamespace)
})
}
func testACLCapabilities(t *testing.T, ns *namespace.Namespace) {
// Create the root policy ACL
ctx := namespace.ContextWithNamespace(context.Background(), ns)
policy, err := ParseACLPolicy(ns, aclPolicy)
2016-03-05 05:03:55 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
2018-09-18 03:03:00 +00:00
acl, err := NewACL(ctx, []*Policy{policy})
2016-03-05 05:03:55 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
2018-09-18 03:03:00 +00:00
actual := acl.Capabilities(ctx, "dev")
expected := []string{"deny"}
2016-03-05 05:03:55 +00:00
if !reflect.DeepEqual(actual, expected) {
2018-09-18 03:03:00 +00:00
t.Fatalf("bad: path: %s\ngot\n%#v\nexpected\n%#v\n", "deny", actual, expected)
2016-03-05 05:03:55 +00:00
}
2018-09-18 03:03:00 +00:00
actual = acl.Capabilities(ctx, "dev/")
2016-03-05 05:03:55 +00:00
expected = []string{"sudo", "read", "list", "update", "delete", "create"}
if !reflect.DeepEqual(actual, expected) {
2018-09-18 03:03:00 +00:00
t.Fatalf("bad: path: %s\ngot\n%#v\nexpected\n%#v\n", "dev/", actual, expected)
2016-03-05 05:03:55 +00:00
}
2018-09-18 03:03:00 +00:00
actual = acl.Capabilities(ctx, "stage/aws/test")
2016-03-05 05:03:55 +00:00
expected = []string{"sudo", "read", "list", "update"}
if !reflect.DeepEqual(actual, expected) {
2018-09-18 03:03:00 +00:00
t.Fatalf("bad: path: %s\ngot\n%#v\nexpected\n%#v\n", "stage/aws/test", actual, expected)
2016-03-05 05:03:55 +00:00
}
}
2015-03-18 01:31:20 +00:00
func TestACL_Root(t *testing.T) {
2018-09-18 03:03:00 +00:00
t.Run("root-ns", func(t *testing.T) {
t.Parallel()
testACLRoot(t, namespace.RootNamespace)
})
}
func testACLRoot(t *testing.T, ns *namespace.Namespace) {
// Create the root policy ACL. Always create on root namespace regardless of
// which namespace to ACL check on.
2015-03-18 01:31:20 +00:00
policy := []*Policy{&Policy{Name: "root"}}
2018-09-18 03:03:00 +00:00
acl, err := NewACL(namespace.TestContext(), policy)
2015-03-18 01:31:20 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
request := new(logical.Request)
request.Operation = logical.UpdateOperation
request.Path = "sys/mount/foo"
2018-09-18 03:03:00 +00:00
ctx := namespace.ContextWithNamespace(context.Background(), ns)
authResults := acl.AllowOperation(ctx, request, false)
2017-10-23 20:42:56 +00:00
if !authResults.RootPrivs {
2015-03-18 01:31:20 +00:00
t.Fatalf("expected root")
}
2017-10-23 20:42:56 +00:00
if !authResults.Allowed {
2016-10-30 22:09:45 +00:00
t.Fatalf("expected permissions")
2015-03-18 01:31:20 +00:00
}
}
func TestACL_Single(t *testing.T) {
2018-09-18 03:03:00 +00:00
t.Run("root-ns", func(t *testing.T) {
t.Parallel()
testACLSingle(t, namespace.RootNamespace)
})
}
func testACLSingle(t *testing.T, ns *namespace.Namespace) {
policy, err := ParseACLPolicy(ns, aclPolicy)
2015-03-18 01:31:20 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
2018-09-18 03:03:00 +00:00
ctx := namespace.ContextWithNamespace(context.Background(), ns)
acl, err := NewACL(ctx, []*Policy{policy})
2015-03-18 01:31:20 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
// Type of operation is not important here as we only care about checking
// sudo/root
2018-09-18 03:03:00 +00:00
ctx = namespace.ContextWithNamespace(context.Background(), ns)
request := new(logical.Request)
request.Operation = logical.ReadOperation
request.Path = "sys/mount/foo"
2018-09-18 03:03:00 +00:00
authResults := acl.AllowOperation(ctx, request, false)
2017-10-23 20:42:56 +00:00
if authResults.RootPrivs {
2015-03-18 01:31:20 +00:00
t.Fatalf("unexpected root")
}
type tcase struct {
op logical.Operation
path string
allowed bool
rootPrivs bool
2015-03-18 01:31:20 +00:00
}
tcases := []tcase{
{logical.ReadOperation, "root", false, false},
{logical.HelpOperation, "root", true, false},
2015-03-18 01:31:20 +00:00
{logical.ReadOperation, "dev/foo", true, true},
{logical.UpdateOperation, "dev/foo", true, true},
2015-03-18 01:31:20 +00:00
{logical.DeleteOperation, "stage/foo", true, false},
{logical.ListOperation, "stage/aws/foo", true, true},
{logical.UpdateOperation, "stage/aws/foo", true, true},
{logical.UpdateOperation, "stage/aws/policy/foo", true, true},
2015-03-18 01:31:20 +00:00
{logical.DeleteOperation, "prod/foo", false, false},
{logical.UpdateOperation, "prod/foo", false, false},
{logical.ReadOperation, "prod/foo", true, false},
{logical.ListOperation, "prod/foo", true, false},
{logical.ReadOperation, "prod/aws/foo", false, false},
{logical.ReadOperation, "foo/bar", true, true},
{logical.ListOperation, "foo/bar", false, true},
{logical.UpdateOperation, "foo/bar", false, true},
{logical.CreateOperation, "foo/bar", true, true},
2015-03-18 01:31:20 +00:00
}
for _, tc := range tcases {
2018-09-18 03:03:00 +00:00
ctx := namespace.ContextWithNamespace(context.Background(), ns)
request := new(logical.Request)
request.Operation = tc.op
request.Path = tc.path
2018-09-18 03:03:00 +00:00
authResults := acl.AllowOperation(ctx, request, false)
2017-10-23 20:42:56 +00:00
if authResults.Allowed != tc.allowed {
t.Fatalf("bad: case %#v: %v, %v", tc, authResults.Allowed, authResults.RootPrivs)
}
2017-10-23 20:42:56 +00:00
if authResults.RootPrivs != tc.rootPrivs {
t.Fatalf("bad: case %#v: %v, %v", tc, authResults.Allowed, authResults.RootPrivs)
2015-03-18 01:31:20 +00:00
}
}
}
func TestACL_Layered(t *testing.T) {
2018-09-18 03:03:00 +00:00
t.Run("root-ns", func(t *testing.T) {
t.Parallel()
policy1, err := ParseACLPolicy(namespace.RootNamespace, aclPolicy)
if err != nil {
t.Fatalf("err: %v", err)
}
2016-11-02 02:48:00 +00:00
2018-09-18 03:03:00 +00:00
policy2, err := ParseACLPolicy(namespace.RootNamespace, aclPolicy2)
if err != nil {
t.Fatalf("err: %v", err)
}
acl, err := NewACL(namespace.RootContext(nil), []*Policy{policy1, policy2})
if err != nil {
t.Fatalf("err: %v", err)
}
testLayeredACL(t, acl, namespace.RootNamespace)
})
2015-03-18 19:17:03 +00:00
}
2018-09-18 03:03:00 +00:00
func testLayeredACL(t *testing.T, acl *ACL, ns *namespace.Namespace) {
// Type of operation is not important here as we only care about checking
// sudo/root
2018-09-18 03:03:00 +00:00
ctx := namespace.ContextWithNamespace(context.Background(), ns)
request := new(logical.Request)
request.Operation = logical.ReadOperation
request.Path = "sys/mount/foo"
2018-09-18 03:03:00 +00:00
authResults := acl.AllowOperation(ctx, request, false)
2017-10-23 20:42:56 +00:00
if authResults.RootPrivs {
2015-03-18 01:31:20 +00:00
t.Fatalf("unexpected root")
}
type tcase struct {
op logical.Operation
path string
allowed bool
rootPrivs bool
2015-03-18 01:31:20 +00:00
}
tcases := []tcase{
{logical.ReadOperation, "root", false, false},
{logical.HelpOperation, "root", true, false},
2015-03-18 01:31:20 +00:00
{logical.ReadOperation, "dev/foo", true, true},
{logical.UpdateOperation, "dev/foo", true, true},
{logical.ReadOperation, "dev/hide/foo", false, false},
{logical.UpdateOperation, "dev/hide/foo", false, false},
2015-03-18 01:31:20 +00:00
{logical.DeleteOperation, "stage/foo", true, false},
{logical.ListOperation, "stage/aws/foo", true, true},
{logical.UpdateOperation, "stage/aws/foo", true, true},
{logical.UpdateOperation, "stage/aws/policy/foo", false, false},
2015-03-18 01:31:20 +00:00
{logical.DeleteOperation, "prod/foo", true, false},
{logical.UpdateOperation, "prod/foo", true, false},
{logical.ReadOperation, "prod/foo", true, false},
{logical.ListOperation, "prod/foo", true, false},
{logical.ReadOperation, "prod/aws/foo", false, false},
2015-07-05 23:34:34 +00:00
{logical.ReadOperation, "sys/status", false, false},
{logical.UpdateOperation, "sys/seal", true, true},
{logical.ReadOperation, "foo/bar", false, false},
{logical.ListOperation, "foo/bar", false, false},
{logical.UpdateOperation, "foo/bar", false, false},
{logical.CreateOperation, "foo/bar", false, false},
2015-03-18 01:31:20 +00:00
}
for _, tc := range tcases {
2018-09-18 03:03:00 +00:00
ctx := namespace.ContextWithNamespace(context.Background(), ns)
request := new(logical.Request)
request.Operation = tc.op
request.Path = tc.path
2018-09-18 03:03:00 +00:00
authResults := acl.AllowOperation(ctx, request, false)
2017-10-23 20:42:56 +00:00
if authResults.Allowed != tc.allowed {
t.Fatalf("bad: case %#v: %v, %v", tc, authResults.Allowed, authResults.RootPrivs)
}
2017-10-23 20:42:56 +00:00
if authResults.RootPrivs != tc.rootPrivs {
t.Fatalf("bad: case %#v: %v, %v", tc, authResults.Allowed, authResults.RootPrivs)
2015-03-18 01:31:20 +00:00
}
}
}
2017-02-16 02:12:26 +00:00
func TestACL_PolicyMerge(t *testing.T) {
2018-09-18 03:03:00 +00:00
t.Run("root-ns", func(t *testing.T) {
t.Parallel()
testACLPolicyMerge(t, namespace.RootNamespace)
})
}
func testACLPolicyMerge(t *testing.T, ns *namespace.Namespace) {
policy, err := ParseACLPolicy(ns, mergingPolicies)
2016-11-02 02:48:00 +00:00
if err != nil {
2016-10-30 22:09:45 +00:00
t.Fatalf("err: %v", err)
}
2018-09-18 03:03:00 +00:00
ctx := namespace.ContextWithNamespace(context.Background(), ns)
acl, err := NewACL(ctx, []*Policy{policy})
2016-10-30 22:09:45 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
2016-11-02 02:48:00 +00:00
type tcase struct {
path string
minWrappingTTL *time.Duration
maxWrappingTTL *time.Duration
allowed map[string][]interface{}
denied map[string][]interface{}
required []string
}
createDuration := func(seconds int) *time.Duration {
ret := time.Duration(seconds) * time.Second
return &ret
}
2016-11-02 02:48:00 +00:00
tcases := []tcase{
{"foo/bar", nil, nil, nil, map[string][]interface{}{"zip": []interface{}{}, "baz": []interface{}{}}, []string{"baz"}},
{"hello/universe", createDuration(50), createDuration(200), map[string][]interface{}{"foo": []interface{}{}, "bar": []interface{}{}}, nil, []string{"foo", "bar"}},
{"allow/all", nil, nil, map[string][]interface{}{"*": []interface{}{}, "test": []interface{}{}, "test1": []interface{}{"foo"}}, nil, nil},
{"allow/all1", nil, nil, map[string][]interface{}{"*": []interface{}{}, "test": []interface{}{}, "test1": []interface{}{"foo"}}, nil, nil},
{"deny/all", nil, nil, nil, map[string][]interface{}{"*": []interface{}{}, "test": []interface{}{}}, nil},
{"deny/all1", nil, nil, nil, map[string][]interface{}{"*": []interface{}{}, "test": []interface{}{}}, nil},
{"value/merge", nil, nil, map[string][]interface{}{"test": []interface{}{3, 4, 1, 2}}, map[string][]interface{}{"test": []interface{}{3, 4, 1, 2}}, nil},
{"value/empty", nil, nil, map[string][]interface{}{"empty": []interface{}{}}, map[string][]interface{}{"empty": []interface{}{}}, nil},
2016-11-02 02:48:00 +00:00
}
for _, tc := range tcases {
2018-09-18 03:03:00 +00:00
policyPath := ns.Path + tc.path
raw, ok := acl.exactRules.Get(policyPath)
if !ok {
2018-09-18 03:03:00 +00:00
t.Fatalf("Could not find acl entry for path %s", policyPath)
}
2017-10-23 20:42:56 +00:00
p := raw.(*ACLPermissions)
if !reflect.DeepEqual(tc.allowed, p.AllowedParameters) {
2018-03-20 18:54:10 +00:00
t.Fatalf("Allowed parameters did not match, Expected: %#v, Got: %#v", tc.allowed, p.AllowedParameters)
}
if !reflect.DeepEqual(tc.denied, p.DeniedParameters) {
2018-03-20 18:54:10 +00:00
t.Fatalf("Denied parameters did not match, Expected: %#v, Got: %#v", tc.denied, p.DeniedParameters)
2016-11-02 02:48:00 +00:00
}
if !reflect.DeepEqual(tc.required, p.RequiredParameters) {
2018-03-20 18:54:10 +00:00
t.Fatalf("Required parameters did not match, Expected: %#v, Got: %#v", tc.required, p.RequiredParameters)
}
if tc.minWrappingTTL != nil && *tc.minWrappingTTL != p.MinWrappingTTL {
t.Fatalf("Min wrapping TTL did not match, Expected: %#v, Got: %#v", tc.minWrappingTTL, p.MinWrappingTTL)
}
if tc.minWrappingTTL != nil && *tc.maxWrappingTTL != p.MaxWrappingTTL {
t.Fatalf("Max wrapping TTL did not match, Expected: %#v, Got: %#v", tc.maxWrappingTTL, p.MaxWrappingTTL)
}
2016-11-02 02:48:00 +00:00
}
}
2017-02-16 02:12:26 +00:00
func TestACL_AllowOperation(t *testing.T) {
2018-09-18 03:03:00 +00:00
t.Run("root-ns", func(t *testing.T) {
t.Parallel()
testACLAllowOperation(t, namespace.RootNamespace)
})
}
func testACLAllowOperation(t *testing.T, ns *namespace.Namespace) {
policy, err := ParseACLPolicy(ns, permissionsPolicy)
2016-11-07 20:28:41 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
2018-09-18 03:03:00 +00:00
ctx := namespace.ContextWithNamespace(context.Background(), ns)
acl, err := NewACL(ctx, []*Policy{policy})
2016-11-07 20:28:41 +00:00
if err != nil {
t.Fatalf("err: %v", err)
}
toperations := []logical.Operation{
logical.UpdateOperation,
logical.CreateOperation,
}
2016-11-07 20:28:41 +00:00
type tcase struct {
path string
wrappingTTL *time.Duration
parameters []string
allowed bool
}
createDuration := func(seconds int) *time.Duration {
ret := time.Duration(seconds) * time.Second
return &ret
2016-11-07 20:28:41 +00:00
}
2016-11-07 20:28:41 +00:00
tcases := []tcase{
{"dev/ops", nil, []string{"zip"}, true},
{"foo/bar", nil, []string{"zap"}, false},
{"foo/bar", nil, []string{"zip"}, false},
{"foo/bar", createDuration(50), []string{"zip"}, false},
{"foo/bar", createDuration(450), []string{"zip"}, false},
{"foo/bar", createDuration(350), []string{"zip"}, true},
{"foo/baz", nil, []string{"hello"}, false},
{"foo/baz", createDuration(50), []string{"hello"}, false},
{"foo/baz", createDuration(450), []string{"hello"}, true},
{"foo/baz", nil, []string{"zap"}, false},
{"broken/phone", nil, []string{"steve"}, false},
{"working/phone", nil, []string{""}, false},
{"working/phone", createDuration(450), []string{""}, false},
{"working/phone", createDuration(350), []string{""}, true},
{"hello/world", nil, []string{"one"}, false},
{"tree/fort", nil, []string{"one"}, true},
{"tree/fort", nil, []string{"foo"}, false},
{"fruit/apple", nil, []string{"pear"}, false},
{"fruit/apple", nil, []string{"one"}, false},
{"cold/weather", nil, []string{"four"}, true},
{"var/aws", nil, []string{"cold", "warm", "kitty"}, false},
{"var/req", nil, []string{"cold", "warm", "kitty"}, false},
{"var/req", nil, []string{"cold", "warm", "kitty", "foo"}, true},
}
for _, tc := range tcases {
2018-09-18 03:03:00 +00:00
request := &logical.Request{
Path: tc.path,
Data: make(map[string]interface{}),
}
for _, parameter := range tc.parameters {
request.Data[parameter] = ""
}
if tc.wrappingTTL != nil {
request.WrapInfo = &logical.RequestWrapInfo{
TTL: *tc.wrappingTTL,
}
}
2016-11-07 20:28:41 +00:00
for _, op := range toperations {
request.Operation = op
2018-09-18 03:03:00 +00:00
ctx := namespace.ContextWithNamespace(context.Background(), ns)
authResults := acl.AllowOperation(ctx, request, false)
2017-10-23 20:42:56 +00:00
if authResults.Allowed != tc.allowed {
t.Fatalf("bad: case %#v: %v", tc, authResults.Allowed)
2016-11-07 20:28:41 +00:00
}
}
}
}
2016-10-30 22:09:45 +00:00
2017-02-16 02:12:26 +00:00
func TestACL_ValuePermissions(t *testing.T) {
2018-09-18 03:03:00 +00:00
t.Run("root-ns", func(t *testing.T) {
t.Parallel()
testACLValuePermissions(t, namespace.RootNamespace)
})
}
func testACLValuePermissions(t *testing.T, ns *namespace.Namespace) {
policy, err := ParseACLPolicy(ns, valuePermissionsPolicy)
if err != nil {
t.Fatalf("err: %v", err)
}
2018-09-18 03:03:00 +00:00
ctx := namespace.ContextWithNamespace(context.Background(), ns)
acl, err := NewACL(ctx, []*Policy{policy})
if err != nil {
t.Fatalf("err: %v", err)
}
toperations := []logical.Operation{
logical.UpdateOperation,
logical.CreateOperation,
}
type tcase struct {
path string
parameters []string
values []interface{}
allowed bool
}
tcases := []tcase{
{"dev/ops", []string{"allow"}, []interface{}{"good"}, true},
{"dev/ops", []string{"allow"}, []interface{}{"bad"}, false},
{"foo/bar", []string{"deny"}, []interface{}{"bad"}, false},
{"foo/bar", []string{"deny"}, []interface{}{"bad glob"}, false},
{"foo/bar", []string{"deny"}, []interface{}{"good"}, true},
{"foo/bar", []string{"allow"}, []interface{}{"good"}, true},
2017-02-17 01:50:10 +00:00
{"foo/baz", []string{"aLLow"}, []interface{}{"good"}, true},
{"foo/baz", []string{"deny"}, []interface{}{"bad"}, false},
2017-02-16 23:20:11 +00:00
{"foo/baz", []string{"deny"}, []interface{}{"good"}, false},
{"foo/baz", []string{"allow", "deny"}, []interface{}{"good", "bad"}, false},
{"foo/baz", []string{"deny", "allow"}, []interface{}{"good", "bad"}, false},
2017-02-17 01:50:10 +00:00
{"foo/baz", []string{"deNy", "allow"}, []interface{}{"bad", "good"}, false},
{"foo/baz", []string{"aLLow"}, []interface{}{"bad"}, false},
{"foo/baz", []string{"Neither"}, []interface{}{"bad"}, false},
{"fizz/buzz", []string{"allow_multi"}, []interface{}{"good"}, true},
{"fizz/buzz", []string{"allow_multi"}, []interface{}{"good1"}, true},
{"fizz/buzz", []string{"allow_multi"}, []interface{}{"good2"}, true},
{"fizz/buzz", []string{"allow_multi"}, []interface{}{"glob good2"}, false},
{"fizz/buzz", []string{"allow_multi"}, []interface{}{"glob good3"}, true},
{"fizz/buzz", []string{"allow_multi"}, []interface{}{"bad"}, false},
{"fizz/buzz", []string{"allow_multi"}, []interface{}{"bad"}, false},
{"fizz/buzz", []string{"allow_multi", "allow"}, []interface{}{"good1", "good"}, true},
{"fizz/buzz", []string{"deny_multi"}, []interface{}{"bad2"}, false},
2017-02-16 23:20:11 +00:00
{"fizz/buzz", []string{"deny_multi", "allow_multi"}, []interface{}{"good", "good2"}, false},
// {"test/types", []string{"array"}, []interface{}{[1]string{"good"}}, true},
{"test/types", []string{"map"}, []interface{}{map[string]interface{}{"good": "one"}}, true},
{"test/types", []string{"map"}, []interface{}{map[string]interface{}{"bad": "one"}}, false},
{"test/types", []string{"int"}, []interface{}{1}, true},
{"test/types", []string{"int"}, []interface{}{3}, false},
2017-02-16 23:20:11 +00:00
{"test/types", []string{"bool"}, []interface{}{false}, true},
{"test/types", []string{"bool"}, []interface{}{true}, false},
{"test/star", []string{"anything"}, []interface{}{true}, true},
{"test/star", []string{"foo"}, []interface{}{true}, true},
{"test/star", []string{"bar"}, []interface{}{false}, true},
{"test/star", []string{"bar"}, []interface{}{true}, false},
}
for _, tc := range tcases {
2018-09-18 03:03:00 +00:00
request := &logical.Request{
Path: tc.path,
Data: make(map[string]interface{}),
}
ctx := namespace.ContextWithNamespace(context.Background(), ns)
for i, parameter := range tc.parameters {
request.Data[parameter] = tc.values[i]
}
for _, op := range toperations {
request.Operation = op
2018-09-18 03:03:00 +00:00
authResults := acl.AllowOperation(ctx, request, false)
2017-10-23 20:42:56 +00:00
if authResults.Allowed != tc.allowed {
t.Fatalf("bad: case %#v: %v", tc, authResults.Allowed)
}
}
}
}
// NOTE: this test doesn't catch any races ATM
func TestACL_CreationRace(t *testing.T) {
2018-09-18 03:03:00 +00:00
policy, err := ParseACLPolicy(namespace.RootNamespace, valuePermissionsPolicy)
if err != nil {
t.Fatalf("err: %v", err)
}
var wg sync.WaitGroup
stopTime := time.Now().Add(20 * time.Second)
for i := 0; i < 50; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for {
if time.Now().After(stopTime) {
return
}
2018-09-18 03:03:00 +00:00
_, err := NewACL(namespace.TestContext(), []*Policy{policy})
if err != nil {
t.Fatalf("err: %v", err)
}
}
}()
}
wg.Wait()
}
var tokenCreationPolicy = `
name = "tokenCreation"
path "auth/token/create*" {
capabilities = ["update", "create", "sudo"]
}
`
var aclPolicy = `
name = "DeV"
path "dev/*" {
policy = "sudo"
}
path "stage/*" {
policy = "write"
}
path "stage/aws/*" {
policy = "read"
capabilities = ["update", "sudo"]
}
path "stage/aws/policy/*" {
policy = "sudo"
}
path "prod/*" {
policy = "read"
}
path "prod/aws/*" {
policy = "deny"
}
path "sys/*" {
policy = "deny"
}
path "foo/bar" {
capabilities = ["read", "create", "sudo"]
}
`
var aclPolicy2 = `
name = "OpS"
path "dev/hide/*" {
policy = "deny"
}
path "stage/aws/policy/*" {
policy = "deny"
# This should have no effect
capabilities = ["read", "update", "sudo"]
}
path "prod/*" {
policy = "write"
}
path "sys/seal" {
policy = "sudo"
}
path "foo/bar" {
capabilities = ["deny"]
}
`
//test merging
var mergingPolicies = `
name = "ops"
path "foo/bar" {
policy = "write"
2017-02-16 02:12:26 +00:00
denied_parameters = {
"baz" = []
}
required_parameters = ["baz"]
}
path "foo/bar" {
policy = "write"
2017-02-16 02:12:26 +00:00
denied_parameters = {
"zip" = []
}
}
path "hello/universe" {
policy = "write"
2017-02-16 02:12:26 +00:00
allowed_parameters = {
"foo" = []
}
required_parameters = ["foo"]
max_wrapping_ttl = 300
min_wrapping_ttl = 100
}
path "hello/universe" {
policy = "write"
2017-02-16 02:12:26 +00:00
allowed_parameters = {
"bar" = []
}
required_parameters = ["bar"]
max_wrapping_ttl = 200
min_wrapping_ttl = 50
}
path "allow/all" {
policy = "write"
2017-02-16 02:12:26 +00:00
allowed_parameters = {
"test" = []
2017-02-17 00:30:08 +00:00
"test1" = ["foo"]
}
}
path "allow/all" {
policy = "write"
2017-02-16 02:12:26 +00:00
allowed_parameters = {
"*" = []
}
}
path "allow/all1" {
policy = "write"
2017-02-16 02:12:26 +00:00
allowed_parameters = {
"*" = []
}
}
path "allow/all1" {
policy = "write"
2017-02-16 02:12:26 +00:00
allowed_parameters = {
"test" = []
2017-02-17 00:30:08 +00:00
"test1" = ["foo"]
2017-02-16 02:12:26 +00:00
}
}
path "deny/all" {
policy = "write"
2017-02-16 02:12:26 +00:00
denied_parameters = {
2017-02-17 00:30:08 +00:00
"test" = []
}
}
path "deny/all" {
policy = "write"
2017-02-16 02:12:26 +00:00
denied_parameters = {
"*" = []
}
}
path "deny/all1" {
policy = "write"
2017-02-16 02:12:26 +00:00
denied_parameters = {
"*" = []
}
}
path "deny/all1" {
policy = "write"
2017-02-16 02:12:26 +00:00
denied_parameters = {
"test" = []
}
}
path "value/merge" {
policy = "write"
2017-02-16 02:12:26 +00:00
allowed_parameters = {
"test" = [1, 2]
}
denied_parameters = {
"test" = [1, 2]
}
}
path "value/merge" {
policy = "write"
2017-02-16 02:12:26 +00:00
allowed_parameters = {
"test" = [3, 4]
}
denied_parameters = {
"test" = [3, 4]
}
}
path "value/empty" {
policy = "write"
allowed_parameters = {
"empty" = []
}
denied_parameters = {
"empty" = [1]
}
}
path "value/empty" {
policy = "write"
allowed_parameters = {
"empty" = [1]
}
denied_parameters = {
"empty" = []
}
}
`
2016-11-02 02:48:00 +00:00
2016-10-30 22:09:45 +00:00
//allow operation testing
var permissionsPolicy = `
name = "dev"
path "dev/*" {
policy = "write"
2017-02-16 02:12:26 +00:00
allowed_parameters = {
"zip" = []
}
2016-10-30 22:09:45 +00:00
}
path "foo/bar" {
policy = "write"
2017-02-16 02:12:26 +00:00
denied_parameters = {
"zap" = []
}
min_wrapping_ttl = 300
max_wrapping_ttl = 400
2016-10-30 22:09:45 +00:00
}
path "foo/baz" {
policy = "write"
2017-02-16 02:12:26 +00:00
allowed_parameters = {
"hello" = []
}
denied_parameters = {
"zap" = []
}
min_wrapping_ttl = 300
}
path "working/phone" {
policy = "write"
max_wrapping_ttl = 400
2016-10-30 22:09:45 +00:00
}
path "broken/phone" {
policy = "write"
2017-02-16 02:12:26 +00:00
allowed_parameters = {
"steve" = []
}
denied_parameters = {
"steve" = []
2016-10-30 22:09:45 +00:00
}
}
path "hello/world" {
2016-10-30 22:09:45 +00:00
policy = "write"
2017-02-16 02:12:26 +00:00
allowed_parameters = {
"*" = []
}
denied_parameters = {
"*" = []
}
2016-10-30 22:09:45 +00:00
}
path "tree/fort" {
2016-10-30 22:09:45 +00:00
policy = "write"
2017-02-16 02:12:26 +00:00
allowed_parameters = {
"*" = []
}
denied_parameters = {
2017-02-17 00:30:08 +00:00
"foo" = []
2017-02-16 02:12:26 +00:00
}
2016-10-30 22:09:45 +00:00
}
path "fruit/apple" {
2016-10-30 22:09:45 +00:00
policy = "write"
2017-02-16 02:12:26 +00:00
allowed_parameters = {
"pear" = []
}
denied_parameters = {
"*" = []
}
2016-10-30 22:09:45 +00:00
}
path "cold/weather" {
2016-10-30 22:09:45 +00:00
policy = "write"
2017-02-16 02:12:26 +00:00
allowed_parameters = {}
denied_parameters = {}
2016-10-30 22:09:45 +00:00
}
path "var/aws" {
2017-02-16 02:12:26 +00:00
policy = "write"
allowed_parameters = {
"*" = []
}
denied_parameters = {
"soft" = []
"warm" = []
"kitty" = []
}
}
path "var/req" {
policy = "write"
required_parameters = ["foo"]
}
2016-10-30 22:09:45 +00:00
`
//allow operation testing
var valuePermissionsPolicy = `
name = "op"
path "dev/*" {
policy = "write"
2017-02-16 02:12:26 +00:00
allowed_parameters = {
"allow" = ["good"]
}
}
path "foo/bar" {
policy = "write"
2017-02-16 02:12:26 +00:00
denied_parameters = {
"deny" = ["bad*"]
}
}
path "foo/baz" {
policy = "write"
2017-02-16 02:12:26 +00:00
allowed_parameters = {
2017-02-17 01:50:10 +00:00
"ALLOW" = ["good"]
2017-02-16 02:12:26 +00:00
}
denied_parameters = {
2017-02-17 01:50:10 +00:00
"dEny" = ["bad"]
}
}
path "fizz/buzz" {
policy = "write"
2017-02-16 02:12:26 +00:00
allowed_parameters = {
"allow_multi" = ["good", "good1", "good2", "*good3"]
2017-02-16 02:12:26 +00:00
"allow" = ["good"]
}
denied_parameters = {
"deny_multi" = ["bad", "bad1", "bad2"]
}
}
path "test/types" {
policy = "write"
2017-02-16 02:12:26 +00:00
allowed_parameters = {
"map" = [{"good" = "one"}]
"int" = [1, 2]
2017-02-16 23:20:11 +00:00
"bool" = [false]
}
denied_parameters = {
}
}
path "test/star" {
policy = "write"
allowed_parameters = {
"*" = []
"foo" = []
"bar" = [false]
2017-02-16 02:12:26 +00:00
}
denied_parameters = {
}
}
`