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 } }