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
}
// 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
// the ACL interface.
type PolicyACL struct {

View File

@ -4,6 +4,18 @@ import (
"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) {
all := AllowAll()
if _, ok := all.(*StaticACL); !ok {

View File

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

View File

@ -5,7 +5,7 @@ import (
)
func TestCache_GetPolicy(t *testing.T) {
c, err := NewCache(1, AllowAll(), nil)
c, err := NewCache(1, nil)
if err != nil {
t.Fatalf("err: %v", err)
}
@ -45,11 +45,11 @@ func TestCache_GetACL(t *testing.T) {
"foo": testSimplePolicy,
"bar": testSimplePolicy2,
}
faultfn := func(id string) (string, error) {
return policies[id], nil
faultfn := func(id string) (string, string, error) {
return "deny", policies[id], nil
}
c, err := NewCache(1, DenyAll(), faultfn)
c, err := NewCache(1, faultfn)
if err != nil {
t.Fatalf("err: %v", err)
}
@ -96,11 +96,11 @@ func TestCache_ClearACL(t *testing.T) {
"foo": testSimplePolicy,
"bar": testSimplePolicy,
}
faultfn := func(id string) (string, error) {
return policies[id], nil
faultfn := func(id string) (string, string, error) {
return "deny", policies[id], nil
}
c, err := NewCache(1, DenyAll(), faultfn)
c, err := NewCache(1, faultfn)
if err != nil {
t.Fatalf("err: %v", err)
}
@ -131,11 +131,11 @@ func TestCache_Purge(t *testing.T) {
"foo": testSimplePolicy,
"bar": testSimplePolicy,
}
faultfn := func(id string) (string, error) {
return policies[id], nil
faultfn := func(id string) (string, string, error) {
return "deny", policies[id], nil
}
c, err := NewCache(1, DenyAll(), faultfn)
c, err := NewCache(1, faultfn)
if err != nil {
t.Fatalf("err: %v", err)
}
@ -164,10 +164,10 @@ func TestCache_GetACLPolicy(t *testing.T) {
"foo": testSimplePolicy,
"bar": testSimplePolicy,
}
faultfn := func(id string) (string, error) {
return policies[id], nil
faultfn := func(id string) (string, string, error) {
return "deny", policies[id], nil
}
c, err := NewCache(1, DenyAll(), faultfn)
c, err := NewCache(1, faultfn)
if err != nil {
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 = `
key "foo/" {
policy = "read"