[Improvement] Align Lance REST authorization decisions between auxiliary and standalone mode
- Dominant language
- Java
- Stars
- 3.2k
- Forks
- 935
- Avg merge
- 1d 16h
- Merged PRs (30d)
- 298
Description
### 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.
Contributor guide
Research direction
Start with LanceTableOperations, GravitinoLanceTableOperations, LanceRESTAuthInterceptionService, and the authorization components named in the issue; compare the auxiliary and standalone request paths. Read #12954 and the authorization differences table in docs/lance-rest-service.md before evaluating the proposed existence endpoint or interceptor changes. Done means the same requests receive consistent authorization decisions across deployment modes and the documented differences are reduced.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- api, authorization, backend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100