mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
Merge pull request #8164 from mitake/auth-granted-keys
allow users to know their roles and permissions
This commit is contained in:
commit
894751ef44
@ -165,6 +165,9 @@ type AuthStore interface {
|
||||
|
||||
// WithRoot generates and installs a token that can be used as a root credential
|
||||
WithRoot(ctx context.Context) context.Context
|
||||
|
||||
// HasRole checks that user has role
|
||||
HasRole(user, role string) bool
|
||||
}
|
||||
|
||||
type TokenProvider interface {
|
||||
@ -1097,3 +1100,23 @@ func (as *authStore) WithRoot(ctx context.Context) context.Context {
|
||||
tokenMD := metadata.New(mdMap)
|
||||
return metadata.NewContext(ctx, tokenMD)
|
||||
}
|
||||
|
||||
func (as *authStore) HasRole(user, role string) bool {
|
||||
tx := as.be.BatchTx()
|
||||
tx.Lock()
|
||||
defer tx.Unlock()
|
||||
|
||||
u := getUser(tx, user)
|
||||
if u == nil {
|
||||
plog.Warningf("tried to check user %s has role %s, but user %s doesn't exist", user, role, user)
|
||||
return false
|
||||
}
|
||||
|
||||
for _, r := range u.Roles {
|
||||
if role == r {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ func TestCtlV3AuthFromKeyPerm(t *testing.T) { testCtl(t, authTestFromKeyPer
|
||||
func TestCtlV3AuthAndWatch(t *testing.T) { testCtl(t, authTestWatch) }
|
||||
|
||||
func TestCtlV3AuthRoleGet(t *testing.T) { testCtl(t, authTestRoleGet) }
|
||||
func TestCtlV3AuthUserGet(t *testing.T) { testCtl(t, authTestUserGet) }
|
||||
func TestCtlV3AuthRoleList(t *testing.T) { testCtl(t, authTestRoleList) }
|
||||
|
||||
func authEnableTest(cx ctlCtx) {
|
||||
@ -758,6 +759,51 @@ func authTestRoleGet(cx ctlCtx) {
|
||||
if err := spawnWithExpects(append(cx.PrefixArgs(), "role", "get", "test-role"), expected...); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// test-user can get the information of test-role because it belongs to the role
|
||||
cx.user, cx.pass = "test-user", "pass"
|
||||
if err := spawnWithExpects(append(cx.PrefixArgs(), "role", "get", "test-role"), expected...); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// test-user cannot get the information of root because it doesn't belong to the role
|
||||
expected = []string{
|
||||
"Error: etcdserver: permission denied",
|
||||
}
|
||||
if err := spawnWithExpects(append(cx.PrefixArgs(), "role", "get", "root"), expected...); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func authTestUserGet(cx ctlCtx) {
|
||||
if err := authEnable(cx); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
cx.user, cx.pass = "root", "root"
|
||||
authSetupTestUser(cx)
|
||||
|
||||
expected := []string{
|
||||
"User: test-user",
|
||||
"Roles: test-role",
|
||||
}
|
||||
|
||||
if err := spawnWithExpects(append(cx.PrefixArgs(), "user", "get", "test-user"), expected...); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// test-user can get the information of test-user itself
|
||||
cx.user, cx.pass = "test-user", "pass"
|
||||
if err := spawnWithExpects(append(cx.PrefixArgs(), "user", "get", "test-user"), expected...); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// test-user cannot get the information of root
|
||||
expected = []string{
|
||||
"Error: etcdserver: permission denied",
|
||||
}
|
||||
if err := spawnWithExpects(append(cx.PrefixArgs(), "user", "get", "root"), expected...); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func authTestRoleList(cx ctlCtx) {
|
||||
|
@ -189,6 +189,28 @@ func (aa *authApplierV3) checkLeasePuts(leaseID lease.LeaseID) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (aa *authApplierV3) UserGet(r *pb.AuthUserGetRequest) (*pb.AuthUserGetResponse, error) {
|
||||
err := aa.as.IsAdminPermitted(&aa.authInfo)
|
||||
if err != nil && r.Name != aa.authInfo.Username {
|
||||
aa.authInfo.Username = ""
|
||||
aa.authInfo.Revision = 0
|
||||
return &pb.AuthUserGetResponse{}, err
|
||||
}
|
||||
|
||||
return aa.applierV3.UserGet(r)
|
||||
}
|
||||
|
||||
func (aa *authApplierV3) RoleGet(r *pb.AuthRoleGetRequest) (*pb.AuthRoleGetResponse, error) {
|
||||
err := aa.as.IsAdminPermitted(&aa.authInfo)
|
||||
if err != nil && !aa.as.HasRole(aa.authInfo.Username, r.Role) {
|
||||
aa.authInfo.Username = ""
|
||||
aa.authInfo.Revision = 0
|
||||
return &pb.AuthRoleGetResponse{}, err
|
||||
}
|
||||
|
||||
return aa.applierV3.RoleGet(r)
|
||||
}
|
||||
|
||||
func needAdminPermission(r *pb.InternalRaftRequest) bool {
|
||||
switch {
|
||||
case r.AuthEnable != nil:
|
||||
@ -203,16 +225,12 @@ func needAdminPermission(r *pb.InternalRaftRequest) bool {
|
||||
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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user