yuqi1129 opened a new issue, #13089:
URL: https://github.com/apache/gravitino/issues/13089

   ### What would you like to be improved?
   
   Lance REST enforces authorization in a different place depending on the 
deployment mode, so the same request from the same user can be authorized 
differently.
   
   - **Auxiliary mode** installs `LanceRESTAuthInterceptionService`, which 
checks each Lance endpoint once against an expression written for that 
endpoint's Lance semantics (`LanceAuthorizationExpressions`), before any 
dispatcher call. Listings are filtered by `LanceAuthorizationMetadataFilter`.
   - **Standalone mode** installs neither: `enableMetadataAuthorization` is 
`auxMode && gravitino.authorization.enable && metalake configured`, so it is 
always false. Every underlying Gravitino REST call is authorized by the 
Gravitino server using the rules of that call.
   
   A concrete, reproducible divergence — no race required:
   
   `TableExists` on an **existing** table, caller holds `USE_CATALOG` + 
`USE_SCHEMA` + `CREATE_TABLE` and nothing else.
   
   - Auxiliary: `LanceTableOperations.tableExists` is annotated with 
`PROBE_TABLE_AUTHORIZATION_EXPRESSION`, which accepts `PROBE_TABLE_LIKE || 
CREATE_TABLE` → **200**.
   - Standalone: `GravitinoLanceTableOperations.tableExists` → 
`GravitinoClient` → `TableCatalog.tableExists`, whose default is 
`loadTable(ident) != null`. The Gravitino server evaluates 
`TableOperations.loadTable`: the primary `LOAD_TABLE` expression fails, 
`allowCheckExistence` passes, and `LoadTableAuthorizationExecutor` then returns 
`!tableExists(ident)` — it only lets the probe through when the table is 
**absent** → **403**.
   
   Other differences follow from the same cause: a Lance endpoint that maps to 
several Gravitino calls (`CreateNamespace` loads before creating) is checked 
once in auxiliary mode and once per underlying call in standalone mode; 
overwrite/drop follow Lance's ownership rule in auxiliary mode and the 
underlying `alter`/`drop` rule in standalone mode.
   
   #12954 documents these as known limits. This issue tracks removing them.
   
   ### How should we improve?
   
   Two options, neither cheap:
   
   1. **Run the Lance interceptor in standalone mode too.** Requires a remote 
implementation of the pieces `BaseMetadataAuthorizationMethodInterceptor` uses 
in-process today — `AuthorizationUtils.checkCurrentUser`, 
`GravitinoAuthorizer.findUnheldRoles`, ownership and privilege lookups behind 
`AuthorizationExpressionEvaluator`. Each Lance authorization would cost several 
REST round trips. Aligns standalone to Lance's semantics.
   2. **Drop the Lance interceptor in auxiliary mode** and rely on 
dispatcher-level authorization on both paths. Cheap, but aligns auxiliary to 
the *less* precise side: the `TableExists` example above would become 403 in 
both modes, and multi-call endpoints would be checked per call everywhere.
   
   A middle path worth evaluating first: give Gravitino a real existence 
endpoint (`HEAD .../tables/{table}` with a probe expression, as the Iceberg 
REST server already has), so standalone's `tableExists` no longer has to be 
modelled as `loadTable`. That removes the most visible divergence without 
moving the interceptor.
   
   Whichever direction, the deployment-mode table in 
`docs/lance-rest-service.md` ("Authorization differences between deployment 
modes") should shrink as differences are closed.
   
   Related: #12984 (forwards the caller's identity in standalone mode; does not 
change where authorization runs), #12574.
   


-- 
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]

Reply via email to