Skip to content

Commit

Permalink
etcdserver: do not allow creating empty role
Browse files Browse the repository at this point in the history
Like user, we should not allow creating empty role.

Related #10905
  • Loading branch information
spzala committed Jul 23, 2019
1 parent 53891cb commit b7a6554
Show file tree
Hide file tree
Showing 10 changed files with 33 additions and 10 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG-3.4.md
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,9 @@ See [security doc](https://github.com/etcd-io/etcd/blob/master/Documentation/op-
- Allow [non-WAL files in `etcd --wal-dir` directory](https://github.com/etcd-io/etcd/pull/9743).
- Previously, existing files such as [`lost+found`](https://github.com/etcd-io/etcd/issues/7287) in WAL directory prevent etcd server boot.
- Now, WAL directory that contains only `lost+found` or a file that's not suffixed with `.wal` is considered non-initialized.
- 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

Expand Down
4 changes: 2 additions & 2 deletions Documentation/dev-guide/api_reference_v3.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ This is a generated documentation. Please read the proto files for more.
| AuthEnable | AuthEnableRequest | AuthEnableResponse | AuthEnable enables authentication. |
| AuthDisable | AuthDisableRequest | AuthDisableResponse | AuthDisable disables authentication. |
| 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. |
| UserList | AuthUserListRequest | AuthUserListResponse | UserList gets a list of all users. |
| UserDelete | AuthUserDeleteRequest | AuthUserDeleteResponse | UserDelete deletes 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. |
| 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. |
| RoleList | AuthRoleListRequest | AuthRoleListResponse | RoleList gets lists of all roles. |
| RoleDelete | AuthRoleDeleteRequest | AuthRoleDeleteResponse | RoleDelete deletes a specified role. |
Expand Down
4 changes: 2 additions & 2 deletions Documentation/dev-guide/apispec/swagger/rpc.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
"tags": [
"Auth"
],
"summary": "RoleAdd adds a new role.",
"summary": "RoleAdd adds a new role. Role name cannot be empty.",
"operationId": "RoleAdd",
"parameters": [
{
Expand Down Expand Up @@ -263,7 +263,7 @@
"tags": [
"Auth"
],
"summary": "UserAdd adds a new user.",
"summary": "UserAdd adds a new user. User name cannot be empty.",
"operationId": "UserAdd",
"parameters": [
{
Expand Down
5 changes: 5 additions & 0 deletions auth/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ var (
ErrUserNotFound = errors.New("auth: user not found")
ErrRoleAlreadyExist = errors.New("auth: role already exists")
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")
ErrPermissionDenied = errors.New("auth: permission denied")
ErrRoleNotGranted = errors.New("auth: role is not granted to the user")
Expand Down Expand Up @@ -796,6 +797,10 @@ func (as *authStore) RoleDelete(r *pb.AuthRoleDeleteRequest) (*pb.AuthRoleDelete
}

func (as *authStore) RoleAdd(r *pb.AuthRoleAddRequest) (*pb.AuthRoleAddResponse, error) {
if len(r.Name) == 0 {
return nil, ErrRoleEmpty
}

tx := as.be.BatchTx()
tx.Lock()
defer tx.Unlock()
Expand Down
6 changes: 6 additions & 0 deletions auth/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,12 @@ func TestRoleAdd(t *testing.T) {
if err != nil {
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) {
Expand Down
5 changes: 5 additions & 0 deletions clientv3/integration/role_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,9 @@ func TestRoleError(t *testing.T) {
if err != rpctypes.ErrRoleAlreadyExist {
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)
}
}
3 changes: 3 additions & 0 deletions etcdserver/api/v3rpc/rpctypes/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ var (
ErrGRPCUserNotFound = status.New(codes.FailedPrecondition, "etcdserver: user name not found").Err()
ErrGRPCRoleAlreadyExist = status.New(codes.FailedPrecondition, "etcdserver: role name already exists").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()
ErrGRPCPermissionDenied = status.New(codes.PermissionDenied, "etcdserver: permission denied").Err()
ErrGRPCRoleNotGranted = status.New(codes.FailedPrecondition, "etcdserver: role is not granted to the user").Err()
Expand Down Expand Up @@ -110,6 +111,7 @@ var (
ErrorDesc(ErrGRPCUserNotFound): ErrGRPCUserNotFound,
ErrorDesc(ErrGRPCRoleAlreadyExist): ErrGRPCRoleAlreadyExist,
ErrorDesc(ErrGRPCRoleNotFound): ErrGRPCRoleNotFound,
ErrorDesc(ErrGRPCRoleEmpty): ErrGRPCRoleEmpty,
ErrorDesc(ErrGRPCAuthFailed): ErrGRPCAuthFailed,
ErrorDesc(ErrGRPCPermissionDenied): ErrGRPCPermissionDenied,
ErrorDesc(ErrGRPCRoleNotGranted): ErrGRPCRoleNotGranted,
Expand Down Expand Up @@ -168,6 +170,7 @@ var (
ErrUserNotFound = Error(ErrGRPCUserNotFound)
ErrRoleAlreadyExist = Error(ErrGRPCRoleAlreadyExist)
ErrRoleNotFound = Error(ErrGRPCRoleNotFound)
ErrRoleEmpty = Error(ErrGRPCRoleEmpty)
ErrAuthFailed = Error(ErrGRPCAuthFailed)
ErrPermissionDenied = Error(ErrGRPCPermissionDenied)
ErrRoleNotGranted = Error(ErrGRPCRoleNotGranted)
Expand Down
1 change: 1 addition & 0 deletions etcdserver/api/v3rpc/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ var toGRPCErrorMap = map[error]error{
auth.ErrUserNotFound: rpctypes.ErrGRPCUserNotFound,
auth.ErrRoleAlreadyExist: rpctypes.ErrGRPCRoleAlreadyExist,
auth.ErrRoleNotFound: rpctypes.ErrGRPCRoleNotFound,
auth.ErrRoleEmpty: rpctypes.ErrGRPCRoleEmpty,
auth.ErrAuthFailed: rpctypes.ErrGRPCAuthFailed,
auth.ErrPermissionDenied: rpctypes.ErrGRPCPermissionDenied,
auth.ErrRoleNotGranted: rpctypes.ErrGRPCRoleNotGranted,
Expand Down
8 changes: 4 additions & 4 deletions etcdserver/etcdserverpb/rpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions etcdserver/etcdserverpb/rpc.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
option (google.api.http) = {
post: "/v3/auth/user/add"
Expand Down Expand Up @@ -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) {
option (google.api.http) = {
post: "/v3/auth/role/add"
Expand Down

0 comments on commit b7a6554

Please sign in to comment.