diff --git a/acl/acl.go b/acl/acl.go index a8ad0de960..b84e309605 100644 --- a/acl/acl.go +++ b/acl/acl.go @@ -328,6 +328,34 @@ type PolicyACL struct { operatorRule string } +func enforce(rule string, requiredPermission string) (allow, recurse bool) { + switch rule { + case PolicyWrite: + // grants read, list and write permissions + return true, false + case PolicyList: + // grants read and list permissions + if requiredPermission == PolicyList || requiredPermission == PolicyRead { + return true, false + } else { + return false, false + } + case PolicyRead: + // grants just read permissions + if requiredPermission == PolicyRead { + return true, false + } else { + return false, false + } + case PolicyDeny: + // explicit denial - do not recurse + return false, false + default: + // need to recurse as there was no specific policy set + return false, true + } +} + // New is used to construct a policy based ACL from a set of policies // and a parent policy to resolve missing cases. func New(parent ACL, policy *Policy, sentinel sentinel.Evaluator) (*PolicyACL, error) { @@ -433,14 +461,9 @@ func (p *PolicyACL) ACLModify() bool { // node. func (p *PolicyACL) AgentRead(node string) bool { // Check for an exact rule or catch-all - _, rule, ok := p.agentRules.LongestPrefix(node) - - if ok { - switch rule { - case PolicyRead, PolicyWrite: - return true - default: - return false + if _, rule, ok := p.agentRules.LongestPrefix(node); ok { + if allow, recurse := enforce(rule.(string), PolicyRead); !recurse { + return allow } } @@ -455,11 +478,8 @@ func (p *PolicyACL) AgentWrite(node string) bool { _, rule, ok := p.agentRules.LongestPrefix(node) if ok { - switch rule { - case PolicyWrite: - return true - default: - return false + if allow, recurse := enforce(rule.(string), PolicyWrite); !recurse { + return allow } } @@ -477,15 +497,12 @@ func (p *PolicyACL) Snapshot() bool { func (p *PolicyACL) EventRead(name string) bool { // Longest-prefix match on event names if _, rule, ok := p.eventRules.LongestPrefix(name); ok { - switch rule { - case PolicyRead, PolicyWrite: - return true - default: - return false + if allow, recurse := enforce(rule.(string), PolicyRead); !recurse { + return allow } } - // Nothing matched, use parent + // No matching rule, use the parent. return p.parent.EventRead(name) } @@ -494,7 +511,9 @@ func (p *PolicyACL) EventRead(name string) bool { func (p *PolicyACL) EventWrite(name string) bool { // Longest-prefix match event names if _, rule, ok := p.eventRules.LongestPrefix(name); ok { - return rule == PolicyWrite + if allow, recurse := enforce(rule.(string), PolicyWrite); !recurse { + return allow + } } // No match, use parent @@ -512,14 +531,10 @@ func (p *PolicyACL) IntentionDefaultAllow() bool { // intention is allowed. func (p *PolicyACL) IntentionRead(prefix string) bool { // Check for an exact rule or catch-all - _, rule, ok := p.intentionRules.LongestPrefix(prefix) - if ok { + if _, rule, ok := p.intentionRules.LongestPrefix(prefix); ok { pr := rule.(PolicyRule) - switch pr.aclPolicy { - case PolicyRead, PolicyWrite: - return true - default: - return false + if allow, recurse := enforce(pr.aclPolicy, PolicyRead); !recurse { + return allow } } @@ -531,14 +546,10 @@ func (p *PolicyACL) IntentionRead(prefix string) bool { // intention is allowed. func (p *PolicyACL) IntentionWrite(prefix string) bool { // Check for an exact rule or catch-all - _, rule, ok := p.intentionRules.LongestPrefix(prefix) - if ok { + if _, rule, ok := p.intentionRules.LongestPrefix(prefix); ok { pr := rule.(PolicyRule) - switch pr.aclPolicy { - case PolicyWrite: - return true - default: - return false + if allow, recurse := enforce(pr.aclPolicy, PolicyWrite); !recurse { + return allow } } @@ -549,14 +560,10 @@ func (p *PolicyACL) IntentionWrite(prefix string) bool { // KeyRead returns if a key is allowed to be read func (p *PolicyACL) KeyRead(key string) bool { // Look for a matching rule - _, rule, ok := p.keyRules.LongestPrefix(key) - if ok { + if _, rule, ok := p.keyRules.LongestPrefix(key); ok { pr := rule.(PolicyRule) - switch pr.aclPolicy { - case PolicyRead, PolicyWrite, PolicyList: - return true - default: - return false + if allow, recurse := enforce(pr.aclPolicy, PolicyRead); !recurse { + return allow } } @@ -567,14 +574,10 @@ func (p *PolicyACL) KeyRead(key string) bool { // KeyList returns if a key is allowed to be listed func (p *PolicyACL) KeyList(key string) bool { // Look for a matching rule - _, rule, ok := p.keyRules.LongestPrefix(key) - if ok { + if _, rule, ok := p.keyRules.LongestPrefix(key); ok { pr := rule.(PolicyRule) - switch pr.aclPolicy { - case PolicyList, PolicyWrite: - return true - default: - return false + if allow, recurse := enforce(pr.aclPolicy, PolicyList); !recurse { + return allow } } @@ -585,13 +588,12 @@ func (p *PolicyACL) KeyList(key string) bool { // KeyWrite returns if a key is allowed to be written func (p *PolicyACL) KeyWrite(key string, scope sentinel.ScopeFn) bool { // Look for a matching rule - _, rule, ok := p.keyRules.LongestPrefix(key) - if ok { + if _, rule, ok := p.keyRules.LongestPrefix(key); ok { pr := rule.(PolicyRule) - switch pr.aclPolicy { - case PolicyWrite: - return p.executeCodePolicy(&pr.sentinelPolicy, scope) - default: + if allow, recurse := enforce(pr.aclPolicy, PolicyWrite); !recurse { + if allow { + return p.executeCodePolicy(&pr.sentinelPolicy, scope) + } return false } } @@ -636,48 +638,48 @@ func (p *PolicyACL) KeyWritePrefix(prefix string) bool { // KeyringRead is used to determine if the keyring can be // read by the current ACL token. func (p *PolicyACL) KeyringRead() bool { - switch p.keyringRule { - case PolicyRead, PolicyWrite: - return true - case PolicyDeny: - return false - default: - return p.parent.KeyringRead() + if allow, recurse := enforce(p.keyringRule, PolicyRead); !recurse { + return allow } + + return p.parent.KeyringRead() } // KeyringWrite determines if the keyring can be manipulated. func (p *PolicyACL) KeyringWrite() bool { - if p.keyringRule == PolicyWrite { - return true + if allow, recurse := enforce(p.keyringRule, PolicyWrite); !recurse { + return allow } + return p.parent.KeyringWrite() } // OperatorRead determines if the read-only operator functions are allowed. func (p *PolicyACL) OperatorRead() bool { - switch p.operatorRule { - case PolicyRead, PolicyWrite: - return true - case PolicyDeny: - return false - default: - return p.parent.OperatorRead() + if allow, recurse := enforce(p.operatorRule, PolicyRead); !recurse { + return allow } + + return p.parent.OperatorRead() +} + +// OperatorWrite determines if the state-changing operator functions are +// allowed. +func (p *PolicyACL) OperatorWrite() bool { + if allow, recurse := enforce(p.operatorRule, PolicyWrite); !recurse { + return allow + } + + return p.parent.OperatorWrite() } // NodeRead checks if reading (discovery) of a node is allowed func (p *PolicyACL) NodeRead(name string) bool { // Check for an exact rule or catch-all - _, rule, ok := p.nodeRules.LongestPrefix(name) - - if ok { + if _, rule, ok := p.nodeRules.LongestPrefix(name); ok { pr := rule.(PolicyRule) - switch pr.aclPolicy { - case PolicyRead, PolicyWrite: - return true - default: - return false + if allow, recurse := enforce(pr.aclPolicy, PolicyRead); !recurse { + return allow } } @@ -688,15 +690,10 @@ func (p *PolicyACL) NodeRead(name string) bool { // NodeWrite checks if writing (registering) a node is allowed func (p *PolicyACL) NodeWrite(name string, scope sentinel.ScopeFn) bool { // Check for an exact rule or catch-all - _, rule, ok := p.nodeRules.LongestPrefix(name) - - if ok { + if _, rule, ok := p.nodeRules.LongestPrefix(name); ok { pr := rule.(PolicyRule) - switch pr.aclPolicy { - case PolicyWrite: - return true - default: - return false + if allow, recurse := enforce(pr.aclPolicy, PolicyWrite); !recurse { + return allow } } @@ -704,27 +701,13 @@ func (p *PolicyACL) NodeWrite(name string, scope sentinel.ScopeFn) bool { return p.parent.NodeWrite(name, scope) } -// OperatorWrite determines if the state-changing operator functions are -// allowed. -func (p *PolicyACL) OperatorWrite() bool { - if p.operatorRule == PolicyWrite { - return true - } - return p.parent.OperatorWrite() -} - // PreparedQueryRead checks if reading (listing) of a prepared query is // allowed - this isn't execution, just listing its contents. func (p *PolicyACL) PreparedQueryRead(prefix string) bool { // Check for an exact rule or catch-all - _, rule, ok := p.preparedQueryRules.LongestPrefix(prefix) - - if ok { - switch rule { - case PolicyRead, PolicyWrite: - return true - default: - return false + if _, rule, ok := p.preparedQueryRules.LongestPrefix(prefix); ok { + if allow, recurse := enforce(rule.(string), PolicyRead); !recurse { + return allow } } @@ -736,14 +719,9 @@ func (p *PolicyACL) PreparedQueryRead(prefix string) bool { // prepared query is allowed. func (p *PolicyACL) PreparedQueryWrite(prefix string) bool { // Check for an exact rule or catch-all - _, rule, ok := p.preparedQueryRules.LongestPrefix(prefix) - - if ok { - switch rule { - case PolicyWrite: - return true - default: - return false + if _, rule, ok := p.preparedQueryRules.LongestPrefix(prefix); ok { + if allow, recurse := enforce(rule.(string), PolicyWrite); !recurse { + return allow } } @@ -754,14 +732,10 @@ func (p *PolicyACL) PreparedQueryWrite(prefix string) bool { // ServiceRead checks if reading (discovery) of a service is allowed func (p *PolicyACL) ServiceRead(name string) bool { // Check for an exact rule or catch-all - _, rule, ok := p.serviceRules.LongestPrefix(name) - if ok { + if _, rule, ok := p.serviceRules.LongestPrefix(name); ok { pr := rule.(PolicyRule) - switch pr.aclPolicy { - case PolicyRead, PolicyWrite: - return true - default: - return false + if allow, recurse := enforce(pr.aclPolicy, PolicyRead); !recurse { + return allow } } @@ -772,14 +746,10 @@ func (p *PolicyACL) ServiceRead(name string) bool { // ServiceWrite checks if writing (registering) a service is allowed func (p *PolicyACL) ServiceWrite(name string, scope sentinel.ScopeFn) bool { // Check for an exact rule or catch-all - _, rule, ok := p.serviceRules.LongestPrefix(name) - if ok { + if _, rule, ok := p.serviceRules.LongestPrefix(name); ok { pr := rule.(PolicyRule) - switch pr.aclPolicy { - case PolicyWrite: - return true - default: - return false + if allow, recurse := enforce(pr.aclPolicy, PolicyWrite); !recurse { + return allow } } @@ -790,14 +760,9 @@ func (p *PolicyACL) ServiceWrite(name string, scope sentinel.ScopeFn) bool { // SessionRead checks for permission to read sessions for a given node. func (p *PolicyACL) SessionRead(node string) bool { // Check for an exact rule or catch-all - _, rule, ok := p.sessionRules.LongestPrefix(node) - - if ok { - switch rule { - case PolicyRead, PolicyWrite: - return true - default: - return false + if _, rule, ok := p.sessionRules.LongestPrefix(node); ok { + if allow, recurse := enforce(rule.(string), PolicyRead); !recurse { + return allow } } @@ -808,14 +773,9 @@ func (p *PolicyACL) SessionRead(node string) bool { // SessionWrite checks for permission to create sessions for a given node. func (p *PolicyACL) SessionWrite(node string) bool { // Check for an exact rule or catch-all - _, rule, ok := p.sessionRules.LongestPrefix(node) - - if ok { - switch rule { - case PolicyWrite: - return true - default: - return false + if _, rule, ok := p.sessionRules.LongestPrefix(node); ok { + if allow, recurse := enforce(rule.(string), PolicyWrite); !recurse { + return allow } } diff --git a/acl/acl_test.go b/acl/acl_test.go index faf6f092f8..f93cd7b78b 100644 --- a/acl/acl_test.go +++ b/acl/acl_test.go @@ -1,930 +1,1526 @@ package acl import ( + "fmt" "testing" + + "github.com/stretchr/testify/require" ) +// +// The following 1 line functions are created to all conform to what +// can be stored in the aclCheck type to make defining ACL tests +// nicer in the embedded struct within TestACL +// + +func checkAllowACLList(t *testing.T, acl ACL, prefix string) { + require.True(t, acl.ACLList()) +} + +func checkAllowACLModify(t *testing.T, acl ACL, prefix string) { + require.True(t, acl.ACLModify()) +} + +func checkAllowAgentRead(t *testing.T, acl ACL, prefix string) { + require.True(t, acl.AgentRead(prefix)) +} + +func checkAllowAgentWrite(t *testing.T, acl ACL, prefix string) { + require.True(t, acl.AgentWrite(prefix)) +} + +func checkAllowEventRead(t *testing.T, acl ACL, prefix string) { + require.True(t, acl.EventRead(prefix)) +} + +func checkAllowEventWrite(t *testing.T, acl ACL, prefix string) { + require.True(t, acl.EventWrite(prefix)) +} + +func checkAllowIntentionDefaultAllow(t *testing.T, acl ACL, prefix string) { + require.True(t, acl.IntentionDefaultAllow()) +} + +func checkAllowIntentionRead(t *testing.T, acl ACL, prefix string) { + require.True(t, acl.IntentionRead(prefix)) +} + +func checkAllowIntentionWrite(t *testing.T, acl ACL, prefix string) { + require.True(t, acl.IntentionWrite(prefix)) +} + +func checkAllowKeyRead(t *testing.T, acl ACL, prefix string) { + require.True(t, acl.KeyRead(prefix)) +} + +func checkAllowKeyList(t *testing.T, acl ACL, prefix string) { + require.True(t, acl.KeyList(prefix)) +} + +func checkAllowKeyringRead(t *testing.T, acl ACL, prefix string) { + require.True(t, acl.KeyringRead()) +} + +func checkAllowKeyringWrite(t *testing.T, acl ACL, prefix string) { + require.True(t, acl.KeyringWrite()) +} + +func checkAllowKeyWrite(t *testing.T, acl ACL, prefix string) { + require.True(t, acl.KeyWrite(prefix, nil)) +} + +func checkAllowKeyWritePrefix(t *testing.T, acl ACL, prefix string) { + require.True(t, acl.KeyWritePrefix(prefix)) +} + +func checkAllowNodeRead(t *testing.T, acl ACL, prefix string) { + require.True(t, acl.NodeRead(prefix)) +} + +func checkAllowNodeWrite(t *testing.T, acl ACL, prefix string) { + require.True(t, acl.NodeWrite(prefix, nil)) +} + +func checkAllowOperatorRead(t *testing.T, acl ACL, prefix string) { + require.True(t, acl.OperatorRead()) +} + +func checkAllowOperatorWrite(t *testing.T, acl ACL, prefix string) { + require.True(t, acl.OperatorWrite()) +} + +func checkAllowPreparedQueryRead(t *testing.T, acl ACL, prefix string) { + require.True(t, acl.PreparedQueryRead(prefix)) +} + +func checkAllowPreparedQueryWrite(t *testing.T, acl ACL, prefix string) { + require.True(t, acl.PreparedQueryWrite(prefix)) +} + +func checkAllowServiceRead(t *testing.T, acl ACL, prefix string) { + require.True(t, acl.ServiceRead(prefix)) +} + +func checkAllowServiceWrite(t *testing.T, acl ACL, prefix string) { + require.True(t, acl.ServiceWrite(prefix, nil)) +} + +func checkAllowSessionRead(t *testing.T, acl ACL, prefix string) { + require.True(t, acl.SessionRead(prefix)) +} + +func checkAllowSessionWrite(t *testing.T, acl ACL, prefix string) { + require.True(t, acl.SessionWrite(prefix)) +} + +func checkAllowSnapshot(t *testing.T, acl ACL, prefix string) { + require.True(t, acl.Snapshot()) +} + +func checkDenyACLList(t *testing.T, acl ACL, prefix string) { + require.False(t, acl.ACLList()) +} + +func checkDenyACLModify(t *testing.T, acl ACL, prefix string) { + require.False(t, acl.ACLModify()) +} + +func checkDenyAgentRead(t *testing.T, acl ACL, prefix string) { + require.False(t, acl.AgentRead(prefix)) +} + +func checkDenyAgentWrite(t *testing.T, acl ACL, prefix string) { + require.False(t, acl.AgentWrite(prefix)) +} + +func checkDenyEventRead(t *testing.T, acl ACL, prefix string) { + require.False(t, acl.EventRead(prefix)) +} + +func checkDenyEventWrite(t *testing.T, acl ACL, prefix string) { + require.False(t, acl.EventWrite(prefix)) +} + +func checkDenyIntentionDefaultAllow(t *testing.T, acl ACL, prefix string) { + require.False(t, acl.IntentionDefaultAllow()) +} + +func checkDenyIntentionRead(t *testing.T, acl ACL, prefix string) { + require.False(t, acl.IntentionRead(prefix)) +} + +func checkDenyIntentionWrite(t *testing.T, acl ACL, prefix string) { + require.False(t, acl.IntentionWrite(prefix)) +} + +func checkDenyKeyRead(t *testing.T, acl ACL, prefix string) { + require.False(t, acl.KeyRead(prefix)) +} + +func checkDenyKeyList(t *testing.T, acl ACL, prefix string) { + require.False(t, acl.KeyList(prefix)) +} + +func checkDenyKeyringRead(t *testing.T, acl ACL, prefix string) { + require.False(t, acl.KeyringRead()) +} + +func checkDenyKeyringWrite(t *testing.T, acl ACL, prefix string) { + require.False(t, acl.KeyringWrite()) +} + +func checkDenyKeyWrite(t *testing.T, acl ACL, prefix string) { + require.False(t, acl.KeyWrite(prefix, nil)) +} + +func checkDenyKeyWritePrefix(t *testing.T, acl ACL, prefix string) { + require.False(t, acl.KeyWritePrefix(prefix)) +} + +func checkDenyNodeRead(t *testing.T, acl ACL, prefix string) { + require.False(t, acl.NodeRead(prefix)) +} + +func checkDenyNodeWrite(t *testing.T, acl ACL, prefix string) { + require.False(t, acl.NodeWrite(prefix, nil)) +} + +func checkDenyOperatorRead(t *testing.T, acl ACL, prefix string) { + require.False(t, acl.OperatorRead()) +} + +func checkDenyOperatorWrite(t *testing.T, acl ACL, prefix string) { + require.False(t, acl.OperatorWrite()) +} + +func checkDenyPreparedQueryRead(t *testing.T, acl ACL, prefix string) { + require.False(t, acl.PreparedQueryRead(prefix)) +} + +func checkDenyPreparedQueryWrite(t *testing.T, acl ACL, prefix string) { + require.False(t, acl.PreparedQueryWrite(prefix)) +} + +func checkDenyServiceRead(t *testing.T, acl ACL, prefix string) { + require.False(t, acl.ServiceRead(prefix)) +} + +func checkDenyServiceWrite(t *testing.T, acl ACL, prefix string) { + require.False(t, acl.ServiceWrite(prefix, nil)) +} + +func checkDenySessionRead(t *testing.T, acl ACL, prefix string) { + require.False(t, acl.SessionRead(prefix)) +} + +func checkDenySessionWrite(t *testing.T, acl ACL, prefix string) { + require.False(t, acl.SessionWrite(prefix)) +} + +func checkDenySnapshot(t *testing.T, acl ACL, prefix string) { + require.False(t, acl.Snapshot()) +} + +func TestACL(t *testing.T) { + type aclCheck struct { + name string + prefix string + check func(t *testing.T, acl ACL, prefix string) + } + + type aclTest struct { + name string + defaultPolicy ACL + policyStack []*Policy + checks []aclCheck + } + + tests := []aclTest{ + { + name: "DenyAll", + defaultPolicy: DenyAll(), + checks: []aclCheck{ + {name: "DenyACLList", check: checkDenyACLList}, + {name: "DenyACLModify", check: checkDenyACLModify}, + {name: "DenyAgentRead", check: checkDenyAgentRead}, + {name: "DenyAgentWrite", check: checkDenyAgentWrite}, + {name: "DenyEventRead", check: checkDenyEventRead}, + {name: "DenyEventWrite", check: checkDenyEventWrite}, + {name: "DenyIntentionDefaultAllow", check: checkDenyIntentionDefaultAllow}, + {name: "DenyIntentionRead", check: checkDenyIntentionRead}, + {name: "DenyIntentionWrite", check: checkDenyIntentionWrite}, + {name: "DenyKeyRead", check: checkDenyKeyRead}, + {name: "DenyKeyringRead", check: checkDenyKeyringRead}, + {name: "DenyKeyringWrite", check: checkDenyKeyringWrite}, + {name: "DenyKeyWrite", check: checkDenyKeyWrite}, + {name: "DenyNodeRead", check: checkDenyNodeRead}, + {name: "DenyNodeWrite", check: checkDenyNodeWrite}, + {name: "DenyOperatorRead", check: checkDenyOperatorRead}, + {name: "DenyOperatorWrite", check: checkDenyOperatorWrite}, + {name: "DenyPreparedQueryRead", check: checkDenyPreparedQueryRead}, + {name: "DenyPreparedQueryWrite", check: checkDenyPreparedQueryWrite}, + {name: "DenyServiceRead", check: checkDenyServiceRead}, + {name: "DenyServiceWrite", check: checkDenyServiceWrite}, + {name: "DenySessionRead", check: checkDenySessionRead}, + {name: "DenySessionWrite", check: checkDenySessionWrite}, + {name: "DenySnapshot", check: checkDenySnapshot}, + }, + }, + { + name: "AllowAll", + defaultPolicy: AllowAll(), + checks: []aclCheck{ + {name: "DenyACLList", check: checkDenyACLList}, + {name: "DenyACLModify", check: checkDenyACLModify}, + {name: "AllowAgentRead", check: checkAllowAgentRead}, + {name: "AllowAgentWrite", check: checkAllowAgentWrite}, + {name: "AllowEventRead", check: checkAllowEventRead}, + {name: "AllowEventWrite", check: checkAllowEventWrite}, + {name: "AllowIntentionDefaultAllow", check: checkAllowIntentionDefaultAllow}, + {name: "AllowIntentionRead", check: checkAllowIntentionRead}, + {name: "AllowIntentionWrite", check: checkAllowIntentionWrite}, + {name: "AllowKeyRead", check: checkAllowKeyRead}, + {name: "AllowKeyringRead", check: checkAllowKeyringRead}, + {name: "AllowKeyringWrite", check: checkAllowKeyringWrite}, + {name: "AllowKeyWrite", check: checkAllowKeyWrite}, + {name: "AllowNodeRead", check: checkAllowNodeRead}, + {name: "AllowNodeWrite", check: checkAllowNodeWrite}, + {name: "AllowOperatorRead", check: checkAllowOperatorRead}, + {name: "AllowOperatorWrite", check: checkAllowOperatorWrite}, + {name: "AllowPreparedQueryRead", check: checkAllowPreparedQueryRead}, + {name: "AllowPreparedQueryWrite", check: checkAllowPreparedQueryWrite}, + {name: "AllowServiceRead", check: checkAllowServiceRead}, + {name: "AllowServiceWrite", check: checkAllowServiceWrite}, + {name: "AllowSessionRead", check: checkAllowSessionRead}, + {name: "AllowSessionWrite", check: checkAllowSessionWrite}, + {name: "DenySnapshot", check: checkDenySnapshot}, + }, + }, + { + name: "ManageAll", + defaultPolicy: ManageAll(), + checks: []aclCheck{ + {name: "AllowACLList", check: checkAllowACLList}, + {name: "AllowACLModify", check: checkAllowACLModify}, + {name: "AllowAgentRead", check: checkAllowAgentRead}, + {name: "AllowAgentWrite", check: checkAllowAgentWrite}, + {name: "AllowEventRead", check: checkAllowEventRead}, + {name: "AllowEventWrite", check: checkAllowEventWrite}, + {name: "AllowIntentionDefaultAllow", check: checkAllowIntentionDefaultAllow}, + {name: "AllowIntentionRead", check: checkAllowIntentionRead}, + {name: "AllowIntentionWrite", check: checkAllowIntentionWrite}, + {name: "AllowKeyRead", check: checkAllowKeyRead}, + {name: "AllowKeyringRead", check: checkAllowKeyringRead}, + {name: "AllowKeyringWrite", check: checkAllowKeyringWrite}, + {name: "AllowKeyWrite", check: checkAllowKeyWrite}, + {name: "AllowNodeRead", check: checkAllowNodeRead}, + {name: "AllowNodeWrite", check: checkAllowNodeWrite}, + {name: "AllowOperatorRead", check: checkAllowOperatorRead}, + {name: "AllowOperatorWrite", check: checkAllowOperatorWrite}, + {name: "AllowPreparedQueryRead", check: checkAllowPreparedQueryRead}, + {name: "AllowPreparedQueryWrite", check: checkAllowPreparedQueryWrite}, + {name: "AllowServiceRead", check: checkAllowServiceRead}, + {name: "AllowServiceWrite", check: checkAllowServiceWrite}, + {name: "AllowSessionRead", check: checkAllowSessionRead}, + {name: "AllowSessionWrite", check: checkAllowSessionWrite}, + {name: "AllowSnapshot", check: checkAllowSnapshot}, + }, + }, + { + name: "AgentBasicDefaultDeny", + defaultPolicy: DenyAll(), + policyStack: []*Policy{ + &Policy{ + Agents: []*AgentPolicy{ + &AgentPolicy{ + Node: "root", + Policy: PolicyRead, + }, + &AgentPolicy{ + Node: "root-nope", + Policy: PolicyDeny, + }, + &AgentPolicy{ + Node: "root-rw", + Policy: PolicyWrite, + }, + }, + }, + }, + checks: []aclCheck{ + {name: "DefaultReadDenied", prefix: "ro", check: checkDenyAgentRead}, + {name: "DefaultWriteDenied", prefix: "ro", check: checkDenyAgentWrite}, + {name: "ROReadAllowed", prefix: "root", check: checkAllowAgentRead}, + {name: "ROWriteDenied", prefix: "root", check: checkDenyAgentWrite}, + {name: "ROSuffixReadAllowed", prefix: "root-ro", check: checkAllowAgentRead}, + {name: "ROSuffixWriteDenied", prefix: "root-ro", check: checkDenyAgentWrite}, + {name: "RWReadAllowed", prefix: "root-rw", check: checkAllowAgentRead}, + {name: "RWWriteDenied", prefix: "root-rw", check: checkAllowAgentWrite}, + {name: "RWSuffixReadAllowed", prefix: "root-rw-sub", check: checkAllowAgentRead}, + {name: "RWSuffixWriteAllowed", prefix: "root-rw-sub", check: checkAllowAgentWrite}, + {name: "DenyReadDenied", prefix: "root-nope", check: checkDenyAgentRead}, + {name: "DenyWriteDenied", prefix: "root-nope", check: checkDenyAgentWrite}, + {name: "DenySuffixReadDenied", prefix: "root-nope-sub", check: checkDenyAgentRead}, + {name: "DenySuffixWriteDenied", prefix: "root-nope-sub", check: checkDenyAgentWrite}, + }, + }, + { + name: "AgentBasicDefaultAllow", + defaultPolicy: AllowAll(), + policyStack: []*Policy{ + &Policy{ + Agents: []*AgentPolicy{ + &AgentPolicy{ + Node: "root", + Policy: PolicyRead, + }, + &AgentPolicy{ + Node: "root-nope", + Policy: PolicyDeny, + }, + &AgentPolicy{ + Node: "root-rw", + Policy: PolicyWrite, + }, + }, + }, + }, + checks: []aclCheck{ + {name: "DefaultReadDenied", prefix: "ro", check: checkAllowAgentRead}, + {name: "DefaultWriteDenied", prefix: "ro", check: checkAllowAgentWrite}, + {name: "ROReadAllowed", prefix: "root", check: checkAllowAgentRead}, + {name: "ROWriteDenied", prefix: "root", check: checkDenyAgentWrite}, + {name: "ROSuffixReadAllowed", prefix: "root-ro", check: checkAllowAgentRead}, + {name: "ROSuffixWriteDenied", prefix: "root-ro", check: checkDenyAgentWrite}, + {name: "RWReadAllowed", prefix: "root-rw", check: checkAllowAgentRead}, + {name: "RWWriteDenied", prefix: "root-rw", check: checkAllowAgentWrite}, + {name: "RWSuffixReadAllowed", prefix: "root-rw-sub", check: checkAllowAgentRead}, + {name: "RWSuffixWriteAllowed", prefix: "root-rw-sub", check: checkAllowAgentWrite}, + {name: "DenyReadDenied", prefix: "root-nope", check: checkDenyAgentRead}, + {name: "DenyWriteDenied", prefix: "root-nope", check: checkDenyAgentWrite}, + {name: "DenySuffixReadDenied", prefix: "root-nope-sub", check: checkDenyAgentRead}, + {name: "DenySuffixWriteDenied", prefix: "root-nope-sub", check: checkDenyAgentWrite}, + }, + }, + { + name: "PreparedQueryDefaultAllow", + defaultPolicy: AllowAll(), + policyStack: []*Policy{ + &Policy{ + PreparedQueries: []*PreparedQueryPolicy{ + &PreparedQueryPolicy{ + Prefix: "other", + Policy: PolicyDeny, + }, + }, + }, + }, + checks: []aclCheck{ + // in version 1.2.1 and below this would have failed + {name: "ReadAllowed", prefix: "foo", check: checkAllowPreparedQueryRead}, + // in version 1.2.1 and below this would have failed + {name: "WriteAllowed", prefix: "foo", check: checkAllowPreparedQueryWrite}, + {name: "ReadDenied", prefix: "other", check: checkDenyPreparedQueryRead}, + {name: "WriteDenied", prefix: "other", check: checkDenyPreparedQueryWrite}, + }, + }, + { + name: "AgentNestedDefaultDeny", + defaultPolicy: DenyAll(), + policyStack: []*Policy{ + &Policy{ + Agents: []*AgentPolicy{ + &AgentPolicy{ + Node: "root-nope", + Policy: PolicyDeny, + }, + &AgentPolicy{ + Node: "root-ro", + Policy: PolicyRead, + }, + &AgentPolicy{ + Node: "root-rw", + Policy: PolicyWrite, + }, + &AgentPolicy{ + Node: "override", + Policy: PolicyDeny, + }, + }, + }, + &Policy{ + Agents: []*AgentPolicy{ + &AgentPolicy{ + Node: "child-nope", + Policy: PolicyDeny, + }, + &AgentPolicy{ + Node: "child-ro", + Policy: PolicyRead, + }, + &AgentPolicy{ + Node: "child-rw", + Policy: PolicyWrite, + }, + &AgentPolicy{ + Node: "override", + Policy: PolicyWrite, + }, + }, + }, + }, + checks: []aclCheck{ + {name: "DefaultReadDenied", prefix: "nope", check: checkDenyAgentRead}, + {name: "DefaultWriteDenied", prefix: "nope", check: checkDenyAgentWrite}, + {name: "DenyReadDenied", prefix: "root-nope", check: checkDenyAgentRead}, + {name: "DenyWriteDenied", prefix: "root-nope", check: checkDenyAgentWrite}, + {name: "ROReadAllowed", prefix: "root-ro", check: checkAllowAgentRead}, + {name: "ROWriteDenied", prefix: "root-ro", check: checkDenyAgentWrite}, + {name: "RWReadAllowed", prefix: "root-rw", check: checkAllowAgentRead}, + {name: "RWWriteAllowed", prefix: "root-rw", check: checkAllowAgentWrite}, + {name: "DenySuffixReadDenied", prefix: "root-nope-prefix", check: checkDenyAgentRead}, + {name: "DenySuffixWriteDenied", prefix: "root-nope-prefix", check: checkDenyAgentWrite}, + {name: "ROSuffixReadAllowed", prefix: "root-ro-prefix", check: checkAllowAgentRead}, + {name: "ROSuffixWriteDenied", prefix: "root-ro-prefix", check: checkDenyAgentWrite}, + {name: "RWSuffixReadAllowed", prefix: "root-rw-prefix", check: checkAllowAgentRead}, + {name: "RWSuffixWriteAllowed", prefix: "root-rw-prefix", check: checkAllowAgentWrite}, + {name: "ChildDenyReadDenied", prefix: "child-nope", check: checkDenyAgentRead}, + {name: "ChildDenyWriteDenied", prefix: "child-nope", check: checkDenyAgentWrite}, + {name: "ChildROReadAllowed", prefix: "child-ro", check: checkAllowAgentRead}, + {name: "ChildROWriteDenied", prefix: "child-ro", check: checkDenyAgentWrite}, + {name: "ChildRWReadAllowed", prefix: "child-rw", check: checkAllowAgentRead}, + {name: "ChildRWWriteAllowed", prefix: "child-rw", check: checkAllowAgentWrite}, + {name: "ChildDenySuffixReadDenied", prefix: "child-nope-prefix", check: checkDenyAgentRead}, + {name: "ChildDenySuffixWriteDenied", prefix: "child-nope-prefix", check: checkDenyAgentWrite}, + {name: "ChildROSuffixReadAllowed", prefix: "child-ro-prefix", check: checkAllowAgentRead}, + {name: "ChildROSuffixWriteDenied", prefix: "child-ro-prefix", check: checkDenyAgentWrite}, + {name: "ChildRWSuffixReadAllowed", prefix: "child-rw-prefix", check: checkAllowAgentRead}, + {name: "ChildRWSuffixWriteAllowed", prefix: "child-rw-prefix", check: checkAllowAgentWrite}, + {name: "ChildOverrideReadAllowed", prefix: "override", check: checkAllowAgentRead}, + {name: "ChildOverrideWriteAllowed", prefix: "override", check: checkAllowAgentWrite}, + }, + }, + { + name: "AgentNestedDefaultAllow", + defaultPolicy: AllowAll(), + policyStack: []*Policy{ + &Policy{ + Agents: []*AgentPolicy{ + &AgentPolicy{ + Node: "root-nope", + Policy: PolicyDeny, + }, + &AgentPolicy{ + Node: "root-ro", + Policy: PolicyRead, + }, + &AgentPolicy{ + Node: "root-rw", + Policy: PolicyWrite, + }, + &AgentPolicy{ + Node: "override", + Policy: PolicyDeny, + }, + }, + }, + &Policy{ + Agents: []*AgentPolicy{ + &AgentPolicy{ + Node: "child-nope", + Policy: PolicyDeny, + }, + &AgentPolicy{ + Node: "child-ro", + Policy: PolicyRead, + }, + &AgentPolicy{ + Node: "child-rw", + Policy: PolicyWrite, + }, + &AgentPolicy{ + Node: "override", + Policy: PolicyWrite, + }, + }, + }, + }, + checks: []aclCheck{ + {name: "DefaultReadAllowed", prefix: "nope", check: checkAllowAgentRead}, + {name: "DefaultWriteAllowed", prefix: "nope", check: checkAllowAgentWrite}, + {name: "DenyReadDenied", prefix: "root-nope", check: checkDenyAgentRead}, + {name: "DenyWriteDenied", prefix: "root-nope", check: checkDenyAgentWrite}, + {name: "ROReadAllowed", prefix: "root-ro", check: checkAllowAgentRead}, + {name: "ROWriteDenied", prefix: "root-ro", check: checkDenyAgentWrite}, + {name: "RWReadAllowed", prefix: "root-rw", check: checkAllowAgentRead}, + {name: "RWWriteAllowed", prefix: "root-rw", check: checkAllowAgentWrite}, + {name: "DenySuffixReadDenied", prefix: "root-nope-prefix", check: checkDenyAgentRead}, + {name: "DenySuffixWriteDenied", prefix: "root-nope-prefix", check: checkDenyAgentWrite}, + {name: "ROSuffixReadAllowed", prefix: "root-ro-prefix", check: checkAllowAgentRead}, + {name: "ROSuffixWriteDenied", prefix: "root-ro-prefix", check: checkDenyAgentWrite}, + {name: "RWSuffixReadAllowed", prefix: "root-rw-prefix", check: checkAllowAgentRead}, + {name: "RWSuffixWriteAllowed", prefix: "root-rw-prefix", check: checkAllowAgentWrite}, + {name: "ChildDenyReadDenied", prefix: "child-nope", check: checkDenyAgentRead}, + {name: "ChildDenyWriteDenied", prefix: "child-nope", check: checkDenyAgentWrite}, + {name: "ChildROReadAllowed", prefix: "child-ro", check: checkAllowAgentRead}, + {name: "ChildROWriteDenied", prefix: "child-ro", check: checkDenyAgentWrite}, + {name: "ChildRWReadAllowed", prefix: "child-rw", check: checkAllowAgentRead}, + {name: "ChildRWWriteAllowed", prefix: "child-rw", check: checkAllowAgentWrite}, + {name: "ChildDenySuffixReadDenied", prefix: "child-nope-prefix", check: checkDenyAgentRead}, + {name: "ChildDenySuffixWriteDenied", prefix: "child-nope-prefix", check: checkDenyAgentWrite}, + {name: "ChildROSuffixReadAllowed", prefix: "child-ro-prefix", check: checkAllowAgentRead}, + {name: "ChildROSuffixWriteDenied", prefix: "child-ro-prefix", check: checkDenyAgentWrite}, + {name: "ChildRWSuffixReadAllowed", prefix: "child-rw-prefix", check: checkAllowAgentRead}, + {name: "ChildRWSuffixWriteAllowed", prefix: "child-rw-prefix", check: checkAllowAgentWrite}, + {name: "ChildOverrideReadAllowed", prefix: "override", check: checkAllowAgentRead}, + {name: "ChildOverrideWriteAllowed", prefix: "override", check: checkAllowAgentWrite}, + }, + }, + { + name: "KeyringDefaultAllowPolicyDeny", + defaultPolicy: AllowAll(), + policyStack: []*Policy{ + &Policy{ + Keyring: PolicyDeny, + }, + }, + checks: []aclCheck{ + {name: "ReadDenied", check: checkDenyKeyringRead}, + // in version 1.2.1 and below this would have failed + {name: "WriteDenied", check: checkDenyKeyringWrite}, + }, + }, + { + name: "KeyringDefaultAllowPolicyRead", + defaultPolicy: AllowAll(), + policyStack: []*Policy{ + &Policy{ + Keyring: PolicyRead, + }, + }, + checks: []aclCheck{ + {name: "ReadAllowed", check: checkAllowKeyringRead}, + // in version 1.2.1 and below this would have failed + {name: "WriteDenied", check: checkDenyKeyringWrite}, + }, + }, + { + name: "KeyringDefaultAllowPolicyWrite", + defaultPolicy: AllowAll(), + policyStack: []*Policy{ + &Policy{ + Keyring: PolicyWrite, + }, + }, + checks: []aclCheck{ + {name: "ReadAllowed", check: checkAllowKeyringRead}, + {name: "WriteAllowed", check: checkAllowKeyringWrite}, + }, + }, + { + name: "KeyringDefaultAllowPolicyNone", + defaultPolicy: AllowAll(), + policyStack: []*Policy{ + &Policy{}, + }, + checks: []aclCheck{ + {name: "ReadAllowed", check: checkAllowKeyringRead}, + {name: "WriteAllowed", check: checkAllowKeyringWrite}, + }, + }, + { + name: "KeyringDefaultDenyPolicyDeny", + defaultPolicy: DenyAll(), + policyStack: []*Policy{ + &Policy{ + Keyring: PolicyDeny, + }, + }, + checks: []aclCheck{ + {name: "ReadDenied", check: checkDenyKeyringRead}, + {name: "WriteDenied", check: checkDenyKeyringWrite}, + }, + }, + { + name: "KeyringDefaultDenyPolicyRead", + defaultPolicy: DenyAll(), + policyStack: []*Policy{ + &Policy{ + Keyring: PolicyRead, + }, + }, + checks: []aclCheck{ + {name: "ReadAllowed", check: checkAllowKeyringRead}, + {name: "WriteDenied", check: checkDenyKeyringWrite}, + }, + }, + { + name: "KeyringDefaultDenyPolicyWrite", + defaultPolicy: DenyAll(), + policyStack: []*Policy{ + &Policy{ + Keyring: PolicyWrite, + }, + }, + checks: []aclCheck{ + {name: "ReadAllowed", check: checkAllowKeyringRead}, + {name: "WriteAllowed", check: checkAllowKeyringWrite}, + }, + }, + { + name: "KeyringDefaultDenyPolicyNone", + defaultPolicy: DenyAll(), + policyStack: []*Policy{ + &Policy{}, + }, + checks: []aclCheck{ + {name: "ReadDenied", check: checkDenyKeyringRead}, + {name: "WriteDenied", check: checkDenyKeyringWrite}, + }, + }, + { + name: "OperatorDefaultAllowPolicyDeny", + defaultPolicy: AllowAll(), + policyStack: []*Policy{ + &Policy{ + Operator: PolicyDeny, + }, + }, + checks: []aclCheck{ + {name: "ReadDenied", check: checkDenyOperatorRead}, + // in version 1.2.1 and below this would have failed + {name: "WriteDenied", check: checkDenyOperatorWrite}, + }, + }, + { + name: "OperatorDefaultAllowPolicyRead", + defaultPolicy: AllowAll(), + policyStack: []*Policy{ + &Policy{ + Operator: PolicyRead, + }, + }, + checks: []aclCheck{ + {name: "ReadAllowed", check: checkAllowOperatorRead}, + // in version 1.2.1 and below this would have failed + {name: "WriteDenied", check: checkDenyOperatorWrite}, + }, + }, + { + name: "OperatorDefaultAllowPolicyWrite", + defaultPolicy: AllowAll(), + policyStack: []*Policy{ + &Policy{ + Operator: PolicyWrite, + }, + }, + checks: []aclCheck{ + {name: "ReadAllowed", check: checkAllowOperatorRead}, + {name: "WriteAllowed", check: checkAllowOperatorWrite}, + }, + }, + { + name: "OperatorDefaultAllowPolicyNone", + defaultPolicy: AllowAll(), + policyStack: []*Policy{ + &Policy{}, + }, + checks: []aclCheck{ + {name: "ReadAllowed", check: checkAllowOperatorRead}, + {name: "WriteAllowed", check: checkAllowOperatorWrite}, + }, + }, + { + name: "OperatorDefaultDenyPolicyDeny", + defaultPolicy: DenyAll(), + policyStack: []*Policy{ + &Policy{ + Operator: PolicyDeny, + }, + }, + checks: []aclCheck{ + {name: "ReadDenied", check: checkDenyOperatorRead}, + {name: "WriteDenied", check: checkDenyOperatorWrite}, + }, + }, + { + name: "OperatorDefaultDenyPolicyRead", + defaultPolicy: DenyAll(), + policyStack: []*Policy{ + &Policy{ + Operator: PolicyRead, + }, + }, + checks: []aclCheck{ + {name: "ReadAllowed", check: checkAllowOperatorRead}, + {name: "WriteDenied", check: checkDenyOperatorWrite}, + }, + }, + { + name: "OperatorDefaultDenyPolicyWrite", + defaultPolicy: DenyAll(), + policyStack: []*Policy{ + &Policy{ + Operator: PolicyWrite, + }, + }, + checks: []aclCheck{ + {name: "ReadAllowed", check: checkAllowOperatorRead}, + {name: "WriteAllowed", check: checkAllowOperatorWrite}, + }, + }, + { + name: "OperatorDefaultDenyPolicyNone", + defaultPolicy: DenyAll(), + policyStack: []*Policy{ + &Policy{}, + }, + checks: []aclCheck{ + {name: "ReadDenied", check: checkDenyOperatorRead}, + {name: "WriteDenied", check: checkDenyOperatorWrite}, + }, + }, + { + name: "NodeDefaultDeny", + defaultPolicy: DenyAll(), + policyStack: []*Policy{ + &Policy{ + Nodes: []*NodePolicy{ + &NodePolicy{ + Name: "root-nope", + Policy: PolicyDeny, + }, + &NodePolicy{ + Name: "root-ro", + Policy: PolicyRead, + }, + &NodePolicy{ + Name: "root-rw", + Policy: PolicyWrite, + }, + &NodePolicy{ + Name: "override", + Policy: PolicyDeny, + }, + }, + }, + &Policy{ + Nodes: []*NodePolicy{ + &NodePolicy{ + Name: "child-nope", + Policy: PolicyDeny, + }, + &NodePolicy{ + Name: "child-ro", + Policy: PolicyRead, + }, + &NodePolicy{ + Name: "child-rw", + Policy: PolicyWrite, + }, + &NodePolicy{ + Name: "override", + Policy: PolicyWrite, + }, + }, + }, + }, + checks: []aclCheck{ + {name: "DefaultReadDenied", prefix: "nope", check: checkDenyNodeRead}, + {name: "DefaultWriteDenied", prefix: "nope", check: checkDenyNodeWrite}, + {name: "DenyReadDenied", prefix: "root-nope", check: checkDenyNodeRead}, + {name: "DenyWriteDenied", prefix: "root-nope", check: checkDenyNodeWrite}, + {name: "ROReadAllowed", prefix: "root-ro", check: checkAllowNodeRead}, + {name: "ROWriteDenied", prefix: "root-ro", check: checkDenyNodeWrite}, + {name: "RWReadAllowed", prefix: "root-rw", check: checkAllowNodeRead}, + {name: "RWWriteAllowed", prefix: "root-rw", check: checkAllowNodeWrite}, + {name: "DenySuffixReadDenied", prefix: "root-nope-prefix", check: checkDenyNodeRead}, + {name: "DenySuffixWriteDenied", prefix: "root-nope-prefix", check: checkDenyNodeWrite}, + {name: "ROSuffixReadAllowed", prefix: "root-ro-prefix", check: checkAllowNodeRead}, + {name: "ROSuffixWriteDenied", prefix: "root-ro-prefix", check: checkDenyNodeWrite}, + {name: "RWSuffixReadAllowed", prefix: "root-rw-prefix", check: checkAllowNodeRead}, + {name: "RWSuffixWriteAllowed", prefix: "root-rw-prefix", check: checkAllowNodeWrite}, + {name: "ChildDenyReadDenied", prefix: "child-nope", check: checkDenyNodeRead}, + {name: "ChildDenyWriteDenied", prefix: "child-nope", check: checkDenyNodeWrite}, + {name: "ChildROReadAllowed", prefix: "child-ro", check: checkAllowNodeRead}, + {name: "ChildROWriteDenied", prefix: "child-ro", check: checkDenyNodeWrite}, + {name: "ChildRWReadAllowed", prefix: "child-rw", check: checkAllowNodeRead}, + {name: "ChildRWWriteAllowed", prefix: "child-rw", check: checkAllowNodeWrite}, + {name: "ChildDenySuffixReadDenied", prefix: "child-nope-prefix", check: checkDenyNodeRead}, + {name: "ChildDenySuffixWriteDenied", prefix: "child-nope-prefix", check: checkDenyNodeWrite}, + {name: "ChildROSuffixReadAllowed", prefix: "child-ro-prefix", check: checkAllowNodeRead}, + {name: "ChildROSuffixWriteDenied", prefix: "child-ro-prefix", check: checkDenyNodeWrite}, + {name: "ChildRWSuffixReadAllowed", prefix: "child-rw-prefix", check: checkAllowNodeRead}, + {name: "ChildRWSuffixWriteAllowed", prefix: "child-rw-prefix", check: checkAllowNodeWrite}, + {name: "ChildOverrideReadAllowed", prefix: "override", check: checkAllowNodeRead}, + {name: "ChildOverrideWriteAllowed", prefix: "override", check: checkAllowNodeWrite}, + }, + }, + { + name: "NodeDefaultAllow", + defaultPolicy: AllowAll(), + policyStack: []*Policy{ + &Policy{ + Nodes: []*NodePolicy{ + &NodePolicy{ + Name: "root-nope", + Policy: PolicyDeny, + }, + &NodePolicy{ + Name: "root-ro", + Policy: PolicyRead, + }, + &NodePolicy{ + Name: "root-rw", + Policy: PolicyWrite, + }, + &NodePolicy{ + Name: "override", + Policy: PolicyDeny, + }, + }, + }, + &Policy{ + Nodes: []*NodePolicy{ + &NodePolicy{ + Name: "child-nope", + Policy: PolicyDeny, + }, + &NodePolicy{ + Name: "child-ro", + Policy: PolicyRead, + }, + &NodePolicy{ + Name: "child-rw", + Policy: PolicyWrite, + }, + &NodePolicy{ + Name: "override", + Policy: PolicyWrite, + }, + }, + }, + }, + checks: []aclCheck{ + {name: "DefaultReadAllowed", prefix: "nope", check: checkAllowNodeRead}, + {name: "DefaultWriteAllowed", prefix: "nope", check: checkAllowNodeWrite}, + {name: "DenyReadDenied", prefix: "root-nope", check: checkDenyNodeRead}, + {name: "DenyWriteDenied", prefix: "root-nope", check: checkDenyNodeWrite}, + {name: "ROReadAllowed", prefix: "root-ro", check: checkAllowNodeRead}, + {name: "ROWriteDenied", prefix: "root-ro", check: checkDenyNodeWrite}, + {name: "RWReadAllowed", prefix: "root-rw", check: checkAllowNodeRead}, + {name: "RWWriteAllowed", prefix: "root-rw", check: checkAllowNodeWrite}, + {name: "DenySuffixReadDenied", prefix: "root-nope-prefix", check: checkDenyNodeRead}, + {name: "DenySuffixWriteDenied", prefix: "root-nope-prefix", check: checkDenyNodeWrite}, + {name: "ROSuffixReadAllowed", prefix: "root-ro-prefix", check: checkAllowNodeRead}, + {name: "ROSuffixWriteDenied", prefix: "root-ro-prefix", check: checkDenyNodeWrite}, + {name: "RWSuffixReadAllowed", prefix: "root-rw-prefix", check: checkAllowNodeRead}, + {name: "RWSuffixWriteAllowed", prefix: "root-rw-prefix", check: checkAllowNodeWrite}, + {name: "ChildDenyReadDenied", prefix: "child-nope", check: checkDenyNodeRead}, + {name: "ChildDenyWriteDenied", prefix: "child-nope", check: checkDenyNodeWrite}, + {name: "ChildROReadAllowed", prefix: "child-ro", check: checkAllowNodeRead}, + {name: "ChildROWriteDenied", prefix: "child-ro", check: checkDenyNodeWrite}, + {name: "ChildRWReadAllowed", prefix: "child-rw", check: checkAllowNodeRead}, + {name: "ChildRWWriteAllowed", prefix: "child-rw", check: checkAllowNodeWrite}, + {name: "ChildDenySuffixReadDenied", prefix: "child-nope-prefix", check: checkDenyNodeRead}, + {name: "ChildDenySuffixWriteDenied", prefix: "child-nope-prefix", check: checkDenyNodeWrite}, + {name: "ChildROSuffixReadAllowed", prefix: "child-ro-prefix", check: checkAllowNodeRead}, + {name: "ChildROSuffixWriteDenied", prefix: "child-ro-prefix", check: checkDenyNodeWrite}, + {name: "ChildRWSuffixReadAllowed", prefix: "child-rw-prefix", check: checkAllowNodeRead}, + {name: "ChildRWSuffixWriteAllowed", prefix: "child-rw-prefix", check: checkAllowNodeWrite}, + {name: "ChildOverrideReadAllowed", prefix: "override", check: checkAllowNodeRead}, + {name: "ChildOverrideWriteAllowed", prefix: "override", check: checkAllowNodeWrite}, + }, + }, + { + name: "SessionDefaultDeny", + defaultPolicy: DenyAll(), + policyStack: []*Policy{ + &Policy{ + Sessions: []*SessionPolicy{ + &SessionPolicy{ + Node: "root-nope", + Policy: PolicyDeny, + }, + &SessionPolicy{ + Node: "root-ro", + Policy: PolicyRead, + }, + &SessionPolicy{ + Node: "root-rw", + Policy: PolicyWrite, + }, + &SessionPolicy{ + Node: "override", + Policy: PolicyDeny, + }, + }, + }, + &Policy{ + Sessions: []*SessionPolicy{ + &SessionPolicy{ + Node: "child-nope", + Policy: PolicyDeny, + }, + &SessionPolicy{ + Node: "child-ro", + Policy: PolicyRead, + }, + &SessionPolicy{ + Node: "child-rw", + Policy: PolicyWrite, + }, + &SessionPolicy{ + Node: "override", + Policy: PolicyWrite, + }, + }, + }, + }, + checks: []aclCheck{ + {name: "DefaultReadDenied", prefix: "nope", check: checkDenySessionRead}, + {name: "DefaultWriteDenied", prefix: "nope", check: checkDenySessionWrite}, + {name: "DenyReadDenied", prefix: "root-nope", check: checkDenySessionRead}, + {name: "DenyWriteDenied", prefix: "root-nope", check: checkDenySessionWrite}, + {name: "ROReadAllowed", prefix: "root-ro", check: checkAllowSessionRead}, + {name: "ROWriteDenied", prefix: "root-ro", check: checkDenySessionWrite}, + {name: "RWReadAllowed", prefix: "root-rw", check: checkAllowSessionRead}, + {name: "RWWriteAllowed", prefix: "root-rw", check: checkAllowSessionWrite}, + {name: "DenySuffixReadDenied", prefix: "root-nope-prefix", check: checkDenySessionRead}, + {name: "DenySuffixWriteDenied", prefix: "root-nope-prefix", check: checkDenySessionWrite}, + {name: "ROSuffixReadAllowed", prefix: "root-ro-prefix", check: checkAllowSessionRead}, + {name: "ROSuffixWriteDenied", prefix: "root-ro-prefix", check: checkDenySessionWrite}, + {name: "RWSuffixReadAllowed", prefix: "root-rw-prefix", check: checkAllowSessionRead}, + {name: "RWSuffixWriteAllowed", prefix: "root-rw-prefix", check: checkAllowSessionWrite}, + {name: "ChildDenyReadDenied", prefix: "child-nope", check: checkDenySessionRead}, + {name: "ChildDenyWriteDenied", prefix: "child-nope", check: checkDenySessionWrite}, + {name: "ChildROReadAllowed", prefix: "child-ro", check: checkAllowSessionRead}, + {name: "ChildROWriteDenied", prefix: "child-ro", check: checkDenySessionWrite}, + {name: "ChildRWReadAllowed", prefix: "child-rw", check: checkAllowSessionRead}, + {name: "ChildRWWriteAllowed", prefix: "child-rw", check: checkAllowSessionWrite}, + {name: "ChildDenySuffixReadDenied", prefix: "child-nope-prefix", check: checkDenySessionRead}, + {name: "ChildDenySuffixWriteDenied", prefix: "child-nope-prefix", check: checkDenySessionWrite}, + {name: "ChildROSuffixReadAllowed", prefix: "child-ro-prefix", check: checkAllowSessionRead}, + {name: "ChildROSuffixWriteDenied", prefix: "child-ro-prefix", check: checkDenySessionWrite}, + {name: "ChildRWSuffixReadAllowed", prefix: "child-rw-prefix", check: checkAllowSessionRead}, + {name: "ChildRWSuffixWriteAllowed", prefix: "child-rw-prefix", check: checkAllowSessionWrite}, + {name: "ChildOverrideReadAllowed", prefix: "override", check: checkAllowSessionRead}, + {name: "ChildOverrideWriteAllowed", prefix: "override", check: checkAllowSessionWrite}, + }, + }, + { + name: "SessionDefaultAllow", + defaultPolicy: AllowAll(), + policyStack: []*Policy{ + &Policy{ + Sessions: []*SessionPolicy{ + &SessionPolicy{ + Node: "root-nope", + Policy: PolicyDeny, + }, + &SessionPolicy{ + Node: "root-ro", + Policy: PolicyRead, + }, + &SessionPolicy{ + Node: "root-rw", + Policy: PolicyWrite, + }, + &SessionPolicy{ + Node: "override", + Policy: PolicyDeny, + }, + }, + }, + &Policy{ + Sessions: []*SessionPolicy{ + &SessionPolicy{ + Node: "child-nope", + Policy: PolicyDeny, + }, + &SessionPolicy{ + Node: "child-ro", + Policy: PolicyRead, + }, + &SessionPolicy{ + Node: "child-rw", + Policy: PolicyWrite, + }, + &SessionPolicy{ + Node: "override", + Policy: PolicyWrite, + }, + }, + }, + }, + checks: []aclCheck{ + {name: "DefaultReadAllowed", prefix: "nope", check: checkAllowSessionRead}, + {name: "DefaultWriteAllowed", prefix: "nope", check: checkAllowSessionWrite}, + {name: "DenyReadDenied", prefix: "root-nope", check: checkDenySessionRead}, + {name: "DenyWriteDenied", prefix: "root-nope", check: checkDenySessionWrite}, + {name: "ROReadAllowed", prefix: "root-ro", check: checkAllowSessionRead}, + {name: "ROWriteDenied", prefix: "root-ro", check: checkDenySessionWrite}, + {name: "RWReadAllowed", prefix: "root-rw", check: checkAllowSessionRead}, + {name: "RWWriteAllowed", prefix: "root-rw", check: checkAllowSessionWrite}, + {name: "DenySuffixReadDenied", prefix: "root-nope-prefix", check: checkDenySessionRead}, + {name: "DenySuffixWriteDenied", prefix: "root-nope-prefix", check: checkDenySessionWrite}, + {name: "ROSuffixReadAllowed", prefix: "root-ro-prefix", check: checkAllowSessionRead}, + {name: "ROSuffixWriteDenied", prefix: "root-ro-prefix", check: checkDenySessionWrite}, + {name: "RWSuffixReadAllowed", prefix: "root-rw-prefix", check: checkAllowSessionRead}, + {name: "RWSuffixWriteAllowed", prefix: "root-rw-prefix", check: checkAllowSessionWrite}, + {name: "ChildDenyReadDenied", prefix: "child-nope", check: checkDenySessionRead}, + {name: "ChildDenyWriteDenied", prefix: "child-nope", check: checkDenySessionWrite}, + {name: "ChildROReadAllowed", prefix: "child-ro", check: checkAllowSessionRead}, + {name: "ChildROWriteDenied", prefix: "child-ro", check: checkDenySessionWrite}, + {name: "ChildRWReadAllowed", prefix: "child-rw", check: checkAllowSessionRead}, + {name: "ChildRWWriteAllowed", prefix: "child-rw", check: checkAllowSessionWrite}, + {name: "ChildDenySuffixReadDenied", prefix: "child-nope-prefix", check: checkDenySessionRead}, + {name: "ChildDenySuffixWriteDenied", prefix: "child-nope-prefix", check: checkDenySessionWrite}, + {name: "ChildROSuffixReadAllowed", prefix: "child-ro-prefix", check: checkAllowSessionRead}, + {name: "ChildROSuffixWriteDenied", prefix: "child-ro-prefix", check: checkDenySessionWrite}, + {name: "ChildRWSuffixReadAllowed", prefix: "child-rw-prefix", check: checkAllowSessionRead}, + {name: "ChildRWSuffixWriteAllowed", prefix: "child-rw-prefix", check: checkAllowSessionWrite}, + {name: "ChildOverrideReadAllowed", prefix: "override", check: checkAllowSessionRead}, + {name: "ChildOverrideWriteAllowed", prefix: "override", check: checkAllowSessionWrite}, + }, + }, + { + name: "Parent", + defaultPolicy: DenyAll(), + policyStack: []*Policy{ + &Policy{ + Keys: []*KeyPolicy{ + &KeyPolicy{ + Prefix: "foo/", + Policy: PolicyWrite, + }, + &KeyPolicy{ + Prefix: "bar/", + Policy: PolicyRead, + }, + }, + PreparedQueries: []*PreparedQueryPolicy{ + &PreparedQueryPolicy{ + Prefix: "other", + Policy: PolicyWrite, + }, + &PreparedQueryPolicy{ + Prefix: "foo", + Policy: PolicyRead, + }, + }, + Services: []*ServicePolicy{ + &ServicePolicy{ + Name: "other", + Policy: PolicyWrite, + }, + &ServicePolicy{ + Name: "foo", + Policy: PolicyRead, + }, + }, + }, + &Policy{ + Keys: []*KeyPolicy{ + &KeyPolicy{ + Prefix: "foo/priv/", + Policy: PolicyRead, + }, + &KeyPolicy{ + Prefix: "bar/", + Policy: PolicyDeny, + }, + &KeyPolicy{ + Prefix: "zip/", + Policy: PolicyRead, + }, + }, + PreparedQueries: []*PreparedQueryPolicy{ + &PreparedQueryPolicy{ + Prefix: "bar", + Policy: PolicyDeny, + }, + }, + Services: []*ServicePolicy{ + &ServicePolicy{ + Name: "bar", + Policy: PolicyDeny, + }, + }, + }, + }, + checks: []aclCheck{ + {name: "KeyReadDenied", prefix: "other", check: checkDenyKeyRead}, + {name: "KeyWriteDenied", prefix: "other", check: checkDenyKeyWrite}, + {name: "KeyWritePrefixDenied", prefix: "other", check: checkDenyKeyWritePrefix}, + {name: "KeyReadAllowed", prefix: "foo/test", check: checkAllowKeyRead}, + {name: "KeyWriteAllowed", prefix: "foo/test", check: checkAllowKeyWrite}, + {name: "KeyWritePrefixAllowed", prefix: "foo/test", check: checkAllowKeyWritePrefix}, + {name: "KeyReadAllowed", prefix: "foo/priv/test", check: checkAllowKeyRead}, + {name: "KeyWriteDenied", prefix: "foo/priv/test", check: checkDenyKeyWrite}, + {name: "KeyWritePrefixDenied", prefix: "foo/priv/test", check: checkDenyKeyWritePrefix}, + {name: "KeyReadDenied", prefix: "bar/any", check: checkDenyKeyRead}, + {name: "KeyWriteDenied", prefix: "bar/any", check: checkDenyKeyWrite}, + {name: "KeyWritePrefixDenied", prefix: "bar/any", check: checkDenyKeyWritePrefix}, + {name: "KeyReadAllowed", prefix: "zip/test", check: checkAllowKeyRead}, + {name: "KeyWriteDenied", prefix: "zip/test", check: checkDenyKeyWrite}, + {name: "KeyWritePrefixDenied", prefix: "zip/test", check: checkDenyKeyWritePrefix}, + {name: "ServiceReadDenied", prefix: "fail", check: checkDenyServiceRead}, + {name: "ServiceWriteDenied", prefix: "fail", check: checkDenyServiceWrite}, + {name: "ServiceReadAllowed", prefix: "other", check: checkAllowServiceRead}, + {name: "ServiceWriteAllowed", prefix: "other", check: checkAllowServiceWrite}, + {name: "ServiceReadAllowed", prefix: "foo", check: checkAllowServiceRead}, + {name: "ServiceWriteDenied", prefix: "foo", check: checkDenyServiceWrite}, + {name: "ServiceReadDenied", prefix: "bar", check: checkDenyServiceRead}, + {name: "ServiceWriteDenied", prefix: "bar", check: checkDenyServiceWrite}, + {name: "PreparedQueryReadAllowed", prefix: "foo", check: checkAllowPreparedQueryRead}, + {name: "PreparedQueryWriteDenied", prefix: "foo", check: checkDenyPreparedQueryWrite}, + {name: "PreparedQueryReadAllowed", prefix: "foobar", check: checkAllowPreparedQueryRead}, + {name: "PreparedQueryWriteDenied", prefix: "foobar", check: checkDenyPreparedQueryWrite}, + {name: "PreparedQueryReadDenied", prefix: "bar", check: checkDenyPreparedQueryRead}, + {name: "PreparedQueryWriteDenied", prefix: "bar", check: checkDenyPreparedQueryWrite}, + {name: "PreparedQueryReadDenied", prefix: "barbaz", check: checkDenyPreparedQueryRead}, + {name: "PreparedQueryWriteDenied", prefix: "barbaz", check: checkDenyPreparedQueryWrite}, + {name: "PreparedQueryReadDenied", prefix: "baz", check: checkDenyPreparedQueryRead}, + {name: "PreparedQueryWriteDenied", prefix: "baz", check: checkDenyPreparedQueryWrite}, + {name: "PreparedQueryReadDenied", prefix: "nope", check: checkDenyPreparedQueryRead}, + {name: "PreparedQueryWriteDenied", prefix: "nope", check: checkDenyPreparedQueryWrite}, + {name: "ACLListDenied", check: checkDenyACLList}, + {name: "ACLModifyDenied", check: checkDenyACLModify}, + {name: "SnapshotDenied", check: checkDenySnapshot}, + {name: "IntentionDefaultAllowDenied", check: checkDenyIntentionDefaultAllow}, + }, + }, + { + name: "ComplexDefaultAllow", + defaultPolicy: AllowAll(), + policyStack: []*Policy{ + &Policy{ + Events: []*EventPolicy{ + &EventPolicy{ + Event: "", + Policy: PolicyRead, + }, + &EventPolicy{ + Event: "foo", + Policy: PolicyWrite, + }, + &EventPolicy{ + Event: "bar", + Policy: PolicyDeny, + }, + }, + Keys: []*KeyPolicy{ + &KeyPolicy{ + Prefix: "foo/", + Policy: PolicyWrite, + }, + &KeyPolicy{ + Prefix: "foo/priv/", + Policy: PolicyDeny, + }, + &KeyPolicy{ + Prefix: "bar/", + Policy: PolicyDeny, + }, + &KeyPolicy{ + Prefix: "zip/", + Policy: PolicyRead, + }, + &KeyPolicy{ + Prefix: "zap/", + Policy: PolicyList, + }, + }, + PreparedQueries: []*PreparedQueryPolicy{ + &PreparedQueryPolicy{ + Prefix: "", + Policy: PolicyRead, + }, + &PreparedQueryPolicy{ + Prefix: "foo", + Policy: PolicyWrite, + }, + &PreparedQueryPolicy{ + Prefix: "bar", + Policy: PolicyDeny, + }, + &PreparedQueryPolicy{ + Prefix: "zoo", + Policy: PolicyWrite, + }, + }, + Services: []*ServicePolicy{ + &ServicePolicy{ + Name: "", + Policy: PolicyWrite, + }, + &ServicePolicy{ + Name: "foo", + Policy: PolicyRead, + }, + &ServicePolicy{ + Name: "bar", + Policy: PolicyDeny, + }, + &ServicePolicy{ + Name: "barfoo", + Policy: PolicyWrite, + Intentions: PolicyWrite, + }, + &ServicePolicy{ + Name: "intbaz", + Policy: PolicyWrite, + Intentions: PolicyDeny, + }, + }, + }, + }, + checks: []aclCheck{ + {name: "KeyReadAllowed", prefix: "other", check: checkAllowKeyRead}, + {name: "KeyWriteAllowed", prefix: "other", check: checkAllowKeyWrite}, + {name: "KeyWritePrefixAllowed", prefix: "other", check: checkAllowKeyWritePrefix}, + {name: "KeyListAllowed", prefix: "other", check: checkAllowKeyList}, + {name: "KeyReadAllowed", prefix: "foo/test", check: checkAllowKeyRead}, + {name: "KeyWriteAllowed", prefix: "foo/test", check: checkAllowKeyWrite}, + {name: "KeyWritePrefixAllowed", prefix: "foo/test", check: checkAllowKeyWritePrefix}, + {name: "KeyListAllowed", prefix: "foo/test", check: checkAllowKeyList}, + {name: "KeyReadDenied", prefix: "foo/priv/test", check: checkDenyKeyRead}, + {name: "KeyWriteDenied", prefix: "foo/priv/test", check: checkDenyKeyWrite}, + {name: "KeyWritePrefixDenied", prefix: "foo/priv/test", check: checkDenyKeyWritePrefix}, + {name: "KeyListDenied", prefix: "foo/priv/test", check: checkDenyKeyList}, + {name: "KeyReadDenied", prefix: "bar/any", check: checkDenyKeyRead}, + {name: "KeyWriteDenied", prefix: "bar/any", check: checkDenyKeyWrite}, + {name: "KeyWritePrefixDenied", prefix: "bar/any", check: checkDenyKeyWritePrefix}, + {name: "KeyListDenied", prefix: "bar/any", check: checkDenyKeyList}, + {name: "KeyReadAllowed", prefix: "zip/test", check: checkAllowKeyRead}, + {name: "KeyWriteDenied", prefix: "zip/test", check: checkDenyKeyWrite}, + {name: "KeyWritePrefixDenied", prefix: "zip/test", check: checkDenyKeyWritePrefix}, + {name: "KeyListDenied", prefix: "zip/test", check: checkDenyKeyList}, + {name: "KeyReadAllowed", prefix: "foo/", check: checkAllowKeyRead}, + {name: "KeyWriteAllowed", prefix: "foo/", check: checkAllowKeyWrite}, + {name: "KeyWritePrefixDenied", prefix: "foo/", check: checkDenyKeyWritePrefix}, + {name: "KeyListAllowed", prefix: "foo/", check: checkAllowKeyList}, + {name: "KeyReadAllowed", prefix: "", check: checkAllowKeyRead}, + {name: "KeyWriteAllowed", prefix: "", check: checkAllowKeyWrite}, + {name: "KeyWritePrefixDenied", prefix: "", check: checkDenyKeyWritePrefix}, + {name: "KeyListAllowed", prefix: "", check: checkAllowKeyList}, + {name: "KeyReadAllowed", prefix: "zap/test", check: checkAllowKeyRead}, + {name: "KeyWriteDenied", prefix: "zap/test", check: checkDenyKeyWrite}, + {name: "KeyWritePrefixDenied", prefix: "zap/test", check: checkDenyKeyWritePrefix}, + {name: "KeyListAllowed", prefix: "zap/test", check: checkAllowKeyList}, + {name: "IntentionReadAllowed", prefix: "other", check: checkAllowIntentionRead}, + {name: "IntentionWriteDenied", prefix: "other", check: checkDenyIntentionWrite}, + {name: "IntentionReadAllowed", prefix: "foo", check: checkAllowIntentionRead}, + {name: "IntentionWriteDenied", prefix: "foo", check: checkDenyIntentionWrite}, + {name: "IntentionReadDenied", prefix: "bar", check: checkDenyIntentionRead}, + {name: "IntentionWriteDenied", prefix: "bar", check: checkDenyIntentionWrite}, + {name: "IntentionReadAllowed", prefix: "foobar", check: checkAllowIntentionRead}, + {name: "IntentionWriteDenied", prefix: "foobar", check: checkDenyIntentionWrite}, + {name: "IntentionReadDenied", prefix: "barfo", check: checkDenyIntentionRead}, + {name: "IntentionWriteDenied", prefix: "barfo", check: checkDenyIntentionWrite}, + {name: "IntentionReadAllowed", prefix: "barfoo", check: checkAllowIntentionRead}, + {name: "IntentionWriteAllowed", prefix: "barfoo", check: checkAllowIntentionWrite}, + {name: "IntentionReadAllowed", prefix: "barfoo2", check: checkAllowIntentionRead}, + {name: "IntentionWriteAllowed", prefix: "barfoo2", check: checkAllowIntentionWrite}, + {name: "IntentionReadDenied", prefix: "intbaz", check: checkDenyIntentionRead}, + {name: "IntentionWriteDenied", prefix: "intbaz", check: checkDenyIntentionWrite}, + {name: "IntentionDefaultAllowAllowed", check: checkAllowIntentionDefaultAllow}, + {name: "ServiceReadAllowed", prefix: "other", check: checkAllowServiceRead}, + {name: "ServiceWriteAllowed", prefix: "other", check: checkAllowServiceWrite}, + {name: "ServiceReadAllowed", prefix: "foo", check: checkAllowServiceRead}, + {name: "ServiceWriteDenied", prefix: "foo", check: checkDenyServiceWrite}, + {name: "ServiceReadDenied", prefix: "bar", check: checkDenyServiceRead}, + {name: "ServiceWriteDenied", prefix: "bar", check: checkDenyServiceWrite}, + {name: "ServiceReadAllowed", prefix: "foobar", check: checkAllowServiceRead}, + {name: "ServiceWriteDenied", prefix: "foobar", check: checkDenyServiceWrite}, + {name: "ServiceReadDenied", prefix: "barfo", check: checkDenyServiceRead}, + {name: "ServiceWriteDenied", prefix: "barfo", check: checkDenyServiceWrite}, + {name: "ServiceReadAllowed", prefix: "barfoo", check: checkAllowServiceRead}, + {name: "ServiceWriteAllowed", prefix: "barfoo", check: checkAllowServiceWrite}, + {name: "ServiceReadAllowed", prefix: "barfoo2", check: checkAllowServiceRead}, + {name: "ServiceWriteAllowed", prefix: "barfoo2", check: checkAllowServiceWrite}, + {name: "EventReadAllowed", prefix: "foo", check: checkAllowEventRead}, + {name: "EventWriteAllowed", prefix: "foo", check: checkAllowEventWrite}, + {name: "EventReadAllowed", prefix: "foobar", check: checkAllowEventRead}, + {name: "EventWriteAllowed", prefix: "foobar", check: checkAllowEventWrite}, + {name: "EventReadDenied", prefix: "bar", check: checkDenyEventRead}, + {name: "EventWriteDenied", prefix: "bar", check: checkDenyEventWrite}, + {name: "EventReadDenied", prefix: "barbaz", check: checkDenyEventRead}, + {name: "EventWriteDenied", prefix: "barbaz", check: checkDenyEventWrite}, + {name: "EventReadAllowed", prefix: "baz", check: checkAllowEventRead}, + {name: "EventWriteDenied", prefix: "baz", check: checkDenyEventWrite}, + {name: "PreparedQueryReadAllowed", prefix: "foo", check: checkAllowPreparedQueryRead}, + {name: "PreparedQueryWriteAllowed", prefix: "foo", check: checkAllowPreparedQueryWrite}, + {name: "PreparedQueryReadAllowed", prefix: "foobar", check: checkAllowPreparedQueryRead}, + {name: "PreparedQueryWriteAllowed", prefix: "foobar", check: checkAllowPreparedQueryWrite}, + {name: "PreparedQueryReadDenied", prefix: "bar", check: checkDenyPreparedQueryRead}, + {name: "PreparedQueryWriteDenied", prefix: "bar", check: checkDenyPreparedQueryWrite}, + {name: "PreparedQueryReadDenied", prefix: "barbaz", check: checkDenyPreparedQueryRead}, + {name: "PreparedQueryWriteDenied", prefix: "barbaz", check: checkDenyPreparedQueryWrite}, + {name: "PreparedQueryReadAllowed", prefix: "baz", check: checkAllowPreparedQueryRead}, + {name: "PreparedQueryWriteDenied", prefix: "baz", check: checkDenyPreparedQueryWrite}, + {name: "PreparedQueryReadAllowed", prefix: "nope", check: checkAllowPreparedQueryRead}, + {name: "PreparedQueryWriteDenied", prefix: "nope", check: checkDenyPreparedQueryWrite}, + {name: "PreparedQueryReadAllowed", prefix: "zoo", check: checkAllowPreparedQueryRead}, + {name: "PreparedQueryWriteAllowed", prefix: "zoo", check: checkAllowPreparedQueryWrite}, + {name: "PreparedQueryReadAllowed", prefix: "zookeeper", check: checkAllowPreparedQueryRead}, + {name: "PreparedQueryWriteAllowed", prefix: "zookeeper", check: checkAllowPreparedQueryWrite}, + }, + }, + } + + for _, tcase := range tests { + t.Run(tcase.name, func(t *testing.T) { + acl := tcase.defaultPolicy + for _, policy := range tcase.policyStack { + newACL, err := New(acl, policy, nil) + require.NoError(t, err) + acl = newACL + } + + for _, check := range tcase.checks { + checkName := check.name + if check.prefix != "" { + checkName = fmt.Sprintf("%s.Prefix(%s)", checkName, check.prefix) + } + t.Run(checkName, func(t *testing.T) { + check.check(t, acl, check.prefix) + }) + } + }) + } +} + func TestRootACL(t *testing.T) { - if RootACL("allow") != AllowAll() { - t.Fatalf("Bad root") - } - if RootACL("deny") != DenyAll() { - t.Fatalf("Bad root") - } - if RootACL("manage") != ManageAll() { - t.Fatalf("Bad root") - } - if RootACL("foo") != nil { - t.Fatalf("bad root") - } + require.Equal(t, AllowAll(), RootACL("allow")) + require.Equal(t, DenyAll(), RootACL("deny")) + require.Equal(t, ManageAll(), RootACL("manage")) + require.Nil(t, RootACL("foo")) } -func TestStaticACL(t *testing.T) { - all := AllowAll() - if _, ok := all.(*StaticACL); !ok { - t.Fatalf("expected static") +func TestACLEnforce(t *testing.T) { + type enforceTest struct { + name string + rule string + required string + allow bool + recurse bool } - none := DenyAll() - if _, ok := none.(*StaticACL); !ok { - t.Fatalf("expected static") + tests := []enforceTest{ + { + name: "RuleNoneRequireRead", + rule: "", + required: PolicyRead, + allow: false, + recurse: true, + }, + { + name: "RuleNoneRequireWrite", + rule: "", + required: PolicyWrite, + allow: false, + recurse: true, + }, + { + name: "RuleNoneRequireList", + rule: "", + required: PolicyList, + allow: false, + recurse: true, + }, + { + name: "RuleReadRequireRead", + rule: PolicyRead, + required: PolicyRead, + allow: true, + recurse: false, + }, + { + name: "RuleReadRequireWrite", + rule: PolicyRead, + required: PolicyWrite, + allow: false, + recurse: false, + }, + { + name: "RuleReadRequireList", + rule: PolicyRead, + required: PolicyList, + allow: false, + recurse: false, + }, + { + name: "RuleListRequireRead", + rule: PolicyList, + required: PolicyRead, + allow: true, + recurse: false, + }, + { + name: "RuleListRequireWrite", + rule: PolicyList, + required: PolicyWrite, + allow: false, + recurse: false, + }, + { + name: "RuleListRequireList", + rule: PolicyList, + required: PolicyList, + allow: true, + recurse: false, + }, + { + name: "RuleWritetRequireRead", + rule: PolicyWrite, + required: PolicyRead, + allow: true, + recurse: false, + }, + { + name: "RuleWritetRequireWrite", + rule: PolicyWrite, + required: PolicyWrite, + allow: true, + recurse: false, + }, + { + name: "RuleWritetRequireList", + rule: PolicyWrite, + required: PolicyList, + allow: true, + recurse: false, + }, + { + name: "RuleDenyRequireRead", + rule: PolicyDeny, + required: PolicyRead, + allow: false, + recurse: false, + }, + { + name: "RuleDenyRequireWrite", + rule: PolicyDeny, + required: PolicyWrite, + allow: false, + recurse: false, + }, + { + name: "RuleDenyRequireList", + rule: PolicyDeny, + required: PolicyList, + allow: false, + recurse: false, + }, } - manage := ManageAll() - if _, ok := manage.(*StaticACL); !ok { - t.Fatalf("expected static") - } - - if all.ACLList() { - t.Fatalf("should not allow") - } - if all.ACLModify() { - t.Fatalf("should not allow") - } - if !all.AgentRead("foobar") { - t.Fatalf("should allow") - } - if !all.AgentWrite("foobar") { - t.Fatalf("should allow") - } - if !all.EventRead("foobar") { - t.Fatalf("should allow") - } - if !all.EventWrite("foobar") { - t.Fatalf("should allow") - } - if !all.IntentionDefaultAllow() { - t.Fatalf("should allow") - } - if !all.IntentionWrite("foobar") { - t.Fatalf("should allow") - } - if !all.KeyRead("foobar") { - t.Fatalf("should allow") - } - if !all.KeyWrite("foobar", nil) { - t.Fatalf("should allow") - } - if !all.KeyringRead() { - t.Fatalf("should allow") - } - if !all.KeyringWrite() { - t.Fatalf("should allow") - } - if !all.NodeRead("foobar") { - t.Fatalf("should allow") - } - if !all.NodeWrite("foobar", nil) { - t.Fatalf("should allow") - } - if !all.OperatorRead() { - t.Fatalf("should allow") - } - if !all.OperatorWrite() { - t.Fatalf("should allow") - } - if !all.PreparedQueryRead("foobar") { - t.Fatalf("should allow") - } - if !all.PreparedQueryWrite("foobar") { - t.Fatalf("should allow") - } - if !all.ServiceRead("foobar") { - t.Fatalf("should allow") - } - if !all.ServiceWrite("foobar", nil) { - t.Fatalf("should allow") - } - if !all.SessionRead("foobar") { - t.Fatalf("should allow") - } - if !all.SessionWrite("foobar") { - t.Fatalf("should allow") - } - if all.Snapshot() { - t.Fatalf("should not allow") - } - - if none.ACLList() { - t.Fatalf("should not allow") - } - if none.ACLModify() { - t.Fatalf("should not allow") - } - if none.AgentRead("foobar") { - t.Fatalf("should not allow") - } - if none.AgentWrite("foobar") { - t.Fatalf("should not allow") - } - if none.EventRead("foobar") { - t.Fatalf("should not allow") - } - if none.EventRead("") { - t.Fatalf("should not allow") - } - if none.EventWrite("foobar") { - t.Fatalf("should not allow") - } - if none.EventWrite("") { - t.Fatalf("should not allow") - } - if none.IntentionDefaultAllow() { - t.Fatalf("should not allow") - } - if none.IntentionWrite("foo") { - t.Fatalf("should not allow") - } - if none.KeyRead("foobar") { - t.Fatalf("should not allow") - } - if none.KeyWrite("foobar", nil) { - t.Fatalf("should not allow") - } - if none.KeyringRead() { - t.Fatalf("should now allow") - } - if none.KeyringWrite() { - t.Fatalf("should not allow") - } - if none.NodeRead("foobar") { - t.Fatalf("should not allow") - } - if none.NodeWrite("foobar", nil) { - t.Fatalf("should not allow") - } - if none.OperatorRead() { - t.Fatalf("should now allow") - } - if none.OperatorWrite() { - t.Fatalf("should not allow") - } - if none.PreparedQueryRead("foobar") { - t.Fatalf("should not allow") - } - if none.PreparedQueryWrite("foobar") { - t.Fatalf("should not allow") - } - if none.ServiceRead("foobar") { - t.Fatalf("should not allow") - } - if none.ServiceWrite("foobar", nil) { - t.Fatalf("should not allow") - } - if none.SessionRead("foobar") { - t.Fatalf("should not allow") - } - if none.SessionWrite("foobar") { - t.Fatalf("should not allow") - } - if none.Snapshot() { - t.Fatalf("should not allow") - } - - if !manage.ACLList() { - t.Fatalf("should allow") - } - if !manage.ACLModify() { - t.Fatalf("should allow") - } - if !manage.AgentRead("foobar") { - t.Fatalf("should allow") - } - if !manage.AgentWrite("foobar") { - t.Fatalf("should allow") - } - if !manage.EventRead("foobar") { - t.Fatalf("should allow") - } - if !manage.EventWrite("foobar") { - t.Fatalf("should allow") - } - if !manage.IntentionDefaultAllow() { - t.Fatalf("should allow") - } - if !manage.IntentionWrite("foobar") { - t.Fatalf("should allow") - } - if !manage.KeyRead("foobar") { - t.Fatalf("should allow") - } - if !manage.KeyWrite("foobar", nil) { - t.Fatalf("should allow") - } - if !manage.KeyringRead() { - t.Fatalf("should allow") - } - if !manage.KeyringWrite() { - t.Fatalf("should allow") - } - if !manage.NodeRead("foobar") { - t.Fatalf("should allow") - } - if !manage.NodeWrite("foobar", nil) { - t.Fatalf("should allow") - } - if !manage.OperatorRead() { - t.Fatalf("should allow") - } - if !manage.OperatorWrite() { - t.Fatalf("should allow") - } - if !manage.PreparedQueryRead("foobar") { - t.Fatalf("should allow") - } - if !manage.PreparedQueryWrite("foobar") { - t.Fatalf("should allow") - } - if !manage.ServiceRead("foobar") { - t.Fatalf("should allow") - } - if !manage.ServiceWrite("foobar", nil) { - t.Fatalf("should allow") - } - if !manage.SessionRead("foobar") { - t.Fatalf("should allow") - } - if !manage.SessionWrite("foobar") { - t.Fatalf("should allow") - } - if !manage.Snapshot() { - t.Fatalf("should allow") - } -} - -func TestPolicyACL(t *testing.T) { - all := AllowAll() - policy := &Policy{ - Events: []*EventPolicy{ - &EventPolicy{ - Event: "", - Policy: PolicyRead, - }, - &EventPolicy{ - Event: "foo", - Policy: PolicyWrite, - }, - &EventPolicy{ - Event: "bar", - Policy: PolicyDeny, - }, - }, - Keys: []*KeyPolicy{ - &KeyPolicy{ - Prefix: "foo/", - Policy: PolicyWrite, - }, - &KeyPolicy{ - Prefix: "foo/priv/", - Policy: PolicyDeny, - }, - &KeyPolicy{ - Prefix: "bar/", - Policy: PolicyDeny, - }, - &KeyPolicy{ - Prefix: "zip/", - Policy: PolicyRead, - }, - &KeyPolicy{ - Prefix: "zap/", - Policy: PolicyList, - }, - }, - PreparedQueries: []*PreparedQueryPolicy{ - &PreparedQueryPolicy{ - Prefix: "", - Policy: PolicyRead, - }, - &PreparedQueryPolicy{ - Prefix: "foo", - Policy: PolicyWrite, - }, - &PreparedQueryPolicy{ - Prefix: "bar", - Policy: PolicyDeny, - }, - &PreparedQueryPolicy{ - Prefix: "zoo", - Policy: PolicyWrite, - }, - }, - Services: []*ServicePolicy{ - &ServicePolicy{ - Name: "", - Policy: PolicyWrite, - }, - &ServicePolicy{ - Name: "foo", - Policy: PolicyRead, - }, - &ServicePolicy{ - Name: "bar", - Policy: PolicyDeny, - }, - &ServicePolicy{ - Name: "barfoo", - Policy: PolicyWrite, - Intentions: PolicyWrite, - }, - &ServicePolicy{ - Name: "intbaz", - Policy: PolicyWrite, - Intentions: PolicyDeny, - }, - }, - } - acl, err := New(all, policy, nil) - if err != nil { - t.Fatalf("err: %v", err) - } - - type keycase struct { - inp string - read bool - write bool - writePrefix bool - list bool - } - cases := []keycase{ - {"other", true, true, true, true}, - {"foo/test", true, true, true, true}, - {"foo/priv/test", false, false, false, false}, - {"bar/any", false, false, false, false}, - {"zip/test", true, false, false, false}, - {"foo/", true, true, false, true}, - {"", true, true, false, true}, - {"zap/test", true, false, false, true}, - } - for _, c := range cases { - if c.read != acl.KeyRead(c.inp) { - t.Fatalf("Read fail: %#v", c) - } - if c.write != acl.KeyWrite(c.inp, nil) { - t.Fatalf("Write fail: %#v", c) - } - if c.writePrefix != acl.KeyWritePrefix(c.inp) { - t.Fatalf("Write prefix fail: %#v", c) - } - } - - // Test the intentions - type intentioncase struct { - inp string - read bool - write bool - } - icases := []intentioncase{ - {"other", true, false}, - {"foo", true, false}, - {"bar", false, false}, - {"foobar", true, false}, - {"barfo", false, false}, - {"barfoo", true, true}, - {"barfoo2", true, true}, - {"intbaz", false, false}, - } - for _, c := range icases { - if c.read != acl.IntentionRead(c.inp) { - t.Fatalf("Read fail: %#v", c) - } - if c.write != acl.IntentionWrite(c.inp) { - t.Fatalf("Write fail: %#v", c) - } - } - - // Test the services - type servicecase struct { - inp string - read bool - write bool - } - scases := []servicecase{ - {"other", true, true}, - {"foo", true, false}, - {"bar", false, false}, - {"foobar", true, false}, - {"barfo", false, false}, - {"barfoo", true, true}, - {"barfoo2", true, true}, - } - for _, c := range scases { - if c.read != acl.ServiceRead(c.inp) { - t.Fatalf("Read fail: %#v", c) - } - if c.write != acl.ServiceWrite(c.inp, nil) { - t.Fatalf("Write fail: %#v", c) - } - } - - // Test the events - type eventcase struct { - inp string - read bool - write bool - } - eventcases := []eventcase{ - {"foo", true, true}, - {"foobar", true, true}, - {"bar", false, false}, - {"barbaz", false, false}, - {"baz", true, false}, - } - for _, c := range eventcases { - if c.read != acl.EventRead(c.inp) { - t.Fatalf("Event fail: %#v", c) - } - if c.write != acl.EventWrite(c.inp) { - t.Fatalf("Event fail: %#v", c) - } - } - - // Test prepared queries - type querycase struct { - inp string - read bool - write bool - } - querycases := []querycase{ - {"foo", true, true}, - {"foobar", true, true}, - {"bar", false, false}, - {"barbaz", false, false}, - {"baz", true, false}, - {"nope", true, false}, - {"zoo", true, true}, - {"zookeeper", true, true}, - } - for _, c := range querycases { - if c.read != acl.PreparedQueryRead(c.inp) { - t.Fatalf("Prepared query fail: %#v", c) - } - if c.write != acl.PreparedQueryWrite(c.inp) { - t.Fatalf("Prepared query fail: %#v", c) - } - } - - // Check default intentions bubble up - if !acl.IntentionDefaultAllow() { - t.Fatal("should allow") - } -} - -func TestPolicyACL_Parent(t *testing.T) { - deny := DenyAll() - policyRoot := &Policy{ - Keys: []*KeyPolicy{ - &KeyPolicy{ - Prefix: "foo/", - Policy: PolicyWrite, - }, - &KeyPolicy{ - Prefix: "bar/", - Policy: PolicyRead, - }, - }, - PreparedQueries: []*PreparedQueryPolicy{ - &PreparedQueryPolicy{ - Prefix: "other", - Policy: PolicyWrite, - }, - &PreparedQueryPolicy{ - Prefix: "foo", - Policy: PolicyRead, - }, - }, - Services: []*ServicePolicy{ - &ServicePolicy{ - Name: "other", - Policy: PolicyWrite, - }, - &ServicePolicy{ - Name: "foo", - Policy: PolicyRead, - }, - }, - } - root, err := New(deny, policyRoot, nil) - if err != nil { - t.Fatalf("err: %v", err) - } - - policy := &Policy{ - Keys: []*KeyPolicy{ - &KeyPolicy{ - Prefix: "foo/priv/", - Policy: PolicyRead, - }, - &KeyPolicy{ - Prefix: "bar/", - Policy: PolicyDeny, - }, - &KeyPolicy{ - Prefix: "zip/", - Policy: PolicyRead, - }, - }, - PreparedQueries: []*PreparedQueryPolicy{ - &PreparedQueryPolicy{ - Prefix: "bar", - Policy: PolicyDeny, - }, - }, - Services: []*ServicePolicy{ - &ServicePolicy{ - Name: "bar", - Policy: PolicyDeny, - }, - }, - } - acl, err := New(root, policy, nil) - if err != nil { - t.Fatalf("err: %v", err) - } - - type keycase struct { - inp string - read bool - write bool - writePrefix bool - } - cases := []keycase{ - {"other", false, false, false}, - {"foo/test", true, true, true}, - {"foo/priv/test", true, false, false}, - {"bar/any", false, false, false}, - {"zip/test", true, false, false}, - } - for _, c := range cases { - if c.read != acl.KeyRead(c.inp) { - t.Fatalf("Read fail: %#v", c) - } - if c.write != acl.KeyWrite(c.inp, nil) { - t.Fatalf("Write fail: %#v", c) - } - if c.writePrefix != acl.KeyWritePrefix(c.inp) { - t.Fatalf("Write prefix fail: %#v", c) - } - } - - // Test the services - type servicecase struct { - inp string - read bool - write bool - } - scases := []servicecase{ - {"fail", false, false}, - {"other", true, true}, - {"foo", true, false}, - {"bar", false, false}, - } - for _, c := range scases { - if c.read != acl.ServiceRead(c.inp) { - t.Fatalf("Read fail: %#v", c) - } - if c.write != acl.ServiceWrite(c.inp, nil) { - t.Fatalf("Write fail: %#v", c) - } - } - - // Test prepared queries - type querycase struct { - inp string - read bool - write bool - } - querycases := []querycase{ - {"foo", true, false}, - {"foobar", true, false}, - {"bar", false, false}, - {"barbaz", false, false}, - {"baz", false, false}, - {"nope", false, false}, - } - for _, c := range querycases { - if c.read != acl.PreparedQueryRead(c.inp) { - t.Fatalf("Prepared query fail: %#v", c) - } - if c.write != acl.PreparedQueryWrite(c.inp) { - t.Fatalf("Prepared query fail: %#v", c) - } - } - - // Check some management functions that chain up - if acl.ACLList() { - t.Fatalf("should not allow") - } - if acl.ACLModify() { - t.Fatalf("should not allow") - } - if acl.Snapshot() { - t.Fatalf("should not allow") - } - - // Check default intentions - if acl.IntentionDefaultAllow() { - t.Fatal("should not allow") - } -} - -func TestPolicyACL_Agent(t *testing.T) { - deny := DenyAll() - policyRoot := &Policy{ - Agents: []*AgentPolicy{ - &AgentPolicy{ - Node: "root-nope", - Policy: PolicyDeny, - }, - &AgentPolicy{ - Node: "root-ro", - Policy: PolicyRead, - }, - &AgentPolicy{ - Node: "root-rw", - Policy: PolicyWrite, - }, - &AgentPolicy{ - Node: "override", - Policy: PolicyDeny, - }, - }, - } - root, err := New(deny, policyRoot, nil) - if err != nil { - t.Fatalf("err: %v", err) - } - - policy := &Policy{ - Agents: []*AgentPolicy{ - &AgentPolicy{ - Node: "child-nope", - Policy: PolicyDeny, - }, - &AgentPolicy{ - Node: "child-ro", - Policy: PolicyRead, - }, - &AgentPolicy{ - Node: "child-rw", - Policy: PolicyWrite, - }, - &AgentPolicy{ - Node: "override", - Policy: PolicyWrite, - }, - }, - } - acl, err := New(root, policy, nil) - if err != nil { - t.Fatalf("err: %v", err) - } - - type agentcase struct { - inp string - read bool - write bool - } - cases := []agentcase{ - {"nope", false, false}, - {"root-nope", false, false}, - {"root-ro", true, false}, - {"root-rw", true, true}, - {"root-nope-prefix", false, false}, - {"root-ro-prefix", true, false}, - {"root-rw-prefix", true, true}, - {"child-nope", false, false}, - {"child-ro", true, false}, - {"child-rw", true, true}, - {"child-nope-prefix", false, false}, - {"child-ro-prefix", true, false}, - {"child-rw-prefix", true, true}, - {"override", true, true}, - } - for _, c := range cases { - if c.read != acl.AgentRead(c.inp) { - t.Fatalf("Read fail: %#v", c) - } - if c.write != acl.AgentWrite(c.inp) { - t.Fatalf("Write fail: %#v", c) - } - } -} - -func TestPolicyACL_Keyring(t *testing.T) { - type keyringcase struct { - inp string - read bool - write bool - } - cases := []keyringcase{ - {"", false, false}, - {PolicyRead, true, false}, - {PolicyWrite, true, true}, - {PolicyDeny, false, false}, - } - for _, c := range cases { - acl, err := New(DenyAll(), &Policy{Keyring: c.inp}, nil) - if err != nil { - t.Fatalf("bad: %s", err) - } - if acl.KeyringRead() != c.read { - t.Fatalf("bad: %#v", c) - } - if acl.KeyringWrite() != c.write { - t.Fatalf("bad: %#v", c) - } - } -} - -func TestPolicyACL_Operator(t *testing.T) { - type operatorcase struct { - inp string - read bool - write bool - } - cases := []operatorcase{ - {"", false, false}, - {PolicyRead, true, false}, - {PolicyWrite, true, true}, - {PolicyDeny, false, false}, - } - for _, c := range cases { - acl, err := New(DenyAll(), &Policy{Operator: c.inp}, nil) - if err != nil { - t.Fatalf("bad: %s", err) - } - if acl.OperatorRead() != c.read { - t.Fatalf("bad: %#v", c) - } - if acl.OperatorWrite() != c.write { - t.Fatalf("bad: %#v", c) - } - } -} - -func TestPolicyACL_Node(t *testing.T) { - deny := DenyAll() - policyRoot := &Policy{ - Nodes: []*NodePolicy{ - &NodePolicy{ - Name: "root-nope", - Policy: PolicyDeny, - }, - &NodePolicy{ - Name: "root-ro", - Policy: PolicyRead, - }, - &NodePolicy{ - Name: "root-rw", - Policy: PolicyWrite, - }, - &NodePolicy{ - Name: "override", - Policy: PolicyDeny, - }, - }, - } - root, err := New(deny, policyRoot, nil) - if err != nil { - t.Fatalf("err: %v", err) - } - - policy := &Policy{ - Nodes: []*NodePolicy{ - &NodePolicy{ - Name: "child-nope", - Policy: PolicyDeny, - }, - &NodePolicy{ - Name: "child-ro", - Policy: PolicyRead, - }, - &NodePolicy{ - Name: "child-rw", - Policy: PolicyWrite, - }, - &NodePolicy{ - Name: "override", - Policy: PolicyWrite, - }, - }, - } - acl, err := New(root, policy, nil) - if err != nil { - t.Fatalf("err: %v", err) - } - - type nodecase struct { - inp string - read bool - write bool - } - cases := []nodecase{ - {"nope", false, false}, - {"root-nope", false, false}, - {"root-ro", true, false}, - {"root-rw", true, true}, - {"root-nope-prefix", false, false}, - {"root-ro-prefix", true, false}, - {"root-rw-prefix", true, true}, - {"child-nope", false, false}, - {"child-ro", true, false}, - {"child-rw", true, true}, - {"child-nope-prefix", false, false}, - {"child-ro-prefix", true, false}, - {"child-rw-prefix", true, true}, - {"override", true, true}, - } - for _, c := range cases { - if c.read != acl.NodeRead(c.inp) { - t.Fatalf("Read fail: %#v", c) - } - if c.write != acl.NodeWrite(c.inp, nil) { - t.Fatalf("Write fail: %#v", c) - } - } -} - -func TestPolicyACL_Session(t *testing.T) { - deny := DenyAll() - policyRoot := &Policy{ - Sessions: []*SessionPolicy{ - &SessionPolicy{ - Node: "root-nope", - Policy: PolicyDeny, - }, - &SessionPolicy{ - Node: "root-ro", - Policy: PolicyRead, - }, - &SessionPolicy{ - Node: "root-rw", - Policy: PolicyWrite, - }, - &SessionPolicy{ - Node: "override", - Policy: PolicyDeny, - }, - }, - } - root, err := New(deny, policyRoot, nil) - if err != nil { - t.Fatalf("err: %v", err) - } - - policy := &Policy{ - Sessions: []*SessionPolicy{ - &SessionPolicy{ - Node: "child-nope", - Policy: PolicyDeny, - }, - &SessionPolicy{ - Node: "child-ro", - Policy: PolicyRead, - }, - &SessionPolicy{ - Node: "child-rw", - Policy: PolicyWrite, - }, - &SessionPolicy{ - Node: "override", - Policy: PolicyWrite, - }, - }, - } - acl, err := New(root, policy, nil) - if err != nil { - t.Fatalf("err: %v", err) - } - - type sessioncase struct { - inp string - read bool - write bool - } - cases := []sessioncase{ - {"nope", false, false}, - {"root-nope", false, false}, - {"root-ro", true, false}, - {"root-rw", true, true}, - {"root-nope-prefix", false, false}, - {"root-ro-prefix", true, false}, - {"root-rw-prefix", true, true}, - {"child-nope", false, false}, - {"child-ro", true, false}, - {"child-rw", true, true}, - {"child-nope-prefix", false, false}, - {"child-ro-prefix", true, false}, - {"child-rw-prefix", true, true}, - {"override", true, true}, - } - for _, c := range cases { - if c.read != acl.SessionRead(c.inp) { - t.Fatalf("Read fail: %#v", c) - } - if c.write != acl.SessionWrite(c.inp) { - t.Fatalf("Write fail: %#v", c) - } + for _, tcase := range tests { + t.Run(tcase.name, func(t *testing.T) { + allow, recurse := enforce(tcase.rule, tcase.required) + require.Equal(t, tcase.allow, allow) + require.Equal(t, tcase.recurse, recurse) + }) } }