acl: Avoid shared cache with different parents

This commit is contained in:
Armon Dadgar 2014-08-14 19:32:05 -07:00
parent 7473bd2fc9
commit 88ee7b45cb
2 changed files with 60 additions and 7 deletions

View File

@ -13,9 +13,9 @@ type FaultFunc func(id string) (string, string, error)
// aclEntry allows us to store the ACL with it's policy ID
type aclEntry struct {
ACL ACL
Parent string
PolicyID string
ACL ACL
Parent string
RuleID string
}
// Cache is used to implement policy and ACL caching
@ -71,13 +71,18 @@ func (c *Cache) ruleID(rules string) string {
return fmt.Sprintf("%x", md5.Sum([]byte(rules)))
}
// policyID returns the cache ID for a policy
func (c *Cache) policyID(parent, ruleID string) string {
return parent + ":" + ruleID
}
// GetACLPolicy is used to get the potentially cached ACL
// policy. If not cached, it will be generated and then cached.
func (c *Cache) GetACLPolicy(id string) (string, *Policy, error) {
// Check for a cached acl
if raw, ok := c.aclCache.Get(id); ok {
cached := raw.(aclEntry)
if raw, ok := c.ruleCache.Get(cached.PolicyID); ok {
if raw, ok := c.ruleCache.Get(cached.RuleID); ok {
return cached.Parent, raw.(*Policy), nil
}
}
@ -110,8 +115,9 @@ func (c *Cache) GetACL(id string) (ACL, error) {
ruleID := c.ruleID(rules)
// Check for a compiled ACL
policyID := c.policyID(parentID, ruleID)
var compiled ACL
if raw, ok := c.policyCache.Get(ruleID); ok {
if raw, ok := c.policyCache.Get(policyID); ok {
compiled = raw.(ACL)
} else {
// Get the policy
@ -136,7 +142,7 @@ func (c *Cache) GetACL(id string) (ACL, error) {
}
// Cache the compiled ACL
c.policyCache.Add(ruleID, acl)
c.policyCache.Add(policyID, acl)
compiled = acl
}

View File

@ -114,7 +114,7 @@ func TestCache_ClearACL(t *testing.T) {
c.ClearACL("foo")
// Clear the policy cache
c.policyCache.Remove(c.ruleID(testSimplePolicy))
c.policyCache.Purge()
acl2, err := c.GetACL("foo")
if err != nil {
@ -238,6 +238,53 @@ func TestCache_GetACL_Parent(t *testing.T) {
}
}
func TestCache_GetACL_ParentCache(t *testing.T) {
// Same rules, different parent
faultfn := func(id string) (string, string, error) {
switch id {
case "foo":
return "allow", testSimplePolicy, nil
case "bar":
return "deny", testSimplePolicy, nil
}
t.Fatalf("bad case")
return "", "", nil
}
c, err := NewCache(16, 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")
}
acl2, err := c.GetACL("bar")
if err != nil {
t.Fatalf("err: %v", err)
}
if acl == acl2 {
t.Fatalf("should not match")
}
if acl2.KeyRead("bar/test") {
t.Fatalf("should not allow")
}
if !acl2.KeyRead("foo/test") {
t.Fatalf("should allow")
}
}
var testSimplePolicy = `
key "foo/" {
policy = "read"