rusackas opened a new pull request, #40671:
URL: https://github.com/apache/superset/pull/40671

   ### SUMMARY
   
   Adds an opt-in, backward-compatible mechanism to revoke outstanding embedded 
guest tokens at runtime.
   
   Superset mints JWT guest tokens for embedded dashboards (carrying the guest 
user, resources, and RLS rules). Once minted, a token is valid until its `exp` 
— there is no way to invalidate an outstanding token before it expires (e.g. 
after a leak, or when a viewer's access/RLS rules should change faster than the 
token lifetime).
   
   This PR adds a coarse-grained "revoke all" primitive:
   
   - **Mint:** new guest tokens carry a revocation version claim (`rev`).
   - **Store:** the expected version lives in the metadata DB via the existing 
`key_value` store (`SharedKey.GUEST_TOKEN_REVOCATION_VERSION`), so it can be 
bumped at runtime without a code deploy and is shared across hosts/workers.
   - **Enforce:** when `GUEST_TOKEN_REVOCATION_ENABLED` is `True`, a token 
whose version is below the expected version is rejected during validation. 
Bumping the version revokes all outstanding tokens.
   - **Trigger:** a new `superset revoke-guest-tokens` CLI command increments 
the version.
   
   **Design rationale** (full write-up in 
`docs/sip/guest-token-revocation.md`): a global epoch/version is the standard, 
lowest-risk first step for JWT revocation. A per-token denylist was rejected as 
disproportionate for the common "revoke all" need (write-on-mint, 
read-on-validate, unbounded GC); short-exp+refresh and secret rotation were 
rejected as not giving a deterministic "revoke now." The version is stored in 
`key_value` rather than config because config changes require a 
redeploy/restart, defeating fast runtime revocation; config is used only for 
the opt-in flag.
   
   **Backward compatibility** is the core constraint and is handled in two 
layers:
   1. Feature is gated behind `GUEST_TOKEN_REVOCATION_ENABLED` (default 
`False`). When off, validation never consults the store and never rejects a 
token.
   2. Missing claim is treated as version `0`. The expected version also starts 
at `0`, so legacy tokens (minted before this change, no `rev` claim) stay valid 
even with the feature enabled — until an admin explicitly bumps the version 
above `0`. The store read is fail-open.
   
   No DB migration required (the version is a lazily-created `key_value` `APP` 
entry).
   
   ### TESTING INSTRUCTIONS
   
   Unit tests: `pytest 
tests/unit_tests/security/guest_token_revocation_test.py` (9 tests) cover: new 
token carries the claim when enabled; store not consulted when disabled; legacy 
token (no claim) valid by default; legacy token rejected after a version bump; 
current-versioned token accepted; malformed claim handling; CLI/bump increments 
and persists the version.
   
   Manual:
   1. Set `GUEST_TOKEN_REVOCATION_ENABLED = True` and `EMBEDDED_SUPERSET` 
feature flag.
   2. Mint a guest token and load an embedded dashboard — works.
   3. Run `superset revoke-guest-tokens` — prints the new version.
   4. Reuse the old token — now rejected (401); a freshly minted token works.
   
   ### ADDITIONAL INFORMATION
   
   - [ ] Has associated issue:
   - [x] Required feature flags: `GUEST_TOKEN_REVOCATION_ENABLED` (config flag, 
opt-in)
   - [ ] Changes UI
   - [ ] Includes DB Migration
   - [x] Introduces new feature or API
   - [ ] Removes existing feature or API
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   


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


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to