acl: Avoid shared cache with different parents
This commit is contained in:
parent
7473bd2fc9
commit
88ee7b45cb
18
acl/cache.go
18
acl/cache.go
|
@ -13,9 +13,9 @@ 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 {
|
||||||
ACL ACL
|
ACL ACL
|
||||||
Parent string
|
Parent string
|
||||||
PolicyID string
|
RuleID string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache is used to implement policy and ACL caching
|
// 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)))
|
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
|
// GetACLPolicy is used to get the potentially cached ACL
|
||||||
// policy. If not cached, it will be generated and then cached.
|
// policy. If not cached, it will be generated and then cached.
|
||||||
func (c *Cache) GetACLPolicy(id string) (string, *Policy, error) {
|
func (c *Cache) GetACLPolicy(id string) (string, *Policy, error) {
|
||||||
// Check for a cached acl
|
// Check for a cached acl
|
||||||
if raw, ok := c.aclCache.Get(id); ok {
|
if raw, ok := c.aclCache.Get(id); ok {
|
||||||
cached := raw.(aclEntry)
|
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
|
return cached.Parent, raw.(*Policy), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,8 +115,9 @@ func (c *Cache) GetACL(id string) (ACL, error) {
|
||||||
ruleID := c.ruleID(rules)
|
ruleID := c.ruleID(rules)
|
||||||
|
|
||||||
// Check for a compiled ACL
|
// Check for a compiled ACL
|
||||||
|
policyID := c.policyID(parentID, ruleID)
|
||||||
var compiled ACL
|
var compiled ACL
|
||||||
if raw, ok := c.policyCache.Get(ruleID); ok {
|
if raw, ok := c.policyCache.Get(policyID); ok {
|
||||||
compiled = raw.(ACL)
|
compiled = raw.(ACL)
|
||||||
} else {
|
} else {
|
||||||
// Get the policy
|
// Get the policy
|
||||||
|
@ -136,7 +142,7 @@ func (c *Cache) GetACL(id string) (ACL, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache the compiled ACL
|
// Cache the compiled ACL
|
||||||
c.policyCache.Add(ruleID, acl)
|
c.policyCache.Add(policyID, acl)
|
||||||
compiled = acl
|
compiled = acl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -114,7 +114,7 @@ func TestCache_ClearACL(t *testing.T) {
|
||||||
c.ClearACL("foo")
|
c.ClearACL("foo")
|
||||||
|
|
||||||
// Clear the policy cache
|
// Clear the policy cache
|
||||||
c.policyCache.Remove(c.ruleID(testSimplePolicy))
|
c.policyCache.Purge()
|
||||||
|
|
||||||
acl2, err := c.GetACL("foo")
|
acl2, err := c.GetACL("foo")
|
||||||
if err != nil {
|
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 = `
|
var testSimplePolicy = `
|
||||||
key "foo/" {
|
key "foo/" {
|
||||||
policy = "read"
|
policy = "read"
|
||||||
|
|
Loading…
Reference in New Issue