acl: Support checking write permissions on a prefix

This commit is contained in:
Armon Dadgar 2014-08-14 15:53:02 -07:00
parent c7cb1f562b
commit 705c6cdb86
2 changed files with 75 additions and 16 deletions

View File

@ -35,9 +35,21 @@ func init() {
// ACL is the interface for policy enforcement.
type ACL interface {
// KeyRead checks for permission to read a given key
KeyRead(string) bool
// KeyWrite checks for permission to write a given key
KeyWrite(string) bool
// KeyWritePrefix checks for permission to write to an
// entire key prefix. This means there must be no sub-policies
// that deny a write.
KeyWritePrefix(string) bool
// ACLList checks for permission to list all the ACLs
ACLList() bool
// ACLModify checks for permission to manipulate ACLs
ACLModify() bool
}
@ -57,6 +69,10 @@ func (s *StaticACL) KeyWrite(string) bool {
return s.defaultAllow
}
func (s *StaticACL) KeyWritePrefix(string) bool {
return s.defaultAllow
}
func (s *StaticACL) ACLList() bool {
return s.allowManage
}
@ -156,6 +172,39 @@ func (p *PolicyACL) KeyWrite(key string) bool {
return p.parent.KeyWrite(key)
}
// KeyWritePrefix returns if a prefix is allowed to be written
func (p *PolicyACL) KeyWritePrefix(prefix string) bool {
// Look for a matching rule that denies
_, rule, ok := p.keyRules.LongestPrefix(prefix)
if ok && rule.(string) != KeyPolicyWrite {
return false
}
// Look if any of our children have a deny policy
deny := false
p.keyRules.WalkPrefix(prefix, func(path string, rule interface{}) bool {
// We have a rule to prevent a write in a sub-directory!
if rule.(string) != KeyPolicyWrite {
deny = true
return true
}
return false
})
// Deny the write if any sub-rules may be violated
if deny {
return false
}
// If we had a matching rule, done
if ok {
return true
}
// No matching rule, use the parent.
return p.parent.KeyWritePrefix(prefix)
}
// ACLList checks if listing of ACLs is allowed
func (p *PolicyACL) ACLList() bool {
return p.parent.ACLList()

View File

@ -103,16 +103,19 @@ func TestPolicyACL(t *testing.T) {
}
type tcase struct {
inp string
read bool
write bool
inp string
read bool
write bool
writePrefix bool
}
cases := []tcase{
{"other", true, true},
{"foo/test", true, true},
{"foo/priv/test", false, false},
{"bar/any", false, false},
{"zip/test", true, false},
{"other", true, true, true},
{"foo/test", true, true, true},
{"foo/priv/test", false, false, false},
{"bar/any", false, false, false},
{"zip/test", true, false, false},
{"foo/", true, true, false},
{"", true, true, false},
}
for _, c := range cases {
if c.read != acl.KeyRead(c.inp) {
@ -121,6 +124,9 @@ func TestPolicyACL(t *testing.T) {
if c.write != acl.KeyWrite(c.inp) {
t.Fatalf("Write fail: %#v", c)
}
if c.writePrefix != acl.KeyWritePrefix(c.inp) {
t.Fatalf("Write prefix fail: %#v", c)
}
}
}
@ -165,16 +171,17 @@ func TestPolicyACL_Parent(t *testing.T) {
}
type tcase struct {
inp string
read bool
write bool
inp string
read bool
write bool
writePrefix bool
}
cases := []tcase{
{"other", false, false},
{"foo/test", true, true},
{"foo/priv/test", true, false},
{"bar/any", false, false},
{"zip/test", true, false},
{"other", false, false, false},
{"foo/test", true, true, true},
{"foo/priv/test", true, false, false},
{"bar/any", false, false, false},
{"zip/test", true, false, false},
}
for _, c := range cases {
if c.read != acl.KeyRead(c.inp) {
@ -183,5 +190,8 @@ func TestPolicyACL_Parent(t *testing.T) {
if c.write != acl.KeyWrite(c.inp) {
t.Fatalf("Write fail: %#v", c)
}
if c.writePrefix != acl.KeyWritePrefix(c.inp) {
t.Fatalf("Write prefix fail: %#v", c)
}
}
}