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

   ### Version
   
   main branch
   
   ### Describe what's wrong
   
   `CatalogDispatcher.loadCatalog()` returns a live `BaseCatalog` to its 
callers. After #12403 the load itself is covered by a `CatalogLease`, but the 
lease is released before the object is returned, so the returned catalog can 
still be closed by a concurrent cache eviction (expiry, remote change-log 
invalidation, or drop) while the caller is using it.
   
   `BaseCatalog.close()` closes the authorization plugin and sets it to `null` 
(`BaseCatalog.java:323-334`). 
`AuthorizationUtils.callAuthorizationPluginImpl()` skips the call **silently** 
when the plugin is `null`, so the failure mode is not an exception but a lost 
privilege update — stale grants can be left behind in the external 
authorization system.
   
   The most visible path is `CatalogHookDispatcher.dropCatalog()`:
   
   1. `dispatcher.loadCatalog(ident)` — lease already released;
   2. `AuthorizationUtils.getMetadataObjectLocation(...)`;
   3. `AuthorizationUtils.removeCatalogPrivileges(catalog, locations)` — no-op 
if the catalog was closed in between;
   4. `dispatcher.dropCatalog(ident, force)` — catalog is gone, privileges 
never revoked.
   
   The same shape applies to the other `loadCatalog()` callers in 
`AuthorizationUtils` (`callAuthorizationPluginForSecurableObjects`, 
`loadMetadataObjectCatalog`, `checkCatalogType`) and should be checked for the 
future-grant path after `createCatalog()`.
   
   This predates #12403 (before it, `loadCatalog` held no lease at all, so the 
window was wider); #12403 fixed the wrapper lifecycle and explicitly left this 
one out because it is a refactor of the authorization call graph.
   
   ### Error message and/or stacktrace
   
   No exception is raised. The symptom is a missing privilege update in the 
external authorization system after a catalog drop, rename, or grant/revoke 
that raced with a catalog cache eviction.
   
   ### How to reproduce
   
   1. Create a catalog with an `authorization-provider` and grant privileges on 
it.
   2. Enter `CatalogHookDispatcher.dropCatalog()` and pause after 
`loadCatalog()`.
   3. Invalidate the catalog cache entry (expiry or remote change-log 
invalidation) and let the wrapper's cleanup run.
   4. Resume: `removeCatalogPrivileges` silently does nothing and the drop 
completes.
   
   ### Additional context
   
   Suggested direction:
   
   - Give the authorization call path a lease-scoped API 
(`CatalogManager.acquireCatalogLease` or a callback-style variant) so the 
plugin invocation happens inside the lease. Note that several call sites only 
hold a `CatalogDispatcher`, so the API has to be reachable from there.
   - Make `callAuthorizationPluginImpl` log (or fail) when a `BaseCatalog` 
configured with an `authorization-provider` has a `null` plugin, so this class 
of bug stops being silent.
   - `loadCatalog`'s returned `BaseCatalog` outliving its lease is the root 
shape — worth deciding whether the public return contract should stay a live 
catalog object.
   
   Related: #12403, #12404
   


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