Skip to content

Commit

Permalink
Merge pull request #8164 from mitake/auth-granted-keys
Browse files Browse the repository at this point in the history
allow users to know their roles and permissions
  • Loading branch information
xiang90 authored Jul 5, 2017
2 parents 1408b33 + db59588 commit 894751e
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 4 deletions.
23 changes: 23 additions & 0 deletions auth/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
}
46 changes: 46 additions & 0 deletions e2e/ctl_v3_auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down
26 changes: 22 additions & 4 deletions etcdserver/apply_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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:
Expand Down

0 comments on commit 894751e

Please sign in to comment.