2015-03-18 01:31:20 +00:00
|
|
|
package vault
|
|
|
|
|
|
|
|
import (
|
2016-03-05 05:03:55 +00:00
|
|
|
"reflect"
|
2015-03-18 01:31:20 +00:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/hashicorp/vault/logical"
|
|
|
|
)
|
|
|
|
|
2016-03-05 05:03:55 +00:00
|
|
|
func TestACL_Capabilities(t *testing.T) {
|
|
|
|
// Create the root policy ACL
|
|
|
|
policy := []*Policy{&Policy{Name: "root"}}
|
|
|
|
acl, err := NewACL(policy)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
actual := acl.Capabilities("any/path")
|
|
|
|
expected := []string{"root"}
|
|
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
|
|
t.Fatalf("bad: got\n%#v\nexpected\n%#v\n", actual, expected)
|
|
|
|
}
|
|
|
|
|
|
|
|
policies, err := Parse(aclPolicy)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
acl, err = NewACL([]*Policy{policies})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
actual = acl.Capabilities("dev")
|
|
|
|
expected = []string{"deny"}
|
|
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
|
|
t.Fatalf("bad: path:%s\ngot\n%#v\nexpected\n%#v\n", "deny", actual, expected)
|
|
|
|
}
|
|
|
|
|
|
|
|
actual = acl.Capabilities("dev/")
|
|
|
|
expected = []string{"sudo", "read", "list", "update", "delete", "create"}
|
|
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
|
|
t.Fatalf("bad: path:%s\ngot\n%#v\nexpected\n%#v\n", "dev/", actual, expected)
|
|
|
|
}
|
|
|
|
|
|
|
|
actual = acl.Capabilities("stage/aws/test")
|
|
|
|
expected = []string{"sudo", "read", "list", "update"}
|
|
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
|
|
t.Fatalf("bad: path:%s\ngot\n%#v\nexpected\n%#v\n", "stage/aws/test", actual, expected)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-03-18 01:31:20 +00:00
|
|
|
func TestACL_Root(t *testing.T) {
|
|
|
|
// Create the root policy ACL
|
|
|
|
policy := []*Policy{&Policy{Name: "root"}}
|
|
|
|
acl, err := NewACL(policy)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
2016-10-22 06:45:39 +00:00
|
|
|
request := new(logical.Request)
|
|
|
|
request.Operation = logical.UpdateOperation
|
|
|
|
request.Path = "sys/mount/foo"
|
|
|
|
allowed, rootPrivs := acl.AllowOperation(request)
|
2016-01-07 20:10:05 +00:00
|
|
|
if !rootPrivs {
|
2015-03-18 01:31:20 +00:00
|
|
|
t.Fatalf("expected root")
|
|
|
|
}
|
2016-01-07 20:10:05 +00:00
|
|
|
if !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) {
|
|
|
|
policy, err := Parse(aclPolicy)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
acl, err := NewACL([]*Policy{policy})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
2016-01-07 20:10:05 +00:00
|
|
|
// Type of operation is not important here as we only care about checking
|
|
|
|
// sudo/root
|
2016-10-22 06:45:39 +00:00
|
|
|
request := new(logical.Request)
|
|
|
|
request.Operation = logical.ReadOperation
|
|
|
|
request.Path = "sys/mount/foo"
|
|
|
|
_, rootPrivs := acl.AllowOperation(request)
|
2016-01-07 20:10:05 +00:00
|
|
|
if rootPrivs {
|
2015-03-18 01:31:20 +00:00
|
|
|
t.Fatalf("unexpected root")
|
|
|
|
}
|
|
|
|
|
|
|
|
type tcase struct {
|
2016-01-07 20:10:05 +00:00
|
|
|
op logical.Operation
|
|
|
|
path string
|
|
|
|
allowed bool
|
|
|
|
rootPrivs bool
|
2015-03-18 01:31:20 +00:00
|
|
|
}
|
|
|
|
tcases := []tcase{
|
2016-01-07 20:10:05 +00:00
|
|
|
{logical.ReadOperation, "root", false, false},
|
|
|
|
{logical.HelpOperation, "root", true, false},
|
2015-03-18 01:31:20 +00:00
|
|
|
|
2016-01-07 20:10:05 +00:00
|
|
|
{logical.ReadOperation, "dev/foo", true, true},
|
|
|
|
{logical.UpdateOperation, "dev/foo", true, true},
|
2015-03-18 01:31:20 +00:00
|
|
|
|
2016-01-07 20:10:05 +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
|
|
|
|
2016-01-07 20:10:05 +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 {
|
2016-10-22 06:45:39 +00:00
|
|
|
request := new(logical.Request)
|
|
|
|
request.Operation = tc.op
|
|
|
|
request.Path = tc.path
|
|
|
|
allowed, rootPrivs := acl.AllowOperation(request)
|
2016-01-07 20:10:05 +00:00
|
|
|
if allowed != tc.allowed {
|
|
|
|
t.Fatalf("bad: case %#v: %v, %v", tc, allowed, rootPrivs)
|
|
|
|
}
|
|
|
|
if rootPrivs != tc.rootPrivs {
|
|
|
|
t.Fatalf("bad: case %#v: %v, %v", tc, allowed, rootPrivs)
|
2015-03-18 01:31:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestACL_Layered(t *testing.T) {
|
|
|
|
policy1, err := Parse(aclPolicy)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
policy2, err := Parse(aclPolicy2)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
2016-11-02 02:48:00 +00:00
|
|
|
|
|
|
|
acl, err := NewACL([]*Policy{policy1, policy2})
|
2015-03-18 01:31:20 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
2016-11-02 02:48:00 +00:00
|
|
|
}
|
2015-03-18 19:17:03 +00:00
|
|
|
testLayeredACL(t, acl)
|
|
|
|
}
|
|
|
|
func testLayeredACL(t *testing.T, acl *ACL) {
|
2016-01-07 20:10:05 +00:00
|
|
|
// Type of operation is not important here as we only care about checking
|
|
|
|
// sudo/root
|
2016-10-22 06:45:39 +00:00
|
|
|
request := new(logical.Request)
|
|
|
|
request.Operation = logical.ReadOperation
|
|
|
|
request.Path = "sys/mount/foo"
|
|
|
|
_, rootPrivs := acl.AllowOperation(request)
|
2016-01-07 20:10:05 +00:00
|
|
|
if rootPrivs {
|
2015-03-18 01:31:20 +00:00
|
|
|
t.Fatalf("unexpected root")
|
|
|
|
}
|
|
|
|
|
|
|
|
type tcase struct {
|
2016-01-07 20:10:05 +00:00
|
|
|
op logical.Operation
|
|
|
|
path string
|
|
|
|
allowed bool
|
|
|
|
rootPrivs bool
|
2015-03-18 01:31:20 +00:00
|
|
|
}
|
|
|
|
tcases := []tcase{
|
2016-01-07 20:10:05 +00:00
|
|
|
{logical.ReadOperation, "root", false, false},
|
|
|
|
{logical.HelpOperation, "root", true, false},
|
2015-03-18 01:31:20 +00:00
|
|
|
|
2016-01-07 20:10:05 +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
|
|
|
|
2016-01-07 20:10:05 +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
|
|
|
|
2016-01-07 20:10:05 +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
|
|
|
|
2016-01-07 20:10:05 +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 {
|
2016-10-22 06:45:39 +00:00
|
|
|
request := new(logical.Request)
|
|
|
|
request.Operation = tc.op
|
|
|
|
request.Path = tc.path
|
|
|
|
allowed, rootPrivs := acl.AllowOperation(request)
|
2016-01-07 20:10:05 +00:00
|
|
|
if allowed != tc.allowed {
|
|
|
|
t.Fatalf("bad: case %#v: %v, %v", tc, allowed, rootPrivs)
|
|
|
|
}
|
|
|
|
if rootPrivs != tc.rootPrivs {
|
|
|
|
t.Fatalf("bad: case %#v: %v, %v", tc, allowed, rootPrivs)
|
2015-03-18 01:31:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-02 02:48:00 +00:00
|
|
|
func TestNewAclMerge(t *testing.T) {
|
|
|
|
policy, err := Parse(permissionsPolicy2)
|
|
|
|
if err != nil {
|
2016-10-30 22:09:45 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
acl, err := NewACL([]*Policy{policy})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
2016-11-02 02:48:00 +00:00
|
|
|
|
|
|
|
type tcase struct {
|
|
|
|
request logical.Request
|
|
|
|
allowed bool
|
|
|
|
rootPrivs bool
|
|
|
|
}
|
|
|
|
|
|
|
|
tcases := []tcase{
|
|
|
|
{logical.Request{Path: "foo/bar", Data: map[string]struct{}{"baz": {}}, Operation: logical.CreateOperation}, false, false},
|
|
|
|
{logical.Request{Path: "foo/bar", Data: map[string]struct{}{"zip": {}}, Operation: logical.CreateOperation}, false, false},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tc := range tcases {
|
|
|
|
allowed, rootPrivs := acl.AllowOperation(tc.request)
|
|
|
|
if allowed != tc.allowed {
|
|
|
|
t.Fatalf("bad: case %#v: %v, %v", tc, allowed, rootPrivs)
|
|
|
|
}
|
|
|
|
if rootPrivs != tc.rootPrivs {
|
|
|
|
t.Fatalf("bad: case %#v: %v, %v", tc, allowed, rootPrivs)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2016-10-30 22:09:45 +00:00
|
|
|
|
2016-08-02 19:21:15 +00:00
|
|
|
var tokenCreationPolicy = `
|
|
|
|
name = "tokenCreation"
|
|
|
|
path "auth/token/create*" {
|
|
|
|
capabilities = ["update", "create", "sudo"]
|
|
|
|
}
|
|
|
|
`
|
|
|
|
|
2015-03-18 01:31:20 +00:00
|
|
|
var aclPolicy = `
|
|
|
|
name = "dev"
|
2015-07-05 23:31:30 +00:00
|
|
|
path "dev/*" {
|
2015-03-18 01:31:20 +00:00
|
|
|
policy = "sudo"
|
|
|
|
}
|
2015-07-05 23:31:30 +00:00
|
|
|
path "stage/*" {
|
2015-03-18 01:31:20 +00:00
|
|
|
policy = "write"
|
|
|
|
}
|
2015-07-05 23:31:30 +00:00
|
|
|
path "stage/aws/*" {
|
2015-03-18 01:31:20 +00:00
|
|
|
policy = "read"
|
2016-01-07 20:10:05 +00:00
|
|
|
capabilities = ["update", "sudo"]
|
2015-03-18 01:31:20 +00:00
|
|
|
}
|
2015-07-05 23:31:30 +00:00
|
|
|
path "stage/aws/policy/*" {
|
2015-03-18 01:31:20 +00:00
|
|
|
policy = "sudo"
|
|
|
|
}
|
2015-07-05 23:31:30 +00:00
|
|
|
path "prod/*" {
|
2015-03-18 01:31:20 +00:00
|
|
|
policy = "read"
|
|
|
|
}
|
2015-07-05 23:31:30 +00:00
|
|
|
path "prod/aws/*" {
|
2015-03-18 01:31:20 +00:00
|
|
|
policy = "deny"
|
|
|
|
}
|
2015-07-05 23:34:34 +00:00
|
|
|
path "sys/*" {
|
|
|
|
policy = "deny"
|
|
|
|
}
|
2016-01-07 20:10:05 +00:00
|
|
|
path "foo/bar" {
|
|
|
|
capabilities = ["read", "create", "sudo"]
|
|
|
|
}
|
2015-03-18 01:31:20 +00:00
|
|
|
`
|
|
|
|
|
|
|
|
var aclPolicy2 = `
|
|
|
|
name = "ops"
|
2015-07-05 23:31:30 +00:00
|
|
|
path "dev/hide/*" {
|
2015-03-18 01:31:20 +00:00
|
|
|
policy = "deny"
|
|
|
|
}
|
2015-07-05 23:31:30 +00:00
|
|
|
path "stage/aws/policy/*" {
|
2015-03-18 01:31:20 +00:00
|
|
|
policy = "deny"
|
2016-01-07 20:10:05 +00:00
|
|
|
# This should have no effect
|
|
|
|
capabilities = ["read", "update", "sudo"]
|
2015-03-18 01:31:20 +00:00
|
|
|
}
|
2015-07-05 23:31:30 +00:00
|
|
|
path "prod/*" {
|
2015-03-18 01:31:20 +00:00
|
|
|
policy = "write"
|
|
|
|
}
|
2015-07-05 23:34:34 +00:00
|
|
|
path "sys/seal" {
|
2016-01-07 20:10:05 +00:00
|
|
|
policy = "sudo"
|
|
|
|
}
|
|
|
|
path "foo/bar" {
|
|
|
|
capabilities = ["deny"]
|
2015-07-05 23:34:34 +00:00
|
|
|
}
|
2015-03-18 01:31:20 +00:00
|
|
|
`
|
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"
|
|
|
|
|
|
|
|
permissionss = {
|
|
|
|
allowed_parameters {
|
|
|
|
"zip": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
path "foo/bar" {
|
|
|
|
policy = "write"
|
|
|
|
permissions = {
|
|
|
|
denied_parameters {
|
|
|
|
"zap": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
path "foo/baz" {
|
|
|
|
policy = "write"
|
|
|
|
permissions = {
|
|
|
|
allowed_parameters {
|
|
|
|
"hello": {}
|
|
|
|
}
|
|
|
|
denied_parameters {
|
|
|
|
"zap": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
path "broken/phone" {
|
|
|
|
policy = "write"
|
|
|
|
permissions = {
|
|
|
|
allowed_parameters {
|
|
|
|
"steve": {}
|
|
|
|
}
|
|
|
|
denied_parameters {
|
|
|
|
"steve": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
path "hello/world" {
|
|
|
|
policy = "write"
|
|
|
|
permissions = {
|
|
|
|
allowed_parameters {
|
|
|
|
"*": {}
|
|
|
|
}
|
|
|
|
denied_parameters {
|
|
|
|
"*": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
path "tree/fort" {
|
|
|
|
policy = "write"
|
|
|
|
permissions = {
|
|
|
|
allowed_parameters {
|
|
|
|
"*": {}
|
|
|
|
}
|
|
|
|
denied_parameters {
|
|
|
|
"beer": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
path "fruit/apple" {
|
|
|
|
policy = "write"
|
|
|
|
permissions = {
|
|
|
|
allowed_parameters {
|
|
|
|
"pear": {}
|
|
|
|
}
|
|
|
|
denied_parameters {
|
|
|
|
"*": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
path "cold/weather" {
|
|
|
|
policy = "write"
|
|
|
|
permissions = {
|
|
|
|
allowed_parameters{}
|
|
|
|
denied_parameters{}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`
|
2016-11-02 02:48:00 +00:00
|
|
|
|
2016-10-30 22:09:45 +00:00
|
|
|
//test merging
|
|
|
|
|
|
|
|
var permissionsPolicy2 = `
|
|
|
|
name = "ops"
|
|
|
|
path "foo/bar" {
|
|
|
|
policy = "write"
|
|
|
|
permissions = {
|
|
|
|
denied_parameters {
|
|
|
|
"baz": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
path "foo/bar" {
|
|
|
|
policy = "write"
|
|
|
|
permissions = {
|
|
|
|
denied_parameters {
|
|
|
|
"zip": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
path "hello/universe" {
|
|
|
|
policy = "write"
|
|
|
|
permissions = {
|
|
|
|
allowed_parameters {
|
|
|
|
"bob": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
path "hello/universe" {
|
|
|
|
policy = "write"
|
|
|
|
permissions = {
|
|
|
|
allowed_parameters {
|
|
|
|
"tom": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
path "rainy/day" {
|
|
|
|
policy = "write"
|
|
|
|
permissions = {
|
|
|
|
allowed_parameters {
|
|
|
|
"bob": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
path "rainy/day" {
|
|
|
|
policy = "write"
|
|
|
|
permissions = {
|
|
|
|
allowed_parameters {
|
|
|
|
"*": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
path "cool/bike" {
|
|
|
|
policy = "write"
|
|
|
|
permissions = {
|
|
|
|
denied_parameters {
|
|
|
|
"frank": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
path "cool/bike" {
|
|
|
|
policy = "write"
|
|
|
|
permissions = {
|
|
|
|
denied_parameters {
|
|
|
|
"*": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
path "clean/bed" {
|
|
|
|
policy = "write"
|
|
|
|
permissions = {
|
|
|
|
denied_parameters {
|
|
|
|
"*": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
path "clean/bed" {
|
|
|
|
policy = "write"
|
|
|
|
permissions = {
|
|
|
|
allowed_parameters {
|
|
|
|
"*": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
path "coca/cola" {
|
|
|
|
policy = "write"
|
|
|
|
permissions = {
|
|
|
|
denied_parameters {
|
|
|
|
"john": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
path "coca/cola" {
|
|
|
|
policy = "write"
|
|
|
|
permissions = {
|
|
|
|
allowed_parameters {
|
|
|
|
"john": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`
|