Browse Source

*: support getting all users and roles in auth v3

This commit expands RPCs for getting user and role and support list up
all users and roles. etcdctl v3 is now support getting all users and
roles with the newly added option --all e.g. etcdctl user get --all
Hitoshi Mitake 9 years ago
parent
commit
18253e2723

+ 34 - 2
Documentation/dev-guide/api_reference_v3.md

@@ -12,13 +12,15 @@ This is a generated documentation. Please read the proto files for more.
 | AuthDisable | AuthDisableRequest | AuthDisableResponse | AuthDisable disables authentication. |
 | AuthDisable | AuthDisableRequest | AuthDisableResponse | AuthDisable disables authentication. |
 | Authenticate | AuthenticateRequest | AuthenticateResponse | Authenticate processes an authenticate request. |
 | Authenticate | AuthenticateRequest | AuthenticateResponse | Authenticate processes an authenticate request. |
 | UserAdd | AuthUserAddRequest | AuthUserAddResponse | UserAdd adds a new user. |
 | UserAdd | AuthUserAddRequest | AuthUserAddResponse | UserAdd adds a new user. |
-| UserGet | AuthUserGetRequest | AuthUserGetResponse | UserGet gets detailed user information or lists all users. |
+| UserGet | AuthUserGetRequest | AuthUserGetResponse | UserGet gets detailed user information. |
+| UserList | AuthUserListRequest | AuthUserListResponse | UserList gets a list of all users. |
 | UserDelete | AuthUserDeleteRequest | AuthUserDeleteResponse | UserDelete deletes a specified user. |
 | UserDelete | AuthUserDeleteRequest | AuthUserDeleteResponse | UserDelete deletes a specified user. |
 | UserChangePassword | AuthUserChangePasswordRequest | AuthUserChangePasswordResponse | UserChangePassword changes the password of a specified user. |
 | UserChangePassword | AuthUserChangePasswordRequest | AuthUserChangePasswordResponse | UserChangePassword changes the password of a specified user. |
 | UserGrantRole | AuthUserGrantRoleRequest | AuthUserGrantRoleResponse | UserGrant grants a role to a specified user. |
 | UserGrantRole | AuthUserGrantRoleRequest | AuthUserGrantRoleResponse | UserGrant grants a role to a specified user. |
 | UserRevokeRole | AuthUserRevokeRoleRequest | AuthUserRevokeRoleResponse | UserRevokeRole revokes a role of specified user. |
 | UserRevokeRole | AuthUserRevokeRoleRequest | AuthUserRevokeRoleResponse | UserRevokeRole revokes a role of specified user. |
 | RoleAdd | AuthRoleAddRequest | AuthRoleAddResponse | RoleAdd adds a new role. |
 | RoleAdd | AuthRoleAddRequest | AuthRoleAddResponse | RoleAdd adds a new role. |
-| RoleGet | AuthRoleGetRequest | AuthRoleGetResponse | RoleGet gets detailed role information or lists all roles. |
+| RoleGet | AuthRoleGetRequest | AuthRoleGetResponse | RoleGet gets detailed role information. |
+| RoleList | AuthRoleListRequest | AuthRoleListResponse | RoleList gets lists of all roles. |
 | RoleDelete | AuthRoleDeleteRequest | AuthRoleDeleteResponse | RoleDelete deletes a specified role. |
 | RoleDelete | AuthRoleDeleteRequest | AuthRoleDeleteResponse | RoleDelete deletes a specified role. |
 | RoleGrantPermission | AuthRoleGrantPermissionRequest | AuthRoleGrantPermissionResponse | RoleGrantPermission grants a permission of a specified key or range to a specified role. |
 | RoleGrantPermission | AuthRoleGrantPermissionRequest | AuthRoleGrantPermissionResponse | RoleGrantPermission grants a permission of a specified key or range to a specified role. |
 | RoleRevokePermission | AuthRoleRevokePermissionRequest | AuthRoleRevokePermissionResponse | RoleRevokePermission revokes a key or range permission of a specified role. |
 | RoleRevokePermission | AuthRoleRevokePermissionRequest | AuthRoleRevokePermissionResponse | RoleRevokePermission revokes a key or range permission of a specified role. |
@@ -204,6 +206,21 @@ Empty field.
 
 
 
 
 
 
+##### message `AuthRoleListRequest` (etcdserver/etcdserverpb/rpc.proto)
+
+Empty field.
+
+
+
+##### message `AuthRoleListResponse` (etcdserver/etcdserverpb/rpc.proto)
+
+| Field | Description | Type |
+| ----- | ----------- | ---- |
+| header |  | ResponseHeader |
+| roles |  | (slice of) string |
+
+
+
 ##### message `AuthRoleRevokePermissionRequest` (etcdserver/etcdserverpb/rpc.proto)
 ##### message `AuthRoleRevokePermissionRequest` (etcdserver/etcdserverpb/rpc.proto)
 
 
 | Field | Description | Type |
 | Field | Description | Type |
@@ -306,6 +323,21 @@ Empty field.
 
 
 
 
 
 
+##### message `AuthUserListRequest` (etcdserver/etcdserverpb/rpc.proto)
+
+Empty field.
+
+
+
+##### message `AuthUserListResponse` (etcdserver/etcdserverpb/rpc.proto)
+
+| Field | Description | Type |
+| ----- | ----------- | ---- |
+| header |  | ResponseHeader |
+| users |  | (slice of) string |
+
+
+
 ##### message `AuthUserRevokeRoleRequest` (etcdserver/etcdserverpb/rpc.proto)
 ##### message `AuthUserRevokeRoleRequest` (etcdserver/etcdserverpb/rpc.proto)
 
 
 | Field | Description | Type |
 | Field | Description | Type |

+ 85 - 3
auth/store.go

