etcdserver: do not allow creating empty role
Like user, we should not allow creating empty role. Related #10905release-3.4
parent
d137fa9d4a
commit
1cef112a79
|
@ -355,6 +355,9 @@ See [security doc](https://github.com/etcd-io/etcd/blob/master/Documentation/op-
|
||||||
- Now, WAL directory that contains only `lost+found` or a file that's not suffixed with `.wal` is considered non-initialized.
|
- Now, WAL directory that contains only `lost+found` or a file that's not suffixed with `.wal` is considered non-initialized.
|
||||||
- Fix [`ETCD_CONFIG_FILE` env variable parsing in `etcd`](https://github.com/etcd-io/etcd/pull/10762).
|
- Fix [`ETCD_CONFIG_FILE` env variable parsing in `etcd`](https://github.com/etcd-io/etcd/pull/10762).
|
||||||
- Fix [race condition in `rafthttp` transport pause/resume](https://github.com/etcd-io/etcd/pull/10826).
|
- Fix [race condition in `rafthttp` transport pause/resume](https://github.com/etcd-io/etcd/pull/10826).
|
||||||
|
- Fix [server crash from creating an empty role](https://github.com/etcd-io/etcd/pull/10907).
|
||||||
|
- Previously, creating a role with an empty name crashed etcd server with an error code `Unavailable`.
|
||||||
|
- Now, creating a role with an empty name is not allowed with an error code `InvalidArgument`.
|
||||||
|
|
||||||
### API
|
### API
|
||||||
|
|
||||||
|
|
|
@ -11,14 +11,14 @@ This is a generated documentation. Please read the proto files for more.
|
||||||
| AuthEnable | AuthEnableRequest | AuthEnableResponse | AuthEnable enables authentication. |
|
| AuthEnable | AuthEnableRequest | AuthEnableResponse | AuthEnable enables authentication. |
|
||||||
| 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. User name cannot be empty. |
|
||||||
| UserGet | AuthUserGetRequest | AuthUserGetResponse | UserGet gets detailed user information. |
|
| UserGet | AuthUserGetRequest | AuthUserGetResponse | UserGet gets detailed user information. |
|
||||||
| UserList | AuthUserListRequest | AuthUserListResponse | UserList gets a list of all users. |
|
| 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. Role name cannot be empty. |
|
||||||
| RoleGet | AuthRoleGetRequest | AuthRoleGetResponse | RoleGet gets detailed role information. |
|
| RoleGet | AuthRoleGetRequest | AuthRoleGetResponse | RoleGet gets detailed role information. |
|
||||||
| RoleList | AuthRoleListRequest | AuthRoleListResponse | RoleList gets lists of all roles. |
|
| 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. |
|
||||||
|
|
|
@ -101,7 +101,7 @@
|
||||||
"tags": [
|
"tags": [
|
||||||
"Auth"
|
"Auth"
|
||||||
],
|
],
|
||||||
"summary": "RoleAdd adds a new role.",
|
"summary": "RoleAdd adds a new role. Role name cannot be empty.",
|
||||||
"operationId": "RoleAdd",
|
"operationId": "RoleAdd",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
|
@ -263,7 +263,7 @@
|
||||||
"tags": [
|
"tags": [
|
||||||
"Auth"
|
"Auth"
|
||||||
],
|
],
|
||||||
"summary": "UserAdd adds a new user.",
|
"summary": "UserAdd adds a new user. User name cannot be empty.",
|
||||||
"operationId": "UserAdd",
|
"operationId": "UserAdd",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
|
|
|
@ -57,6 +57,7 @@ var (
|
||||||
ErrUserNotFound = errors.New("auth: user not found")
|
ErrUserNotFound = errors.New("auth: user not found")
|
||||||
ErrRoleAlreadyExist = errors.New("auth: role already exists")
|
ErrRoleAlreadyExist = errors.New("auth: role already exists")
|
||||||
ErrRoleNotFound = errors.New("auth: role not found")
|
ErrRoleNotFound = errors.New("auth: role not found")
|
||||||
|
ErrRoleEmpty = errors.New("auth: role name is empty")
|
||||||
ErrAuthFailed = errors.New("auth: authentication failed, invalid user ID or password")
|
ErrAuthFailed = errors.New("auth: authentication failed, invalid user ID or password")
|
||||||
ErrPermissionDenied = errors.New("auth: permission denied")
|
ErrPermissionDenied = errors.New("auth: permission denied")
|
||||||
ErrRoleNotGranted = errors.New("auth: role is not granted to the user")
|
ErrRoleNotGranted = errors.New("auth: role is not granted to the user")
|
||||||
|
@ -796,6 +797,10 @@ func (as *authStore) RoleDelete(r *pb.AuthRoleDeleteRequest) (*pb.AuthRoleDelete
|
||||||
}
|
}
|
||||||
|
|
||||||
func (as *authStore) RoleAdd(r *pb.AuthRoleAddRequest) (*pb.AuthRoleAddResponse, error) {
|
func (as *authStore) RoleAdd(r *pb.AuthRoleAddRequest) (*pb.AuthRoleAddResponse, error) {
|
||||||
|
if len(r.Name) == 0 {
|
||||||
|
return nil, ErrRoleEmpty
|
||||||
|
}
|
||||||
|
|
||||||
tx := as.be.BatchTx()
|
tx := as.be.BatchTx()
|
||||||
tx.Lock()
|
tx.Lock()
|
||||||
defer tx.Unlock()
|
defer tx.Unlock()
|
||||||
|
|
|
@ -269,6 +269,12 @@ func TestRoleAdd(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add a role with empty name
|
||||||
|
_, err = as.RoleAdd(&pb.AuthRoleAddRequest{Name: ""})
|
||||||
|
if err != ErrRoleEmpty {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUserGrant(t *testing.T) {
|
func TestUserGrant(t *testing.T) {
|
||||||
|
|
|
@ -40,4 +40,9 @@ func TestRoleError(t *testing.T) {
|
||||||
if err != rpctypes.ErrRoleAlreadyExist {
|
if err != rpctypes.ErrRoleAlreadyExist {
|
||||||
t.Fatalf("expected %v, got %v", rpctypes.ErrRoleAlreadyExist, err)
|
t.Fatalf("expected %v, got %v", rpctypes.ErrRoleAlreadyExist, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, err = authapi.RoleAdd(context.TODO(), "")
|
||||||
|
if err != rpctypes.ErrRoleEmpty {
|
||||||
|
t.Fatalf("expected %v, got %v", rpctypes.ErrRoleEmpty, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@ var (
|
||||||
ErrGRPCUserNotFound = status.New(codes.FailedPrecondition, "etcdserver: user name not found").Err()
|
ErrGRPCUserNotFound = status.New(codes.FailedPrecondition, "etcdserver: user name not found").Err()
|
||||||
ErrGRPCRoleAlreadyExist = status.New(codes.FailedPrecondition, "etcdserver: role name already exists").Err()
|
ErrGRPCRoleAlreadyExist = status.New(codes.FailedPrecondition, "etcdserver: role name already exists").Err()
|
||||||
ErrGRPCRoleNotFound = status.New(codes.FailedPrecondition, "etcdserver: role name not found").Err()
|
ErrGRPCRoleNotFound = status.New(codes.FailedPrecondition, "etcdserver: role name not found").Err()
|
||||||
|
ErrGRPCRoleEmpty = status.New(codes.InvalidArgument, "etcdserver: role name is empty").Err()
|
||||||
ErrGRPCAuthFailed = status.New(codes.InvalidArgument, "etcdserver: authentication failed, invalid user ID or password").Err()
|
ErrGRPCAuthFailed = status.New(codes.InvalidArgument, "etcdserver: authentication failed, invalid user ID or password").Err()
|
||||||
ErrGRPCPermissionDenied = status.New(codes.PermissionDenied, "etcdserver: permission denied").Err()
|
ErrGRPCPermissionDenied = status.New(codes.PermissionDenied, "etcdserver: permission denied").Err()
|
||||||
ErrGRPCRoleNotGranted = status.New(codes.FailedPrecondition, "etcdserver: role is not granted to the user").Err()
|
ErrGRPCRoleNotGranted = status.New(codes.FailedPrecondition, "etcdserver: role is not granted to the user").Err()
|
||||||
|
@ -110,6 +111,7 @@ var (
|
||||||
ErrorDesc(ErrGRPCUserNotFound): ErrGRPCUserNotFound,
|
ErrorDesc(ErrGRPCUserNotFound): ErrGRPCUserNotFound,
|
||||||
ErrorDesc(ErrGRPCRoleAlreadyExist): ErrGRPCRoleAlreadyExist,
|
ErrorDesc(ErrGRPCRoleAlreadyExist): ErrGRPCRoleAlreadyExist,
|
||||||
ErrorDesc(ErrGRPCRoleNotFound): ErrGRPCRoleNotFound,
|
ErrorDesc(ErrGRPCRoleNotFound): ErrGRPCRoleNotFound,
|
||||||
|
ErrorDesc(ErrGRPCRoleEmpty): ErrGRPCRoleEmpty,
|
||||||
ErrorDesc(ErrGRPCAuthFailed): ErrGRPCAuthFailed,
|
ErrorDesc(ErrGRPCAuthFailed): ErrGRPCAuthFailed,
|
||||||
ErrorDesc(ErrGRPCPermissionDenied): ErrGRPCPermissionDenied,
|
ErrorDesc(ErrGRPCPermissionDenied): ErrGRPCPermissionDenied,
|
||||||
ErrorDesc(ErrGRPCRoleNotGranted): ErrGRPCRoleNotGranted,
|
ErrorDesc(ErrGRPCRoleNotGranted): ErrGRPCRoleNotGranted,
|
||||||
|
@ -168,6 +170,7 @@ var (
|
||||||
ErrUserNotFound = Error(ErrGRPCUserNotFound)
|
ErrUserNotFound = Error(ErrGRPCUserNotFound)
|
||||||
ErrRoleAlreadyExist = Error(ErrGRPCRoleAlreadyExist)
|
ErrRoleAlreadyExist = Error(ErrGRPCRoleAlreadyExist)
|
||||||
ErrRoleNotFound = Error(ErrGRPCRoleNotFound)
|
ErrRoleNotFound = Error(ErrGRPCRoleNotFound)
|
||||||
|
ErrRoleEmpty = Error(ErrGRPCRoleEmpty)
|
||||||
ErrAuthFailed = Error(ErrGRPCAuthFailed)
|
ErrAuthFailed = Error(ErrGRPCAuthFailed)
|
||||||
ErrPermissionDenied = Error(ErrGRPCPermissionDenied)
|
ErrPermissionDenied = Error(ErrGRPCPermissionDenied)
|
||||||
ErrRoleNotGranted = Error(ErrGRPCRoleNotGranted)
|
ErrRoleNotGranted = Error(ErrGRPCRoleNotGranted)
|
||||||
|
|
|
@ -69,6 +69,7 @@ var toGRPCErrorMap = map[error]error{
|
||||||
auth.ErrUserNotFound: rpctypes.ErrGRPCUserNotFound,
|
auth.ErrUserNotFound: rpctypes.ErrGRPCUserNotFound,
|
||||||
auth.ErrRoleAlreadyExist: rpctypes.ErrGRPCRoleAlreadyExist,
|
auth.ErrRoleAlreadyExist: rpctypes.ErrGRPCRoleAlreadyExist,
|
||||||
auth.ErrRoleNotFound: rpctypes.ErrGRPCRoleNotFound,
|
auth.ErrRoleNotFound: rpctypes.ErrGRPCRoleNotFound,
|
||||||
|
auth.ErrRoleEmpty: rpctypes.ErrGRPCRoleEmpty,
|
||||||
auth.ErrAuthFailed: rpctypes.ErrGRPCAuthFailed,
|
auth.ErrAuthFailed: rpctypes.ErrGRPCAuthFailed,
|
||||||
auth.ErrPermissionDenied: rpctypes.ErrGRPCPermissionDenied,
|
auth.ErrPermissionDenied: rpctypes.ErrGRPCPermissionDenied,
|
||||||
auth.ErrRoleNotGranted: rpctypes.ErrGRPCRoleNotGranted,
|
auth.ErrRoleNotGranted: rpctypes.ErrGRPCRoleNotGranted,
|
||||||
|
|
|
@ -4537,7 +4537,7 @@ type AuthClient interface {
|
||||||
AuthDisable(ctx context.Context, in *AuthDisableRequest, opts ...grpc.CallOption) (*AuthDisableResponse, error)
|
AuthDisable(ctx context.Context, in *AuthDisableRequest, opts ...grpc.CallOption) (*AuthDisableResponse, error)
|
||||||
// Authenticate processes an authenticate request.
|
// Authenticate processes an authenticate request.
|
||||||
Authenticate(ctx context.Context, in *AuthenticateRequest, opts ...grpc.CallOption) (*AuthenticateResponse, error)
|
Authenticate(ctx context.Context, in *AuthenticateRequest, opts ...grpc.CallOption) (*AuthenticateResponse, error)
|
||||||
// UserAdd adds a new user.
|
// UserAdd adds a new user. User name cannot be empty.
|
||||||
UserAdd(ctx context.Context, in *AuthUserAddRequest, opts ...grpc.CallOption) (*AuthUserAddResponse, error)
|
UserAdd(ctx context.Context, in *AuthUserAddRequest, opts ...grpc.CallOption) (*AuthUserAddResponse, error)
|
||||||
// UserGet gets detailed user information.
|
// UserGet gets detailed user information.
|
||||||
UserGet(ctx context.Context, in *AuthUserGetRequest, opts ...grpc.CallOption) (*AuthUserGetResponse, error)
|
UserGet(ctx context.Context, in *AuthUserGetRequest, opts ...grpc.CallOption) (*AuthUserGetResponse, error)
|
||||||
|
@ -4551,7 +4551,7 @@ type AuthClient interface {
|
||||||
UserGrantRole(ctx context.Context, in *AuthUserGrantRoleRequest, opts ...grpc.CallOption) (*AuthUserGrantRoleResponse, error)
|
UserGrantRole(ctx context.Context, in *AuthUserGrantRoleRequest, opts ...grpc.CallOption) (*AuthUserGrantRoleResponse, error)
|
||||||
// UserRevokeRole revokes a role of specified user.
|
// UserRevokeRole revokes a role of specified user.
|
||||||
UserRevokeRole(ctx context.Context, in *AuthUserRevokeRoleRequest, opts ...grpc.CallOption) (*AuthUserRevokeRoleResponse, error)
|
UserRevokeRole(ctx context.Context, in *AuthUserRevokeRoleRequest, opts ...grpc.CallOption) (*AuthUserRevokeRoleResponse, error)
|
||||||
// RoleAdd adds a new role.
|
// RoleAdd adds a new role. Role name cannot be empty.
|
||||||
RoleAdd(ctx context.Context, in *AuthRoleAddRequest, opts ...grpc.CallOption) (*AuthRoleAddResponse, error)
|
RoleAdd(ctx context.Context, in *AuthRoleAddRequest, opts ...grpc.CallOption) (*AuthRoleAddResponse, error)
|
||||||
// RoleGet gets detailed role information.
|
// RoleGet gets detailed role information.
|
||||||
RoleGet(ctx context.Context, in *AuthRoleGetRequest, opts ...grpc.CallOption) (*AuthRoleGetResponse, error)
|
RoleGet(ctx context.Context, in *AuthRoleGetRequest, opts ...grpc.CallOption) (*AuthRoleGetResponse, error)
|
||||||
|
@ -4726,7 +4726,7 @@ type AuthServer interface {
|
||||||
AuthDisable(context.Context, *AuthDisableRequest) (*AuthDisableResponse, error)
|
AuthDisable(context.Context, *AuthDisableRequest) (*AuthDisableResponse, error)
|
||||||
// Authenticate processes an authenticate request.
|
// Authenticate processes an authenticate request.
|
||||||
Authenticate(context.Context, *AuthenticateRequest) (*AuthenticateResponse, error)
|
Authenticate(context.Context, *AuthenticateRequest) (*AuthenticateResponse, error)
|
||||||
// UserAdd adds a new user.
|
// UserAdd adds a new user. User name cannot be empty.
|
||||||
UserAdd(context.Context, *AuthUserAddRequest) (*AuthUserAddResponse, error)
|
UserAdd(context.Context, *AuthUserAddRequest) (*AuthUserAddResponse, error)
|
||||||
// UserGet gets detailed user information.
|
// UserGet gets detailed user information.
|
||||||
UserGet(context.Context, *AuthUserGetRequest) (*AuthUserGetResponse, error)
|
UserGet(context.Context, *AuthUserGetRequest) (*AuthUserGetResponse, error)
|
||||||
|
@ -4740,7 +4740,7 @@ type AuthServer interface {
|
||||||
UserGrantRole(context.Context, *AuthUserGrantRoleRequest) (*AuthUserGrantRoleResponse, error)
|
UserGrantRole(context.Context, *AuthUserGrantRoleRequest) (*AuthUserGrantRoleResponse, error)
|
||||||
// UserRevokeRole revokes a role of specified user.
|
// UserRevokeRole revokes a role of specified user.
|
||||||
UserRevokeRole(context.Context, *AuthUserRevokeRoleRequest) (*AuthUserRevokeRoleResponse, error)
|
UserRevokeRole(context.Context, *AuthUserRevokeRoleRequest) (*AuthUserRevokeRoleResponse, error)
|
||||||
// RoleAdd adds a new role.
|
// RoleAdd adds a new role. Role name cannot be empty.
|
||||||
RoleAdd(context.Context, *AuthRoleAddRequest) (*AuthRoleAddResponse, error)
|
RoleAdd(context.Context, *AuthRoleAddRequest) (*AuthRoleAddResponse, error)
|
||||||
// RoleGet gets detailed role information.
|
// RoleGet gets detailed role information.
|
||||||
RoleGet(context.Context, *AuthRoleGetRequest) (*AuthRoleGetResponse, error)
|
RoleGet(context.Context, *AuthRoleGetRequest) (*AuthRoleGetResponse, error)
|
||||||
|
|
|
@ -264,7 +264,7 @@ service Auth {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserAdd adds a new user.
|
// UserAdd adds a new user. User name cannot be empty.
|
||||||
rpc UserAdd(AuthUserAddRequest) returns (AuthUserAddResponse) {
|
rpc UserAdd(AuthUserAddRequest) returns (AuthUserAddResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
post: "/v3/auth/user/add"
|
post: "/v3/auth/user/add"
|
||||||
|
@ -320,7 +320,7 @@ service Auth {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// RoleAdd adds a new role.
|
// RoleAdd adds a new role. Role name cannot be empty.
|
||||||
rpc RoleAdd(AuthRoleAddRequest) returns (AuthRoleAddResponse) {
|
rpc RoleAdd(AuthRoleAddRequest) returns (AuthRoleAddResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
post: "/v3/auth/role/add"
|
post: "/v3/auth/role/add"
|
||||||
|
|
Loading…
Reference in New Issue