etcd/acl/acl.go
2015-02-28 10:45:22 -08:00

145 lines
3.0 KiB
Go

package acl
import (
"bytes"
"log"
)
const (
read = "read"
write = "write"
manage = "manage"
)
type ACL interface {
// Read checks the permission to read the prefix.
// Read permission can read the value of the prefix as a key or list the keys under prefix.
Read(prefix []byte) bool
// Write checks the permission to write the prefix.
// Write permission can write a key under the given prefix (including the prefix as a key).
Write(prefix []byte) bool
// Manage checks the permission to grant /revoke permission for the prefix.
Manage(prefix []byte) bool
// Manage the ACL
// Before call these functions, the caller must check the management permission on its own.
// For example, A wants to grant B read permission for prefix "foo". A must check its own manage
// permission before calling GrantRead("foo") on B.
GrantRead(prefix []byte)
GrantWrite(prefix []byte)
GrantManage(prefix []byte)
RevokeRead(prefix []byte)
RevokeWrite(prefix []byte)
RevokeManage(prefix []byte)
Clear()
}
type acl struct {
write [][]byte
read [][]byte
manage [][]byte
parent ACL
}
func (a *acl) Read(prefix []byte) bool {
if a.check(read, prefix) {
return true
}
if a.parent != nil {
return a.parent.Read(prefix)
}
return false
}
func (a *acl) Write(prefix []byte) bool {
if a.check(write, prefix) {
return true
}
if a.parent != nil {
return a.parent.Write(prefix)
}
return false
}
func (a *acl) Manage(prefix []byte) bool {
if a.check(manage, prefix) {
return true
}
if a.parent != nil {
return a.parent.Manage(prefix)
}
return false
}
func (a *acl) GrantRead(prefix []byte) { a.grant(read, prefix) }
func (a *acl) GrantWrite(prefix []byte) { a.grant(write, prefix) }
func (a *acl) GrantManage(prefix []byte) { a.grant(manage, prefix) }
func (a *acl) RevokeRead(prefix []byte) { a.revoke(read, prefix) }
func (a *acl) RevokeWrite(prefix []byte) { a.revoke(write, prefix) }
func (a *acl) RevokeManage(prefix []byte) { a.revoke(manage, prefix) }
func (a *acl) Clear() {
a.read = nil
a.write = nil
a.manage = nil
}
func (a *acl) check(op string, prefix []byte) bool {
list := a.list(op)
for _, pp := range list {
if len(pp) == 0 {
continue
}
if bytes.HasPrefix(prefix, pp) {
return true
}
}
return false
}
func (a *acl) grant(op string, prefix []byte) {
list := a.list(op)
for _, pp := range list {
if bytes.Equal(prefix, pp) {
return
}
}
switch op {
case read:
a.read = append(a.read, prefix)
case write:
a.write = append(a.write, prefix)
case manage:
a.manage = append(a.manage, prefix)
default:
log.Panicf("acl: unexpected check operation %s", op)
}
return
}
func (a *acl) revoke(op string, prefix []byte) {
list := a.list(op)
for i, pp := range list {
if bytes.Equal(prefix, pp) {
list[i] = nil
}
}
}
func (a *acl) list(op string) [][]byte {
switch op {
case read:
return a.read
case write:
return a.write
case manage:
return a.manage
default:
log.Panicf("acl: unexpected check operation %s", op)
}
return nil
}