@@ -83,7 +83,7 @@ type AuthStore interface {
 	// UserGrantRole grants a role to the user
 	// UserGrantRole grants a role to the user
 	UserGrantRole(r *pb.AuthUserGrantRoleRequest) (*pb.AuthUserGrantRoleResponse, error)
 	UserGrantRole(r *pb.AuthUserGrantRoleRequest) (*pb.AuthUserGrantRoleResponse, error)
 
 
-	// UserGet gets the detailed information of a user
+	// UserGet gets the detailed information of a users
 	UserGet(r *pb.AuthUserGetRequest) (*pb.AuthUserGetResponse, error)
 	UserGet(r *pb.AuthUserGetRequest) (*pb.AuthUserGetResponse, error)
 
 
 	// UserRevokeRole revokes a role of a user
 	// UserRevokeRole revokes a role of a user
@@ -104,6 +104,12 @@ type AuthStore interface {
 	// RoleDelete gets the detailed information of a role
 	// RoleDelete gets the detailed information of a role
 	RoleDelete(r *pb.AuthRoleDeleteRequest) (*pb.AuthRoleDeleteResponse, error)
 	RoleDelete(r *pb.AuthRoleDeleteRequest) (*pb.AuthRoleDeleteResponse, error)
 
 
+	// UserList gets a list of all users
+	UserList(r *pb.AuthUserListRequest) (*pb.AuthUserListResponse, error)
+
+	// RoleList gets a list of all roles
+	RoleList(r *pb.AuthRoleListRequest) (*pb.AuthRoleListResponse, error)
+
 	// UsernameFromToken gets a username from the given Token
 	// UsernameFromToken gets a username from the given Token
 	UsernameFromToken(token string) (string, bool)
 	UsernameFromToken(token string) (string, bool)
 
 
@@ -339,12 +345,13 @@ func (as *authStore) UserGet(r *pb.AuthUserGetRequest) (*pb.AuthUserGetResponse,
 	tx.Lock()
 	tx.Lock()
 	defer tx.Unlock()
 	defer tx.Unlock()
 
 
+	var resp pb.AuthUserGetResponse
+
 	user := getUser(tx, r.Name)
 	user := getUser(tx, r.Name)
 	if user == nil {
 	if user == nil {
 		return nil, ErrUserNotFound
 		return nil, ErrUserNotFound
 	}
 	}
 
 
-	var resp pb.AuthUserGetResponse
 	for _, role := range user.Roles {
 	for _, role := range user.Roles {
 		resp.Roles = append(resp.Roles, role)
 		resp.Roles = append(resp.Roles, role)
 	}
 	}
@@ -352,6 +359,22 @@ func (as *authStore) UserGet(r *pb.AuthUserGetRequest) (*pb.AuthUserGetResponse,
 	return &resp, nil
 	return &resp, nil
 }
 }
 
 
+func (as *authStore) UserList(r *pb.AuthUserListRequest) (*pb.AuthUserListResponse, error) {
+	tx := as.be.BatchTx()
+	tx.Lock()
+	defer tx.Unlock()
+
+	var resp pb.AuthUserListResponse
+
+	users := getAllUsers(tx)
+
+	for _, u := range users {
+		resp.Users = append(resp.Users, string(u.Name))
+	}
+
+	return &resp, nil
+}
+
 func (as *authStore) UserRevokeRole(r *pb.AuthUserRevokeRoleRequest) (*pb.AuthUserRevokeRoleResponse, error) {
 func (as *authStore) UserRevokeRole(r *pb.AuthUserRevokeRoleRequest) (*pb.AuthUserRevokeRoleResponse, error) {
 	tx := as.be.BatchTx()
 	tx := as.be.BatchTx()
 	tx.Lock()
 	tx.Lock()
@@ -390,12 +413,13 @@ func (as *authStore) RoleGet(r *pb.AuthRoleGetRequest) (*pb.AuthRoleGetResponse,
 	tx.Lock()
 	tx.Lock()
 	defer tx.Unlock()
 	defer tx.Unlock()
 
 
+	var resp pb.AuthRoleGetResponse
+
 	role := getRole(tx, r.Role)
 	role := getRole(tx, r.Role)
 	if role == nil {
 	if role == nil {
 		return nil, ErrRoleNotFound
 		return nil, ErrRoleNotFound
 	}
 	}
 
 
-	var resp pb.AuthRoleGetResponse
 	for _, perm := range role.KeyPermission {
 	for _, perm := range role.KeyPermission {
 		resp.Perm = append(resp.Perm, perm)
 		resp.Perm = append(resp.Perm, perm)
 	}
 	}
@@ -403,6 +427,22 @@ func (as *authStore) RoleGet(r *pb.AuthRoleGetRequest) (*pb.AuthRoleGetResponse,
 	return &resp, nil
 	return &resp, nil
 }
 }
 
 
+func (as *authStore) RoleList(r *pb.AuthRoleListRequest) (*pb.AuthRoleListResponse, error) {
+	tx := as.be.BatchTx()
+	tx.Lock()
+	defer tx.Unlock()
+
+	var resp pb.AuthRoleListResponse
+
+	roles := getAllRoles(tx)
+
+	for _, r := range roles {
+		resp.Roles = append(resp.Roles, string(r.Name))
+	}
+
+	return &resp, nil
+}
+
 func (as *authStore) RoleRevokePermission(r *pb.AuthRoleRevokePermissionRequest) (*pb.AuthRoleRevokePermissionResponse, error) {
 func (as *authStore) RoleRevokePermission(r *pb.AuthRoleRevokePermissionRequest) (*pb.AuthRoleRevokePermissionResponse, error) {
 	tx := as.be.BatchTx()
 	tx := as.be.BatchTx()
 	tx.Lock()
 	tx.Lock()
@@ -613,6 +653,27 @@ func getUser(tx backend.BatchTx, username string) *authpb.User {
 	return user
 	return user
 }
 }
 
 
+func getAllUsers(tx backend.BatchTx) []*authpb.User {
+	_, vs := tx.UnsafeRange(authUsersBucketName, []byte{0}, []byte{0xff}, -1)
+	if len(vs) == 0 {
+		return nil
+	}
+
+	var users []*authpb.User
+
+	for _, v := range vs {
+		user := &authpb.User{}
+		err := user.Unmarshal(v)
+		if err != nil {
+			plog.Panicf("failed to unmarshal user struct: %s", err)
+		}
+
+		users = append(users, user)
+	}
+
+	return users
+}
+
 func putUser(tx backend.BatchTx, user *authpb.User) {
 func putUser(tx backend.BatchTx, user *authpb.User) {
 	b, err := user.Marshal()
 	b, err := user.Marshal()
 	if err != nil {
 	if err != nil {
@@ -639,6 +700,27 @@ func getRole(tx backend.BatchTx, rolename string) *authpb.Role {
 	return role
 	return role
 }
 }
 
 
+func getAllRoles(tx backend.BatchTx) []*authpb.Role {
+	_, vs := tx.UnsafeRange(authRolesBucketName, []byte{0}, []byte{0xff}, -1)
+	if len(vs) == 0 {
+		return nil
+	}
+
+	var roles []*authpb.Role
+
+	for _, v := range vs {
+		role := &authpb.Role{}
+		err := role.Unmarshal(v)
+		if err != nil {
+			plog.Panicf("failed to unmarshal role struct: %s", err)
+		}
+
+		roles = append(roles, role)
+	}
+
+	return roles
+}
+
 func putRole(tx backend.BatchTx, role *authpb.Role) {
 func putRole(tx backend.BatchTx, role *authpb.Role) {
 	b, err := role.Marshal()
 	b, err := role.Marshal()
 	if err != nil {
 	if err != nil {

+ 18 - 0
clientv3/auth.go

@@ -39,6 +39,8 @@ type (
 	AuthRoleGetResponse              pb.AuthRoleGetResponse
 	AuthRoleGetResponse              pb.AuthRoleGetResponse
 	AuthRoleRevokePermissionResponse pb.AuthRoleRevokePermissionResponse
 	AuthRoleRevokePermissionResponse pb.AuthRoleRevokePermissionResponse
 	AuthRoleDeleteResponse           pb.AuthRoleDeleteResponse
 	AuthRoleDeleteResponse           pb.AuthRoleDeleteResponse
+	AuthUserListResponse             pb.AuthUserListResponse
+	AuthRoleListResponse             pb.AuthRoleListResponse
 
 
 	PermissionType authpb.Permission_Type
 	PermissionType authpb.Permission_Type
 )
 )
@@ -71,6 +73,9 @@ type Auth interface {
 	// UserGet gets a detailed information of a user.
 	// UserGet gets a detailed information of a user.
 	UserGet(ctx context.Context, name string) (*AuthUserGetResponse, error)
 	UserGet(ctx context.Context, name string) (*AuthUserGetResponse, error)
 
 
+	// UserList gets a list of all users.
+	UserList(ctx context.Context) (*AuthUserListResponse, error)
+
 	// UserRevokeRole revokes a role of a user.
 	// UserRevokeRole revokes a role of a user.
 	UserRevokeRole(ctx context.Context, name string, role string) (*AuthUserRevokeRoleResponse, error)
 	UserRevokeRole(ctx context.Context, name string, role string) (*AuthUserRevokeRoleResponse, error)
 
 
@@ -83,6 +88,9 @@ type Auth interface {
 	// RoleGet gets a detailed information of a role.
 	// RoleGet gets a detailed information of a role.
 	RoleGet(ctx context.Context, role string) (*AuthRoleGetResponse, error)
 	RoleGet(ctx context.Context, role string) (*AuthRoleGetResponse, error)
 
 
+	// RoleList gets a list of all roles.
+	RoleList(ctx context.Context) (*AuthRoleListResponse, error)
+
 	// RoleRevokePermission revokes a permission from a role.
 	// RoleRevokePermission revokes a permission from a role.
 	RoleRevokePermission(ctx context.Context, role string, key, rangeEnd string) (*AuthRoleRevokePermissionResponse, error)
 	RoleRevokePermission(ctx context.Context, role string, key, rangeEnd string) (*AuthRoleRevokePermissionResponse, error)
 
 
@@ -141,6 +149,11 @@ func (auth *auth) UserGet(ctx context.Context, name string) (*AuthUserGetRespons
 	return (*AuthUserGetResponse)(resp), toErr(ctx, err)
 	return (*AuthUserGetResponse)(resp), toErr(ctx, err)
 }
 }
 
 
+func (auth *auth) UserList(ctx context.Context) (*AuthUserListResponse, error) {
+	resp, err := auth.remote.UserList(ctx, &pb.AuthUserListRequest{})
+	return (*AuthUserListResponse)(resp), toErr(ctx, err)
+}
+
 func (auth *auth) UserRevokeRole(ctx context.Context, name string, role string) (*AuthUserRevokeRoleResponse, error) {
 func (auth *auth) UserRevokeRole(ctx context.Context, name string, role string) (*AuthUserRevokeRoleResponse, error) {
 	resp, err := auth.remote.UserRevokeRole(ctx, &pb.AuthUserRevokeRoleRequest{Name: name, Role: role})
 	resp, err := auth.remote.UserRevokeRole(ctx, &pb.AuthUserRevokeRoleRequest{Name: name, Role: role})
 	return (*AuthUserRevokeRoleResponse)(resp), toErr(ctx, err)
 	return (*AuthUserRevokeRoleResponse)(resp), toErr(ctx, err)
@@ -166,6 +179,11 @@ func (auth *auth) RoleGet(ctx context.Context, role string) (*AuthRoleGetRespons
 	return (*AuthRoleGetResponse)(resp), toErr(ctx, err)
 	return (*AuthRoleGetResponse)(resp), toErr(ctx, err)
 }
 }
 
 
+func (auth *auth) RoleList(ctx context.Context) (*AuthRoleListResponse, error) {
+	resp, err := auth.remote.RoleList(ctx, &pb.AuthRoleListRequest{})
+	return (*AuthRoleListResponse)(resp), toErr(ctx, err)
+}
+
 func (auth *auth) RoleRevokePermission(ctx context.Context, role string, key, rangeEnd string) (*AuthRoleRevokePermissionResponse, error) {
 func (auth *auth) RoleRevokePermission(ctx context.Context, role string, key, rangeEnd string) (*AuthRoleRevokePermissionResponse, error) {
 	resp, err := auth.remote.RoleRevokePermission(ctx, &pb.AuthRoleRevokePermissionRequest{Role: role, Key: key, RangeEnd: rangeEnd})
 	resp, err := auth.remote.RoleRevokePermission(ctx, &pb.AuthRoleRevokePermissionRequest{Role: role, Key: key, RangeEnd: rangeEnd})
 	return (*AuthRoleRevokePermissionResponse)(resp), toErr(ctx, err)
 	return (*AuthRoleRevokePermissionResponse)(resp), toErr(ctx, err)

+ 28 - 2
etcdctl/ctlv3/command/role_command.go

@@ -32,6 +32,7 @@ func NewRoleCommand() *cobra.Command {
 	ac.AddCommand(newRoleAddCommand())
 	ac.AddCommand(newRoleAddCommand())
 	ac.AddCommand(newRoleDeleteCommand())
 	ac.AddCommand(newRoleDeleteCommand())
 	ac.AddCommand(newRoleGetCommand())
 	ac.AddCommand(newRoleGetCommand())
+	ac.AddCommand(newRoleListCommand())
 	ac.AddCommand(newRoleRevokePermissionCommand())
 	ac.AddCommand(newRoleRevokePermissionCommand())
 	ac.AddCommand(newRoleGrantPermissionCommand())
 	ac.AddCommand(newRoleGrantPermissionCommand())
 
 
@@ -62,6 +63,14 @@ func newRoleGetCommand() *cobra.Command {
 	}
 	}
 }
 }
 
 
+func newRoleListCommand() *cobra.Command {
+	return &cobra.Command{
+		Use:   "list",
+		Short: "list up all roles",
+		Run:   roleListCommandFunc,
+	}
+}
+
 func newRoleGrantPermissionCommand() *cobra.Command {
 func newRoleGrantPermissionCommand() *cobra.Command {
 	return &cobra.Command{
 	return &cobra.Command{
 		Use:   "grant-permission <role name> <permission type> <key> [endkey]",
 		Use:   "grant-permission <role name> <permission type> <key> [endkey]",
@@ -112,12 +121,13 @@ func roleGetCommandFunc(cmd *cobra.Command, args []string) {
 		ExitWithError(ExitBadArgs, fmt.Errorf("role get command requires role name as its argument."))
 		ExitWithError(ExitBadArgs, fmt.Errorf("role get command requires role name as its argument."))
 	}
 	}
 
 
-	resp, err := mustClientFromCmd(cmd).Auth.RoleGet(context.TODO(), args[0])
+	name := args[0]
+	resp, err := mustClientFromCmd(cmd).Auth.RoleGet(context.TODO(), name)
 	if err != nil {
 	if err != nil {
 		ExitWithError(ExitError, err)
 		ExitWithError(ExitError, err)
 	}
 	}
 
 
-	fmt.Printf("Role %s\n", args[0])
+	fmt.Printf("Role %s\n", name)
 	fmt.Println("KV Read:")
 	fmt.Println("KV Read:")
 	for _, perm := range resp.Perm {
 	for _, perm := range resp.Perm {
 		if perm.PermType == clientv3.PermRead || perm.PermType == clientv3.PermReadWrite {
 		if perm.PermType == clientv3.PermRead || perm.PermType == clientv3.PermReadWrite {
@@ -140,6 +150,22 @@ func roleGetCommandFunc(cmd *cobra.Command, args []string) {
 	}
 	}
 }
 }
 
 
+// roleListCommandFunc executes the "role list" command.
+func roleListCommandFunc(cmd *cobra.Command, args []string) {
+	if len(args) != 0 {
+		ExitWithError(ExitBadArgs, fmt.Errorf("role list command requires no arguments."))
+	}
+
+	resp, err := mustClientFromCmd(cmd).Auth.RoleList(context.TODO())
+	if err != nil {
+		ExitWithError(ExitError, err)
+	}
+
+	for _, role := range resp.Roles {
+		fmt.Printf("%s\n", role)
+	}
+}
+
 // roleGrantPermissionCommandFunc executes the "role grant-permission" command.
 // roleGrantPermissionCommandFunc executes the "role grant-permission" command.
 func roleGrantPermissionCommandFunc(cmd *cobra.Command, args []string) {
 func roleGrantPermissionCommandFunc(cmd *cobra.Command, args []string) {
 	if len(args) < 3 {
 	if len(args) < 3 {

+ 28 - 2
etcdctl/ctlv3/command/user_command.go

@@ -33,6 +33,7 @@ func NewUserCommand() *cobra.Command {
 	ac.AddCommand(newUserAddCommand())
 	ac.AddCommand(newUserAddCommand())
 	ac.AddCommand(newUserDeleteCommand())
 	ac.AddCommand(newUserDeleteCommand())
 	ac.AddCommand(newUserGetCommand())
 	ac.AddCommand(newUserGetCommand())
+	ac.AddCommand(newUserListCommand())
 	ac.AddCommand(newUserChangePasswordCommand())
 	ac.AddCommand(newUserChangePasswordCommand())
 	ac.AddCommand(newUserGrantRoleCommand())
 	ac.AddCommand(newUserGrantRoleCommand())
 	ac.AddCommand(newUserRevokeRoleCommand())
 	ac.AddCommand(newUserRevokeRoleCommand())
@@ -73,6 +74,14 @@ func newUserGetCommand() *cobra.Command {
 	}
 	}
 }
 }
 
 
+func newUserListCommand() *cobra.Command {
+	return &cobra.Command{
+		Use:   "list",
+		Short: "list up all users",
+		Run:   userListCommandFunc,
+	}
+}
+
 func newUserChangePasswordCommand() *cobra.Command {
 func newUserChangePasswordCommand() *cobra.Command {
 	cmd := cobra.Command{
 	cmd := cobra.Command{
 		Use:   "passwd <user name>",
 		Use:   "passwd <user name>",
@@ -143,12 +152,13 @@ func userGetCommandFunc(cmd *cobra.Command, args []string) {
 		ExitWithError(ExitBadArgs, fmt.Errorf("user get command requires user name as its argument."))
 		ExitWithError(ExitBadArgs, fmt.Errorf("user get command requires user name as its argument."))
 	}
 	}
 
 
-	resp, err := mustClientFromCmd(cmd).Auth.UserGet(context.TODO(), args[0])
+	name := args[0]
+	resp, err := mustClientFromCmd(cmd).Auth.UserGet(context.TODO(), name)
 	if err != nil {
 	if err != nil {
 		ExitWithError(ExitError, err)
 		ExitWithError(ExitError, err)
 	}
 	}
 
 
-	fmt.Printf("User: %s\n", args[0])
+	fmt.Printf("User: %s\n", name)
 	fmt.Printf("Roles:")
 	fmt.Printf("Roles:")
 	for _, role := range resp.Roles {
 	for _, role := range resp.Roles {
 		fmt.Printf(" %s", role)
 		fmt.Printf(" %s", role)
@@ -156,6 +166,22 @@ func userGetCommandFunc(cmd *cobra.Command, args []string) {
 	fmt.Printf("\n")
 	fmt.Printf("\n")
 }
 }
 
 
+// userListCommandFunc executes the "user list" command.
+func userListCommandFunc(cmd *cobra.Command, args []string) {
+	if len(args) != 0 {
+		ExitWithError(ExitBadArgs, fmt.Errorf("user list command requires no arguments."))
+	}
+
+	resp, err := mustClientFromCmd(cmd).Auth.UserList(context.TODO())
+	if err != nil {
+		ExitWithError(ExitError, err)
+	}
+
+	for _, user := range resp.Users {
+		fmt.Printf("%s\n", user)
+	}
+}
+
 // userChangePasswordCommandFunc executes the "user passwd" command.
 // userChangePasswordCommandFunc executes the "user passwd" command.
 func userChangePasswordCommandFunc(cmd *cobra.Command, args []string) {
 func userChangePasswordCommandFunc(cmd *cobra.Command, args []string) {
 	if len(args) != 1 {
 	if len(args) != 1 {

+ 16 - 0
etcdserver/api/v3rpc/auth.go

@@ -76,6 +76,14 @@ func (as *AuthServer) RoleGet(ctx context.Context, r *pb.AuthRoleGetRequest) (*p
 	return resp, nil
 	return resp, nil
 }
 }
 
 
+func (as *AuthServer) RoleList(ctx context.Context, r *pb.AuthRoleListRequest) (*pb.AuthRoleListResponse, error) {
+	resp, err := as.authenticator.RoleList(ctx, r)
+	if err != nil {
+		return nil, togRPCError(err)
+	}
+	return resp, nil
+}
+
 func (as *AuthServer) RoleRevokePermission(ctx context.Context, r *pb.AuthRoleRevokePermissionRequest) (*pb.AuthRoleRevokePermissionResponse, error) {
 func (as *AuthServer) RoleRevokePermission(ctx context.Context, r *pb.AuthRoleRevokePermissionRequest) (*pb.AuthRoleRevokePermissionResponse, error) {
 	resp, err := as.authenticator.RoleRevokePermission(ctx, r)
 	resp, err := as.authenticator.RoleRevokePermission(ctx, r)
 	if err != nil {
 	if err != nil {
@@ -116,6 +124,14 @@ func (as *AuthServer) UserGet(ctx context.Context, r *pb.AuthUserGetRequest) (*p
 	return resp, nil
 	return resp, nil
 }
 }
 
 
+func (as *AuthServer) UserList(ctx context.Context, r *pb.AuthUserListRequest) (*pb.AuthUserListResponse, error) {
+	resp, err := as.authenticator.UserList(ctx, r)
+	if err != nil {
+		return nil, togRPCError(err)
+	}
+	return resp, nil
+}
+
 func (as *AuthServer) UserGrantRole(ctx context.Context, r *pb.AuthUserGrantRoleRequest) (*pb.AuthUserGrantRoleResponse, error) {
 func (as *AuthServer) UserGrantRole(ctx context.Context, r *pb.AuthUserGrantRoleRequest) (*pb.AuthUserGrantRoleResponse, error) {
 	resp, err := as.authenticator.UserGrantRole(ctx, r)
 	resp, err := as.authenticator.UserGrantRole(ctx, r)
 	if err != nil {
 	if err != nil {

+ 14 - 0
etcdserver/apply.go

@@ -78,6 +78,8 @@ type applierV3 interface {
 	RoleGet(ua *pb.AuthRoleGetRequest) (*pb.AuthRoleGetResponse, error)
 	RoleGet(ua *pb.AuthRoleGetRequest) (*pb.AuthRoleGetResponse, error)
 	RoleRevokePermission(ua *pb.AuthRoleRevokePermissionRequest) (*pb.AuthRoleRevokePermissionResponse, error)
 	RoleRevokePermission(ua *pb.AuthRoleRevokePermissionRequest) (*pb.AuthRoleRevokePermissionResponse, error)
 	RoleDelete(ua *pb.AuthRoleDeleteRequest) (*pb.AuthRoleDeleteResponse, error)
 	RoleDelete(ua *pb.AuthRoleDeleteRequest) (*pb.AuthRoleDeleteResponse, error)
+	UserList(ua *pb.AuthUserListRequest) (*pb.AuthUserListResponse, error)
+	RoleList(ua *pb.AuthRoleListRequest) (*pb.AuthRoleListResponse, error)
 }
 }
 
 
 type applierV3backend struct {
 type applierV3backend struct {
@@ -140,6 +142,10 @@ func (a *applierV3backend) Apply(r *pb.InternalRaftRequest) *applyResult {
 		ar.resp, ar.err = a.s.applyV3.RoleRevokePermission(r.AuthRoleRevokePermission)
 		ar.resp, ar.err = a.s.applyV3.RoleRevokePermission(r.AuthRoleRevokePermission)
 	case r.AuthRoleDelete != nil:
 	case r.AuthRoleDelete != nil:
 		ar.resp, ar.err = a.s.applyV3.RoleDelete(r.AuthRoleDelete)
 		ar.resp, ar.err = a.s.applyV3.RoleDelete(r.AuthRoleDelete)
+	case r.AuthUserList != nil:
+		ar.resp, ar.err = a.s.applyV3.UserList(r.AuthUserList)
+	case r.AuthRoleList != nil:
+		ar.resp, ar.err = a.s.applyV3.RoleList(r.AuthRoleList)
 	default:
 	default:
 		panic("not implemented")
 		panic("not implemented")
 	}
 	}
@@ -590,6 +596,14 @@ func (a *applierV3backend) RoleDelete(r *pb.AuthRoleDeleteRequest) (*pb.AuthRole
 	return a.s.AuthStore().RoleDelete(r)
 	return a.s.AuthStore().RoleDelete(r)
 }
 }
 
 
+func (a *applierV3backend) UserList(r *pb.AuthUserListRequest) (*pb.AuthUserListResponse, error) {
+	return a.s.AuthStore().UserList(r)
+}
+
+func (a *applierV3backend) RoleList(r *pb.AuthRoleListRequest) (*pb.AuthRoleListResponse, error) {
+	return a.s.AuthStore().RoleList(r)
+}
+
 type quotaApplierV3 struct {
 type quotaApplierV3 struct {
 	applierV3
 	applierV3
 	q Quota
 	q Quota

+ 4 - 0
etcdserver/apply_auth.go

@@ -146,6 +146,10 @@ func needAdminPermission(r *pb.InternalRaftRequest) bool {
 		return true
 		return true
 	case r.AuthRoleDelete != nil:
 	case r.AuthRoleDelete != nil:
 		return true
 		return true
+	case r.AuthUserList != nil:
+		return true
+	case r.AuthRoleList != nil:
+		return true
 	default:
 	default:
 		return false
 		return false
 	}
 	}

+ 4 - 0
etcdserver/etcdserverpb/etcdserver.pb.go

@@ -72,6 +72,8 @@
 		AuthUserRevokeRoleRequest
 		AuthUserRevokeRoleRequest
 		AuthRoleAddRequest
 		AuthRoleAddRequest
 		AuthRoleGetRequest
 		AuthRoleGetRequest
+		AuthUserListRequest
+		AuthRoleListRequest
 		AuthRoleDeleteRequest
 		AuthRoleDeleteRequest
 		AuthRoleGrantPermissionRequest
 		AuthRoleGrantPermissionRequest
 		AuthRoleRevokePermissionRequest
 		AuthRoleRevokePermissionRequest
@@ -86,6 +88,8 @@
 		AuthUserRevokeRoleResponse
 		AuthUserRevokeRoleResponse
 		AuthRoleAddResponse
 		AuthRoleAddResponse
 		AuthRoleGetResponse
 		AuthRoleGetResponse
+		AuthRoleListResponse
+		AuthUserListResponse
 		AuthRoleDeleteResponse
 		AuthRoleDeleteResponse
 		AuthRoleGrantPermissionResponse
 		AuthRoleGrantPermissionResponse
 		AuthRoleRevokePermissionResponse
 		AuthRoleRevokePermissionResponse

+ 162 - 60
etcdserver/etcdserverpb/raft_internal.pb.go

@@ -53,6 +53,8 @@ type InternalRaftRequest struct {
 	AuthUserChangePassword   *AuthUserChangePasswordRequest   `protobuf:"bytes,1103,opt,name=auth_user_change_password,json=authUserChangePassword" json:"auth_user_change_password,omitempty"`
 	AuthUserChangePassword   *AuthUserChangePasswordRequest   `protobuf:"bytes,1103,opt,name=auth_user_change_password,json=authUserChangePassword" json:"auth_user_change_password,omitempty"`
 	AuthUserGrantRole        *AuthUserGrantRoleRequest        `protobuf:"bytes,1104,opt,name=auth_user_grant_role,json=authUserGrantRole" json:"auth_user_grant_role,omitempty"`
 	AuthUserGrantRole        *AuthUserGrantRoleRequest        `protobuf:"bytes,1104,opt,name=auth_user_grant_role,json=authUserGrantRole" json:"auth_user_grant_role,omitempty"`
 	AuthUserRevokeRole       *AuthUserRevokeRoleRequest       `protobuf:"bytes,1105,opt,name=auth_user_revoke_role,json=authUserRevokeRole" json:"auth_user_revoke_role,omitempty"`
 	AuthUserRevokeRole       *AuthUserRevokeRoleRequest       `protobuf:"bytes,1105,opt,name=auth_user_revoke_role,json=authUserRevokeRole" json:"auth_user_revoke_role,omitempty"`
+	AuthUserList             *AuthUserListRequest             `protobuf:"bytes,1106,opt,name=auth_user_list,json=authUserList" json:"auth_user_list,omitempty"`
+	AuthRoleList             *AuthRoleListRequest             `protobuf:"bytes,1107,opt,name=auth_role_list,json=authRoleList" json:"auth_role_list,omitempty"`
 	AuthRoleAdd              *AuthRoleAddRequest              `protobuf:"bytes,1200,opt,name=auth_role_add,json=authRoleAdd" json:"auth_role_add,omitempty"`
 	AuthRoleAdd              *AuthRoleAddRequest              `protobuf:"bytes,1200,opt,name=auth_role_add,json=authRoleAdd" json:"auth_role_add,omitempty"`
 	AuthRoleDelete           *AuthRoleDeleteRequest           `protobuf:"bytes,1201,opt,name=auth_role_delete,json=authRoleDelete" json:"auth_role_delete,omitempty"`
 	AuthRoleDelete           *AuthRoleDeleteRequest           `protobuf:"bytes,1201,opt,name=auth_role_delete,json=authRoleDelete" json:"auth_role_delete,omitempty"`
 	AuthRoleGet              *AuthRoleGetRequest              `protobuf:"bytes,1202,opt,name=auth_role_get,json=authRoleGet" json:"auth_role_get,omitempty"`
 	AuthRoleGet              *AuthRoleGetRequest              `protobuf:"bytes,1202,opt,name=auth_role_get,json=authRoleGet" json:"auth_role_get,omitempty"`
@@ -355,17 +357,41 @@ func (m *InternalRaftRequest) MarshalTo(data []byte) (int, error) {
 		}
 		}
 		i += n19
 		i += n19
 	}
 	}
+	if m.AuthUserList != nil {
+		data[i] = 0x92
+		i++
+		data[i] = 0x45
+		i++
+		i = encodeVarintRaftInternal(data, i, uint64(m.AuthUserList.Size()))
+		n20, err := m.AuthUserList.MarshalTo(data[i:])
+		if err != nil {
+			return 0, err
+		}
+		i += n20
+	}
+	if m.AuthRoleList != nil {
+		data[i] = 0x9a
+		i++
+		data[i] = 0x45
+		i++
+		i = encodeVarintRaftInternal(data, i, uint64(m.AuthRoleList.Size()))
+		n21, err := m.AuthRoleList.MarshalTo(data[i:])
+		if err != nil {
+			return 0, err
+		}
+		i += n21
+	}
 	if m.AuthRoleAdd != nil {
 	if m.AuthRoleAdd != nil {
 		data[i] = 0x82
 		data[i] = 0x82
 		i++
 		i++
 		data[i] = 0x4b
 		data[i] = 0x4b
 		i++
 		i++
 		i = encodeVarintRaftInternal(data, i, uint64(m.AuthRoleAdd.Size()))
 		i = encodeVarintRaftInternal(data, i, uint64(m.AuthRoleAdd.Size()))
-		n20, err := m.AuthRoleAdd.MarshalTo(data[i:])
+		n22, err := m.AuthRoleAdd.MarshalTo(data[i:])
 		if err != nil {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
-		i += n20
+		i += n22
 	}
 	}
 	if m.AuthRoleDelete != nil {
 	if m.AuthRoleDelete != nil {
 		data[i] = 0x8a
 		data[i] = 0x8a
@@ -373,11 +399,11 @@ func (m *InternalRaftRequest) MarshalTo(data []byte) (int, error) {
 		data[i] = 0x4b
 		data[i] = 0x4b
 		i++
 		i++
 		i = encodeVarintRaftInternal(data, i, uint64(m.AuthRoleDelete.Size()))
 		i = encodeVarintRaftInternal(data, i, uint64(m.AuthRoleDelete.Size()))
-		n21, err := m.AuthRoleDelete.MarshalTo(data[i:])
+		n23, err := m.AuthRoleDelete.MarshalTo(data[i:])
 		if err != nil {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
-		i += n21
+		i += n23
 	}
 	}
 	if m.AuthRoleGet != nil {
 	if m.AuthRoleGet != nil {
 		data[i] = 0x92
 		data[i] = 0x92
@@ -385,11 +411,11 @@ func (m *InternalRaftRequest) MarshalTo(data []byte) (int, error) {
 		data[i] = 0x4b
 		data[i] = 0x4b
 		i++
 		i++
 		i = encodeVarintRaftInternal(data, i, uint64(m.AuthRoleGet.Size()))
 		i = encodeVarintRaftInternal(data, i, uint64(m.AuthRoleGet.Size()))
-		n22, err := m.AuthRoleGet.MarshalTo(data[i:])
+		n24, err := m.AuthRoleGet.MarshalTo(data[i:])
 		if err != nil {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
-		i += n22
+		i += n24
 	}
 	}
 	if m.AuthRoleGrantPermission != nil {
 	if m.AuthRoleGrantPermission != nil {
 		data[i] = 0x9a
 		data[i] = 0x9a
@@ -397,11 +423,11 @@ func (m *InternalRaftRequest) MarshalTo(data []byte) (int, error) {
 		data[i] = 0x4b
 		data[i] = 0x4b
 		i++
 		i++
 		i = encodeVarintRaftInternal(data, i, uint64(m.AuthRoleGrantPermission.Size()))
 		i = encodeVarintRaftInternal(data, i, uint64(m.AuthRoleGrantPermission.Size()))
-		n23, err := m.AuthRoleGrantPermission.MarshalTo(data[i:])
+		n25, err := m.AuthRoleGrantPermission.MarshalTo(data[i:])
 		if err != nil {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
-		i += n23
+		i += n25
 	}
 	}
 	if m.AuthRoleRevokePermission != nil {
 	if m.AuthRoleRevokePermission != nil {
 		data[i] = 0xa2
 		data[i] = 0xa2
@@ -409,11 +435,11 @@ func (m *InternalRaftRequest) MarshalTo(data []byte) (int, error) {
 		data[i] = 0x4b
 		data[i] = 0x4b
 		i++
 		i++
 		i = encodeVarintRaftInternal(data, i, uint64(m.AuthRoleRevokePermission.Size()))
 		i = encodeVarintRaftInternal(data, i, uint64(m.AuthRoleRevokePermission.Size()))
-		n24, err := m.AuthRoleRevokePermission.MarshalTo(data[i:])
+		n26, err := m.AuthRoleRevokePermission.MarshalTo(data[i:])
 		if err != nil {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
-		i += n24
+		i += n26
 	}
 	}
 	return i, nil
 	return i, nil
 }
 }
@@ -594,6 +620,14 @@ func (m *InternalRaftRequest) Size() (n int) {
 		l = m.AuthUserRevokeRole.Size()
 		l = m.AuthUserRevokeRole.Size()
 		n += 2 + l + sovRaftInternal(uint64(l))
 		n += 2 + l + sovRaftInternal(uint64(l))
 	}
 	}
+	if m.AuthUserList != nil {
+		l = m.AuthUserList.Size()
+		n += 2 + l + sovRaftInternal(uint64(l))
+	}
+	if m.AuthRoleList != nil {
+		l = m.AuthRoleList.Size()
+		n += 2 + l + sovRaftInternal(uint64(l))
+	}
 	if m.AuthRoleAdd != nil {
 	if m.AuthRoleAdd != nil {
 		l = m.AuthRoleAdd.Size()
 		l = m.AuthRoleAdd.Size()
 		n += 2 + l + sovRaftInternal(uint64(l))
 		n += 2 + l + sovRaftInternal(uint64(l))
@@ -1427,6 +1461,72 @@ func (m *InternalRaftRequest) Unmarshal(data []byte) error {
 				return err
 				return err
 			}
 			}
 			iNdEx = postIndex
 			iNdEx = postIndex
+		case 1106:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field AuthUserList", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowRaftInternal
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthRaftInternal
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if m.AuthUserList == nil {
+				m.AuthUserList = &AuthUserListRequest{}
+			}
+			if err := m.AuthUserList.Unmarshal(data[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		case 1107:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field AuthRoleList", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowRaftInternal
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthRaftInternal
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if m.AuthRoleList == nil {
+				m.AuthRoleList = &AuthRoleListRequest{}
+			}
+			if err := m.AuthRoleList.Unmarshal(data[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
 		case 1200:
 		case 1200:
 			if wireType != 2 {
 			if wireType != 2 {
 				return fmt.Errorf("proto: wrong wireType = %d for field AuthRoleAdd", wireType)
 				return fmt.Errorf("proto: wrong wireType = %d for field AuthRoleAdd", wireType)
@@ -1906,54 +2006,56 @@ var (
 )
 )
 
 
 var fileDescriptorRaftInternal = []byte{
 var fileDescriptorRaftInternal = []byte{
-	// 770 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x7c, 0x95, 0x4b, 0x6f, 0x13, 0x3b,
-	0x14, 0xc7, 0x6f, 0xd2, 0x67, 0x9c, 0xa4, 0xb7, 0xd7, 0x6d, 0x2f, 0x26, 0x95, 0x4a, 0x09, 0xe2,
-	0x0d, 0x05, 0xb5, 0x4b, 0x16, 0x10, 0x9a, 0xaa, 0x54, 0x42, 0xa8, 0x1a, 0x15, 0x09, 0x89, 0xc5,
-	0xc8, 0xcd, 0x98, 0x74, 0x60, 0x5e, 0x78, 0x9c, 0x52, 0xbe, 0x15, 0xaf, 0x0f, 0xd1, 0x05, 0x8f,
-	0xb2, 0x65, 0x05, 0xac, 0xd8, 0xc3, 0x07, 0xc0, 0xaf, 0xf1, 0xcc, 0x24, 0x4e, 0x17, 0x91, 0x66,
-	0xce, 0xf9, 0x9f, 0xdf, 0x39, 0x9e, 0xbf, 0x1d, 0x83, 0x05, 0x8a, 0x9f, 0x31, 0xd7, 0x8f, 0x18,
-	0xa1, 0x11, 0x0e, 0xd6, 0x12, 0x1a, 0xb3, 0x18, 0x36, 0x08, 0xeb, 0x79, 0x29, 0xa1, 0x87, 0x84,
-	0x26, 0xfb, 0xad, 0xc5, 0x7e, 0xdc, 0x8f, 0x65, 0xe2, 0x96, 0x78, 0x52, 0x9a, 0xd6, 0x7c, 0xae,
-	0xd1, 0x91, 0x1a, 0x4d, 0x7a, 0xea, 0xb1, 0x7d, 0x07, 0x34, 0x1d, 0xf2, 0x72, 0x40, 0x52, 0xf6,
-	0x80, 0x60, 0x8f, 0x50, 0x38, 0x07, 0xaa, 0x3b, 0x5d, 0x54, 0x59, 0xad, 0x5c, 0x99, 0x74, 0xaa,
-	0x7e, 0x17, 0xb6, 0xc0, 0xec, 0x20, 0x15, 0x2d, 0x43, 0x82, 0xaa, 0x3c, 0x5a, 0x73, 0xcc, 0x7b,
-	0xfb, 0x5b, 0x13, 0x2c, 0xec, 0xe8, 0x81, 0x1c, 0x3e, 0x9d, 0x26, 0x8d, 0x30, 0x2e, 0x82, 0xea,
-	0xe1, 0xba, 0xac, 0xae, 0xaf, 0x2f, 0xad, 0x15, 0x47, 0x5e, 0xd3, 0x25, 0x0e, 0x17, 0xc0, 0xdb,
-	0x60, 0x8a, 0xe2, 0xa8, 0x4f, 0xd0, 0x84, 0x54, 0xb6, 0x86, 0x94, 0x22, 0x95, 0xc9, 0x95, 0x10,
-	0x5e, 0x03, 0x13, 0xc9, 0x80, 0xa1, 0x49, 0xa9, 0x47, 0x65, 0xfd, 0xee, 0x20, 0x9b, 0xc7, 0x11,
-	0x22, 0xb8, 0x09, 0x1a, 0x1e, 0x09, 0x08, 0x23, 0xae, 0x6a, 0x32, 0x25, 0x8b, 0x56, 0xcb, 0x45,
-	0x5d, 0xa9, 0x28, 0xb5, 0xaa, 0x7b, 0x79, 0x4c, 0x34, 0x64, 0x47, 0x11, 0x9a, 0xb6, 0x35, 0xdc,
-	0x3b, 0x8a, 0x4c, 0x43, 0x2e, 0x82, 0x77, 0x01, 0xe8, 0xc5, 0x61, 0x82, 0x7b, 0xcc, 0x8f, 0x23,
-	0x34, 0x23, 0x4b, 0xce, 0x95, 0x4b, 0x36, 0x4d, 0x3e, 0xab, 0x2c, 0x94, 0xc0, 0x7b, 0xa0, 0x1e,
-	0x10, 0x9c, 0x12, 0xb7, 0xcf, 0x27, 0x66, 0x68, 0xd6, 0x46, 0x78, 0x28, 0x04, 0xdb, 0x22, 0x6f,
-	0x08, 0x81, 0x09, 0x89, 0x35, 0x2b, 0x02, 0x25, 0x87, 0xf1, 0x0b, 0x82, 0x6a, 0xb6, 0x35, 0x4b,
-	0x84, 0x23, 0x05, 0x66, 0xcd, 0x41, 0x1e, 0x13, 0xb6, 0xe0, 0x00, 0xd3, 0x10, 0x01, 0x9b, 0x2d,
-	0x1d, 0x91, 0x32, 0xb6, 0x48, 0x21, 0xdc, 0x00, 0xd3, 0x07, 0x72, 0x37, 0x21, 0x4f, 0x96, 0x2c,
-	0x5b, 0x3d, 0x57, 0x1b, 0xce, 0xd1, 0x52, 0xd8, 0x01, 0x75, 0x3c, 0x60, 0x07, 0x2e, 0x89, 0xf0,
-	0x7e, 0x40, 0xd0, 0x2f, 0xeb, 0x07, 0xeb, 0x70, 0xc5, 0x96, 0x14, 0x98, 0xe5, 0x62, 0x13, 0x82,
-	0x5d, 0xd0, 0x90, 0x08, 0xcf, 0x4f, 0x25, 0xe3, 0xf7, 0x8c, 0x6d, 0xbd, 0x82, 0xd1, 0x55, 0x0a,
-	0xb3, 0x5e, 0x9c, 0xc7, 0xe0, 0x23, 0x45, 0x21, 0x11, 0xf3, 0x7b, 0x98, 0x11, 0xf4, 0x47, 0x51,
-	0xae, 0x96, 0x29, 0xd9, 0xbe, 0xef, 0x14, 0xa4, 0x19, 0xae, 0x54, 0x0f, 0xb7, 0x40, 0x53, 0x4e,
-	0x25, 0x8e, 0x8d, 0x8b, 0x3d, 0x0f, 0x7d, 0x9c, 0x1d, 0x37, 0xd6, 0x63, 0xfe, 0xd6, 0xf1, 0xbc,
-	0xd2, 0x58, 0x3a, 0xc6, 0xc7, 0x9a, 0xcf, 0x31, 0x6a, 0x4f, 0xa2, 0x4f, 0x8a, 0x74, 0xc1, 0x4e,
-	0xd2, 0x9b, 0x59, 0xc3, 0xe6, 0x70, 0x29, 0x5c, 0x1e, 0xab, 0x4f, 0x18, 0xfa, 0x7c, 0xea, 0x58,
-	0xdb, 0x84, 0x8d, 0x8c, 0xc5, 0x63, 0xb0, 0x0f, 0xce, 0xe6, 0x98, 0xde, 0x81, 0x38, 0x25, 0x6e,
-	0x82, 0xd3, 0xf4, 0x55, 0x4c, 0x3d, 0xf4, 0x45, 0x21, 0xaf, 0xdb, 0x91, 0x9b, 0x52, 0xbd, 0xab,
-	0xc5, 0x19, 0xfd, 0x7f, 0x6c, 0x4d, 0xc3, 0x27, 0x60, 0xb1, 0x30, 0xaf, 0xd8, 0xde, 0x2e, 0x8d,
-	0xb9, 0xc9, 0x27, 0xaa, 0xc7, 0xa5, 0x31, 0x63, 0xcb, 0xa3, 0x11, 0xe7, 0x56, 0xff, 0x87, 0x87,
-	0x33, 0xf0, 0x29, 0x58, 0xca, 0xc9, 0xea, 0xa4, 0x28, 0xf4, 0x57, 0x85, 0xbe, 0x6c, 0x47, 0xeb,
-	0x23, 0x53, 0x60, 0x43, 0x3c, 0x92, 0x32, 0x9f, 0x59, 0x00, 0xa5, 0xfb, 0x6f, 0x6a, 0xe3, 0x3e,
-	0xb3, 0xd0, 0x0f, 0xbb, 0xaf, 0x63, 0xc6, 0x7d, 0x89, 0xd1, 0xee, 0xbf, 0xad, 0x8d, 0x73, 0x5f,
-	0x54, 0x59, 0xdc, 0xcf, 0xc3, 0xe5, 0xb1, 0x84, 0xfb, 0xef, 0x4e, 0x1d, 0x6b, 0xd8, 0x7d, 0x1d,
-	0x83, 0xcf, 0x41, 0xab, 0x80, 0x91, 0xa6, 0x24, 0x84, 0x86, 0x7e, 0x9a, 0x8a, 0xff, 0xbc, 0xf7,
-	0x8a, 0x79, 0x63, 0x0c, 0x53, 0xc8, 0x77, 0x8d, 0x3a, 0xe3, 0x9f, 0xc1, 0xf6, 0x3c, 0x0c, 0xc1,
-	0x72, 0xde, 0x4b, 0xdb, 0x54, 0x68, 0xf6, 0x41, 0x35, 0xbb, 0x69, 0x6f, 0xa6, 0x1c, 0x19, 0xed,
-	0x86, 0xf0, 0x18, 0x41, 0xfb, 0x5f, 0xd0, 0xdc, 0x0a, 0x13, 0xf6, 0xda, 0x21, 0x69, 0x12, 0x47,
-	0x29, 0x69, 0x27, 0x60, 0xf9, 0x94, 0x43, 0x0f, 0x21, 0x98, 0x94, 0x97, 0x64, 0x45, 0x5e, 0x92,
-	0xf2, 0x59, 0x5c, 0x9e, 0xe6, 0x2c, 0xe8, 0xcb, 0x33, 0x7b, 0x87, 0xe7, 0x41, 0x23, 0xf5, 0xc3,
-	0x84, 0xaf, 0x85, 0xf1, 0xc6, 0x91, 0xbc, 0xf4, 0x6a, 0x4e, 0x5d, 0xc5, 0xf6, 0x44, 0xe8, 0xfe,
-	0xfc, 0xf1, 0x8f, 0x95, 0x7f, 0x8e, 0x7f, 0xae, 0x54, 0x4e, 0xf8, 0xef, 0x3b, 0xff, 0xed, 0x4f,
-	0xcb, 0x5b, 0x7b, 0xe3, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa6, 0x96, 0x31, 0x96, 0x0d, 0x08,
-	0x00, 0x00,
+	// 808 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x7c, 0x96, 0x4b, 0x6f, 0xd3, 0x4a,
+	0x14, 0xc7, 0x6f, 0xd2, 0x67, 0x26, 0x69, 0x6e, 0xef, 0xb4, 0xbd, 0x77, 0x6e, 0x2a, 0x95, 0x36,
+	0x88, 0x37, 0x14, 0xd4, 0x2e, 0x59, 0x40, 0x68, 0xaa, 0xb6, 0x52, 0x85, 0x2a, 0xab, 0x48, 0x48,
+	0x2c, 0xac, 0x69, 0x3c, 0xa4, 0x06, 0xbf, 0xb0, 0x27, 0xa5, 0x7c, 0x2b, 0x5e, 0x1f, 0xa2, 0x0b,
+	0x1e, 0x05, 0xbe, 0x00, 0xb0, 0x62, 0xc5, 0x06, 0x3e, 0x00, 0xf3, 0xf2, 0xd8, 0x4e, 0xc6, 0x5d,
+	0x44, 0xb2, 0xcf, 0xf9, 0x9f, 0xdf, 0x39, 0xd3, 0xf9, 0x8f, 0xa7, 0x60, 0x2e, 0xc6, 0x8f, 0xa9,
+	0xed, 0x06, 0x94, 0xc4, 0x01, 0xf6, 0x56, 0xa3, 0x38, 0xa4, 0x21, 0x6c, 0x10, 0xda, 0x73, 0x12,
+	0x12, 0x1f, 0x91, 0x38, 0x3a, 0x68, 0xcd, 0xf7, 0xc3, 0x7e, 0x28, 0x12, 0x37, 0xf9, 0x93, 0xd4,
+	0xb4, 0x66, 0x33, 0x8d, 0x8a, 0xd4, 0xe2, 0xa8, 0x27, 0x1f, 0xdb, 0xb7, 0xc1, 0x8c, 0x45, 0x9e,
+	0x0d, 0x48, 0x42, 0xb7, 0x09, 0x76, 0x48, 0x0c, 0x9b, 0xa0, 0xba, 0xd3, 0x45, 0x95, 0xe5, 0xca,
+	0xe5, 0x71, 0xab, 0xea, 0x76, 0x61, 0x0b, 0x4c, 0x0f, 0x12, 0xde, 0xd2, 0x27, 0xa8, 0xca, 0xa2,
+	0x35, 0x4b, 0xbf, 0xb7, 0x7f, 0x36, 0xc1, 0xdc, 0x8e, 0x1a, 0xc8, 0x62, 0xd3, 0x29, 0xd2, 0x08,
+	0xe3, 0x02, 0xa8, 0x1e, 0xad, 0x89, 0xea, 0xfa, 0xda, 0xc2, 0x6a, 0x7e, 0xe4, 0x55, 0x55, 0x62,
+	0x31, 0x01, 0xbc, 0x05, 0x26, 0x62, 0x1c, 0xf4, 0x09, 0x1a, 0x13, 0xca, 0xd6, 0x90, 0x92, 0xa7,
+	0x52, 0xb9, 0x14, 0xc2, 0xab, 0x60, 0x2c, 0x1a, 0x50, 0x34, 0x2e, 0xf4, 0xa8, 0xa8, 0xdf, 0x1b,
+	0xa4, 0xf3, 0x58, 0x5c, 0x04, 0x37, 0x40, 0xc3, 0x21, 0x1e, 0xa1, 0xc4, 0x96, 0x4d, 0x26, 0x44,
+	0xd1, 0x72, 0xb1, 0xa8, 0x2b, 0x14, 0x85, 0x56, 0x75, 0x27, 0x8b, 0xf1, 0x86, 0xf4, 0x38, 0x40,
+	0x93, 0xa6, 0x86, 0xfb, 0xc7, 0x81, 0x6e, 0xc8, 0x44, 0xf0, 0x0e, 0x00, 0xbd, 0xd0, 0x8f, 0x70,
+	0x8f, 0xba, 0x61, 0x80, 0xa6, 0x44, 0xc9, 0xb9, 0x62, 0xc9, 0x86, 0xce, 0xa7, 0x95, 0xb9, 0x12,
+	0x78, 0x17, 0xd4, 0x3d, 0x82, 0x13, 0x62, 0xf7, 0xd9, 0xc4, 0x14, 0x4d, 0x9b, 0x08, 0xbb, 0x5c,
+	0xb0, 0xc5, 0xf3, 0x9a, 0xe0, 0xe9, 0x10, 0x5f, 0xb3, 0x24, 0xc4, 0xe4, 0x28, 0x7c, 0x4a, 0x50,
+	0xcd, 0xb4, 0x66, 0x81, 0xb0, 0x84, 0x40, 0xaf, 0xd9, 0xcb, 0x62, 0x7c, 0x5b, 0xb0, 0x87, 0x63,
+	0x1f, 0x01, 0xd3, 0xb6, 0x74, 0x78, 0x4a, 0x6f, 0x8b, 0x10, 0xc2, 0x75, 0x30, 0x79, 0x28, 0xdc,
+	0x84, 0x1c, 0x51, 0xb2, 0x68, 0xdc, 0x73, 0x69, 0x38, 0x4b, 0x49, 0x61, 0x07, 0xd4, 0xf1, 0x80,
+	0x1e, 0xda, 0x24, 0xc0, 0x07, 0x1e, 0x41, 0x3f, 0x8c, 0x7f, 0xb0, 0x0e, 0x53, 0x6c, 0x0a, 0x81,
+	0x5e, 0x2e, 0xd6, 0x21, 0xd8, 0x05, 0x0d, 0x81, 0x70, 0xdc, 0x44, 0x30, 0x7e, 0x4d, 0x99, 0xd6,
+	0xcb, 0x19, 0x5d, 0xa9, 0xd0, 0xeb, 0xc5, 0x59, 0x0c, 0xde, 0x97, 0x14, 0x12, 0x50, 0xb7, 0x87,
+	0x29, 0x41, 0xbf, 0x25, 0xe5, 0x4a, 0x91, 0x92, 0xfa, 0xbe, 0x93, 0x93, 0xa6, 0xb8, 0x42, 0x3d,
+	0xdc, 0x04, 0x33, 0x62, 0x2a, 0x7e, 0x6c, 0x6c, 0xec, 0x38, 0xe8, 0xdd, 0x74, 0xd9, 0x58, 0x0f,
+	0xd8, 0x5b, 0xc7, 0x71, 0x0a, 0x63, 0xa9, 0x18, 0x1b, 0x6b, 0x36, 0xc3, 0x48, 0x4f, 0xa2, 0xf7,
+	0x92, 0x74, 0xde, 0x4c, 0x52, 0x66, 0x56, 0xb0, 0x26, 0x2e, 0x84, 0x8b, 0x63, 0xf5, 0x09, 0x45,
+	0x1f, 0xce, 0x1c, 0x6b, 0x8b, 0xd0, 0x91, 0xb1, 0x58, 0x0c, 0xf6, 0xc1, 0xff, 0x19, 0xa6, 0x77,
+	0xc8, 0x4f, 0x89, 0x1d, 0xe1, 0x24, 0x79, 0x1e, 0xc6, 0x0e, 0xfa, 0x28, 0x91, 0xd7, 0xcc, 0xc8,
+	0x0d, 0xa1, 0xde, 0x53, 0xe2, 0x94, 0xfe, 0x2f, 0x36, 0xa6, 0xe1, 0x43, 0x30, 0x9f, 0x9b, 0x97,
+	0xdb, 0xdb, 0x8e, 0x43, 0xb6, 0xc9, 0xa7, 0xb2, 0xc7, 0xc5, 0x92, 0xb1, 0xc5, 0xd1, 0x08, 0xb3,
+	0xad, 0xfe, 0x07, 0x0f, 0x67, 0xe0, 0x23, 0xb0, 0x90, 0x91, 0xe5, 0x49, 0x91, 0xe8, 0x4f, 0x12,
+	0x7d, 0xc9, 0x8c, 0x56, 0x47, 0x26, 0xc7, 0x86, 0x78, 0x24, 0x05, 0xb7, 0x41, 0x33, 0x83, 0x7b,
+	0x6e, 0x42, 0xd1, 0x67, 0x49, 0x5d, 0x31, 0x53, 0x77, 0x99, 0xa4, 0xe0, 0xa3, 0x34, 0xa8, 0x49,
+	0x7c, 0x34, 0x49, 0xfa, 0x52, 0x4a, 0xe2, 0xad, 0x47, 0x48, 0x69, 0x50, 0x6f, 0xbd, 0x20, 0x71,
+	0x47, 0xbe, 0xac, 0x95, 0x6d, 0x3d, 0xaf, 0x19, 0x76, 0xa4, 0x8a, 0x69, 0x47, 0x0a, 0x8c, 0x72,
+	0xe4, 0xab, 0x5a, 0x99, 0x23, 0x79, 0x95, 0xc1, 0x91, 0x59, 0xb8, 0x38, 0x16, 0x77, 0xe4, 0xeb,
+	0x33, 0xc7, 0x1a, 0x76, 0xa4, 0x8a, 0xc1, 0x27, 0xa0, 0x95, 0xc3, 0x08, 0xa3, 0x44, 0x24, 0xf6,
+	0xdd, 0x24, 0xe1, 0xdf, 0xe1, 0x37, 0x92, 0x79, 0xbd, 0x84, 0xc9, 0xe5, 0x7b, 0x5a, 0x9d, 0xf2,
+	0xff, 0xc3, 0xe6, 0x3c, 0xf4, 0xc1, 0x62, 0xd6, 0x4b, 0x59, 0x27, 0xd7, 0xec, 0xad, 0x6c, 0x76,
+	0xc3, 0xdc, 0x4c, 0xba, 0x64, 0xb4, 0x1b, 0xc2, 0x25, 0x82, 0xf6, 0xdf, 0x60, 0x66, 0xd3, 0x8f,
+	0xe8, 0x0b, 0x8b, 0x24, 0x51, 0x18, 0x24, 0xa4, 0x1d, 0x81, 0xc5, 0x33, 0x3e, 0x44, 0x10, 0x82,
+	0x71, 0x71, 0x71, 0x57, 0xc4, 0xc5, 0x2d, 0x9e, 0xf9, 0x85, 0xae, 0xcf, 0xa7, 0xba, 0xd0, 0xd3,
+	0x77, 0xb8, 0x02, 0x1a, 0x89, 0xeb, 0x47, 0x6c, 0x2d, 0x94, 0x35, 0x0e, 0xc4, 0x45, 0x5c, 0xb3,
+	0xea, 0x32, 0xb6, 0xcf, 0x43, 0xf7, 0x66, 0x4f, 0xbe, 0x2d, 0xfd, 0x75, 0xf2, 0x7d, 0xa9, 0x72,
+	0xca, 0x7e, 0x5f, 0xd9, 0xef, 0x60, 0x52, 0xfc, 0x27, 0xb1, 0xfe, 0x27, 0x00, 0x00, 0xff, 0xff,
+	0xdc, 0xb1, 0xbb, 0xb7, 0xa1, 0x08, 0x00, 0x00,
 }
 }

+ 2 - 0
etcdserver/etcdserverpb/raft_internal.proto

@@ -46,6 +46,8 @@ message InternalRaftRequest {
   AuthUserChangePasswordRequest auth_user_change_password = 1103;
   AuthUserChangePasswordRequest auth_user_change_password = 1103;
   AuthUserGrantRoleRequest auth_user_grant_role = 1104;
   AuthUserGrantRoleRequest auth_user_grant_role = 1104;
   AuthUserRevokeRoleRequest auth_user_revoke_role = 1105;
   AuthUserRevokeRoleRequest auth_user_revoke_role = 1105;
+  AuthUserListRequest auth_user_list = 1106;
+  AuthRoleListRequest auth_role_list = 1107;
 
 
   AuthRoleAddRequest auth_role_add = 1200;
   AuthRoleAddRequest auth_role_add = 1200;
   AuthRoleDeleteRequest auth_role_delete = 1201;
   AuthRoleDeleteRequest auth_role_delete = 1201;

File diff suppressed because it is too large
+ 664 - 50
etcdserver/etcdserverpb/rpc.pb.go


+ 90 - 0
etcdserver/etcdserverpb/rpc.pb.gw.go

@@ -387,6 +387,19 @@ func request_Auth_UserGet_0(ctx context.Context, marshaler runtime.Marshaler, cl
 
 
 }
 }
 
 
+func request_Auth_UserList_0(ctx context.Context, marshaler runtime.Marshaler, client AuthClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq AuthUserListRequest
+	var metadata runtime.ServerMetadata
+
+	if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+		return nil, metadata, grpc.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := client.UserList(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+	return msg, metadata, err
+
+}
+
 func request_Auth_UserDelete_0(ctx context.Context, marshaler runtime.Marshaler, client AuthClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
 func request_Auth_UserDelete_0(ctx context.Context, marshaler runtime.Marshaler, client AuthClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
 	var protoReq AuthUserDeleteRequest
 	var protoReq AuthUserDeleteRequest
 	var metadata runtime.ServerMetadata
 	var metadata runtime.ServerMetadata
@@ -465,6 +478,19 @@ func request_Auth_RoleGet_0(ctx context.Context, marshaler runtime.Marshaler, cl
 
 
 }
 }
 
 
+func request_Auth_RoleList_0(ctx context.Context, marshaler runtime.Marshaler, client AuthClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq AuthRoleListRequest
+	var metadata runtime.ServerMetadata
+
+	if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
+		return nil, metadata, grpc.Errorf(codes.InvalidArgument, "%v", err)
+	}
+
+	msg, err := client.RoleList(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+	return msg, metadata, err
+
+}
+
 func request_Auth_RoleDelete_0(ctx context.Context, marshaler runtime.Marshaler, client AuthClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
 func request_Auth_RoleDelete_0(ctx context.Context, marshaler runtime.Marshaler, client AuthClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
 	var protoReq AuthRoleDeleteRequest
 	var protoReq AuthRoleDeleteRequest
 	var metadata runtime.ServerMetadata
 	var metadata runtime.ServerMetadata
@@ -1403,6 +1429,34 @@ func RegisterAuthHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.
 
 
 	})
 	})
 
 
+	mux.Handle("POST", pattern_Auth_UserList_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(ctx)
+		defer cancel()
+		if cn, ok := w.(http.CloseNotifier); ok {
+			go func(done <-chan struct{}, closed <-chan bool) {
+				select {
+				case <-done:
+				case <-closed:
+					cancel()
+				}
+			}(ctx.Done(), cn.CloseNotify())
+		}
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateContext(ctx, req)
+		if err != nil {
+			runtime.HTTPError(ctx, outboundMarshaler, w, req, err)
+		}
+		resp, md, err := request_Auth_UserList_0(rctx, inboundMarshaler, client, req, pathParams)
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_Auth_UserList_0(ctx, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
 	mux.Handle("POST", pattern_Auth_UserDelete_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
 	mux.Handle("POST", pattern_Auth_UserDelete_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
 		ctx, cancel := context.WithCancel(ctx)
 		ctx, cancel := context.WithCancel(ctx)
 		defer cancel()
 		defer cancel()
@@ -1571,6 +1625,34 @@ func RegisterAuthHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.
 
 
 	})
 	})
 
 
+	mux.Handle("POST", pattern_Auth_RoleList_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(ctx)
+		defer cancel()
+		if cn, ok := w.(http.CloseNotifier); ok {
+			go func(done <-chan struct{}, closed <-chan bool) {
+				select {
+				case <-done:
+				case <-closed:
+					cancel()
+				}
+			}(ctx.Done(), cn.CloseNotify())
+		}
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateContext(ctx, req)
+		if err != nil {
+			runtime.HTTPError(ctx, outboundMarshaler, w, req, err)
+		}
+		resp, md, err := request_Auth_RoleList_0(rctx, inboundMarshaler, client, req, pathParams)
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_Auth_RoleList_0(ctx, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
 	mux.Handle("POST", pattern_Auth_RoleDelete_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
 	mux.Handle("POST", pattern_Auth_RoleDelete_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
 		ctx, cancel := context.WithCancel(ctx)
 		ctx, cancel := context.WithCancel(ctx)
 		defer cancel()
 		defer cancel()
@@ -1669,6 +1751,8 @@ var (
 
 
 	pattern_Auth_UserGet_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v3alpha", "auth", "user", "get"}, ""))
 	pattern_Auth_UserGet_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v3alpha", "auth", "user", "get"}, ""))
 
 
+	pattern_Auth_UserList_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v3alpha", "auth", "user", "list"}, ""))
+
 	pattern_Auth_UserDelete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v3alpha", "auth", "user", "delete"}, ""))
 	pattern_Auth_UserDelete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v3alpha", "auth", "user", "delete"}, ""))
 
 
 	pattern_Auth_UserChangePassword_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v3alpha", "auth", "user", "changepw"}, ""))
 	pattern_Auth_UserChangePassword_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v3alpha", "auth", "user", "changepw"}, ""))
@@ -1681,6 +1765,8 @@ var (
 
 
 	pattern_Auth_RoleGet_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v3alpha", "auth", "role", "get"}, ""))
 	pattern_Auth_RoleGet_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v3alpha", "auth", "role", "get"}, ""))
 
 
+	pattern_Auth_RoleList_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v3alpha", "auth", "role", "list"}, ""))
+
 	pattern_Auth_RoleDelete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v3alpha", "auth", "role", "delete"}, ""))
 	pattern_Auth_RoleDelete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v3alpha", "auth", "role", "delete"}, ""))
 
 
 	pattern_Auth_RoleGrantPermission_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v3alpha", "auth", "role", "grant"}, ""))
 	pattern_Auth_RoleGrantPermission_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v3alpha", "auth", "role", "grant"}, ""))
@@ -1699,6 +1785,8 @@ var (
 
 
 	forward_Auth_UserGet_0 = runtime.ForwardResponseMessage
 	forward_Auth_UserGet_0 = runtime.ForwardResponseMessage
 
 
+	forward_Auth_UserList_0 = runtime.ForwardResponseMessage
+
 	forward_Auth_UserDelete_0 = runtime.ForwardResponseMessage
 	forward_Auth_UserDelete_0 = runtime.ForwardResponseMessage
 
 
 	forward_Auth_UserChangePassword_0 = runtime.ForwardResponseMessage
 	forward_Auth_UserChangePassword_0 = runtime.ForwardResponseMessage
@@ -1711,6 +1799,8 @@ var (
 
 
 	forward_Auth_RoleGet_0 = runtime.ForwardResponseMessage
 	forward_Auth_RoleGet_0 = runtime.ForwardResponseMessage
 
 
+	forward_Auth_RoleList_0 = runtime.ForwardResponseMessage
+
 	forward_Auth_RoleDelete_0 = runtime.ForwardResponseMessage
 	forward_Auth_RoleDelete_0 = runtime.ForwardResponseMessage
 
 
 	forward_Auth_RoleGrantPermission_0 = runtime.ForwardResponseMessage
 	forward_Auth_RoleGrantPermission_0 = runtime.ForwardResponseMessage

+ 36 - 2
etcdserver/etcdserverpb/rpc.proto

@@ -214,7 +214,7 @@ service Auth {
     };
     };
   }
   }
 
 
-  // UserGet gets detailed user information or lists all users.
+  // UserGet gets detailed user information.
   rpc UserGet(AuthUserGetRequest) returns (AuthUserGetResponse) {
   rpc UserGet(AuthUserGetRequest) returns (AuthUserGetResponse) {
       option (google.api.http) = {
       option (google.api.http) = {
         post: "/v3alpha/auth/user/get"
         post: "/v3alpha/auth/user/get"
@@ -222,6 +222,14 @@ service Auth {
     };
     };
   }
   }
 
 
+  // UserList gets a list of all users.
+  rpc UserList(AuthUserListRequest) returns (AuthUserListResponse) {
+      option (google.api.http) = {
+        post: "/v3alpha/auth/user/list"
+        body: "*"
+    };
+  }
+
   // UserDelete deletes a specified user.
   // UserDelete deletes a specified user.
   rpc UserDelete(AuthUserDeleteRequest) returns (AuthUserDeleteResponse) {
   rpc UserDelete(AuthUserDeleteRequest) returns (AuthUserDeleteResponse) {
       option (google.api.http) = {
       option (google.api.http) = {
@@ -262,7 +270,7 @@ service Auth {
     };
     };
   }
   }
 
 
-  // RoleGet gets detailed role information or lists all roles.
+  // RoleGet gets detailed role information.
   rpc RoleGet(AuthRoleGetRequest) returns (AuthRoleGetResponse) {
   rpc RoleGet(AuthRoleGetRequest) returns (AuthRoleGetResponse) {
       option (google.api.http) = {
       option (google.api.http) = {
         post: "/v3alpha/auth/role/get"
         post: "/v3alpha/auth/role/get"
@@ -270,6 +278,14 @@ service Auth {
     };
     };
   }
   }
 
 
+  // RoleList gets lists of all roles.
+  rpc RoleList(AuthRoleListRequest) returns (AuthRoleListResponse) {
+      option (google.api.http) = {
+        post: "/v3alpha/auth/role/list"
+        body: "*"
+    };
+  }
+
   // RoleDelete deletes a specified role.
   // RoleDelete deletes a specified role.
   rpc RoleDelete(AuthRoleDeleteRequest) returns (AuthRoleDeleteResponse) {
   rpc RoleDelete(AuthRoleDeleteRequest) returns (AuthRoleDeleteResponse) {
       option (google.api.http) = {
       option (google.api.http) = {
@@ -766,6 +782,12 @@ message AuthRoleGetRequest {
   string role = 1;
   string role = 1;
 }
 }
 
 
+message AuthUserListRequest {
+}
+
+message AuthRoleListRequest {
+}
+
 message AuthRoleDeleteRequest {
 message AuthRoleDeleteRequest {
   string role = 1;
   string role = 1;
 }
 }
@@ -833,6 +855,18 @@ message AuthRoleGetResponse {
   repeated authpb.Permission perm = 2;
   repeated authpb.Permission perm = 2;
 }
 }
 
 
+message AuthRoleListResponse {
+  ResponseHeader header = 1;
+
+  repeated string roles = 2;
+}
+
+message AuthUserListResponse {
+  ResponseHeader header = 1;
+
+  repeated string users = 2;
+}
+
 message AuthRoleDeleteResponse {
 message AuthRoleDeleteResponse {
   ResponseHeader header = 1;
   ResponseHeader header = 1;
 }
 }

+ 24 - 0
etcdserver/v3_server.go

@@ -72,6 +72,8 @@ type Authenticator interface {
 	RoleGet(ctx context.Context, r *pb.AuthRoleGetRequest) (*pb.AuthRoleGetResponse, error)
 	RoleGet(ctx context.Context, r *pb.AuthRoleGetRequest) (*pb.AuthRoleGetResponse, error)
 	RoleRevokePermission(ctx context.Context, r *pb.AuthRoleRevokePermissionRequest) (*pb.AuthRoleRevokePermissionResponse, error)
 	RoleRevokePermission(ctx context.Context, r *pb.AuthRoleRevokePermissionRequest) (*pb.AuthRoleRevokePermissionResponse, error)
 	RoleDelete(ctx context.Context, r *pb.AuthRoleDeleteRequest) (*pb.AuthRoleDeleteResponse, error)
 	RoleDelete(ctx context.Context, r *pb.AuthRoleDeleteRequest) (*pb.AuthRoleDeleteResponse, error)
+	UserList(ctx context.Context, r *pb.AuthUserListRequest) (*pb.AuthUserListResponse, error)
+	RoleList(ctx context.Context, r *pb.AuthRoleListRequest) (*pb.AuthRoleListResponse, error)
 }
 }
 
 
 func (s *EtcdServer) Range(ctx context.Context, r *pb.RangeRequest) (*pb.RangeResponse, error) {
 func (s *EtcdServer) Range(ctx context.Context, r *pb.RangeRequest) (*pb.RangeResponse, error) {
@@ -350,6 +352,17 @@ func (s *EtcdServer) UserGet(ctx context.Context, r *pb.AuthUserGetRequest) (*pb
 	return result.resp.(*pb.AuthUserGetResponse), nil
 	return result.resp.(*pb.AuthUserGetResponse), nil
 }
 }
 
 
+func (s *EtcdServer) UserList(ctx context.Context, r *pb.AuthUserListRequest) (*pb.AuthUserListResponse, error) {
+	result, err := s.processInternalRaftRequest(ctx, pb.InternalRaftRequest{AuthUserList: r})
+	if err != nil {
+		return nil, err
+	}
+	if result.err != nil {
+		return nil, result.err
+	}
+	return result.resp.(*pb.AuthUserListResponse), nil
+}
+
 func (s *EtcdServer) UserRevokeRole(ctx context.Context, r *pb.AuthUserRevokeRoleRequest) (*pb.AuthUserRevokeRoleResponse, error) {
 func (s *EtcdServer) UserRevokeRole(ctx context.Context, r *pb.AuthUserRevokeRoleRequest) (*pb.AuthUserRevokeRoleResponse, error) {
 	result, err := s.processInternalRaftRequest(ctx, pb.InternalRaftRequest{AuthUserRevokeRole: r})
 	result, err := s.processInternalRaftRequest(ctx, pb.InternalRaftRequest{AuthUserRevokeRole: r})
 	if err != nil {
 	if err != nil {
@@ -394,6 +407,17 @@ func (s *EtcdServer) RoleGet(ctx context.Context, r *pb.AuthRoleGetRequest) (*pb
 	return result.resp.(*pb.AuthRoleGetResponse), nil
 	return result.resp.(*pb.AuthRoleGetResponse), nil
 }
 }
 
 
+func (s *EtcdServer) RoleList(ctx context.Context, r *pb.AuthRoleListRequest) (*pb.AuthRoleListResponse, error) {
+	result, err := s.processInternalRaftRequest(ctx, pb.InternalRaftRequest{AuthRoleList: r})
+	if err != nil {
+		return nil, err
+	}
+	if result.err != nil {
+		return nil, result.err
+	}
+	return result.resp.(*pb.AuthRoleListResponse), nil
+}
+
 func (s *EtcdServer) RoleRevokePermission(ctx context.Context, r *pb.AuthRoleRevokePermissionRequest) (*pb.AuthRoleRevokePermissionResponse, error) {
 func (s *EtcdServer) RoleRevokePermission(ctx context.Context, r *pb.AuthRoleRevokePermissionRequest) (*pb.AuthRoleRevokePermissionResponse, error) {
 	result, err := s.processInternalRaftRequest(ctx, pb.InternalRaftRequest{AuthRoleRevokePermission: r})
 	result, err := s.processInternalRaftRequest(ctx, pb.InternalRaftRequest{AuthRoleRevokePermission: r})
 	if err != nil {
 	if err != nil {

Some files were not shown because too many files changed in this diff