This is an automated email from the ASF dual-hosted git repository.
rusackas pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/master by this push:
new 99841fb504b fix(async): include datasets and rev claims in guest
channel HMAC (#41487)
99841fb504b is described below
commit 99841fb504bbc3c42c4b3055fbc783b74e368676
Author: Evan Rusackas <[email protected]>
AuthorDate: Fri Jul 24 13:29:58 2026 -0700
fix(async): include datasets and rev claims in guest channel HMAC (#41487)
Co-authored-by: Claude Opus 4.8 <[email protected]>
---
superset/async_events/async_query_manager.py | 5 +++
.../async_events/async_query_manager_tests.py | 38 ++++++++++++++++++++++
2 files changed, 43 insertions(+)
diff --git a/superset/async_events/async_query_manager.py
b/superset/async_events/async_query_manager.py
index 7cfbd6892df..cda66bfde4a 100644
--- a/superset/async_events/async_query_manager.py
+++ b/superset/async_events/async_query_manager.py
@@ -249,6 +249,11 @@ class AsyncQueryManager:
"iat": token.get("iat"),
"exp": token.get("exp"),
"aud": token.get("aud"),
+ # ``datasets`` and ``rev`` are optional scope claims, so tokens
+ # that differ only in their dataset allowlist or revocation
+ # version still derive distinct channels.
+ "datasets": token.get("datasets"),
+ "rev": token.get("rev"),
},
sort_keys=True,
).encode("utf-8")
diff --git a/tests/unit_tests/async_events/async_query_manager_tests.py
b/tests/unit_tests/async_events/async_query_manager_tests.py
index 421f4159fbb..f5b5c97c8a2 100644
--- a/tests/unit_tests/async_events/async_query_manager_tests.py
+++ b/tests/unit_tests/async_events/async_query_manager_tests.py
@@ -223,6 +223,44 @@ def
test_parse_channel_id_from_request_as_guest_user_differs_per_token(
assert first != second
[email protected]("superset.is_feature_enabled")
+def test_parse_channel_id_from_request_as_guest_user_differs_per_scope(
+ is_feature_enabled_mock, async_query_manager
+):
+ """
+ Tokens that differ only in the optional ``datasets`` allowlist or ``rev``
+ revocation version must still derive distinct channel ids, otherwise two
+ differently scoped embedded sessions would collide on the same stream.
+ """
+ is_feature_enabled_mock.return_value = True
+
+ base_token = {
+ "user": {},
+ "resources": [{"type": "dashboard", "id": "some-uuid"}],
+ "rls_rules": [{"clause": '"STATEID" = 3'}],
+ "iat": 1700000000.0,
+ "exp": 1700000300.0,
+ "aud": "http://0.0.0.0:8080/",
+ "type": "guest",
+ }
+
+ request = Mock()
+ request.cookies = {}
+
+ g.user = security_manager.get_guest_user_from_token(dict(base_token))
+ baseline = async_query_manager.parse_channel_id_from_request(request)
+
+ g.user = security_manager.get_guest_user_from_token({**base_token,
"datasets": [1]})
+ with_datasets = async_query_manager.parse_channel_id_from_request(request)
+
+ g.user = security_manager.get_guest_user_from_token({**base_token, "rev":
1})
+ with_rev = async_query_manager.parse_channel_id_from_request(request)
+
+ assert baseline != with_datasets
+ assert baseline != with_rev
+ assert with_datasets != with_rev
+
+
@mark.parametrize(
"cache_type, cache_backend",
[