acl: Adding cached policy fetch via ACL
This commit is contained in:
parent
1c54400d08
commit
dcd4508ca9
51
acl/cache.go
51
acl/cache.go
|
@ -11,6 +11,12 @@ import (
|
||||||
// ACL given it's ID
|
// ACL given it's ID
|
||||||
type FaultFunc func(id string) (string, error)
|
type FaultFunc func(id string) (string, error)
|
||||||
|
|
||||||
|
// aclEntry allows us to store the ACL with it's policy ID
|
||||||
|
type aclEntry struct {
|
||||||
|
ACL ACL
|
||||||
|
PolicyID string
|
||||||
|
}
|
||||||
|
|
||||||
// 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
|
aclCache *lru.Cache
|
||||||
|
@ -38,8 +44,13 @@ func NewCache(size int, parent ACL, faultfn FaultFunc) (*Cache, error) {
|
||||||
// GetPolicy is used to get a potentially cached policy set.
|
// GetPolicy is used to get a potentially cached policy set.
|
||||||
// If not cached, it will be parsed, and then cached.
|
// If not cached, it will be parsed, and then cached.
|
||||||
func (c *Cache) GetPolicy(rules string) (*Policy, error) {
|
func (c *Cache) GetPolicy(rules string) (*Policy, error) {
|
||||||
hash := fmt.Sprintf("%x", md5.Sum([]byte(rules)))
|
return c.getPolicy(c.ruleID(rules), rules)
|
||||||
raw, ok := c.policyCache.Get(hash)
|
}
|
||||||
|
|
||||||
|
// getPolicy is an internal method to get a cached policy,
|
||||||
|
// but it assumes a pre-computed ID
|
||||||
|
func (c *Cache) getPolicy(id, rules string) (*Policy, error) {
|
||||||
|
raw, ok := c.policyCache.Get(id)
|
||||||
if ok {
|
if ok {
|
||||||
return raw.(*Policy), nil
|
return raw.(*Policy), nil
|
||||||
}
|
}
|
||||||
|
@ -47,8 +58,35 @@ func (c *Cache) GetPolicy(rules string) (*Policy, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c.policyCache.Add(hash, policy)
|
c.policyCache.Add(id, policy)
|
||||||
return policy, nil
|
return policy, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ruleID is used to generate an ID for a rule
|
||||||
|
func (c *Cache) ruleID(rules string) string {
|
||||||
|
return fmt.Sprintf("%x", md5.Sum([]byte(rules)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) (*Policy, error) {
|
||||||
|
// Check for a cached acl
|
||||||
|
if raw, ok := c.aclCache.Get(id); ok {
|
||||||
|
cached := raw.(aclEntry)
|
||||||
|
if raw, ok := c.policyCache.Get(cached.PolicyID); ok {
|
||||||
|
return raw.(*Policy), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fault in the rules
|
||||||
|
rules, err := c.faultfn(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get cached
|
||||||
|
return c.GetPolicy(rules)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetACL is used to get a potentially cached ACL policy.
|
// GetACL is used to get a potentially cached ACL policy.
|
||||||
|
@ -57,7 +95,7 @@ func (c *Cache) GetACL(id string) (ACL, error) {
|
||||||
// Look for the ACL directly
|
// Look for the ACL directly
|
||||||
raw, ok := c.aclCache.Get(id)
|
raw, ok := c.aclCache.Get(id)
|
||||||
if ok {
|
if ok {
|
||||||
return raw.(ACL), nil
|
return raw.(aclEntry).ACL, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the rules
|
// Get the rules
|
||||||
|
@ -65,9 +103,10 @@ func (c *Cache) GetACL(id string) (ACL, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
ruleID := c.ruleID(rules)
|
||||||
|
|
||||||
// Get the policy
|
// Get the policy
|
||||||
policy, err := c.GetPolicy(rules)
|
policy, err := c.getPolicy(ruleID, rules)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -79,7 +118,7 @@ func (c *Cache) GetACL(id string) (ACL, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache and return the ACL
|
// Cache and return the ACL
|
||||||
c.aclCache.Add(id, acl)
|
c.aclCache.Add(id, aclEntry{acl, ruleID})
|
||||||
return acl, nil
|
return acl, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,6 +123,48 @@ func TestCache_ClearACL(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCache_GetACLPolicy(t *testing.T) {
|
||||||
|
policies := map[string]string{
|
||||||
|
"foo": testSimplePolicy,
|
||||||
|
"bar": testSimplePolicy,
|
||||||
|
}
|
||||||
|
faultfn := func(id string) (string, error) {
|
||||||
|
return policies[id], nil
|
||||||
|
}
|
||||||
|
c, err := NewCache(1, DenyAll(), faultfn)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p, err := c.GetPolicy(testSimplePolicy)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = c.GetACL("foo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p2, err := c.GetACLPolicy("foo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if p2 != p {
|
||||||
|
t.Fatalf("expected cached policy")
|
||||||
|
}
|
||||||
|
|
||||||
|
p3, err := c.GetACLPolicy("bar")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if p3 != p {
|
||||||
|
t.Fatalf("expected cached policy")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var testSimplePolicy = `
|
var testSimplePolicy = `
|
||||||
key "foo/" {
|
key "foo/" {
|
||||||
policy = "read"
|
policy = "read"
|
||||||
|
|
|
@ -17,7 +17,7 @@ key "foo/bar/" {
|
||||||
policy = "read"
|
policy = "read"
|
||||||
}
|
}
|
||||||
key "foo/bar/baz" {
|
key "foo/bar/baz" {
|
||||||
polizy = "deny"
|
policy = "deny"
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
exp := &Policy{
|
exp := &Policy{
|
||||||
|
|
Loading…
Reference in New Issue