From 883c5dd0014364fef891d62fc553954f2cfbcaa1 Mon Sep 17 00:00:00 2001 From: Matt Keeler Date: Tue, 24 Jul 2018 16:21:56 -0400 Subject: [PATCH 1/2] Fix ACL enforcement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This creates one function that takes a rule and the required permissions and returns whether it should be allowed and whether to leave the decision to the parent acl. Then this function is used everywhere. This makes acl enforcement consistent. There were several places where a default allow policy with explicit deny rules wasnt being handled and several others where it wasn’t using the parent acl appropriately but would lump no policy in with a deny policy. All of that has been fixed. --- acl/acl.go | 242 ++++++++++++++++++++++------------------------------- 1 file changed, 101 insertions(+), 141 deletions(-) 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 } } From fbb1a7a52bc36ea1d225f4464aa571c2f4919c02 Mon Sep 17 00:00:00 2001 From: Matt Keeler Date: Tue, 24 Jul 2018 16:37:01 -0400 Subject: [PATCH 2/2] Rewrite all of acl_test.go This is now using table driven testing. In addition to conversion of old tests I also implemented several new tests for the acl fixes in my previous commit. In particular the issues I saw with ACLs for prepared queries, keyring and operator all have tests for those and comments indicating that they would have previously failed. --- acl/acl_test.go | 2426 +++++++++++++++++++++++++++++------------------ 1 file changed, 1511 insertions(+), 915 deletions(-) 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) + }) } }