From f1c6fa48f5bd754ab70f2be42c45e5f6fbcee122 Mon Sep 17 00:00:00 2001 From: Xiang Li Date: Thu, 9 Jun 2016 13:40:26 -0700 Subject: [PATCH] *: add admin permission checking --- auth/store.go | 38 ++++++++++++++++++++++++++++++-------- etcdserver/apply.go | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 8 deletions(-) diff --git a/auth/store.go b/auth/store.go index 0aec49a52..2aa1ccbed 100644 --- a/auth/store.go +++ b/auth/store.go @@ -111,6 +111,9 @@ type AuthStore interface { // IsRangePermitted checks range permission of the user IsRangePermitted(header *pb.RequestHeader, key, rangeEnd string) bool + + // IsAdminPermitted checks admin permission of the user + IsAdminPermitted(username string) bool } type authStore struct { @@ -137,14 +140,7 @@ func (as *authStore) AuthEnable() error { return ErrRootUserNotExist } - rootRoleExist := false - for _, r := range u.Roles { - if r == rootRole { - rootRoleExist = true - break - } - } - if !rootRoleExist { + if !hasRootRole(u) { return ErrRootRoleNotExist } @@ -664,6 +660,23 @@ func (as *authStore) IsRangePermitted(header *pb.RequestHeader, key, rangeEnd st return as.isOpPermitted(header.Username, key, rangeEnd, false, true) } +func (as *authStore) IsAdminPermitted(username string) bool { + if !as.isAuthEnabled() { + return true + } + + tx := as.be.BatchTx() + tx.Lock() + defer tx.Unlock() + + u := getUser(tx, username) + if u == nil { + return false + } + + return hasRootRole(u) +} + func getUser(tx backend.BatchTx, username string) *authpb.User { _, vs := tx.UnsafeRange(authUsersBucketName, []byte(username), nil, 0) if len(vs) == 0 { @@ -699,3 +712,12 @@ func NewAuthStore(be backend.Backend) *authStore { be: be, } } + +func hasRootRole(u *authpb.User) bool { + for _, r := range u.Roles { + if r == rootRole { + return true + } + } + return false +} diff --git a/etcdserver/apply.go b/etcdserver/apply.go index d8a0cb3cb..7143cd53e 100644 --- a/etcdserver/apply.go +++ b/etcdserver/apply.go @@ -79,6 +79,13 @@ type applierV3backend struct { func (s *EtcdServer) applyV3Request(r *pb.InternalRaftRequest) *applyResult { ar := &applyResult{} + username := r.Header.Username + + if needAdminPermission(r) && !s.AuthStore().IsAdminPermitted(username) { + ar.err = auth.ErrPermissionDenied + return ar + } + switch { case r.Range != nil: if s.AuthStore().IsRangePermitted(r.Header, string(r.Range.Key), string(r.Range.RangeEnd)) { @@ -104,6 +111,7 @@ func (s *EtcdServer) applyV3Request(r *pb.InternalRaftRequest) *applyResult { ar.resp, ar.err = s.applyV3.LeaseRevoke(r.LeaseRevoke) case r.Alarm != nil: ar.resp, ar.err = s.applyV3.Alarm(r.Alarm) + case r.AuthEnable != nil: ar.resp, ar.err = s.applyV3.AuthEnable() case r.AuthDisable != nil: @@ -710,3 +718,36 @@ func compareInt64(a, b int64) int { func isGteRange(rangeEnd []byte) bool { return len(rangeEnd) == 1 && rangeEnd[0] == 0 } + +func needAdminPermission(r *pb.InternalRaftRequest) bool { + switch { + case r.AuthEnable != nil: + return true + case r.AuthDisable != nil: + return true + case r.AuthUserAdd != nil: + return true + case r.AuthUserDelete != nil: + return true + case r.AuthUserChangePassword != nil: + return true + case r.AuthUserGrantRole != nil: + return true + case r.AuthUserGet != nil: + return true + case r.AuthUserRevokeRole != nil: + return true + case r.AuthRoleAdd != nil: + return true + case r.AuthRoleGrantPermission != nil: + return true + case r.AuthRoleGet != nil: + return true + case r.AuthRoleRevokePermission != nil: + return true + case r.AuthRoleDelete != nil: + return true + default: + return false + } +}