You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by be...@apache.org on 2024/03/12 17:36:23 UTC

(superset) 01/01: fix: check if guest user modified query

This is an automated email from the ASF dual-hosted git repository.

beto pushed a commit to branch sc-79188
in repository https://gitbox.apache.org/repos/asf/superset.git

commit f74908e8aeb9a707f6c531ba526aa990ce3d40cb
Author: Beto Dealmeida <ro...@dealmeida.net>
AuthorDate: Tue Mar 12 12:38:40 2024 -0400

    fix: check if guest user modified query
---
 superset/security/manager.py | 52 +++++++++++++++++++++++++++++++++-----------
 1 file changed, 39 insertions(+), 13 deletions(-)

diff --git a/superset/security/manager.py b/superset/security/manager.py
index 83e12fb2dc..66bf4c623a 100644
--- a/superset/security/manager.py
+++ b/superset/security/manager.py
@@ -67,6 +67,7 @@ from superset.security.guest_token import (
     GuestTokenUser,
     GuestUser,
 )
+from superset.superset_typing import AdhocMetric
 from superset.utils.core import (
     DatasourceName,
     DatasourceType,
@@ -143,6 +144,43 @@ RoleModelView.edit_columns = ["name", "permissions", "user"]
 RoleModelView.related_views = []
 
 
+def query_context_modified(query_context: "QueryContext") -> bool:
+    """
+    Check if a query context has been modified.
+
+    This is used to ensure guest users don't modify the payload and fetch data
+    different from what was shared with them in dashboards.
+    """
+    form_data = query_context.form_data
+    stored_chart = query_context.slice_
+
+    # sanity checks
+    if form_data is None or stored_chart is None:
+        return True
+
+    # cannot request a different chart
+    if form_data.get("slice_id") != stored_chart.id:
+        return True
+
+    # compare form_data
+    requested_metrics = set(form_data.get("metrics") or [])
+    stored_metrics = set(stored_chart.params_dict.get("metrics") or [])
+    if requested_metrics != stored_metrics:
+        return True
+
+    # compare queries in query_context
+    queries_metrics: set[Union[AdhocMetric, str]] = set()
+    for query in query_context.queries:
+        queries_metrics.update(query.metrics or [])
+
+    if stored_chart.query_context:
+        stored_query_context = json.loads(cast(str, stored_chart.query_context))
+        for query in stored_query_context.get("queries") or []:
+            stored_metrics.update(query.get("metrics") or [])  # type: ignore
+
+    return queries_metrics != stored_metrics
+
+
 class SupersetSecurityManager(  # pylint: disable=too-many-public-methods
     SecurityManager
 ):
@@ -1944,19 +1982,7 @@ class SupersetSecurityManager(  # pylint: disable=too-many-public-methods
         if self.is_guest_user() and query_context:
             # Guest users MUST not modify the payload so it's requesting a different
             # chart or different ad-hoc metrics from what's saved.
-            form_data = query_context.form_data
-            stored_chart = query_context.slice_
-
-            if (
-                form_data is None
-                or stored_chart is None
-                or form_data.get("slice_id") != stored_chart.id
-                or form_data.get("metrics", []) != stored_chart.params_dict["metrics"]
-                or any(
-                    query.metrics != stored_chart.params_dict["metrics"]
-                    for query in query_context.queries
-                )
-            ):
+            if query_context_modified(query_context):
                 raise SupersetSecurityException(
                     SupersetError(
                         error_type=SupersetErrorType.DASHBOARD_SECURITY_ACCESS_ERROR,