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]
