jiangxt2 opened a new issue, #12785:
URL: https://github.com/apache/gravitino/issues/12785
### Version
main branch
### Describe what's wrong
When a client loads a table with `privileges=MODIFY_TABLE`, Gravitino
selects the secondary modify-table authorization expression. If that
authorization is denied, `LoadTableAuthorizationExecutor` still evaluates the
table-like existence-probe expression and may call
`tableDispatcher().tableExists()` when the caller has probe permissions such as
`USE_CATALOG`, `USE_SCHEMA`, and `SELECT_TABLE`. For external JDBC catalogs,
this existence check performs physical metadata I/O; for `jdbc-doris`, the JDBC
table loader opens a MySQL-protocol connection before checking whether the
table exists. A write request that should fail at authorization therefore opens
an external connection, adds latency and resource pressure, and makes the
authorization result depend on external catalog availability.
### Error message and/or stacktrace
Expected behavior is a deterministic `403 Forbidden` for a denied
`MODIFY_TABLE` request without contacting the configured external catalog. The
observed behavior includes a TCP connection to the configured JDBC endpoint on
the denied path. If the endpoint is unavailable, the connection failure can be
caught by the authorization interceptor and returned as an internal
authorization error instead of the original authorization denial.
### How to reproduce
1. Run Gravitino main with authorization enabled and create an external
`jdbc-doris` catalog whose JDBC and Doris endpoints can record incoming
connections.
2. Create a role with `USE_CATALOG`, `USE_SCHEMA`, and `SELECT_TABLE`
allowed, and `MODIFY_TABLE` denied.
3. Execute a Spark 3.5 write or send a table-load request carrying
`privileges=MODIFY_TABLE` for that catalog and table.
4. As a quick path that does not require Spark, use a Java client and call
`RelationalCatalog.loadTable(NameIdentifier.of("schema", "table"),
Set.of(Privilege.Name.MODIFY_TABLE))` for the same catalog and table.
5. Observe that Gravitino denies the request but the configured JDBC
endpoint receives a connection attempt before the denial response is completed.
6. Point the catalog at an unavailable endpoint and observe that the failure
can change the response from a deterministic authorization denial to an
internal authorization error.
### Additional context
The `allowCheckExistence` path is useful for ordinary load authorization
because it distinguishes a missing table from an existing table that the caller
cannot load. It should not run after an explicit write authorization request
has already failed. Spark 3.5 uses `MODIFY_TABLE` to enforce write intent, and
that authorization is required to complete before any physical write delegate
or Doris I/O is constructed.
This is not an authorization bypass: the caller is still denied the write.
It is an authorization correctness and isolation-boundary bug that causes
external I/O after a failed authorization check and can mask the intended error
semantics.
The fix should return the denial before any existence probing for an
explicit failed write authorization, while ordinary load denials retain their
existing existence-probe behavior. The intentional fail-closed consequence is
that a missing table requested with denied `MODIFY_TABLE` may return `403`
instead of probing to produce `404`.
The behavior was introduced by the interaction between the write-aware
load-table authorization path and the later generic table-like existence-probe
path. Related context:
[#12480](https://github.com/apache/gravitino/issues/12480) and
[#12482](https://github.com/apache/gravitino/pull/12482).
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]