rusackas opened a new pull request, #41397:
URL: https://github.com/apache/superset/pull/41397
### SUMMARY
Adopts **anandraiin3/superset#23** (originally authored via the Devin AI bot
— credit to **@anandraiin3**). This brings the fix onto current
`apache/superset` master with the touched code re-verified against master's
`async_query_manager`.
Closes #31492 ("Getting error when using RLS filtering in Guest token when
`GLOBAL_ASYNC_QUERIES` is enabled").
When `GLOBAL_ASYNC_QUERIES` is enabled and an embedded dashboard is loaded
with a guest token that contains `rls_rules`, every chart and filter request
fails with `Not authorized` (HTTP 401) and the frontend surfaces:
> This session has encountered an interruption, and some controls may not
work as intended. If you are the developer of this app, please check that the
guest token is being generated correctly.
#### Root cause
The async-query path identifies a client through a server-issued
`async-token` JWT cookie, created in `validate_session` and read back in
`parse_channel_id_from_request` for both `POST /api/v1/chart/data` (scheduling
the celery job) and `GET /api/v1/async_event/` (polling for completion events).
For embedded dashboards the page renders inside a third-party iframe, so the
`async-token` cookie is unreliable: modern browsers strip it for cross-site
contexts or never set it (depending on `SameSite`/third-party-cookie settings).
Subsequent polling requests typically arrive without it, which makes
`parse_channel_id_from_request` raise `AsyncQueryTokenException` → 401. The
error surfaces most often when RLS rules are present because the per-token
cache key prevents a sync cache-hit shortcut from masking the cookie issue.
#### Fix
For requests that arrive with a guest user attached
(`security_manager.get_current_guest_user_if_guest()`), the channel id is
derived deterministically from stable claims of the guest token (`user`,
`resources`, `iat`, `exp`, `aud`) using HMAC-SHA256 keyed with
`GLOBAL_ASYNC_QUERIES_JWT_SECRET`:
- Removes the dependency on a third-party cookie inside the embedded iframe.
- Yields the same channel id for the chart-data POST, the celery worker, and
the polling endpoint, so events written to `async-events-<channel>` are
readable by the same guest session.
- Stays unguessable to outside callers because the digest is keyed with the
existing JWT secret.
- Leaves the cookie path completely untouched for non-guest (regular) users.
`validate_session` also short-circuits for guest users so it does not
pointlessly issue an `async-token` cookie that would either fail to be set or
never be sent back.
Files changed:
- `superset/async_events/async_query_manager.py` — new
`get_guest_user_channel_id` helper; `parse_channel_id_from_request` and
`validate_session` branch on `get_current_guest_user_if_guest()`.
- `tests/unit_tests/async_events/async_query_manager_tests.py` — guest-user
fixture mirrors the realistic guest-token payload from the bug report (RLS
rules, `iat`/`exp`/`aud`/`type`); three new tests cover the new code path.
#### Security note (reviewer aid)
The channel id is the sole authz boundary for `GET /api/v1/async_event/`.
The HMAC is keyed with the same `GLOBAL_ASYNC_QUERIES_JWT_SECRET` that protects
the cookie JWT, so the derived channel is equally unguessable. The guest token
signature/expiry is already validated before this code runs, and a guest can
only derive their own channel (channel scope == token scope). No privilege
escalation found.
### BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
N/A — backend-only change. The user-visible effect is that embedded
dashboards with `rls_rules` and `GLOBAL_ASYNC_QUERIES=True` no longer return
401 on chart and filter APIs.
### TESTING INSTRUCTIONS
Automated:
```bash
pytest tests/unit_tests/async_events/async_query_manager_tests.py -v
```
The new tests `test_parse_channel_id_from_request_as_guest_user_no_cookie`,
`test_parse_channel_id_from_request_as_guest_user_is_deterministic`, and
`test_parse_channel_id_from_request_as_guest_user_differs_per_token` cover the
regression directly. The pre-existing guest-token tests continue to pass and
now exercise a guest-token payload that matches the one in the issue.
Manual reproduction (matches the issue):
1. Set `FEATURE_FLAGS = {"EMBEDDED_SUPERSET": True, "GLOBAL_ASYNC_QUERIES":
True}` and configure the celery worker + Redis as documented.
2. Mint a guest token whose payload includes `rls_rules` (e.g. `[{"clause":
"\"STATEID\" = 3"}]`) for an embedded dashboard.
3. Load the dashboard in an iframe on a different origin from Superset.
4. **Before this PR**: every `POST /api/v1/chart/data` and `GET
/api/v1/async_event/` returns 401 with `Not authorized`, and the embedded SDK
surfaces the "session has encountered an interruption" toast.
5. **After this PR**: chart-data requests return 202 with a job id, the
polling endpoint streams completion events, and the dashboard renders normally
with the RLS predicate applied.
### ADDITIONAL INFORMATION
- [x] Has associated issue: closes #31492
- [x] Required feature flags: `EMBEDDED_SUPERSET`, `GLOBAL_ASYNC_QUERIES`
(existing flags; no new flags introduced)
- [ ] Changes UI
- [ ] Includes DB Migration (follow approval process in
[SIP-59](https://github.com/apache/superset/issues/13351))
- [ ] Migration is atomic, supports rollback & is backwards-compatible
- [ ] Confirm DB migration upgrade and downgrade tested
- [ ] Runtime estimates and downtime expectations provided
- [ ] Introduces new feature or API
- [ ] Removes existing feature or API
---
Adopted from anandraiin3/superset#23, originally authored via the Devin AI
bot. Credit to **@anandraiin3**.
--
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]