mirror of https://github.com/status-im/consul.git
acl: Support checking write permissions on a prefix
This commit is contained in:
parent
c7cb1f562b
commit
705c6cdb86
49
acl/acl.go
49
acl/acl.go
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue