acl: Simplify parent ACL, adding root policies

This commit is contained in:
Armon Dadgar 2014-08-12 10:35:27 -07:00
parent 9e16caa497
commit 32e1f8e259
4 changed files with 86 additions and 24 deletions

View File

@ -49,6 +49,18 @@ func DenyAll() ACL {
return denyAll return denyAll
} }
// RootACL returns a possible ACL if the ID matches a root policy
func RootACL(id string) ACL {
switch id {
case "allow":
return allowAll
case "deny":
return denyAll
default:
return nil
}
}
// PolicyACL is used to wrap a set of ACL policies to provide // PolicyACL is used to wrap a set of ACL policies to provide
// the ACL interface. // the ACL interface.
type PolicyACL struct { type PolicyACL struct {

View File

@ -4,6 +4,18 @@ import (
"testing" "testing"
) )
func TestRootACL(t *testing.T) {
if RootACL("allow") != AllowAll() {
t.Fatalf("Bad root")
}
if RootACL("deny") != DenyAll() {
t.Fatalf("Bad root")
}
if RootACL("foo") != nil {
t.Fatalf("bad root")
}
}
func TestStaticACL(t *testing.T) { func TestStaticACL(t *testing.T) {
all := AllowAll() all := AllowAll()
if _, ok := all.(*StaticACL); !ok { if _, ok := all.(*StaticACL); !ok {

View File

@ -7,9 +7,9 @@ import (
"github.com/hashicorp/golang-lru" "github.com/hashicorp/golang-lru"
) )
// FaultFunc is a function used to fault in the rules for an // FaultFunc is a function used to fault in the parent,
// ACL given it's ID // rules for an ACL given it's ID
type FaultFunc func(id string) (string, error) type FaultFunc func(id string) (string, string, error)
// aclEntry allows us to store the ACL with it's policy ID // aclEntry allows us to store the ACL with it's policy ID
type aclEntry struct { type aclEntry struct {
@ -19,15 +19,14 @@ type aclEntry struct {
// Cache is used to implement policy and ACL caching // Cache is used to implement policy and ACL caching
type Cache struct { type Cache struct {
aclCache *lru.Cache // Cache id -> acl
faultfn FaultFunc faultfn FaultFunc
parent ACL aclCache *lru.Cache // Cache id -> acl
policyCache *lru.Cache // Cache policy -> acl policyCache *lru.Cache // Cache policy -> acl
ruleCache *lru.Cache // Cache rules -> policy ruleCache *lru.Cache // Cache rules -> policy
} }
// NewCache contructs a new policy and ACL cache of a given size // NewCache contructs a new policy and ACL cache of a given size
func NewCache(size int, parent ACL, faultfn FaultFunc) (*Cache, error) { func NewCache(size int, faultfn FaultFunc) (*Cache, error) {
if size <= 0 { if size <= 0 {
return nil, fmt.Errorf("Must provide positive cache size") return nil, fmt.Errorf("Must provide positive cache size")
} }
@ -35,9 +34,8 @@ func NewCache(size int, parent ACL, faultfn FaultFunc) (*Cache, error) {
pc, _ := lru.New(size) pc, _ := lru.New(size)
ac, _ := lru.New(size) ac, _ := lru.New(size)
c := &Cache{ c := &Cache{
aclCache: ac,
faultfn: faultfn, faultfn: faultfn,
parent: parent, aclCache: ac,
policyCache: pc, policyCache: pc,
ruleCache: rc, ruleCache: rc,
} }
@ -84,7 +82,7 @@ func (c *Cache) GetACLPolicy(id string) (*Policy, error) {
} }
// Fault in the rules // Fault in the rules
rules, err := c.faultfn(id) _, rules, err := c.faultfn(id)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -103,7 +101,7 @@ func (c *Cache) GetACL(id string) (ACL, error) {
} }
// Get the rules // Get the rules
rules, err := c.faultfn(id) parentID, rules, err := c.faultfn(id)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -120,8 +118,17 @@ func (c *Cache) GetACL(id string) (ACL, error) {
return nil, err return nil, err
} }
// Get the parent ACL
parent := RootACL(parentID)
if parent == nil {
parent, err = c.GetACL(parentID)
if err != nil {
return nil, err
}
}
// Compile the ACL // Compile the ACL
acl, err := New(c.parent, policy) acl, err := New(parent, policy)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -5,7 +5,7 @@ import (
) )
func TestCache_GetPolicy(t *testing.T) { func TestCache_GetPolicy(t *testing.T) {
c, err := NewCache(1, AllowAll(), nil) c, err := NewCache(1, nil)
if err != nil { if err != nil {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
@ -45,11 +45,11 @@ func TestCache_GetACL(t *testing.T) {
"foo": testSimplePolicy, "foo": testSimplePolicy,
"bar": testSimplePolicy2, "bar": testSimplePolicy2,
} }
faultfn := func(id string) (string, error) { faultfn := func(id string) (string, string, error) {
return policies[id], nil return "deny", policies[id], nil
} }
c, err := NewCache(1, DenyAll(), faultfn) c, err := NewCache(1, faultfn)
if err != nil { if err != nil {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
@ -96,11 +96,11 @@ func TestCache_ClearACL(t *testing.T) {
"foo": testSimplePolicy, "foo": testSimplePolicy,
"bar": testSimplePolicy, "bar": testSimplePolicy,
} }
faultfn := func(id string) (string, error) { faultfn := func(id string) (string, string, error) {
return policies[id], nil return "deny", policies[id], nil
} }
c, err := NewCache(1, DenyAll(), faultfn) c, err := NewCache(1, faultfn)
if err != nil { if err != nil {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
@ -131,11 +131,11 @@ func TestCache_Purge(t *testing.T) {
"foo": testSimplePolicy, "foo": testSimplePolicy,
"bar": testSimplePolicy, "bar": testSimplePolicy,
} }
faultfn := func(id string) (string, error) { faultfn := func(id string) (string, string, error) {
return policies[id], nil return "deny", policies[id], nil
} }
c, err := NewCache(1, DenyAll(), faultfn) c, err := NewCache(1, faultfn)
if err != nil { if err != nil {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
@ -164,10 +164,10 @@ func TestCache_GetACLPolicy(t *testing.T) {
"foo": testSimplePolicy, "foo": testSimplePolicy,
"bar": testSimplePolicy, "bar": testSimplePolicy,
} }
faultfn := func(id string) (string, error) { faultfn := func(id string) (string, string, error) {
return policies[id], nil return "deny", policies[id], nil
} }
c, err := NewCache(1, DenyAll(), faultfn) c, err := NewCache(1, faultfn)
if err != nil { if err != nil {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
@ -201,6 +201,37 @@ func TestCache_GetACLPolicy(t *testing.T) {
} }
} }
func TestCache_GetACL_Parent(t *testing.T) {
faultfn := func(id string) (string, string, error) {
switch id {
case "foo":
// Foo inherits from bar
return "bar", testSimplePolicy, nil
case "bar":
return "deny", testSimplePolicy2, nil
}
t.Fatalf("bad case")
return "", "", nil
}
c, err := NewCache(1, faultfn)
if err != nil {
t.Fatalf("err: %v", err)
}
acl, err := c.GetACL("foo")
if err != nil {
t.Fatalf("err: %v", err)
}
if !acl.KeyRead("bar/test") {
t.Fatalf("should allow")
}
if !acl.KeyRead("foo/test") {
t.Fatalf("should allow")
}
}
var testSimplePolicy = ` var testSimplePolicy = `
key "foo/" { key "foo/" {
policy = "read" policy = "read"