This is an automated email from the ASF dual-hosted git repository.
mchades pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/main by this push:
new 149b06250c [#11259] docs(open-api): Add OpenAPI spec for built-in IdP
REST APIs (#11260)
149b06250c is described below
commit 149b06250ca6d43d983ab504addfd5b88f739717
Author: MaSai <[email protected]>
AuthorDate: Wed May 27 23:19:16 2026 +0800
[#11259] docs(open-api): Add OpenAPI spec for built-in IdP REST APIs
(#11260)
### What changes were proposed in this pull request?
Add OpenAPI documentation for built-in IDP REST APIs exposed by the
`idp-basic` plugin (when the `basic` authenticator is enabled):
- **`docs/open-api/idp/openapi.yaml`** — standalone entry spec (info,
servers, security, path refs)
- **`docs/open-api/idp/idp.yaml`** — IdP paths, request/response
schemas, and examples
- **`docs/build.gradle.kts`** — add `lintIdpOpenAPI` and run it in
`docs:build` alongside the existing main spec lint
Documented endpoints:
| Method | Path | Description |
|--------|------|-------------|
| POST | `/idp/users` | Add IDP user |
| GET | `/idp/users/{user}` | Get IDP user |
| PUT | `/idp/users/{user}` | Change password |
| DELETE | `/idp/users/{user}` | Remove IDP user |
| POST | `/idp/groups` | Add IDP group |
| GET | `/idp/groups/{group}` | Get IDP group |
| DELETE | `/idp/groups/{group}` | Remove IDP group (`force` query) |
| PUT | `/idp/groups/{group}/users` | Change group membership
(`usersToAdd` / `usersToRemove`) |
Shared components (`ErrorModel`, common error responses, path
parameters, `BasicAuth`) are referenced from
`docs/open-api/openapi.yaml` where applicable. IdP-specific payloads
live under `components/schemas` in `idp.yaml`.
**Note:** IdP paths are **not** registered in the main
`docs/open-api/openapi.yaml`; they are validated via the dedicated
`idp/openapi.yaml` entry (see `lintIdpOpenAPI`).
### Why are the changes needed?
IdP REST endpoints are implemented but were missing from published
OpenAPI documentation, making discovery and review harder for clients
and contributors.
Fix: #11259
### Does this PR introduce _any_ user-facing change?
No runtime behavior change. Documentation-only: adds OpenAPI
descriptions for existing IdP REST APIs.
### How was this patch tested?
```bash
./gradlew :docs:build
```
This runs Redocly lint (`recommended-strict`) for both:
- `docs/open-api/openapi.yaml`
- `docs/open-api/idp/openapi.yaml`
---------
Co-authored-by: Cursor <[email protected]>
---
docs/build.gradle.kts | 12 +
docs/open-api/idp/idp.yaml | 505 +++++++++++++++++++++++++++++++++++++++++
docs/open-api/idp/openapi.yaml | 69 ++++++
3 files changed, 586 insertions(+)
diff --git a/docs/build.gradle.kts b/docs/build.gradle.kts
index 60b0be907a..39810c3dda 100644
--- a/docs/build.gradle.kts
+++ b/docs/build.gradle.kts
@@ -32,7 +32,19 @@ tasks {
args.set(listOf("lint", "--extends=recommended-strict",
"${project.projectDir}/open-api/openapi.yaml"))
}
+ val lintIdpOpenAPI by registering(NpxTask::class) {
+ command.set("@redocly/[email protected]")
+ args.set(
+ listOf(
+ "lint",
+ "--extends=recommended-strict",
+ "${project.projectDir}/open-api/idp/openapi.yaml"
+ )
+ )
+ }
+
build {
dependsOn(lintOpenAPI)
+ dependsOn(lintIdpOpenAPI)
}
}
diff --git a/docs/open-api/idp/idp.yaml b/docs/open-api/idp/idp.yaml
new file mode 100644
index 0000000000..bc5e211ea9
--- /dev/null
+++ b/docs/open-api/idp/idp.yaml
@@ -0,0 +1,505 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+---
+
+paths:
+
+ /idp/users:
+ post:
+ tags:
+ - IDP
+ summary: Add built-in IDP user
+ description: >
+ Creates a built-in IDP user with the given username and password.
+ Requires the `basic` authenticator and the `idp-basic` plugin to be
enabled.
+ operationId: addIdpUser
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/AddUserRequest"
+ examples:
+ AddUserRequest:
+ $ref: "#/components/examples/AddUserRequest"
+ responses:
+ "200":
+ description: Returns the added built-in IDP user
+ content:
+ application/vnd.gravitino.v1+json:
+ schema:
+ $ref: "#/components/schemas/IdpUserResponse"
+ examples:
+ IdpUserResponse:
+ $ref: "#/components/examples/IdpUserResponse"
+ "400":
+ $ref: "../openapi.yaml#/components/responses/BadRequestErrorResponse"
+ "403":
+ $ref: "#/components/responses/IdpForbiddenErrorResponse"
+ "409":
+ description: Conflict - The built-in IDP user already exists
+ content:
+ application/vnd.gravitino.v1+json:
+ schema:
+ $ref: "../openapi.yaml#/components/schemas/ErrorModel"
+ examples:
+ AlreadyExistsException:
+ $ref: "#/components/examples/IdpAlreadyExistsException"
+ "5xx":
+ $ref: "../openapi.yaml#/components/responses/ServerErrorResponse"
+
+ /idp/users/{user}:
+ parameters:
+ - $ref: "../openapi.yaml#/components/parameters/user"
+
+ get:
+ tags:
+ - IDP
+ summary: Get built-in IDP user
+ description: Returns the specified built-in IDP user, including group
membership.
+ operationId: getIdpUser
+ responses:
+ "200":
+ description: Returns the built-in IDP user object
+ content:
+ application/vnd.gravitino.v1+json:
+ schema:
+ $ref: "#/components/schemas/IdpUserResponse"
+ examples:
+ IdpUserResponse:
+ $ref: "#/components/examples/IdpUserResponse"
+ "403":
+ $ref: "#/components/responses/IdpForbiddenErrorResponse"
+ "404":
+ description: Not Found - The specified built-in IDP user does not
exist
+ content:
+ application/vnd.gravitino.v1+json:
+ schema:
+ $ref: "../openapi.yaml#/components/schemas/ErrorModel"
+ examples:
+ NotFoundException:
+ $ref: "#/components/examples/IdpNotFoundException"
+ "5xx":
+ $ref: "../openapi.yaml#/components/responses/ServerErrorResponse"
+
+ put:
+ tags:
+ - IDP
+ summary: Change built-in IDP user password
+ description: Updates the password of the specified built-in IDP user.
+ operationId: changeIdpUserPassword
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ChangePasswordRequest"
+ examples:
+ ChangePasswordRequest:
+ $ref: "#/components/examples/ChangePasswordRequest"
+ responses:
+ "200":
+ description: Returns the built-in IDP user after the password change
+ content:
+ application/vnd.gravitino.v1+json:
+ schema:
+ $ref: "#/components/schemas/IdpUserResponse"
+ examples:
+ IdpUserResponse:
+ $ref: "#/components/examples/IdpUserResponse"
+ "400":
+ $ref: "../openapi.yaml#/components/responses/BadRequestErrorResponse"
+ "403":
+ $ref: "#/components/responses/IdpForbiddenErrorResponse"
+ "404":
+ description: Not Found - The specified built-in IDP user does not
exist
+ content:
+ application/vnd.gravitino.v1+json:
+ schema:
+ $ref: "../openapi.yaml#/components/schemas/ErrorModel"
+ examples:
+ NotFoundException:
+ $ref: "#/components/examples/IdpNotFoundException"
+ "5xx":
+ $ref: "../openapi.yaml#/components/responses/ServerErrorResponse"
+
+ delete:
+ tags:
+ - IDP
+ summary: Remove built-in IDP user
+ operationId: removeIdpUser
+ responses:
+ "200":
+ $ref: "../openapi.yaml#/components/responses/RemoveResponse"
+ "400":
+ $ref: "../openapi.yaml#/components/responses/BadRequestErrorResponse"
+ "403":
+ $ref: "#/components/responses/IdpForbiddenErrorResponse"
+ "404":
+ description: Not Found - The specified built-in IDP user does not
exist
+ content:
+ application/vnd.gravitino.v1+json:
+ schema:
+ $ref: "../openapi.yaml#/components/schemas/ErrorModel"
+ examples:
+ NotFoundException:
+ $ref: "#/components/examples/IdpNotFoundException"
+ "5xx":
+ $ref: "../openapi.yaml#/components/responses/ServerErrorResponse"
+
+ /idp/groups:
+ post:
+ tags:
+ - IDP
+ summary: Add built-in IDP group
+ description: Creates a built-in IDP group with the given name.
+ operationId: addIdpGroup
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/AddGroupRequest"
+ examples:
+ AddGroupRequest:
+ $ref: "#/components/examples/AddGroupRequest"
+ responses:
+ "200":
+ description: Returns the added built-in IDP group
+ content:
+ application/vnd.gravitino.v1+json:
+ schema:
+ $ref: "#/components/schemas/IdpGroupResponse"
+ examples:
+ IdpGroupResponse:
+ $ref: "#/components/examples/IdpGroupResponse"
+ "400":
+ $ref: "../openapi.yaml#/components/responses/BadRequestErrorResponse"
+ "403":
+ $ref: "#/components/responses/IdpForbiddenErrorResponse"
+ "409":
+ description: Conflict - The built-in IDP group already exists
+ content:
+ application/vnd.gravitino.v1+json:
+ schema:
+ $ref: "../openapi.yaml#/components/schemas/ErrorModel"
+ examples:
+ AlreadyExistsException:
+ $ref: "#/components/examples/IdpAlreadyExistsException"
+ "5xx":
+ $ref: "../openapi.yaml#/components/responses/ServerErrorResponse"
+
+ /idp/groups/{group}:
+ parameters:
+ - $ref: "../openapi.yaml#/components/parameters/group"
+
+ get:
+ tags:
+ - IDP
+ summary: Get built-in IDP group
+ description: Returns the specified built-in IDP group, including member
usernames.
+ operationId: getIdpGroup
+ responses:
+ "200":
+ description: Returns the built-in IDP group object
+ content:
+ application/vnd.gravitino.v1+json:
+ schema:
+ $ref: "#/components/schemas/IdpGroupResponse"
+ examples:
+ IdpGroupResponse:
+ $ref: "#/components/examples/IdpGroupResponse"
+ "403":
+ $ref: "#/components/responses/IdpForbiddenErrorResponse"
+ "404":
+ description: Not Found - The specified built-in IDP group does not
exist
+ content:
+ application/vnd.gravitino.v1+json:
+ schema:
+ $ref: "../openapi.yaml#/components/schemas/ErrorModel"
+ examples:
+ NotFoundException:
+ $ref: "#/components/examples/IdpNotFoundException"
+ "5xx":
+ $ref: "../openapi.yaml#/components/responses/ServerErrorResponse"
+
+ delete:
+ tags:
+ - IDP
+ summary: Remove built-in IDP group
+ operationId: removeIdpGroup
+ parameters:
+ - $ref: "../openapi.yaml#/components/parameters/force"
+ responses:
+ "200":
+ $ref: "../openapi.yaml#/components/responses/RemoveResponse"
+ "400":
+ $ref: "../openapi.yaml#/components/responses/BadRequestErrorResponse"
+ "403":
+ $ref: "#/components/responses/IdpForbiddenErrorResponse"
+ "404":
+ description: Not Found - The specified built-in IDP group does not
exist
+ content:
+ application/vnd.gravitino.v1+json:
+ schema:
+ $ref: "../openapi.yaml#/components/schemas/ErrorModel"
+ examples:
+ NotFoundException:
+ $ref: "#/components/examples/IdpNotFoundException"
+ "405":
+ description: Method Not Allowed - The group is not empty and force
is false
+ content:
+ application/vnd.gravitino.v1+json:
+ schema:
+ $ref: "../openapi.yaml#/components/schemas/ErrorModel"
+ examples:
+ GroupNotEmptyException:
+ $ref: "#/components/examples/IdpGroupNotEmptyException"
+ "5xx":
+ $ref: "../openapi.yaml#/components/responses/ServerErrorResponse"
+
+ /idp/groups/{group}/users:
+ parameters:
+ - $ref: "../openapi.yaml#/components/parameters/group"
+
+ put:
+ tags:
+ - IDP
+ summary: Change built-in IDP group membership
+ description: >
+ Adds and/or removes users from the specified built-in IDP group in a
single request,
+ similar to tag association. At least one of `usersToAdd` or
`usersToRemove` must be set.
+ operationId: changeIdpGroupMembership
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/GroupMembershipChangeRequest"
+ examples:
+ GroupMembershipChangeRequest:
+ $ref: "#/components/examples/GroupMembershipChangeRequest"
+ responses:
+ "200":
+ description: Returns the built-in IDP group after membership changes
+ content:
+ application/vnd.gravitino.v1+json:
+ schema:
+ $ref: "#/components/schemas/IdpGroupResponse"
+ examples:
+ IdpGroupResponse:
+ $ref: "#/components/examples/IdpGroupResponse"
+ "400":
+ $ref: "../openapi.yaml#/components/responses/BadRequestErrorResponse"
+ "403":
+ $ref: "#/components/responses/IdpForbiddenErrorResponse"
+ "404":
+ description: Not Found - The specified built-in IDP group or user
does not exist
+ content:
+ application/vnd.gravitino.v1+json:
+ schema:
+ $ref: "../openapi.yaml#/components/schemas/ErrorModel"
+ examples:
+ NotFoundException:
+ $ref: "#/components/examples/IdpNotFoundException"
+ "5xx":
+ $ref: "../openapi.yaml#/components/responses/ServerErrorResponse"
+
+components:
+ schemas:
+ IdpUser:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ description: The username of the built-in IDP user
+ groups:
+ type: array
+ items:
+ type: string
+ description: The built-in IDP groups the user belongs to
+
+ IdpGroup:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ description: The name of the built-in IDP group
+ users:
+ type: array
+ items:
+ type: string
+ description: The usernames of members in the built-in IDP group
+
+ AddUserRequest:
+ type: object
+ required:
+ - user
+ - password
+ properties:
+ user:
+ type: string
+ description: >
+ The username to add. Request payloads use `user`, while user
objects in
+ responses use `name` (see IdpUser), matching the server JSON field
names.
+ password:
+ type: string
+ format: password
+ description: The password of the built-in IDP user to add
+ writeOnly: true
+
+ ChangePasswordRequest:
+ type: object
+ required:
+ - password
+ properties:
+ password:
+ type: string
+ format: password
+ description: The new password of the built-in IDP user
+ writeOnly: true
+
+ AddGroupRequest:
+ type: object
+ required:
+ - group
+ properties:
+ group:
+ type: string
+ description: >
+ The group name to add. Request payloads use `group`, while group
objects in
+ responses use `name` (see IdpGroup), matching the server JSON
field names.
+
+ GroupMembershipChangeRequest:
+ type: object
+ anyOf:
+ - required:
+ - usersToAdd
+ - required:
+ - usersToRemove
+ properties:
+ usersToAdd:
+ type: array
+ items:
+ type: string
+ minItems: 1
+ description: The usernames to add to the built-in IDP group
+ usersToRemove:
+ type: array
+ items:
+ type: string
+ minItems: 1
+ description: The usernames to remove from the built-in IDP group
+
+ IdpUserResponse:
+ type: object
+ properties:
+ code:
+ type: integer
+ format: int32
+ description: Status code of the response
+ enum:
+ - 0
+ user:
+ $ref: "#/components/schemas/IdpUser"
+
+ IdpGroupResponse:
+ type: object
+ properties:
+ code:
+ type: integer
+ format: int32
+ description: Status code of the response
+ enum:
+ - 0
+ group:
+ $ref: "#/components/schemas/IdpGroup"
+
+ responses:
+ IdpForbiddenErrorResponse:
+ description: Forbidden - Built-in IDP REST APIs are disabled or the
caller is not authorized
+ content:
+ application/vnd.gravitino.v1+json:
+ schema:
+ $ref: "../openapi.yaml#/components/schemas/ErrorModel"
+
+ examples:
+ AddUserRequest:
+ value: {
+ "user": "alice",
+ "password": "secret"
+ }
+
+ ChangePasswordRequest:
+ value: {
+ "password": "new-secret"
+ }
+
+ AddGroupRequest:
+ value: {
+ "group": "engineers"
+ }
+
+ GroupMembershipChangeRequest:
+ value: {
+ "usersToAdd": ["alice", "bob"],
+ "usersToRemove": ["carol"]
+ }
+
+ IdpUserResponse:
+ value: {
+ "code": 0,
+ "user": {
+ "name": "alice",
+ "groups": ["engineers"]
+ }
+ }
+
+ IdpGroupResponse:
+ value: {
+ "code": 0,
+ "group": {
+ "name": "engineers",
+ "users": ["alice", "bob"]
+ }
+ }
+
+ IdpNotFoundException:
+ value: {
+ "code": 1003,
+ "type": "NotFoundException",
+ "message": "Failed to operate built-in IdP user [alice] operation
[GET], reason [User does not exist]"
+ }
+
+ IdpAlreadyExistsException:
+ value: {
+ "code": 1004,
+ "type": "AlreadyExistsException",
+ "message": "Failed to operate built-in IdP user [] operation [ADD],
reason [User already exists]"
+ }
+
+ IdpGroupNotEmptyException:
+ value: {
+ "code": 1003,
+ "type": "IllegalStateException",
+ "message": "Failed to operate built-in IdP group [engineers] operation
[REMOVE], reason [Group is not empty]"
+ }
diff --git a/docs/open-api/idp/openapi.yaml b/docs/open-api/idp/openapi.yaml
new file mode 100644
index 0000000000..76e064083f
--- /dev/null
+++ b/docs/open-api/idp/openapi.yaml
@@ -0,0 +1,69 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+---
+openapi: 3.0.3
+info:
+ title: Gravitino Built-in IDP REST API
+ license:
+ name: Apache 2.0
+ url: https://www.apache.org/licenses/LICENSE-2.0.html
+ version: 1.3.0-SNAPSHOT
+ description: |
+ OpenAPI specification for built-in IDP user and group management APIs
exposed
+ by the `idp-basic` plugin when the `basic` authenticator is enabled.
+
+servers:
+ - url: "{scheme}://{host}:{port}/{basePath}"
+ description: Generic base server URL, with all parts configurable.
+ variables:
+ scheme:
+ description: The scheme of the URI, either http or https.
+ default: http
+ host:
+ description: The host address for the specified server
+ default: localhost
+ port:
+ description: The port used when addressing the host
+ default: "8090"
+ basePath:
+ description: Optional prefix to be appended to all routes
+ default: "api"
+
+security:
+ - BasicAuth: []
+
+paths:
+ /idp/users:
+ $ref: "./idp.yaml#/paths/~1idp~1users"
+
+ /idp/users/{user}:
+ $ref: "./idp.yaml#/paths/~1idp~1users~1%7Buser%7D"
+
+ /idp/groups:
+ $ref: "./idp.yaml#/paths/~1idp~1groups"
+
+ /idp/groups/{group}:
+ $ref: "./idp.yaml#/paths/~1idp~1groups~1%7Bgroup%7D"
+
+ /idp/groups/{group}/users:
+ $ref: "./idp.yaml#/paths/~1idp~1groups~1%7Bgroup%7D~1users"
+
+components:
+ securitySchemes:
+ BasicAuth:
+ $ref: "../openapi.yaml#/components/securitySchemes/BasicAuth"