This is an automated email from the ASF dual-hosted git repository.
jerryshao pushed a commit to branch branch-1.3
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/branch-1.3 by this push:
new 456e239a33 [Cherry-pick to branch-1.3] Docs: update the security
section (#12391) (#12413)
456e239a33 is described below
commit 456e239a334a03498b4c9044baaa57d4e3baaa25
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Tue Aug 11 20:19:50 2026 +0800
[Cherry-pick to branch-1.3] Docs: update the security section (#12391)
(#12413)
**Cherry-pick Information:**
- Original commit: 36425469a1b50a6650b4506431ce054952793257
- Target branch: `branch-1.3`
- Status: ✅ Clean cherry-pick (no conflicts)
Co-authored-by: Mark Hoerth <[email protected]>
---
.../flink-authentication-with-gravitino.md | 6 +-
docs/gravitino-server-config.md | 10 +-
docs/how-to-use-gvfs.md | 10 +-
docs/iceberg-rest-engine/flink.md | 3 +
docs/iceberg-rest-engine/ray.md | 3 +
docs/iceberg-rest-engine/spark.md | 2 +-
docs/iceberg-rest-engine/trino.md | 3 +-
docs/index.md | 2 +-
docs/open-api/idp/idp.yaml | 102 ++--
docs/open-api/idp/openapi.yaml | 8 +-
docs/security/access-control.md | 3 +-
docs/security/authorization-pushdown.md | 140 +++---
docs/security/how-to-authenticate.md | 14 +-
docs/security/how-to-use-built-in-idp.md | 530 ---------------------
docs/security/how-to-use-cors.md | 74 +--
docs/security/how-to-use-https.md | 122 +++--
docs/security/local-users-and-groups.md | 197 ++++++++
docs/security/security.md | 28 --
.../spark-authentication-with-gravitino.md | 6 +-
docs/trino-connector/authentication.md | 10 +-
docs/webui-v2.md | 8 +-
docs/webui.md | 6 +-
22 files changed, 467 insertions(+), 820 deletions(-)
diff --git a/docs/flink-connector/flink-authentication-with-gravitino.md
b/docs/flink-connector/flink-authentication-with-gravitino.md
index 9b5b6c7188..2e0bb5c557 100644
--- a/docs/flink-connector/flink-authentication-with-gravitino.md
+++ b/docs/flink-connector/flink-authentication-with-gravitino.md
@@ -22,14 +22,14 @@ In simple mode, the username originates from Flink. The
resolution order is:
## Basic Mode
In Basic mode, the Flink connector authenticates to the Gravitino server using
HTTP Basic credentials
-against the built-in IDP. The Gravitino server must have Basic authentication
enabled. See
+against the local user store. The Gravitino server must have Basic
authentication enabled. See
[How to authenticate](../security/how-to-authenticate.md#basic-mode) for
server-side setup.
| Property | Type |
Default Value | Description | Required
|
|---------------------------------------------------------------|--------|---------------|------------------------------------------------|---------------------|
| table.catalog-store.gravitino.gravitino.client.auth.type | string |
(none) | Set to `basic` to enable Basic authentication. | Yes, for Basic
mode |
-| table.catalog-store.gravitino.gravitino.client.basic.username | string |
(none) | The built-in IDP username. | Yes, for Basic
mode |
-| table.catalog-store.gravitino.gravitino.client.basic.password | string |
(none) | The built-in IDP password. | Yes, for Basic
mode |
+| table.catalog-store.gravitino.gravitino.client.basic.username | string |
(none) | Username in the local user store. | Yes,
for Basic mode |
+| table.catalog-store.gravitino.gravitino.client.basic.password | string |
(none) | Password for that user. | Yes, for Basic
mode |
### Basic Configuration Example
diff --git a/docs/gravitino-server-config.md b/docs/gravitino-server-config.md
index 5c5afaa792..707791a1fd 100644
--- a/docs/gravitino-server-config.md
+++ b/docs/gravitino-server-config.md
@@ -16,7 +16,7 @@ authorization on.
This page covers the server itself. Catalog properties, which configure an
individual catalog
rather than the server, are covered further down. Properties for the auxiliary
services live with
those services: see [Iceberg REST Catalog Service](iceberg-rest-service.md) and
-[Security](security/security.md).
+[Security](security/how-to-authenticate.md).
## Quick Start
@@ -104,7 +104,7 @@ plain HTTP, so clients and the Web UI must move to
`httpsPort`, which defaults t
JWKS endpoint, which is the common case for an external identity provider.
Static sign keys,
Kerberos, and the OIDC login flow for the Web UI each take a different set of
properties. See
[How to Authenticate](security/how-to-authenticate.md), or
-[How to Use the Built-in IdP](security/how-to-use-built-in-idp.md) to keep
users and groups in
+[Local users and groups](security/local-users-and-groups.md) to keep users and
groups in
Gravitino's own metadata store instead of an external provider.
**`gravitino.authorization.serviceAdmins` has no default.** It is the one
property here that
@@ -354,7 +354,7 @@ Naming an authenticator is one line; configuring it is not.
Each value reads its
`gravitino.authenticator.*` properties, covered in
[How to Authenticate](security/how-to-authenticate.md). To hold users,
password hashes, and group
membership in Gravitino's own relational store rather than an external
provider, see
-[How to Use the Built-in IdP](security/how-to-use-built-in-idp.md).
+[Local users and groups](security/local-users-and-groups.md).
`gravitino.authenticator`, in the singular, is a deprecated spelling that
still works.
@@ -651,7 +651,7 @@ in `conf/gravitino-env.sh`.
properties of the auxiliary service named by `gravitino.auxService.names`
- [How to Authenticate](security/how-to-authenticate.md), for the
`gravitino.authenticator.*`
properties behind each value of `gravitino.authenticators`
-- [How to Use the Built-in IdP](security/how-to-use-built-in-idp.md), for
holding users, password
+- [Local users and groups](security/local-users-and-groups.md), for holding
users, password
hashes, and group membership in Gravitino's own relational store
- [Access Control](security/access-control.md), for the privilege model the
authorizer enforces once
`gravitino.authorization.enable` is set: roles, grants, ownership, and
metalake administration
@@ -663,4 +663,4 @@ in `conf/gravitino-env.sh`.
store, and client certificate properties
- [CORS](security/how-to-use-cors.md), for letting browser clients served from
another origin call
the API
-- [Security](security/security.md)
+- [Security](security/how-to-authenticate.md)
diff --git a/docs/how-to-use-gvfs.md b/docs/how-to-use-gvfs.md
index f7eaa514d4..0f7e030a68 100644
--- a/docs/how-to-use-gvfs.md
+++ b/docs/how-to-use-gvfs.md
@@ -349,7 +349,7 @@ FileSystem fs = filesetPath.getFileSystem(conf);
#### `OAuth` Authentication
If you want to use `oauth2` authentication for the Gravitino client in the
Gravitino Virtual File System,
-refer to this document to complete the configuration of the Gravitino server
and the OAuth server: [Security](security/security.md).
+refer to this document to complete the configuration of the Gravitino server
and the OAuth server: [Security](security/how-to-authenticate.md).
Then, you can configure the Hadoop configuration like this:
@@ -373,7 +373,7 @@ FileSystem fs = filesetPath.getFileSystem(conf);
#### `Kerberos` Authentication
If you want to use `kerberos` authentication for the Gravitino client in the
Gravitino Virtual File System,
-refer to this document to complete the configuration of the Gravitino server:
[Security](security/security.md).
+refer to this document to complete the configuration of the Gravitino server:
[Security](security/how-to-authenticate.md).
Then, you can configure the Hadoop configuration like this:
@@ -413,8 +413,8 @@ to recompile the native libraries like `libhdfs` and
others, and completely repl
| `cache_size` | The cache capacity of the Gravitino
Virtual File System.
| `20` | No
[...]
| `cache_expired_time` | The value of time that the cache expires
after accessing in the Gravitino Virtual File System. The value is in
`seconds`.
| `3600`
| No [...]
| `auth_type` | The auth type the Gravitino client uses
with the Gravitino Virtual File System. Supports `simple`, `basic`, and
`oauth2`.
| `simple` |
No [...]
-| `basic_username` | The username for the Gravitino client when
using `basic` auth type with the built-in IDP.
|
(none) | Yes if
you use `basic` a [...]
-| `basic_password` | The password for the Gravitino client when
using `basic` auth type with the built-in IDP.
|
(none) | Yes if
you use `basic` a [...]
+| `basic_username` | The username for the Gravitino client when
using `basic` auth type with the local user store.
| (none) | Yes if
you use `basi [...]
+| `basic_password` | The password for the Gravitino client when
using `basic` auth type with the local user store.
| (none) | Yes if
you use `basi [...]
| `oauth2_server_uri` | The auth server URI for the Gravitino
client when using `oauth2` auth type.
| (none) | Yes
if you use `oauth2` [...]
| `oauth2_credential` | The auth credential for the Gravitino
client when using `oauth2` auth type.
| (none) | Yes
if you use `oauth2` [...]
| `oauth2_path` | The auth server path for the Gravitino
client when using `oauth2` auth type. Please remove the first slash `/` from
the path, for example `oauth/token`.
| (none) | Yes
if you use `oauth2` [...]
@@ -734,7 +734,7 @@
print(fs.ls("gvfs://fileset/fileset_catalog/tmp/test_fileset"))
#### `OAuth` Authentication
First, make sure that your Gravitino server is also configured to use the
`oauth2` authentication mode,
-and you have an OAuth server to fetch the token:
[Security](security/security.md).
+and you have an OAuth server to fetch the token:
[Security](security/how-to-authenticate.md).
Then, you can configure the authentication like this:
diff --git a/docs/iceberg-rest-engine/flink.md
b/docs/iceberg-rest-engine/flink.md
index 8a247bc4ab..70581975c9 100755
--- a/docs/iceberg-rest-engine/flink.md
+++ b/docs/iceberg-rest-engine/flink.md
@@ -78,6 +78,9 @@ CREATE CATALOG gravitino_irc WITH (
### Basic Authentication
+If Gravitino uses [local users and
groups](../security/local-users-and-groups.md) for Basic
+authentication, set the auth properties on the catalog:
+
```sql
CREATE CATALOG gravitino_irc WITH (
'type' = 'iceberg',
diff --git a/docs/iceberg-rest-engine/ray.md b/docs/iceberg-rest-engine/ray.md
index fc74863a9a..4b1265d2ee 100644
--- a/docs/iceberg-rest-engine/ray.md
+++ b/docs/iceberg-rest-engine/ray.md
@@ -39,6 +39,9 @@ catalog_kwargs = {
### Credential Vending with Basic Authentication
+If Gravitino uses [local users and
groups](../security/local-users-and-groups.md) for Basic
+authentication, pass the credentials in the catalog arguments:
+
```python
catalog_kwargs = {
"name": "default",
diff --git a/docs/iceberg-rest-engine/spark.md
b/docs/iceberg-rest-engine/spark.md
index b69923c391..08e47a5666 100755
--- a/docs/iceberg-rest-engine/spark.md
+++ b/docs/iceberg-rest-engine/spark.md
@@ -80,7 +80,7 @@ instance profile, in which case the explicit credential lines
can be omitted.
### Basic Authentication
-If Gravitino uses [built-in IDP](../security/how-to-use-built-in-idp.md) Basic
authentication,
+If Gravitino uses [local users and
groups](../security/local-users-and-groups.md) for Basic authentication,
add the auth properties to `$SPARK_HOME/conf/spark-defaults.conf`:
```properties
diff --git a/docs/iceberg-rest-engine/trino.md
b/docs/iceberg-rest-engine/trino.md
index aafb32def3..b2ecd19dcc 100755
--- a/docs/iceberg-rest-engine/trino.md
+++ b/docs/iceberg-rest-engine/trino.md
@@ -293,7 +293,8 @@ is reached, which surfaces as a 403 rather than as a
storage error.
Requires Trino 481 or later.
`iceberg.rest-catalog.security` has no Basic value, so Trino cannot be
configured to authenticate to
-a REST catalog with a username and password. Gravitino's IRC does accept HTTP
Basic, so the way
+a REST catalog with a username and password. Gravitino's IRC does accept HTTP
Basic against
+[local users and groups](../security/local-users-and-groups.md), so the way
across is to construct the header yourself and have Trino attach it to every
REST catalog request.
Trino 481 added `iceberg.rest-catalog.http-headers`
([trinodb/trino#24236](https://github.com/trinodb/trino/issues/24236)) for
sending arbitrary headers,
diff --git a/docs/index.md b/docs/index.md
index 1819d190cb..9b71df7e5b 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -212,7 +212,7 @@ Gravitino provides security configurations for Gravitino,
including HTTPS, authe
* [HTTPS](./security/how-to-use-https.md): provides HTTPS configurations.
* [Authentication](./security/how-to-authenticate.md): provides authentication
configurations including simple, basic, OAuth, and Kerberos.
-* [Built-in IDP](./security/how-to-use-built-in-idp.md): operator guide for
the built-in identity provider (`idp-basic` plugin), including service admin
setup and `/api/idp` management APIs.
+* [Local users and groups](./security/local-users-and-groups.md): operator
guide for the local user store behind HTTP Basic authentication, including
service admin setup and `/api/idp` management APIs.
* [Access Control](./security/access-control.md): provides access control
configurations.
* [CORS](./security/how-to-use-cors.md): provides CORS configurations.
diff --git a/docs/open-api/idp/idp.yaml b/docs/open-api/idp/idp.yaml
index 51b44480db..2437519f9d 100644
--- a/docs/open-api/idp/idp.yaml
+++ b/docs/open-api/idp/idp.yaml
@@ -23,10 +23,10 @@ paths:
post:
tags:
- IDP
- summary: Add built-in IDP user
+ summary: Add local user store user
description: >
- Creates a built-in IDP user with the given username and password.
- Requires the `idp-basic` plugin and built-in IdP Basic authentication.
Built-in IdP is
+ Creates a local user store user with the given username and password.
+ Requires the `idp-basic` plugin and local user store Basic
authentication. Local user store is
incompatible with the `simple` authenticator (the default),
`gravitino.authenticators` must
include `basic` and must not include `simple`.
operationId: addIdpUser
@@ -41,7 +41,7 @@ paths:
$ref: "#/components/examples/AddUserRequest"
responses:
"200":
- description: Returns the added built-in IDP user
+ description: Returns the added local user store user
content:
application/vnd.gravitino.v1+json:
schema:
@@ -59,7 +59,7 @@ paths:
IllegalArgumentException:
$ref:
"#/components/examples/IdpAddUserIllegalArgumentException"
"409":
- description: Conflict - The built-in IDP user already exists
+ description: Conflict - The local user store user already exists
content:
application/vnd.gravitino.v1+json:
schema:
@@ -79,12 +79,12 @@ paths:
get:
tags:
- IDP
- summary: Get built-in IDP user
- description: Returns the specified built-in IDP user, including group
membership (empty if none; the example shows a user who already belongs to
groups).
+ summary: Get local user store user
+ description: Returns the specified local user store user, including
group membership (empty if none; the example shows a user who already belongs
to groups).
operationId: getIdpUser
responses:
"200":
- description: Returns the built-in IDP user object
+ description: Returns the local user store user object
content:
application/vnd.gravitino.v1+json:
schema:
@@ -95,7 +95,7 @@ paths:
"403":
$ref: "#/components/responses/IdpForbiddenErrorResponse"
"404":
- description: Not Found - The specified built-in IDP user does not
exist
+ description: Not Found - The specified local user store user does
not exist
content:
application/vnd.gravitino.v1+json:
schema:
@@ -109,8 +109,8 @@ paths:
put:
tags:
- IDP
- summary: Change built-in IDP user password
- description: Updates the password of the specified built-in IDP user and
returns the user object with unchanged group membership.
+ summary: Change local user store user password
+ description: Updates the password of the specified local user store user
and returns the user object with unchanged group membership.
operationId: changeIdpUserPassword
requestBody:
required: true
@@ -123,7 +123,7 @@ paths:
$ref: "#/components/examples/ChangePasswordRequest"
responses:
"200":
- description: Returns the built-in IDP user after the password change
+ description: Returns the local user store user after the password
change
content:
application/vnd.gravitino.v1+json:
schema:
@@ -143,7 +143,7 @@ paths:
"403":
$ref: "#/components/responses/IdpForbiddenErrorResponse"
"404":
- description: Not Found - The specified built-in IDP user does not
exist
+ description: Not Found - The specified local user store user does
not exist
content:
application/vnd.gravitino.v1+json:
schema:
@@ -157,8 +157,8 @@ paths:
delete:
tags:
- IDP
- summary: Remove built-in IDP user
- description: Removes the specified built-in IDP user.
+ summary: Remove local user store user
+ description: Removes the specified local user store user.
operationId: removeIdpUser
responses:
"200":
@@ -172,8 +172,8 @@ paths:
post:
tags:
- IDP
- summary: Add built-in IDP group
- description: Creates a built-in IDP group with the given name.
+ summary: Add local user store group
+ description: Creates a local user store group with the given name.
operationId: addIdpGroup
requestBody:
required: true
@@ -186,7 +186,7 @@ paths:
$ref: "#/components/examples/AddGroupRequest"
responses:
"200":
- description: Returns the added built-in IDP group
+ description: Returns the added local user store group
content:
application/vnd.gravitino.v1+json:
schema:
@@ -204,7 +204,7 @@ paths:
IllegalArgumentException:
$ref:
"#/components/examples/IdpAddGroupIllegalArgumentException"
"409":
- description: Conflict - The built-in IDP group already exists
+ description: Conflict - The local user store group already exists
content:
application/vnd.gravitino.v1+json:
schema:
@@ -224,12 +224,12 @@ paths:
get:
tags:
- IDP
- summary: Get built-in IDP group
- description: Returns the specified built-in IDP group, including member
usernames (empty if none; the example shows a group that already has members).
+ summary: Get local user store group
+ description: Returns the specified local user store group, including
member usernames (empty if none; the example shows a group that already has
members).
operationId: getIdpGroup
responses:
"200":
- description: Returns the built-in IDP group object
+ description: Returns the local user store group object
content:
application/vnd.gravitino.v1+json:
schema:
@@ -240,7 +240,7 @@ paths:
"403":
$ref: "#/components/responses/IdpForbiddenErrorResponse"
"404":
- description: Not Found - The specified built-in IDP group does not
exist
+ description: Not Found - The specified local user store group does
not exist
content:
application/vnd.gravitino.v1+json:
schema:
@@ -254,8 +254,8 @@ paths:
delete:
tags:
- IDP
- summary: Remove built-in IDP group
- description: Removes the specified built-in IDP group.
+ summary: Remove local user store group
+ description: Removes the specified local user store group.
operationId: removeIdpGroup
parameters:
- $ref: "../openapi.yaml#/components/parameters/force"
@@ -283,8 +283,8 @@ paths:
put:
tags:
- IDP
- summary: Change built-in IDP group membership
- description: Adds and/or removes users from the specified built-in IDP
group.
+ summary: Change local user store group membership
+ description: Adds and/or removes users from the specified local user
store group.
operationId: changeIdpGroupMembership
requestBody:
required: true
@@ -297,7 +297,7 @@ paths:
$ref: "#/components/examples/GroupMembershipChangeRequest"
responses:
"200":
- description: Returns the built-in IDP group after membership changes
+ description: Returns the local user store group after membership
changes
content:
application/vnd.gravitino.v1+json:
schema:
@@ -317,7 +317,7 @@ paths:
"403":
$ref: "#/components/responses/IdpForbiddenErrorResponse"
"404":
- description: Not Found - The specified built-in IDP group or user
does not exist
+ description: Not Found - The specified local user store group or
user does not exist
content:
application/vnd.gravitino.v1+json:
schema:
@@ -340,13 +340,13 @@ components:
name:
type: string
maxLength: 128
- description: The username of the built-in IDP user
+ description: The username of the local user store user
groups:
type: array
items:
type: string
maxLength: 128
- description: The built-in IDP groups the user belongs to
+ description: The local user store groups the user belongs to
IdpGroup:
type: object
@@ -356,13 +356,13 @@ components:
name:
type: string
maxLength: 128
- description: The name of the built-in IDP group
+ description: The name of the local user store group
users:
type: array
items:
type: string
maxLength: 128
- description: The usernames of members in the built-in IDP group
+ description: The usernames of members in the local user store group
AddUserRequest:
type: object
@@ -381,7 +381,7 @@ components:
format: password
minLength: 12
maxLength: 64
- description: The password of the built-in IDP user to add.
+ description: The password of the local user store user to add.
writeOnly: true
ChangePasswordRequest:
@@ -394,7 +394,7 @@ components:
format: password
minLength: 12
maxLength: 64
- description: The new password of the built-in IDP user.
+ description: The new password of the local user store user.
writeOnly: true
AddGroupRequest:
@@ -423,7 +423,7 @@ components:
minLength: 1
maxLength: 128
minItems: 1
- description: The usernames to add to the built-in IDP group
+ description: The usernames to add to the local user store group
usersToRemove:
type: array
items:
@@ -431,7 +431,7 @@ components:
minLength: 1
maxLength: 128
minItems: 1
- description: The usernames to remove from the built-in IDP group
+ description: The usernames to remove from the local user store group
IdpUserResponse:
type: object
@@ -461,7 +461,7 @@ components:
IdpForbiddenErrorResponse:
description:
Forbidden - Only callers listed in
`gravitino.authorization.serviceAdmins` may
- manage built-in IDP users and groups. Unauthenticated requests and
authenticated
+ manage local user store users and groups. Unauthenticated requests and
authenticated
non-service-admin users receive this response.
content:
application/vnd.gravitino.v1+json:
@@ -552,89 +552,89 @@ components:
value: {
"code": 1001,
"type": "IllegalArgumentException",
- "message": "Failed to operate built-in IdP user [] operation [ADD],
reason [\"user\" field is required and cannot be empty]"
+ "message": "Failed to operate local user store user [] operation
[ADD], reason [\"user\" field is required and cannot be empty]"
}
IdpChangePasswordIllegalArgumentException:
value: {
"code": 1001,
"type": "IllegalArgumentException",
- "message": "Failed to operate built-in IdP user [alice] operation
[UPDATE], reason [\"password\" field is required and cannot be empty]"
+ "message": "Failed to operate local user store user [alice] operation
[UPDATE], reason [\"password\" field is required and cannot be empty]"
}
IdpAddGroupIllegalArgumentException:
value: {
"code": 1001,
"type": "IllegalArgumentException",
- "message": "Failed to operate built-in IdP group [] operation [ADD],
reason [\"group\" field is required and cannot be empty]"
+ "message": "Failed to operate local user store group [] operation
[ADD], reason [\"group\" field is required and cannot be empty]"
}
IdpGroupMembershipIllegalArgumentException:
value: {
"code": 1001,
"type": "IllegalArgumentException",
- "message": "Failed to operate built-in IdP group [engineers] operation
[UPDATE], reason [usersToAdd and usersToRemove cannot both be null]"
+ "message": "Failed to operate local user store group [engineers]
operation [UPDATE], reason [usersToAdd and usersToRemove cannot both be null]"
}
IdpNotFoundException:
value: {
"code": 1003,
"type": "NotFoundException",
- "message": "Failed to operate built-in IdP user [missing-user]
operation [GET], reason [IdP user not found: missing-user]"
+ "message": "Failed to operate local user store user [missing-user]
operation [GET], reason [IdP user not found: missing-user]"
}
IdpAlreadyExistsException:
value: {
"code": 1004,
"type": "AlreadyExistsException",
- "message": "Failed to operate built-in IdP user [alice] operation
[ADD], reason [IdP user alice already exists]"
+ "message": "Failed to operate local user store user [alice] operation
[ADD], reason [IdP user alice already exists]"
}
IdpUserUpdateNotFoundException:
value: {
"code": 1003,
"type": "NotFoundException",
- "message": "Failed to operate built-in IdP user [missing-user]
operation [UPDATE], reason [IdP user not found: missing-user]"
+ "message": "Failed to operate local user store user [missing-user]
operation [UPDATE], reason [IdP user not found: missing-user]"
}
IdpGroupNotFoundException:
value: {
"code": 1003,
"type": "NotFoundException",
- "message": "Failed to operate built-in IdP group [missing-group]
operation [GET], reason [IdP group not found: missing-group]"
+ "message": "Failed to operate local user store group [missing-group]
operation [GET], reason [IdP group not found: missing-group]"
}
IdpGroupUpdateNotFoundException:
value: {
"code": 1003,
"type": "NotFoundException",
- "message": "Failed to operate built-in IdP group [missing-group]
operation [UPDATE], reason [IdP group not found: missing-group]"
+ "message": "Failed to operate local user store group [missing-group]
operation [UPDATE], reason [IdP group not found: missing-group]"
}
IdpMembershipUserNotFoundException:
value: {
"code": 1003,
"type": "NotFoundException",
- "message": "Failed to operate built-in IdP group [engineers] operation
[UPDATE], reason [IdP user not found: missing-user]"
+ "message": "Failed to operate local user store group [engineers]
operation [UPDATE], reason [IdP user not found: missing-user]"
}
IdpGroupAlreadyExistsException:
value: {
"code": 1004,
"type": "AlreadyExistsException",
- "message": "Failed to operate built-in IdP group [engineers] operation
[ADD], reason [IdP group engineers already exists]"
+ "message": "Failed to operate local user store group [engineers]
operation [ADD], reason [IdP group engineers already exists]"
}
IdpGroupNotEmptyException:
value: {
"code": 1006,
"type": "IllegalStateException",
- "message": "Failed to operate built-in IdP group [engineers] operation
[REMOVE], reason [IdP group engineers is not empty, use force=true to delete
it]"
+ "message": "Failed to operate local user store group [engineers]
operation [REMOVE], reason [IdP group engineers is not empty, use force=true to
delete it]"
}
IdpForbiddenException:
value: {
"code": 1008,
"type": "ForbiddenException",
- "message": "Only service admins can manage built-in IdP users and
groups."
+ "message": "Only service admins can manage local user store users and
groups."
}
diff --git a/docs/open-api/idp/openapi.yaml b/docs/open-api/idp/openapi.yaml
index d8271fab8d..263c50c7fa 100644
--- a/docs/open-api/idp/openapi.yaml
+++ b/docs/open-api/idp/openapi.yaml
@@ -18,17 +18,17 @@
---
openapi: 3.0.3
info:
- title: Gravitino Built-in IDP REST API
+ title: Gravitino Local Users and Groups 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
+ OpenAPI specification for local user store user and group management APIs
exposed
by the `idp-basic` plugin. Clients authenticate with Basic credentials
validated against
- built-in IdP user metadata. Enable built-in IdP by registering
+ local user metadata. Enable local user store by registering
`org.apache.gravitino.idp.web.rest.feature` in
`gravitino.server.rest.extensionPackages`.
- Built-in IdP is incompatible with the `simple` authenticator (the default),
+ Local user store is incompatible with the `simple` authenticator (the
default),
`gravitino.authenticators` must include `basic` and must not include
`simple`.
servers:
diff --git a/docs/security/access-control.md b/docs/security/access-control.md
index 538a80abba..bbc8c41d0c 100755
--- a/docs/security/access-control.md
+++ b/docs/security/access-control.md
@@ -587,5 +587,4 @@ client.setOwner(schema, "analyst", Owner.Type.USER);
- [Authorization Pushdown](authorization-pushdown.md), for pushing enforcement
down to the underlying
data source or to an external system such as Apache Ranger
- [How to Authenticate](how-to-authenticate.md), for establishing who the
caller is
-- [How to Use the Built-in IdP](how-to-use-built-in-idp.md)
-- [Security](security.md)
+- [Local users and groups](local-users-and-groups.md)
diff --git a/docs/security/authorization-pushdown.md
b/docs/security/authorization-pushdown.md
index 0bc406c1d0..dea56c5d03 100644
--- a/docs/security/authorization-pushdown.md
+++ b/docs/security/authorization-pushdown.md
@@ -1,99 +1,98 @@
---
title: "Authorization Pushdown"
slug: "/security/authorization-pushdown"
-keyword: "security"
+keywords:
+ - security
+ - authorization
+ - ranger
license: "This software is licensed under the Apache License version 2."
---
-## Introduction
+## Overview
-
+Authorization pushdown applies a grant made in Gravitino to Apache Ranger, so
the permission is enforced where the data is rather than only inside Gravitino.
An engine that reads the table directly is still subject to it.
-Gravitino offers a set of authorization frameworks that integrate with various
underlying data source permission systems, such as MySQL's native permission
management and Apache Ranger for big data. These frameworks align with
Gravitino's own authorization model and methodology.
-Gravitino manages different data sources through Catalogs, and when a user
performs an authorization operation on data within a Catalog, Gravitino invokes
the Authorization Plugin module for that Catalog.
-This module translates Gravitino's authorization model into the permission
rules of the underlying data source. The permissions are then enforced by the
underlying permission system via the respective client, such as JDBC or the
Apache Ranger client.
+Pushdown is configured per catalog with the `authorization-provider` property.
Set it to `ranger` when the catalog's permissions live in a single Ranger
service, or to `chain` when one catalog needs its grants applied in more than
one. A catalog without the property manages access in Gravitino alone.
-### Ranger Hadoop SQL Plugin
+Gravitino resolves which catalog holds the object being granted on, hands the
operation to that catalog's plugin, and the plugin maps the Gravitino privilege
onto Ranger's model and writes it through the Ranger admin REST API. The plugin
interface is not specific to Ranger, so other permission systems can be added,
and Ranger is what ships today.
-To use the Ranger Hadoop SQL Plugin, you need to configure the following
properties:
+Once a catalog is configured, grants are made through the ordinary
[authorization REST
API](https://gravitino.apache.org/docs/latest/api/rest/grant-role-to-user). No
separate pushdown call exists.
-| Property Name | Description
| Default Value
| Required |
-|-------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------|----------|
-| `authorization-provider` | Providers to use to
implement authorization plugin such as `ranger`.
| (none)
| No |
-| `authorization.ranger.admin.url` | The Apache Ranger
web URIs.
| (none)
| No |
-| `authorization.ranger.service.type` | The Apache Ranger
service type. Supports `HadoopSQL` or `HDFS`.
| (none)
| No |
-| `authorization.ranger.auth.type` | The Apache Ranger
authentication type `simple` or `kerberos`.
| `simple`
| No |
-| `authorization.ranger.username` | The Apache Ranger
admin web login username (auth type=simple), or kerberos principal(auth
type=kerberos), Need have Ranger administrator permission. | (none)
| No |
-| `authorization.ranger.password` | The Apache Ranger
admin web login user password (auth type=simple), or path of the keytab
file(auth type=kerberos) | (none)
| No |
-| `authorization.ranger.service.name` | The Apache Ranger
service name.
| (none)
| No |
-| `authorization.ranger.service.create-if-absent` | If this property is
true and the Ranger service doesn't exist, Gravitino will create a Ranger
service | false
| No |
-| `authorization.ranger.jdbc.driverClassName` | The property is used
to specify driver class name when creating Ranger HadoopSQL service
|
`org.apache.hive.jdbc.HiveDrive` | No |
-| `authorization.ranger.jdbc.url` | The property is used
to specify jdbc url when creating Ranger HadoopSQL service
| `jdbc:hive2://127.0.0.1:8081`
| No |
-| `authorization.ranger.hadoop.security.authentication` | The property is used
to specify Hadoop security authentication when creating Ranger HDFS service
| `simple`
| No |
-| `authorization.ranger.hadoop.rpc.protection` | The property is used
to specify Hadoop rpc protection when creating Ranger HDFS service
| `authentication`
| No |
-| `authorization.ranger.fs.default.name` | The property is used
to specify default filesystem when creating Ranger HDFS service
| `hdfs://127.0.0.1:8090`
| No |
+## Ranger
-:::caution
-The Gravitino Ranger authorization plugin only supports the Apache Ranger
HadoopSQL Plugin and Apache Ranger HDFS Plugin.
-:::
+The Ranger provider covers two Ranger service types. `HadoopSQL` governs
schemas, tables, and columns for the Hive, Iceberg, and Paimon catalogs. `HDFS`
governs paths, which is what a fileset catalog needs. A catalog selects one of
them with `authorization.ranger.service.type`.
-Once you have used the correct configuration, you can perform authorization
operations by calling Gravitino [authorization RESTful
API](https://gravitino.apache.org/docs/latest/api/rest/grant-role-to-user).
+Spark reaches these catalogs through the Kyuubi authorization plugin. That
plugin cannot push updates or deletes for a Paimon catalog.
-Gravitino will initially create three roles in Apache Ranger:
+### Configuration
-- GRAVITINO_METALAKE_OWNER_ROLE: Includes users and user groups designated as
metalake owners, corresponding to the owner's privileges in Ranger policies.
-- GRAVITINO_CATALOG_OWNER_ROLE: Includes users and user groups designated as
catalog owners, corresponding to the owner's privileges in Ranger policies.
-- GRAVITINO_OWNER_ROLE: Used to label Ranger policy items related to schema
and table owner privileges. It does not include any users or user groups.
+| Property Name | Description
| Default Value |
+|-------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|-----------------------------------|
+| `authorization-provider` | Set to `ranger` to
push grants into Apache Ranger
| (none) |
+| `authorization.ranger.admin.url` | The Ranger admin web
URI
| (none) |
+| `authorization.ranger.service.type` | `HadoopSQL` or
`HDFS`
| (none) |
+| `authorization.ranger.service.name` | The Ranger service
to write policies into
| (none) |
+| `authorization.ranger.auth.type` | `simple` or
`kerberos`
| `simple` |
+| `authorization.ranger.username` | Ranger admin login
username, or the Kerberos principal. Requires Ranger administrator permission
| (none) |
+| `authorization.ranger.password` | Ranger admin login
password, or the path to the keytab file
| (none) |
+| `authorization.ranger.service.create-if-absent` | Creates the Ranger
service when it does not already exist
| `false` |
-#### Configure the Ranger Hadoop SQL Plugin
+The remaining properties apply only when `create-if-absent` is `true`, since
they describe the service Gravitino creates.
-Suppose you have an Apache Hive service in your datacenter and have created a
`hiveRepo` in Apache Ranger to manage its permissions.
-The Ranger service is accessible at `172.0.0.100:6080`, with the username
`Jack` and the password `PWD123`.
-To add this Hive service to Gravitino using the Hive catalog, you'll need to
configure the following parameters.
+| Property Name | Description
| Default Value
|
+|-------------------------------------------------------|--------------------------------------------------------------------------|-----------------------------------|
+| `authorization.ranger.jdbc.driverClassName` | Driver class for a
new HadoopSQL service |
`org.apache.hive.jdbc.HiveDriver` |
+| `authorization.ranger.jdbc.url` | JDBC URL for a new
HadoopSQL service |
`jdbc:hive2://127.0.0.1:8081` |
+| `authorization.ranger.hadoop.security.authentication` | Hadoop security
authentication for a new HDFS service | `simple`
|
+| `authorization.ranger.hadoop.security.authorization` | Hadoop security
authorization for a new HDFS service | (none)
|
+| `authorization.ranger.hadoop.rpc.protection` | Hadoop RPC
protection for a new HDFS service |
`authentication` |
+| `authorization.ranger.fs.default.name` | Default filesystem
for a new HDFS service | `hdfs://127.0.0.1:8090`
|
+
+### Example
+
+A Hive service is already managed by a Ranger service named `hiveRepo`, and
Ranger is reachable at `172.0.0.100:6080`. Adding that Hive service to
Gravitino as a Hive catalog with pushdown enabled takes the following catalog
properties.
```properties
authorization-provider=ranger
authorization.ranger.admin.url=172.0.0.100:6080
authorization.ranger.auth.type=simple
-authorization.ranger.username=Jack
-authorization.ranger.password=PWD123
+authorization.ranger.username={ranger_admin_user}
+authorization.ranger.password={ranger_admin_password}
authorization.ranger.service.type=HadoopSQL
authorization.ranger.service.name=hiveRepo
```
-:::caution
-Gravitino supports authorization pushdown to Apache Ranger for the Hive,
Iceberg, and Paimon catalogs through the Ranger Hadoop SQL Plugin.
-Spark can use Kyuubi authorization plugin to access Gravitino's catalog. But
the plugin can't support to update or delete data for Paimon catalog.
-More data source authorization is under development.
-:::
+### Roles Gravitino Creates
+
+Gravitino creates three roles in Ranger and manages their membership itself,
so treat them as owned by Gravitino rather than editing them in the Ranger UI.
+
+| Role | Purpose
|
+|---------------------------------|---------------------------------------------------------------------------------------------------|
+| `GRAVITINO_METALAKE_OWNER_ROLE` | Holds the users and groups that own the
metalake, carrying owner privileges in Ranger policies |
+| `GRAVITINO_CATALOG_OWNER_ROLE` | Holds the users and groups that own the
catalog, carrying owner privileges in Ranger policies |
+| `GRAVITINO_OWNER_ROLE` | Labels the policy items covering schema
and table owner privileges, and holds no members |
-### Chain Authorization Plugin
+## Chaining Plugins
-Gravitino supports chaining multiple authorization plugins to secure one
catalog.
-The authorization plugin chain is defined in the `authorization.chain.plugins`
property, with the plugin names separated by commas.
-When a user performs an authorization operation on data within a catalog, the
chained plugin will apply the authorization rules for every plugin defined in
the chain.
+One catalog often needs permissions applied in more than one place. A Hive
catalog storing its data on HDFS needs both the table grant in the HadoopSQL
service and the corresponding path grant in the HDFS service, or an engine
reading the files directly bypasses the table permission.
-To use the chained authorization plugin, you need to configure the following
properties:
+The `chain` provider handles this. Set `authorization.chain.plugins` to a
comma-separated list of names you choose, then configure each named plugin with
`authorization.chain.{plugin_name}` as its property prefix. Every plugin in the
chain is applied on each authorization operation.
-| Property Name | Description
| Default
Value | Required |
-|----------------------------------------------------------|--------------------------------------------------------------------------------------|---------------|-----------------------------|
-| `authorization-provider` | Providers to use
to implement authorization plugin such as `chain` | (none)
| No |
-| `authorization.chain.plugins` | The
comma-separated list of plugin names, like
`${plugin-name1},${plugin-name2},...` | (none) | Yes if you use chain
plugin |
-| `authorization.chain.${plugin-name}.ranger.admin.url` | The Ranger
authorization plugin properties of the `${plugin-name}` |
(none) | Yes if you use chain plugin |
-| `authorization.chain.${plugin-name}.ranger.service.type` | The Ranger
authorization plugin properties of the `${plugin-name}` |
(none) | Yes if you use chain plugin |
-| `authorization.chain.${plugin-name}.ranger.service.name` | The Ranger
authorization plugin properties of the `${plugin-name}` |
(none) | Yes if you use chain plugin |
-| `authorization.chain.${plugin-name}.ranger.username` | The Ranger
authorization plugin properties of the `${plugin-name}` |
(none) | Yes if you use chain plugin |
-| `authorization.chain.${plugin-name}.ranger.password` | The Ranger
authorization plugin properties of the `${plugin-name}` |
(none) | Yes if you use chain plugin |
+| Property Name | Description
|
+|----------------------------------------------------------|-----------------------------------------------------------------|
+| `authorization-provider` | Set to `chain` to
apply several plugins to this catalog |
+| `authorization.chain.plugins` | Comma-separated
plugin names, each naming a prefix below |
+| `authorization.chain.{plugin_name}.ranger.admin.url` | The admin URI for
that plugin |
+| `authorization.chain.{plugin_name}.ranger.service.type` | `HadoopSQL` or
`HDFS` for that plugin |
+| `authorization.chain.{plugin_name}.ranger.service.name` | The Ranger
service for that plugin |
+| `authorization.chain.{plugin_name}.ranger.username` | The Ranger admin
login username for that plugin |
+| `authorization.chain.{plugin_name}.ranger.password` | The Ranger admin
login password for that plugin |
-:::caution
-The Gravitino chain authorization plugin only supports the Apache Ranger
HadoopSQL Plugin and Apache Ranger HDFS Plugin.
-The properties of every chained authorization plugin should use
`authorization.chain.${plugin-name}` as the prefix.
-:::
+The names in `authorization.chain.plugins` are labels rather than plugin
types, so any name works as long as it matches the prefix used by its
properties. Every plugin in a chain is a Ranger plugin, since Ranger is the
only provider available to chain.
-#### Configure the Chain Authorization Plugin
+### Example
-Suppose you have an Apache Hive service in your datacenter and have created a
`hiveRepo` in Apache Ranger to manage its permissions.
-The Apache Hive service will use HDFS to store its data. You have created a
`hdfsRepo` in Apache Ranger to manage HDFS's permissions.
+The Hive service is managed by the Ranger service `hiveRepo` and its
underlying HDFS storage by `hdfsRepo`. Chaining the two keeps the table grant
and the path grant in step.
```properties
authorization-provider=chain
@@ -102,12 +101,17 @@
authorization.chain.hive.ranger.admin.url=http://ranger-service:6080
authorization.chain.hive.ranger.service.type=HadoopSQL
authorization.chain.hive.ranger.service.name=hiveRepo
authorization.chain.hive.ranger.auth.type=simple
-authorization.chain.hive.ranger.username=Jack
-authorization.chain.hive.ranger.password=PWD123
+authorization.chain.hive.ranger.username={ranger_admin_user}
+authorization.chain.hive.ranger.password={ranger_admin_password}
authorization.chain.hdfs.ranger.admin.url=http://ranger-service:6080
authorization.chain.hdfs.ranger.service.type=HDFS
authorization.chain.hdfs.ranger.service.name=hdfsRepo
authorization.chain.hdfs.ranger.auth.type=simple
-authorization.chain.hdfs.ranger.username=Jack
-authorization.chain.hdfs.ranger.password=PWD123
-```
\ No newline at end of file
+authorization.chain.hdfs.ranger.username={ranger_admin_user}
+authorization.chain.hdfs.ranger.password={ranger_admin_password}
+```
+
+## Further Reading
+
+- [Access Control](access-control.md) for the Gravitino privilege model that
pushdown translates from
+- [Authorization REST
API](https://gravitino.apache.org/docs/latest/api/rest/grant-role-to-user) for
making the grants
diff --git a/docs/security/how-to-authenticate.md
b/docs/security/how-to-authenticate.md
index c3cbfccdff..28b273a875 100644
--- a/docs/security/how-to-authenticate.md
+++ b/docs/security/how-to-authenticate.md
@@ -45,7 +45,7 @@ curl -v -X GET \
### Basic Mode
-In Basic mode, Gravitino verifies HTTP Basic credentials against built-in IDP
user metadata stored
+In Basic mode, Gravitino verifies HTTP Basic credentials against local user
metadata stored
in the relational entity store.
To enable Basic mode:
@@ -53,14 +53,14 @@ To enable Basic mode:
- Set `gravitino.authenticators` to `basic`.
- Set `gravitino.server.rest.extensionPackages` to
`org.apache.gravitino.idp.web.rest.feature`.
- Set `gravitino.authorization.serviceAdmins` to the service admin usernames
that should exist in
- the built-in IDP.
+ the local user store.
-Built-in IdP is **incompatible** with the `simple` authenticator (the default),
+Local user store is **incompatible** with the `simple` authenticator (the
default),
`gravitino.authenticators` must include `basic` and must not include `simple`.
- On the first startup, if any configured service admin does not yet have a
password, set the
`GRAVITINO_INITIAL_ADMIN_PASSWORD` environment variable to the initial
password (12 to 64
characters) before starting Gravitino. The same password is applied to every
configured service
- admin that does not yet exist in the built-in IDP.
+ admin that does not yet exist in the local user store.
For the client side, enable Basic mode with the following code:
@@ -91,8 +91,8 @@ curl -v -X GET \
```
The Web UI uses the first entry in `gravitino.authenticators` from `/configs`.
When it is `basic`,
-the login page shows a username and password form backed by built-in IdP user
metadata. See
-[built-in IDP Web UI](how-to-use-built-in-idp.md#web-ui).
+the login page shows a username and password form backed by local user
metadata. See
+[Local users and groups](local-users-and-groups.md).
### OAuth Mode
@@ -383,7 +383,7 @@ This example shows how to enable built-in Basic
authentication.
- Gravitino distribution package (includes the idp-basic plugin on the server
classpath)
-Built-in IdP is **incompatible** with the `simple` authenticator (the default),
+Local user store is **incompatible** with the `simple` authenticator (the
default),
`gravitino.authenticators` must include `basic` and must not include `simple`.
**Configuration:**
diff --git a/docs/security/how-to-use-built-in-idp.md
b/docs/security/how-to-use-built-in-idp.md
deleted file mode 100644
index 9eb2e64b6a..0000000000
--- a/docs/security/how-to-use-built-in-idp.md
+++ /dev/null
@@ -1,530 +0,0 @@
----
-title: How to use built-in IDP
-slug: /security/how-to-use-built-in-idp
-keyword: security authentication idp
-license: "This software is licensed under the Apache License version 2."
----
-
-## Introduction
-
-Apache Gravitino can store **built-in IDP** (identity provider) users and
groups in the relational
-metadata store through the `idp-basic` plugin. This gives you a self-contained
way to manage
-**global** login identities (usernames, password hashes, and group membership)
without an external server.
-
-Built-in IDP is aimed at POC, offline, and isolated deployments. It is **not**
a replacement for
-enterprise IDPs such as Okta, Azure AD, or Keycloak. Use it only where a
lightweight local identity
-store is acceptable; restrict management APIs to **service admins**, store
password hashes only,
-and prefer [HTTPS](how-to-use-https.md) when credentials travel over the
network.
-
-This guide describes how to enable and operate the management APIs in
`plugins:idp-basic`. For
-request and response schemas, see the [Built-in IDP
OpenAPI](../open-api/idp/openapi.yaml).
-
-## Web UI
-
-When built-in IdP Basic authentication is enabled, the Web UI exposes a
username and password login
-form. Configure **both** of the following in `gravitino.conf`:
-
-```properties
-gravitino.authenticators = basic
-gravitino.server.rest.extensionPackages =
org.apache.gravitino.idp.web.rest.feature
-```
-
-The Web UI reads `gravitino.authenticators` from `/configs` and uses the first
entry as the active
-authentication type. List `basic` first when you want the built-in IdP login
form. Built-in IdP is
-**incompatible** with the `simple` authenticator (the default). When IdP is
enabled, do not include
-`simple` in `gravitino.authenticators`.
-
----
-
-## Prerequisites
-
-Before you call `/api/idp/*`, ensure the following:
-
-1. **IDP REST API registration** — In `gravitino.conf`, set:
-
- ```properties
- gravitino.authenticators = basic
- gravitino.server.rest.extensionPackages =
org.apache.gravitino.idp.web.rest.feature
- ```
-
-2. **Server authenticator** — Built-in IdP is **incompatible** with the
`simple` authenticator
- (the default). Do not list `simple` together with `basic` in
`gravitino.authenticators`.
-
-3. **Service admin passwords** — Built-in IDP requires every username in
- `gravitino.authorization.serviceAdmins` to have a password stored in
`idp_user_meta` before you
- can call management APIs.
-
- 1. Set service admin usernames in `gravitino.conf` (see [Access
control](access-control.md)):
-
- ```properties
- gravitino.authorization.serviceAdmins = admin
- ```
-
- 2. **Initialize service admin passwords at startup** — Before the first
start, set
- `GRAVITINO_INITIAL_ADMIN_PASSWORD` to the initial password. Usernames
come from
- `gravitino.authorization.serviceAdmins`. The value must satisfy the
- [password rules](#password-and-username-rules) below.
-
- ```shell
- export GRAVITINO_INITIAL_ADMIN_PASSWORD='Passw0rd-Admin12'
- ```
-
- 3. **Start Gravitino**.
-
- 4. **Call management APIs** — Use Basic authentication with a service admin
username and
- password (for example `admin` / `Passw0rd-Admin12`).
-
----
-
-## Configuration
-
-Set service admins in `gravitino.conf` (see also
[Prerequisites](#prerequisites)):
-
-| Configuration item | Description
| Example
|
-|-------------------------------------------|--------------------------------------------------------------------------|---------------------------------------------|
-| `gravitino.authenticators` | Must include `basic` when the
built-in IdP plugin is enabled | `basic`
|
-| `gravitino.server.rest.extensionPackages` | Registers built-in IdP REST APIs
|
`org.apache.gravitino.idp.web.rest.feature` |
-| `gravitino.authorization.serviceAdmins` | Comma-separated service admin
that can call built-in IDP management APIs | `admin`
|
-
-Example:
-
-```properties
-gravitino.authenticators = basic
-gravitino.server.rest.extensionPackages =
org.apache.gravitino.idp.web.rest.feature
-gravitino.authorization.serviceAdmins = admin
-```
-
----
-
-## Operations
-
-The following sections show how to call built-in IDP management APIs with
`curl`. Replace
-`localhost:8090`, usernames, and passwords with values that match your
deployment. Examples use
-Basic authentication with `admin` / `Passw0rd-Admin12` (from
[Prerequisites](#prerequisites)).
-
-**Base URL** — `http://<host>:<port>/api/idp`
-
-**Common headers**
-
-| Header | Value |
-|----------------|----------------------------------------------|
-| `Accept` | `application/vnd.gravitino.v1+json` |
-| `Content-Type` | `application/json` (for POST and PUT bodies) |
-
-Example:
-
-```shell
-curl -s -H "Accept: application/vnd.gravitino.v1+json" \
- -H "Authorization: Basic $(echo -n 'admin:Passw0rd-Admin12' | base64)" \
- http://localhost:8090/api/idp/users/alice
-```
-
-### Password and username rules
-
-Password rules apply to add-user, change-password, and
`GRAVITINO_INITIAL_ADMIN_PASSWORD`:
-
-| Rule | Value |
-|-----------------|------------------------------------|
-| Username | Required; must **not** contain `:` |
-| Password length | 12–64 characters (inclusive) |
-
-Password reset is **admin-only** (request body has `password` only; no
`oldPassword`).
-
-### User operations
-
-#### Get a user
-
-`GET /api/idp/users/{user}`
-
-```shell
-curl -s -H "Accept: application/vnd.gravitino.v1+json" \
- -H "Authorization: Basic $(echo -n 'admin:Passw0rd-Admin12' | base64)" \
- http://localhost:8090/api/idp/users/alice
-```
-
-#### Add a user
-
-`POST /api/idp/users`
-
-The request body uses field `user` (not `name`):
-
-```shell
-curl -s -X POST -H "Accept: application/vnd.gravitino.v1+json" \
- -H "Content-Type: application/json" \
- -H "Authorization: Basic $(echo -n 'admin:Passw0rd-Admin12' | base64)" \
- -d '{"user":"alice","password":"Passw0rd-Alice"}' \
- http://localhost:8090/api/idp/users
-```
-
-#### Change a user password
-
-`PUT /api/idp/users/{user}`
-
-Administrator reset only:
-
-```shell
-curl -s -X PUT -H "Accept: application/vnd.gravitino.v1+json" \
- -H "Content-Type: application/json" \
- -H "Authorization: Basic $(echo -n 'admin:Passw0rd-Admin12' | base64)" \
- -d '{"password":"Passw0rd-Alice-V2"}' \
- http://localhost:8090/api/idp/users/alice
-```
-
-#### Remove a user
-
-`DELETE /api/idp/users/{user}`
-
-```shell
-curl -s -X DELETE -H "Accept: application/vnd.gravitino.v1+json" \
- -H "Authorization: Basic $(echo -n 'admin:Passw0rd-Admin12' | base64)" \
- http://localhost:8090/api/idp/users/alice
-```
-
-### Group operations
-
-#### Get a group
-
-`GET /api/idp/groups/{group}`
-
-```shell
-curl -s -H "Accept: application/vnd.gravitino.v1+json" \
- -H "Authorization: Basic $(echo -n 'admin:Passw0rd-Admin12' | base64)" \
- http://localhost:8090/api/idp/groups/engineering
-```
-
-#### Add a group
-
-`POST /api/idp/groups`
-
-The request body uses field `group` (not `name`):
-
-```shell
-curl -s -X POST -H "Accept: application/vnd.gravitino.v1+json" \
- -H "Content-Type: application/json" \
- -H "Authorization: Basic $(echo -n 'admin:Passw0rd-Admin12' | base64)" \
- -d '{"group":"engineering"}' \
- http://localhost:8090/api/idp/groups
-```
-
-#### Remove a group
-
-`DELETE /api/idp/groups/{group}?force={true|false}`
-
-If the group still has members, deletion fails unless `force=true`.
-
-```shell
-curl -s -X DELETE -H "Accept: application/vnd.gravitino.v1+json" \
- -H "Authorization: Basic $(echo -n 'admin:Passw0rd-Admin12' | base64)" \
- 'http://localhost:8090/api/idp/groups/engineering?force=true'
-```
-
-#### Change group membership
-
-`PUT /api/idp/groups/{group}/users`
-
-Add and/or remove members in one request. At least one of `usersToAdd` or
`usersToRemove` is required.
-
-```shell
-curl -s -X PUT -H "Accept: application/vnd.gravitino.v1+json" \
- -H "Content-Type: application/json" \
- -H "Authorization: Basic $(echo -n 'admin:Passw0rd-Admin12' | base64)" \
- -d '{"usersToAdd":["alice","bob"],"usersToRemove":["carol"]}' \
- http://localhost:8090/api/idp/groups/engineering/users
-```
-
-For full request and response definitions, see the [Built-in IDP
OpenAPI](../open-api/idp/openapi.yaml).
-
----
-
-## Engines using Basic authentication
-
-Configure Basic credentials on each engine connector. See
-[Spark
authentication](../spark-connector/spark-authentication-with-gravitino.md),
-[Flink
authentication](../flink-connector/flink-authentication-with-gravitino.md), and
-[Trino authentication](../trino-connector/authentication.md) for full
connector setup.
-
-### Spark
-
-```properties
-spark.sql.gravitino.authType=basic
-spark.sql.gravitino.basic.username=${username}
-spark.sql.gravitino.basic.password=${password}
-```
-
-### Flink
-
-```yaml
-table.catalog-store.gravitino.gravitino.client.auth.type: basic
-table.catalog-store.gravitino.gravitino.client.basic.username: ${username}
-table.catalog-store.gravitino.gravitino.client.basic.password: ${password}
-```
-
-### Trino
-
-In `etc/catalog/gravitino.properties`:
-
-```properties
-gravitino.client.authType=basic
-gravitino.client.basic.username=${username}
-gravitino.client.basic.password=${password}
-```
-
----
-
-## Engines using Basic authentication for Iceberg REST catalog
-
-Connect Spark, Flink, and Trino directly to the Gravitino Iceberg REST (IRC)
endpoint at
-`http://<gravitino-host>:9001/iceberg/`. No Gravitino engine connector plugin
is required.
-Configure only the Basic auth properties below. See
-[Connect Spark via Iceberg REST](../iceberg-rest-engine/spark.md),
-[Connect Flink via Iceberg REST](../iceberg-rest-engine/flink.md), and
-[Connect Trino via Iceberg REST](../iceberg-rest-engine/trino.md) for full IRC
setup.
-
-### Spark
-
-```properties
-spark.sql.catalog.<catalog-name>.rest.auth.type=basic
-spark.sql.catalog.<catalog-name>.rest.auth.basic.username=${username}
-spark.sql.catalog.<catalog-name>.rest.auth.basic.password=${password}
-```
-
-### Flink
-
-```sql
-'rest.auth.type' = 'basic',
-'rest.auth.basic.username' = '${username}',
-'rest.auth.basic.password' = '${password}'
-```
-
-### Trino
-
-Requires Trino **481+**. Trino has no native Basic mode for Iceberg REST; pass
-`Authorization` via HTTP headers.
-
-Generate Base64 once:
-
-```shell
-echo -n '${username}:${password}' | base64
-```
-
-In `etc/catalog/<catalog-name>.properties`:
-
-```properties
-iceberg.rest-catalog.http-headers=Authorization: Basic <base64-credentials>
-```
-
-Replace `<base64-credentials>` with the output of `echo -n
'${username}:${password}' | base64`.
-
----
-
-## End-to-end setup
-
-The following steps provision Gravitino and engines so a named user can
connect with Basic
-credentials. The examples use service admin `admin` / `Passw0rd-Admin12`,
engine user
-`alice` / `Passw0rd-Alice12`, metalake `example`, and Gravitino at
`http://localhost:8090`.
-Replace these with values that match your deployment.
-
-### 1. Admin initialization
-
-1. Append the following to `gravitino.conf` (see also
[Prerequisites](#prerequisites) and
- [Configuration](#configuration)):
-
- ```properties
- gravitino.authenticators = basic
- gravitino.server.rest.extensionPackages =
org.apache.gravitino.idp.web.rest.feature
- gravitino.authorization.enable = true
- gravitino.authorization.serviceAdmins = admin
- ```
-
- Built-in IdP is **incompatible** with the `simple` authenticator (the
default),
- `gravitino.authenticators` must include `basic` and must not include
`simple`.
-
-2. Before the first start, set the initial service admin password (see
- [password rules](#password-and-username-rules)):
-
- ```shell
- export GRAVITINO_INITIAL_ADMIN_PASSWORD='Passw0rd-Admin12'
- ```
-
-3. Start Gravitino and verify the service admin can call the API:
-
- ```shell
- curl -s -H "Accept: application/vnd.gravitino.v1+json" \
- -H "Authorization: Basic $(echo -n 'admin:Passw0rd-Admin12' | base64)" \
- http://localhost:8090/api/version
- ```
-
-### 2. Create users
-
-Create a built-in IdP user for each engine or operator account. Service admins
call
-`/api/idp/users` (see [Add a user](#add-a-user)):
-
-```shell
-curl -s -X POST -H "Accept: application/vnd.gravitino.v1+json" \
- -H "Content-Type: application/json" \
- -H "Authorization: Basic $(echo -n 'admin:Passw0rd-Admin12' | base64)" \
- -d '{"user":"alice","password":"Passw0rd-Alice12"}' \
- http://localhost:8090/api/idp/users
-```
-
-### 3. Create a metalake
-
-Create a metalake with a service admin account. When authorization is enabled,
only service admins
-can create metalakes (see [Access control](access-control.md)). See also
-[Manage metalakes](../manage-metalake-using-gravitino.md#create-a-metalake).
-
-```shell
-curl -s -X POST -H "Accept: application/vnd.gravitino.v1+json" \
- -H "Content-Type: application/json" \
- -H "Authorization: Basic $(echo -n 'admin:Passw0rd-Admin12' | base64)" \
- -d '{"name":"example","comment":"Basic auth example","properties":{}}' \
- http://localhost:8090/api/metalakes
-```
-
-Create catalogs in this metalake before engines can query data. See
-[Manage relational metadata](../manage-relational-metadata-using-gravitino.md).
-
-### 4. Add users to the metalake
-
-Register the engine user in the metalake authorization namespace (see
-[Add a user](access-control.md#add-a-user)). The username must match a
built-in IdP user created in
-step 2:
-
-```shell
-curl -s -X POST -H "Accept: application/vnd.gravitino.v1+json" \
- -H "Content-Type: application/json" \
- -H "Authorization: Basic $(echo -n 'admin:Passw0rd-Admin12' | base64)" \
- -d '{"name":"alice"}' \
- http://localhost:8090/api/metalakes/example/users
-```
-
-Grant roles or ownership as needed so the user can access catalogs and
metadata. See
-[Access control](access-control.md).
-
-### 5. Configure engines to use Basic authentication
-
-Configure each engine with `http://localhost:8090`, metalake `example`, and
user `alice` /
-`Passw0rd-Alice12` from step 2. Deploy the Gravitino connector for each engine
first; see
-[Spark
authentication](../spark-connector/spark-authentication-with-gravitino.md),
-[Flink
authentication](../flink-connector/flink-authentication-with-gravitino.md), and
-[Trino authentication](../trino-connector/authentication.md).
-
-#### Spark
-
-```shell
-$SPARK_HOME/bin/spark-sql \
- --conf
spark.plugins=org.apache.gravitino.spark.connector.plugin.GravitinoSparkPlugin \
- --conf spark.sql.gravitino.uri=http://localhost:8090 \
- --conf spark.sql.gravitino.metalake=example \
- --conf spark.sql.gravitino.authType=basic \
- --conf spark.sql.gravitino.basic.username=alice \
- --conf spark.sql.gravitino.basic.password=Passw0rd-Alice12 \
- -e "SHOW CATALOGS;"
-```
-
-#### Flink
-
-```shell
-$FLINK_HOME/bin/sql-client.sh \
- -D table.catalog-store.kind=gravitino \
- -D table.catalog-store.gravitino.gravitino.uri=http://localhost:8090 \
- -D table.catalog-store.gravitino.gravitino.metalake=example \
- -D table.catalog-store.gravitino.gravitino.client.auth.type=basic \
- -D table.catalog-store.gravitino.gravitino.client.basic.username=alice \
- -D
table.catalog-store.gravitino.gravitino.client.basic.password=Passw0rd-Alice12
-```
-
-#### Trino
-
-Create `etc/catalog/gravitino.properties`:
-
-```properties
-connector.name=gravitino
-gravitino.uri=http://localhost:8090
-gravitino.metalake=example
-gravitino.client.authType=basic
-gravitino.client.basic.username=alice
-gravitino.client.basic.password=Passw0rd-Alice12
-```
-
-Set `catalog.management=dynamic` in `etc/config.properties`, restart Trino,
then verify:
-
-```shell
-$TRINO_HOME/bin/launcher restart
-java -jar trino-cli.jar --server http://localhost:8080 --user alice \
- --execute "SHOW CATALOGS"
-```
-
-### 6. Access Iceberg REST catalog with Basic authentication
-
-Connect engines directly to `http://localhost:9001/iceberg`. No Gravitino
connector plugin is
-required. Use user `alice` / `Passw0rd-Alice12` from step 2. See
-[Connect Spark via Iceberg REST](../iceberg-rest-engine/spark.md),
-[Connect Flink via Iceberg REST](../iceberg-rest-engine/flink.md), and
-[Connect Trino via Iceberg REST](../iceberg-rest-engine/trino.md) for full IRC
setup.
-
-#### Spark
-
-```shell
-$SPARK_HOME/bin/spark-sql \
- --conf
spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions
\
- --conf spark.sql.catalog.gravitino_irc=org.apache.iceberg.spark.SparkCatalog
\
- --conf spark.sql.catalog.gravitino_irc.type=rest \
- --conf spark.sql.catalog.gravitino_irc.uri=http://localhost:9001/iceberg \
- --conf spark.sql.catalog.gravitino_irc.rest.auth.type=basic \
- --conf spark.sql.catalog.gravitino_irc.rest.auth.basic.username=alice \
- --conf
spark.sql.catalog.gravitino_irc.rest.auth.basic.password=Passw0rd-Alice12 \
- -e "SHOW NAMESPACES IN gravitino_irc;"
-```
-
-#### Flink
-
-```shell
-cat > /tmp/flink-irc.sql <<'EOF'
-CREATE CATALOG gravitino_irc WITH (
- 'type' = 'iceberg',
- 'catalog-type' = 'rest',
- 'uri' = 'http://localhost:9001/iceberg',
- 'rest.auth.type' = 'basic',
- 'rest.auth.basic.username' = 'alice',
- 'rest.auth.basic.password' = 'Passw0rd-Alice12'
-);
-USE CATALOG gravitino_irc;
-SHOW DATABASES;
-EOF
-
-$FLINK_HOME/bin/sql-client.sh -f /tmp/flink-irc.sql
-```
-
-#### Trino
-
-Requires Trino **481+**. Trino has no native Basic mode for Iceberg REST; pass
`Authorization`
-via HTTP headers.
-
-```shell
-echo -n 'alice:Passw0rd-Alice12' | base64
-```
-
-Create `etc/catalog/gravitino_irc.properties`:
-
-```properties
-connector.name=iceberg
-iceberg.catalog.type=rest
-iceberg.rest-catalog.uri=http://localhost:9001/iceberg
-iceberg.rest-catalog.http-headers=Authorization: Basic
YWxpc2U6UGFzc3cwcmQtQWxpY2UxMg==
-```
-
-Restart Trino and verify:
-
-```shell
-$TRINO_HOME/bin/launcher restart
-java -jar trino-cli.jar --server http://localhost:8080 --user alice \
- --execute "SHOW SCHEMAS FROM gravitino_irc"
-```
-
----
-
-## Further reading
-
-- [Built-in IDP OpenAPI](../open-api/idp/openapi.yaml) — API paths, bodies,
and schemas
-- [How to use HTTPS](how-to-use-https.md) — transport security for credentials
diff --git a/docs/security/how-to-use-cors.md b/docs/security/how-to-use-cors.md
index 724228989c..7436affba1 100644
--- a/docs/security/how-to-use-cors.md
+++ b/docs/security/how-to-use-cors.md
@@ -1,38 +1,48 @@
---
title: "CORS"
slug: "/security/how-to-use-cors"
-keyword: "security cors"
+keywords:
+ - security
+ - cors
license: "This software is licensed under the Apache License version 2."
---
-## Introduction
-
-Cross-Origin Resource Sharing (CORS) is a browser security mechanism that
controls which web origins can call the Gravitino HTTP API. Without CORS
configuration, browsers block requests from a web UI hosted on a different
origin than the Gravitino server. Configure CORS when the Gravitino web UI or
any other browser-based client runs on a different host, port, or protocol than
the server.
-
-## Server Configuration
-
-| Configuration item | Description
| Default value | Required
|
-|----------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------|----------|
-| `gravitino.server.webserver.enableCorsFilter` | Enable cross-origin
resource share filter.
| false | No
|
-| `gravitino.server.webserver.allowedOrigins` | A comma separated list
of allowed origins to access the resources. The default value is *, which means
all origins.
| `*` | No
|
-| `gravitino.server.webserver.allowedTimingOrigins` | A comma separated list
of allowed origins to time the resource. The default value is the empty string,
which means no origins.
| ''(empty string) | No
|
-| `gravitino.server.webserver.allowedMethods` | A comma separated list
of allowed HTTP methods used when accessing the resources. The default values
are GET, POST, HEAD, and DELETE.
| `GET,POST,HEAD,DELETE,PUT` | No
|
-| `gravitino.server.webserver.allowedHeaders` | A comma separated list
of allowed HTTP headers specified when accessing the resources. The default
value is X-Requested-With,Content-Type,Accept,Origin. If the value is a single
*, it accepts all headers. | `X-Requested-With,Content-Type,Accept,Origin` | No
|
-| `gravitino.server.webserver.preflightMaxAgeInSecs` | The number of seconds
to cache preflight requests by the client. The default value is 1800 seconds or
30 minutes.
| `1800` | No
|
-| `gravitino.server.webserver.allowCredentials` | A boolean indicating if
the resource allows requests with credentials. The default value is true.
| `true` | No
|
-| `gravitino.server.webserver.exposedHeaders` | A comma separated list
of allowed HTTP headers exposed on the client. The default value is the empty
list.
| ''(empty string) | No
|
-| `gravitino.server.webserver.chainPreflight` | If true chained
preflight requests for normal handling (as an OPTION request). Otherwise, the
filter responds to the preflight. The default is true.
| `true`
| No |
-
-## Apache Iceberg REST Service Configuration
-
-| Configuration item | Description
| Default value | Required |
-|------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------|----------|
-| `gravitino.iceberg-rest.enableCorsFilter` | Enable cross-origin
resource share filter.
| false | No
|
-| `gravitino.iceberg-rest.allowedOrigins` | A comma separated list of
allowed origins that access the resources. The default value is *, which means
all origins.
| `*` | No |
-| `gravitino.iceberg-rest.allowedTimingOrigins` | A comma separated list of
allowed origins that time the resource. The default value is the empty string,
which means no origins.
| ''(empty string) | No |
-| `gravitino.iceberg-rest.allowedMethods` | A comma separated list of
allowed HTTP methods used when accessing the resources. The default values are
GET, POST, HEAD, and DELETE.
| `GET,POST,HEAD,DELETE,PUT` | No |
-| `gravitino.iceberg-rest.allowedHeaders` | A comma separated list of
HTTP allowed headers specified when accessing the resources. The default value
is X-Requested-With,Content-Type,Accept,Origin. If the value is a single *, it
accepts all headers. | `X-Requested-With,Content-Type,Accept,Origin` | No
|
-| `gravitino.iceberg-rest.preflightMaxAgeInSecs` | The number of seconds to
cache preflight requests by the client. The default value is 1800 seconds or 30
minutes.
| `1800` | No |
-| `gravitino.iceberg-rest.allowCredentials` | A boolean indicating if the
resource allows requests with credentials. The default value is true.
| `true` | No |
-| `gravitino.iceberg-rest.exposedHeaders` | A comma separated list of
allowed HTTP headers exposed on the client. The default value is the empty
list.
| ''(empty string) | No
|
-| `gravitino.iceberg-rest.chainPreflight` | If true chained preflight
requests for normal handling (as an OPTION request). Otherwise, the filter
responds to the preflight. The default is true.
| `true` | No
|
+## Overview
+
+Cross-Origin Resource Sharing is a browser mechanism that controls which web
origins may call an HTTP API. A browser blocks a request from a page whose
origin differs from the server's in host, port, or protocol unless the server
says otherwise, so any browser-based client hosted separately from Gravitino
needs the CORS filter enabled.
+
+The filter is off by default and applies only to browsers. Requests from
engines, the CLI, and other server-side clients are unaffected either way.
+
+## Configuration
+
+The Gravitino server and the Iceberg REST service each have their own CORS
filter, configured with the same property names under different prefixes. Use
`gravitino.server.webserver.` for the Gravitino server and
`gravitino.iceberg-rest.` for the Iceberg REST service, and set each one only
for the service that needs it.
+
+| Property Name | Description
| Default Value
|
+|-------------------------|---------------------------------------------------------------------------------------------|-----------------------------------------------|
+| `enableCorsFilter` | Enables the CORS filter
| `false`
|
+| `allowedOrigins` | Comma-separated origins allowed to access the
resources, or `*` for all | `*`
|
+| `allowedTimingOrigins` | Comma-separated origins allowed to time the
resources. Empty means none | (empty)
|
+| `allowedMethods` | Comma-separated HTTP methods allowed when
accessing the resources | `GET,POST,HEAD,DELETE,PUT`
|
+| `allowedHeaders` | Comma-separated request headers allowed, or a
single `*` to accept any header |
`X-Requested-With,Content-Type,Accept,Origin` |
+| `exposedHeaders` | Comma-separated response headers made readable to
the client. Empty means none | (empty)
|
+| `preflightMaxAgeInSecs` | How long a client may cache a preflight response
| `1800`
|
+| `allowCredentials` | Whether requests carrying credentials are allowed
| `true`
|
+| `chainPreflight` | Passes preflight requests to the target resource
as an `OPTIONS` request instead of answering them in the filter | `true`
|
+
+### Origins and Credentials
+
+The two defaults do not work together. Browsers reject a response that allows
credentials while allowing every origin, so leaving `allowedOrigins` at `*`
with `allowCredentials` at `true` means any authenticated browser request fails
even though the filter is enabled.
+
+List the origins your clients actually use instead. A wildcard origin is only
usable when `allowCredentials` is `false`, which rules out any request carrying
a token or a cookie.
+
+### Example
+
+A web UI served from `https://console.example.com` calling a Gravitino server
elsewhere needs the following in `gravitino.conf`.
+
+```properties
+gravitino.server.webserver.enableCorsFilter = true
+gravitino.server.webserver.allowedOrigins = https://console.example.com
+gravitino.server.webserver.allowedHeaders =
X-Requested-With,Content-Type,Accept,Origin,Authorization
+```
+
+`Authorization` is added because the default header list omits it, and a
browser sending a bearer token names that header in its preflight request.
diff --git a/docs/security/how-to-use-https.md
b/docs/security/how-to-use-https.md
index b5e36e541d..3be70815fa 100644
--- a/docs/security/how-to-use-https.md
+++ b/docs/security/how-to-use-https.md
@@ -1,102 +1,83 @@
---
title: "HTTPS"
slug: "/security/how-to-use-https"
-keyword: "security HTTPS protocol"
+keywords:
+ - security
+ - https
+ - tls
license: "This software is licensed under the Apache License version 2."
---
-## Introduction
+## Overview
-For users choosing OAuth 2.0 as the authentication method, it is recommended
to use HTTPS instead of HTTP. HTTPS encrypts the request headers, offering
better protection against smuggling attacks.
+HTTPS encrypts request headers, which matters most when those headers carry
credentials. Any deployment using OAuth 2.0 or [local users and
groups](local-users-and-groups.md) should enable it, since both put a token or
a password in a header on every request.
-Note that Gravitino cannot simultaneously support both HTTP and HTTPS within a
single server instance. If HTTPS is enabled, Gravitino will no longer provide
HTTP service.
+A server instance serves one protocol. Enabling HTTPS stops the plain HTTP
listener rather than adding to it, so clients configured against the HTTP port
need updating at the same time.
-Both the Gravitino server and Iceberg REST service can configure and support
HTTPS.
+## Configuration
-### Apache Gravitino Server Configuration
+The Gravitino server and the Iceberg REST service are configured separately
with the same property names under different prefixes. Use
`gravitino.server.webserver.` for the Gravitino server and
`gravitino.iceberg-rest.` for the Iceberg REST service.
-| Configuration item | Description
| Default value | Required
|
-|-----------------------------------------------------|--------------------------------------------------------------------|-------------------|---------------------------------------------------|
-| `gravitino.server.webserver.enableHttps` | Enables HTTPS.
| `false` | No
|
-| `gravitino.server.webserver.httpsPort` | The HTTPS port number
of the Jetty web server. | `8433` | No
|
-| `gravitino.server.webserver.keyStorePath` | Path to the key store
file. | (none) | Yes if use
HTTPS |
-| `gravitino.server.webserver.keyStorePassword` | Password to the key
store. | (none) | Yes if use
HTTPS |
-| `gravitino.server.webserver.keyStoreType` | The type to the key
store. | `JKS` | No
|
-| `gravitino.server.webserver.managerPassword` | Manager password to
the key store. | (none) | Yes if use
HTTPS |
-| `gravitino.server.webserver.tlsProtocol` | TLS protocol to use.
The JVM must support the TLS protocol to use. | (none) | No
|
-| `gravitino.server.webserver.enableCipherAlgorithms` | The collection of
enabled cipher algorithms. | '' (empty string) | No
|
-| `gravitino.server.webserver.enableClientAuth` | Enables the
authentication of the client. | `false` | No
|
-| `gravitino.server.webserver.trustStorePath` | Path to the trust
store file. | (none) | Yes if
use HTTPS and the authentication of client |
-| `gravitino.server.webserver.trustStorePassword` | Password to the trust
store. | (none) | Yes if use
HTTPS and the authentication of client |
-| `gravitino.server.webserver.trustStoreType` | The type to the trust
store. | `JKS` | No
|
+| Property Name | Description |
Default Value | Required |
+|---------------------------|------------------------------------------------|---------------|--------------------------------|
+| `enableHttps` | Enables HTTPS |
`false` | No |
+| `httpsPort` | HTTPS port for the Jetty web server |
`8433` and `9433` | No |
+| `keyStorePath` | Path to the key store file |
(none) | Yes |
+| `keyStorePassword` | Password for the key store |
(none) | Yes |
+| `managerPassword` | Manager password for the key store |
(none) | Yes |
+| `keyStoreType` | Key store type |
`JKS` | No |
+| `tlsProtocol` | TLS protocol to use, which the JVM must support|
(none) | No |
+| `enableCipherAlgorithms` | Cipher algorithms to enable |
(empty) | No |
+| `enableClientAuth` | Requires clients to authenticate with a
certificate | `false` | No |
+| `trustStorePath` | Path to the trust store file |
(none) | Yes with client authentication |
+| `trustStorePassword` | Password for the trust store |
(none) | Yes with client authentication |
+| `trustStoreType` | Trust store type |
`JKS` | No |
-### Apache Iceberg REST Service Configuration
+The default HTTPS port is `8433` for the Gravitino server and `9433` for the
Iceberg REST service. Everything in the Required column applies once
`enableHttps` is `true`.
-| Configuration item | Description
| Default value | Required
|
-|-------------------------------------------------|--------------------------------------------------------------------|-------------------|---------------------------------------------------|
-| `gravitino.iceberg-rest.enableHttps` | Enables HTTPS.
| `false` | No
|
-| `gravitino.iceberg-rest.httpsPort` | The HTTPS port number of
the Jetty web server. | `9433` | No
|
-| `gravitino.iceberg-rest.keyStorePath` | Path to the key store
file. | (none) | Yes if use
HTTPS |
-| `gravitino.iceberg-rest.keyStorePassword` | Password to the key store.
| (none) | Yes if use HTTPS
|
-| `gravitino.iceberg-rest.keyStoreType` | The type to the key store.
| `JKS` | No
|
-| `gravitino.iceberg-rest.managerPassword` | Manager password to the
key store. | (none) | Yes if use
HTTPS |
-| `gravitino.iceberg-rest.tlsProtocol` | TLS protocol to use. The
JVM must support the TLS protocol to use. | (none) | No
|
-| `gravitino.iceberg-rest.enableCipherAlgorithms` | The collection of enabled
cipher algorithms. | '' (empty string) | No
|
-| `gravitino.iceberg-rest.enableClientAuth` | Enables the authentication
of the client. | `false` | No
|
-| `gravitino.iceberg-rest.trustStorePath` | Path to the trust store
file. | (none) | Yes if use
HTTPS and the authentication of client |
-| `gravitino.iceberg-rest.trustStorePassword` | Password to the trust
store. | (none) | Yes if use
HTTPS and the authentication of client |
-| `gravitino.iceberg-rest.trustStoreType` | The type to the trust
store. | `JKS` | No
|
+For the values `tlsProtocol` and `enableCipherAlgorithms` accept, see the
"Additional JSSE Standard Names" section of the Java security guide, under
[protocols](https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#jssenames)
and [cipher
suites](https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#ciphersuites)
respectively.
-Refer to the "Additional JSSE Standard Names" section of the [Java security
guide](https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#jssenames)
for the list of protocols related to tlsProtocol. You can find the list of
`tlsProtocol` values for Java 8 in this document.
+## Local Development Example
-Refer to the "Additional JSSE Standard Names" section of the [Java security
guide](https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#ciphersuites)
for the list of protocols related to tlsProtocol. You can find the list of
`enableCipherAlgorithms` values for Java 8 in this document.
+The following produces a self-signed certificate so you can exercise an HTTPS
endpoint on one machine. It is not a production setup, since a self-signed
certificate trusted by editing a JVM trust store is not how certificates are
managed in a real deployment.
-### Example
-
-Follow these steps to set up an HTTPS server:
-
-1. Prerequisite
- - You need to install the JDK8, wget, and set the environment JAVA_HOME.
- - If you want to use the command `curl` to request the Gravitino server,
you should install openSSL.
-2. Generate the key store
+**1. Generate a key store.**
```shell
cd $JAVA_HOME
-bin/keytool -genkeypair -alias localhost \
--keyalg RSA -keysize 4096 -keypass localhost \
--sigalg SHA256withRSA \
--keystore localhost.jks -storetype JKS -storepass localhost \
--dname "cn=localhost,ou=localhost,o=localhost,l=beijing,st=beijing,c=cn" \
--validity 36500
+bin/keytool -genkeypair -alias localhost \
+ -keyalg RSA -keysize 4096 -keypass {key_password} \
+ -sigalg SHA256withRSA \
+ -keystore localhost.jks -storetype JKS -storepass {store_password} \
+ -dname "cn=localhost,ou=localhost,o=localhost,l=beijing,st=beijing,c=cn" \
+ -validity 36500
```
-3. Generate the certificate
+**2. Export the certificate.**
```shell
-bin/keytool -export -alias localhost -keystore localhost.jks -file
localhost.crt -storepass localhost
+bin/keytool -export -alias localhost -keystore localhost.jks \
+ -file localhost.crt -storepass {store_password}
```
-4. Import the certificate
+**3. Import it into the JVM trust store** so a local Java client will accept
it.
```shell
-bin/keytool -import -alias localhost -keystore jre/lib/security/cacerts -file
localhost.crt -storepass changeit -noprompt
+bin/keytool -import -alias localhost -keystore jre/lib/security/cacerts \
+ -file localhost.crt -storepass changeit -noprompt
```
-5. Refer to the [Configurations](../gravitino-server-config.md) and append the
configuration to the conf/gravitino.conf.
- Configuration doesn't support resolving environment variables, so you
should replace `${JAVA_HOME}` with the actual value.
- Then, You can start the Gravitino server.
+**4. Configure the server.** Append the following to `conf/gravitino.conf`,
then start Gravitino. Configuration files do not resolve environment variables,
so write the expanded path rather than `${JAVA_HOME}`.
-```text
+```properties
gravitino.server.webserver.host = localhost
gravitino.server.webserver.enableHttps = true
-gravitino.server.webserver.keyStorePath = ${JAVA_HOME}/localhost.jks
-gravitino.server.webserver.keyStorePassword = localhost
-gravitino.server.webserver.managerPassword = localhost
+gravitino.server.webserver.keyStorePath = {java_home}/localhost.jks
+gravitino.server.webserver.keyStorePassword = {store_password}
+gravitino.server.webserver.managerPassword = {key_password}
```
-6. Request the Gravitino server
-
-- If you use Java, you can copy the code below to a file named Main.java
+**5. Connect.** From Java, the client takes the HTTPS URI directly:
```java
import org.apache.gravitino.client.GravitinoClient;
@@ -112,9 +93,16 @@ public class Main {
}
```
-- If you want to use the command `curl`, you can follow the commands:
+From `curl`, convert the certificate to PEM first:
```shell
openssl x509 -inform der -in $JAVA_HOME/localhost.crt -out certificate.pem
-curl -v -X GET --cacert ./certificate.pem -H "Accept:
application/vnd.gravitino.v1+json" -H "Content-Type: application/json"
https://localhost:8433/api/version
+curl -v -X GET --cacert ./certificate.pem \
+ -H "Accept: application/vnd.gravitino.v1+json" \
+ https://localhost:8433/api/version
```
+
+## Further Reading
+
+- [Configurations](../gravitino-server-config.md) for the rest of the web
server settings
+- [How to Authenticate](how-to-authenticate.md) for the authentication methods
HTTPS protects
diff --git a/docs/security/local-users-and-groups.md
b/docs/security/local-users-and-groups.md
new file mode 100644
index 0000000000..069ab8d31d
--- /dev/null
+++ b/docs/security/local-users-and-groups.md
@@ -0,0 +1,197 @@
+---
+title: "Local Users and Groups"
+slug: "/security/local-users-and-groups"
+keywords:
+ - security
+ - authentication
+ - basic authentication
+license: "This software is licensed under the Apache License version 2."
+---
+
+## Overview
+
+Apache Gravitino can store login identities in its own relational metadata
store through the `idp-basic` plugin. Usernames, password hashes, and group
membership live alongside the rest of the server's metadata, and clients
authenticate with HTTP Basic credentials. Nothing outside Gravitino is required.
+
+The local user store authenticates callers to Gravitino. It does not issue
tokens or assertions that other services can consume, so it is not a single
sign-on system and not a replacement for Okta, Microsoft Entra ID, or Keycloak.
Use it for proofs of concept, offline installations, and isolated deployments
where a self-contained identity store is acceptable. For anything else, see
[How to Authenticate](how-to-authenticate.md).
+
+Credentials travel in an HTTP header on every request, so run the server
behind [HTTPS](how-to-use-https.md) wherever the network is not fully trusted.
+
+The management endpoints are served under `/api/idp/`, which reflects the
plugin's original name rather than the feature's scope. For request and
response schemas, see the [OpenAPI definition](../open-api/idp/openapi.yaml).
+
+## Quick Start
+
+**1. Configure the server.** Add the following to `gravitino.conf`. Both
properties are required, since the `basic` authenticator refuses to start
without the REST extension package registered.
+
+```properties
+gravitino.authenticators = basic
+gravitino.server.rest.extensionPackages =
org.apache.gravitino.idp.web.rest.feature
+gravitino.authorization.serviceAdmins = admin
+```
+
+**2. Set the initial administrator password.** Every username in
`gravitino.authorization.serviceAdmins` needs a stored password before it can
call the management endpoints. Set this before the first start.
+
+```shell
+export GRAVITINO_INITIAL_ADMIN_PASSWORD='{admin_password}'
+```
+
+**3. Start Gravitino and confirm the administrator works.**
+
+```shell
+curl -s -H "Accept: application/vnd.gravitino.v1+json" \
+ -H "Authorization: Basic $(echo -n 'admin:{admin_password}' | base64)" \
+ http://localhost:8090/api/version
+```
+
+**4. Create a user.**
+
+```shell
+curl -s -X POST -H "Accept: application/vnd.gravitino.v1+json" \
+ -H "Content-Type: application/json" \
+ -H "Authorization: Basic $(echo -n 'admin:{admin_password}' | base64)" \
+ -d '{"user":"alice","password":"{user_password}"}' \
+ http://localhost:8090/api/idp/users
+```
+
+## Configuration
+
+| Configuration Item | Description
| Example |
+|-------------------------------------------|-------------------------------------------------------------------|---------------------------------------------|
+| `gravitino.authenticators` | Must be `basic`, and must not
include `simple` | `basic`
|
+| `gravitino.server.rest.extensionPackages` | Registers the user and group
management endpoints |
`org.apache.gravitino.idp.web.rest.feature` |
+| `gravitino.authorization.serviceAdmins` | Comma-separated usernames
allowed to manage users and groups | `admin`
|
+
+The local user store is incompatible with the `simple` authenticator, which is
the server default and accepts the username a client supplies without checking
a password. Both authenticators claim the same `Basic` authorization header,
and the server uses the first one listed that claims it, so listing `simple`
ahead of `basic` means passwords are never checked. Replace `simple` rather
than adding to it.
+
+The Web UI reads `gravitino.authenticators` from the server and presents a
username and password form when `basic` is the active authenticator.
+
+### Password and Username Rules
+
+These rules apply to user creation, password changes, and
`GRAVITINO_INITIAL_ADMIN_PASSWORD` alike.
+
+| Rule | Value |
+|-----------------|-------------------------------------------|
+| Username | Required, and must not contain a colon |
+| Password length | 12 to 64 characters inclusive |
+
+Passwords are reset by an administrator rather than changed by the user, so a
password change request carries the new password only and no current password.
+
+## Managing Users and Groups
+
+All management endpoints are under `http://{host}:{port}/api/idp` and require
Basic authentication as a service admin. Send `Accept:
application/vnd.gravitino.v1+json` on every request, and `Content-Type:
application/json` on requests with a body.
+
+### User Operations
+
+| Operation | Method | Path | Body
|
+|-----------------|--------|--------------------------|---------------------------------------------|
+| Get a user | GET | `/api/idp/users/{user}` | None
|
+| Add a user | POST | `/api/idp/users` |
`{"user":"alice","password":"{password}"}` |
+| Reset a password| PUT | `/api/idp/users/{user}` |
`{"password":"{new_password}"}` |
+| Remove a user | DELETE | `/api/idp/users/{user}` | None
|
+
+The add-user body uses the field name `user` rather than `name`.
+
+```shell
+curl -s -X POST -H "Accept: application/vnd.gravitino.v1+json" \
+ -H "Content-Type: application/json" \
+ -H "Authorization: Basic $(echo -n 'admin:{admin_password}' | base64)" \
+ -d '{"user":"alice","password":"{user_password}"}' \
+ http://localhost:8090/api/idp/users
+```
+
+### Group Operations
+
+| Operation | Method | Path
| Body |
+|--------------------------|--------|---------------------------------------------|------------------------------------------------------------|
+| Get a group | GET | `/api/idp/groups/{group}`
| None |
+| Add a group | POST | `/api/idp/groups`
| `{"group":"engineering"}` |
+| Remove a group | DELETE | `/api/idp/groups/{group}?force={true
false}`| None |
+| Change group membership | PUT | `/api/idp/groups/{group}/users`
| `{"usersToAdd":["alice"],"usersToRemove":["carol"]}` |
+
+The add-group body uses the field name `group` rather than `name`. Removing a
group that still has members fails unless `force=true`. A membership change
requires at least one of `usersToAdd` or `usersToRemove`, and accepts both in a
single request.
+
+```shell
+curl -s -X PUT -H "Accept: application/vnd.gravitino.v1+json" \
+ -H "Content-Type: application/json" \
+ -H "Authorization: Basic $(echo -n 'admin:{admin_password}' | base64)" \
+ -d '{"usersToAdd":["alice","bob"],"usersToRemove":["carol"]}' \
+ http://localhost:8090/api/idp/groups/engineering/users
+```
+
+## Granting Access to Metadata
+
+A local user can authenticate as soon as it exists, but it can only reach
metadata once it is registered in a metalake and granted privileges there. The
two are separate steps, and the username must match.
+
+```shell
+curl -s -X POST -H "Accept: application/vnd.gravitino.v1+json" \
+ -H "Content-Type: application/json" \
+ -H "Authorization: Basic $(echo -n 'admin:{admin_password}' | base64)" \
+ -d '{"name":"alice"}' \
+ http://localhost:8090/api/metalakes/{metalake}/users
+```
+
+When `gravitino.authorization.enable` is set to `true`, only service admins
can create metalakes. See [Access Control](access-control.md) for roles,
privileges, and ownership, and [Manage
Metalakes](../manage-metalake-using-gravitino.md#create-a-metalake) for
metalake creation.
+
+## Connecting Engines
+
+An engine reaches Gravitino by one of two paths, and each takes its own Basic
credentials.
+
+### Through the Gravitino Connector
+
+Configure the connector for each engine, then add the credentials below. See
[Spark
Authentication](../spark-connector/spark-authentication-with-gravitino.md),
[Flink
Authentication](../flink-connector/flink-authentication-with-gravitino.md), and
[Trino Authentication](../trino-connector/authentication.md) for the rest of
the connector setup.
+
+```properties
+# Spark
+spark.sql.gravitino.authType=basic
+spark.sql.gravitino.basic.username={username}
+spark.sql.gravitino.basic.password={password}
+```
+
+```yaml
+# Flink
+table.catalog-store.gravitino.gravitino.client.auth.type: basic
+table.catalog-store.gravitino.gravitino.client.basic.username: {username}
+table.catalog-store.gravitino.gravitino.client.basic.password: {password}
+```
+
+```properties
+# Trino, in etc/catalog/gravitino.properties
+gravitino.client.authType=basic
+gravitino.client.basic.username={username}
+gravitino.client.basic.password={password}
+```
+
+Trino also needs `catalog.management=dynamic` in `etc/config.properties` and a
restart before the catalogs appear.
+
+### Through the Iceberg REST Endpoint
+
+Engines can connect straight to the Iceberg REST service at
`http://{host}:9001/iceberg/` with no Gravitino connector plugin. See [Connect
Spark via Iceberg REST](../iceberg-rest-engine/spark.md), [Connect Flink via
Iceberg REST](../iceberg-rest-engine/flink.md), and [Connect Trino via Iceberg
REST](../iceberg-rest-engine/trino.md) for the rest of the setup.
+
+```properties
+# Spark
+spark.sql.catalog.{catalog}.rest.auth.type=basic
+spark.sql.catalog.{catalog}.rest.auth.basic.username={username}
+spark.sql.catalog.{catalog}.rest.auth.basic.password={password}
+```
+
+```sql
+-- Flink
+'rest.auth.type' = 'basic',
+'rest.auth.basic.username' = '{username}',
+'rest.auth.basic.password' = '{password}'
+```
+
+Trino has no native Basic mode for Iceberg REST and requires Trino 481 or
later, so the header is set directly. Generate the encoded credentials with
`echo -n '{username}:{password}' | base64`, then set:
+
+```properties
+# Trino, in etc/catalog/{catalog}.properties
+connector.name=iceberg
+iceberg.catalog.type=rest
+iceberg.rest-catalog.uri=http://localhost:9001/iceberg
+iceberg.rest-catalog.http-headers=Authorization: Basic {base64_credentials}
+```
+
+## Further Reading
+
+- [OpenAPI definition](../open-api/idp/openapi.yaml) for full request and
response schemas
+- [How to Use HTTPS](how-to-use-https.md) for protecting credentials in transit
+- [Access Control](access-control.md) for what an authenticated user is
allowed to do
diff --git a/docs/security/security.md b/docs/security/security.md
deleted file mode 100644
index c4d02963cc..0000000000
--- a/docs/security/security.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-title: "Security"
-slug: "/security/security"
-keyword: "security"
-license: "This software is licensed under the Apache License version 2."
----
-
-## Overview
-
-Gravitino provides features that ensure the highest levels of security for you.
-
-## Capabilities
-
-Gravitino has supported the following security features:
-
-### [Authorization Pushdown](./authorization-pushdown.md)
-
-### [Authentication](how-to-authenticate.md)
-
-### [Built-in IDP](how-to-use-built-in-idp.md)
-
-### [HTTPS](how-to-use-https.md)
-
-### [Access Control](access-control.md)
-
-### [Credential vending](credential-vending.md)
-
-### [CORS](how-to-use-cors.md)
diff --git a/docs/spark-connector/spark-authentication-with-gravitino.md
b/docs/spark-connector/spark-authentication-with-gravitino.md
index d5c6849d1c..1a1dff900b 100644
--- a/docs/spark-connector/spark-authentication-with-gravitino.md
+++ b/docs/spark-connector/spark-authentication-with-gravitino.md
@@ -23,14 +23,14 @@ In the simple mode, the username originates from Spark, and
is obtained using th
## Basic Mode
In Basic mode, the Spark connector authenticates to the Gravitino server using
HTTP Basic credentials
-against the built-in IDP. The Gravitino server must have Basic authentication
enabled. See
+against the local user store. The Gravitino server must have Basic
authentication enabled. See
[How to authenticate](../security/how-to-authenticate.md#basic-mode) for
server-side setup.
| Property | Type | Default Value | Description
| Required |
|------------------------------------|--------|---------------|------------------------------------------------|---------------------|
| spark.sql.gravitino.authType | string | `simple` | Set to `basic`
to enable Basic authentication. | Yes, for Basic mode |
-| spark.sql.gravitino.basic.username | string | (none) | The built-in
IDP username. | Yes, for Basic mode |
-| spark.sql.gravitino.basic.password | string | (none) | The built-in
IDP password. | Yes, for Basic mode |
+| spark.sql.gravitino.basic.username | string | (none) | Username in
the local user store. | Yes, for Basic mode |
+| spark.sql.gravitino.basic.password | string | (none) | Password for
that user. | Yes, for Basic mode |
### Basic Configuration Example
diff --git a/docs/trino-connector/authentication.md
b/docs/trino-connector/authentication.md
index 0818b20db3..5ec6de6018 100644
--- a/docs/trino-connector/authentication.md
+++ b/docs/trino-connector/authentication.md
@@ -36,7 +36,7 @@ gravitino.user=admin
### Basic Authentication
-Basic authentication uses HTTP Basic credentials against the Gravitino
built-in IDP. The Gravitino
+Basic authentication uses HTTP Basic credentials against the Gravitino local
user store. The Gravitino
server must have Basic authentication enabled. See
[How to authenticate](../security/how-to-authenticate.md#basic-mode) for
server-side setup.
@@ -47,7 +47,7 @@ connector.name=gravitino
gravitino.metalake=metalake
gravitino.uri=http://localhost:8090
-# Basic authentication with built-in IDP
+# Basic authentication with local user store
gravitino.client.authType=basic
gravitino.client.basic.username=admin
gravitino.client.basic.password=YourSecureGravitinoPassword
@@ -58,8 +58,8 @@ gravitino.client.basic.password=YourSecureGravitinoPassword
| Property | Description
| Default value | Required |
|-----------------------------------|-----------------------------------------------------------------|---------------|----------------------------|
| `gravitino.client.authType` | Authentication type: `simple`, `basic`,
`oauth2`, or `kerberos` | (none) | Yes (to enable Basic) |
-| `gravitino.client.basic.username` | Built-in IDP username
| (none) | Yes if authType is `basic` |
-| `gravitino.client.basic.password` | Built-in IDP password
| (none) | Yes if authType is `basic` |
+| `gravitino.client.basic.username` | Local user store username
| (none) | Yes if authType is `basic` |
+| `gravitino.client.basic.password` | Local user store password
| (none) | Yes if authType is `basic` |
### OAuth2 Authentication
@@ -184,5 +184,5 @@ gravitino.client.session.forwardUser=true
### See Also
- [Gravitino Server Authentication
Configuration](../security/how-to-authenticate.md)
-- [How to use the built-in IDP](../security/how-to-use-built-in-idp.md)
+- [Local users and groups](../security/local-users-and-groups.md)
- [Trino Connector Configuration](./configuration.md)
diff --git a/docs/webui-v2.md b/docs/webui-v2.md
index bc3fad8182..d45318725c 100644
--- a/docs/webui-v2.md
+++ b/docs/webui-v2.md
@@ -50,11 +50,11 @@ The Web V2 landing page depends on both the authentication
mode and whether auth

-- When `gravitino.authenticators=basic` and the built-in IdP extension package
is configured, the
- Web UI shows a username and password login form backed by built-in IdP user
metadata. See
- [built-in IDP Web UI](security/how-to-use-built-in-idp.md#web-ui).
+- When `gravitino.authenticators=basic` and the local user REST extension
package is registered, the
+ Web UI shows a username and password login form backed by local user
metadata. See
+ [Local users and groups](security/local-users-and-groups.md).
-- When `gravitino.authenticators=oauth`, OAuth configuration is required for
login. OAuth mode requires `gravitino.authorization.enable=true`. See the
details in [Security](security/security.md)
+- When `gravitino.authenticators=oauth`, OAuth configuration is required for
login. OAuth mode requires `gravitino.authorization.enable=true`. See the
details in [Security](security/how-to-authenticate.md)

diff --git a/docs/webui.md b/docs/webui.md
index 28da4d45d4..e9df9d419a 100644
--- a/docs/webui.md
+++ b/docs/webui.md
@@ -12,13 +12,13 @@ license: "This software is licensed under the Apache
License version 2."
This document primarily outlines how users can manage metadata within Apache
Gravitino using the web UI, the graphical interface is accessible through a web
browser as an alternative to writing code or using the REST interface.
-Integrate [OAuth settings](security/security.md) to view, add, modify, and
delete metalakes, create catalogs, and view catalogs, schemas, and tables,
among other functions.
+Integrate [OAuth settings](security/how-to-authenticate.md) to view, add,
modify, and delete metalakes, create catalogs, and view catalogs, schemas, and
tables, among other functions.
[Build](./how-to-build.md#quick-start) and
[deploy](./getting-started/index.md#local-workstation) the Gravitino Web UI and
open it in a browser at `http://<gravitino-host>:<gravitino-port>`, by default
is [http://localhost:8090](http://localhost:8090).
## Initial Page
-The web UI homepage displayed in Gravitino depends on the configuration
parameter for OAuth mode, see the details in [Security](security/security.md).
+The web UI homepage displayed in Gravitino depends on the configuration
parameter for OAuth mode, see the details in
[Security](security/how-to-authenticate.md).
Set parameter for `gravitino.authenticators`: [`simple`](#simple-mode),
[`basic`](../security/how-to-authenticate.md#basic-mode), or
[`oauth`](#oauth-mode). Simple mode is the default authentication option. If
multiple authenticators are set, the first one is taken by default.
@@ -59,7 +59,7 @@ Such as Safari need to enable the developer menu, and select
`Disable Cross-Orig

-1. Enter the values corresponding to your specific configuration. For detailed
instructions, refer to [Security](security/security.md).
+1. Enter the values corresponding to your specific configuration. For detailed
instructions, refer to [Security](security/how-to-authenticate.md).
2. Click on the `LOGIN` button takes you to the homepage.