mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
commit
dfa625407f
144
acl/acl.go
144
acl/acl.go
@ -1,144 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
@ -1,81 +0,0 @@
|
|||||||
package acl
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func TestACLRead(t *testing.T) {
|
|
||||||
readp := []byte("foobar")
|
|
||||||
acl := newTestEmpty()
|
|
||||||
acl.GrantRead(readp)
|
|
||||||
|
|
||||||
for i := 0; i < len(readp); i++ {
|
|
||||||
r := acl.Read(readp[:i])
|
|
||||||
if r == true {
|
|
||||||
t.Errorf("#%d.deny: r = %t, want %t", i, r, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < len(readp); i++ {
|
|
||||||
r := acl.Read(append(readp, readp[:i]...))
|
|
||||||
if r == false {
|
|
||||||
t.Errorf("#%d.allow: r = %t, want %t", i, r, true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestACLWrite(t *testing.T) {
|
|
||||||
writep := []byte("foobar")
|
|
||||||
acl := newTestEmpty()
|
|
||||||
acl.GrantWrite(writep)
|
|
||||||
|
|
||||||
for i := 0; i < len(writep); i++ {
|
|
||||||
w := acl.Write(writep[:i])
|
|
||||||
if w == true {
|
|
||||||
t.Errorf("#%d.deny: w = %t, want %t", i, w, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < len(writep); i++ {
|
|
||||||
w := acl.Write(append(writep, writep[:i]...))
|
|
||||||
if w == false {
|
|
||||||
t.Errorf("#%d.allow: w = %t, want %t", i, w, true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestACLManage(t *testing.T) {
|
|
||||||
managep := []byte("foobar")
|
|
||||||
acl := newTestEmpty()
|
|
||||||
acl.GrantManage(managep)
|
|
||||||
|
|
||||||
for i := 0; i < len(managep); i++ {
|
|
||||||
m := acl.Manage(managep[:i])
|
|
||||||
if m == true {
|
|
||||||
t.Errorf("#%d.deny: m = %t, want %t", i, m, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < len(managep); i++ {
|
|
||||||
m := acl.Manage(append(managep, managep[:i]...))
|
|
||||||
if m == false {
|
|
||||||
t.Errorf("#%d.allow: m = %t, want %t", i, m, true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestACLRevoke(t *testing.T) {
|
|
||||||
readp := []byte("foobar")
|
|
||||||
acl := newTestEmpty()
|
|
||||||
acl.GrantRead(readp)
|
|
||||||
if !acl.Read(readp) {
|
|
||||||
t.Errorf("r = %t, want %t", false, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
acl.RevokeRead(readp)
|
|
||||||
if acl.Read(readp) {
|
|
||||||
t.Errorf("r = %t, want %t", true, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newTestEmpty() ACL {
|
|
||||||
return &acl{}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user