open-consul/acl/acl.go
2014-08-18 15:46:21 -07:00

119 lines
2.6 KiB
Go

package acl
import (
"fmt"
"github.com/armon/go-radix"
)
var (
// allowAll is a singleton policy which allows all actions
allowAll ACL
// denyAll is a singleton policy which denies all actions
denyAll ACL
)
func init() {
// Setup the singletons
allowAll = &StaticACL{defaultAllow: true}
denyAll = &StaticACL{defaultAllow: false}
}
// ACL is the interface for policy enforcement.
type ACL interface {
KeyRead(string) bool
KeyWrite(string) bool
}
// StaticACL is used to implement a base ACL policy. It either
// allows or denies all requests. This can be used as a parent
// ACL to act in a blacklist or whitelist mode.
type StaticACL struct {
defaultAllow bool
}
func (s *StaticACL) KeyRead(string) bool {
return s.defaultAllow
}
func (s *StaticACL) KeyWrite(string) bool {
return s.defaultAllow
}
// AllowAll returns an ACL rule that allows all operations
func AllowAll() ACL {
return allowAll
}
// DenyAll returns an ACL rule that denies all operations
func DenyAll() ACL {
return denyAll
}
// PolicyACL is used to wrap a set of ACL policies to provide
// the ACL interface.
type PolicyACL struct {
// parent is used to resolve policy if we have
// no matching rule.
parent ACL
// keyRead contains the read policies
keyRead *radix.Tree
// keyWrite contains the write policies
keyWrite *radix.Tree
}
// 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) (*PolicyACL, error) {
p := &PolicyACL{
parent: parent,
keyRead: radix.New(),
keyWrite: radix.New(),
}
// Load the key policy
for _, kp := range policy.Keys {
switch kp.Policy {
case KeyPolicyDeny:
p.keyRead.Insert(kp.Prefix, false)
p.keyWrite.Insert(kp.Prefix, false)
case KeyPolicyRead:
p.keyRead.Insert(kp.Prefix, true)
p.keyWrite.Insert(kp.Prefix, false)
case KeyPolicyWrite:
p.keyRead.Insert(kp.Prefix, true)
p.keyWrite.Insert(kp.Prefix, true)
default:
return nil, fmt.Errorf("Invalid key policy: %#v", kp)
}
}
return p, nil
}
// 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.keyRead.LongestPrefix(key)
if ok {
return rule.(bool)
}
// No matching rule, use the parent.
return p.parent.KeyRead(key)
}
// KeyWrite returns if a key is allowed to be written
func (p *PolicyACL) KeyWrite(key string) bool {
// Look for a matching rule
_, rule, ok := p.keyWrite.LongestPrefix(key)
if ok {
return rule.(bool)
}
// No matching rule, use the parent.
return p.parent.KeyWrite(key)
}