sadpandajoe commented on code in PR #45342:
URL: https://github.com/apache/superset/pull/45342#discussion_r4288079316


##########
superset/commands/dataset/importers/v1/utils.py:
##########
@@ -585,6 +605,22 @@ def import_dataset(  # noqa: C901
     if not ignore_permissions:
         try:
             security_manager.raise_for_access(datasource=dataset)
+            # The datasource check accepts editorship of the dataset itself,
+            # and an overwrite or restore only requires editorship of the row
+            # being replaced. Without this check an editor could re-import a
+            # ``SELECT 1`` decoy as a physical dataset over an arbitrary
+            # table. A physical dataset that is new or bound to a different
+            # table must be authorized by data access on that table.
+            if not dataset.sql and _table_binding(dataset) != previous_binding:
+                security_manager.raise_for_access(
+                    database=dataset.database,

Review Comment:
   On an overwrite that changes `database_uuid`, `import_from_dict` sets 
`existing.database_id` but `dataset.database` can still be the previously 
loaded `Database` (the overwrite path already read it for the uniqueness 
check). `_table_binding` sees the new `database_id` and triggers this check, 
but the check then runs against the old connection. A user with a schema grant 
on another connection could create the dataset there, then re-import the same 
UUID pointing at a database they can't read and have the table check pass 
against the stale one. Should this use the database resolved from 
`dataset.database_id` (and likewise for the virtual-SQL check below)? A test 
that changes the database on overwrite would pin it down.



##########
superset/common/query_context_processor.py:
##########
@@ -1031,7 +1031,10 @@ def raise_for_access(self) -> None:
         # caller is not allowed to access.
         if self._qc_datasource.type == DatasourceType.QUERY:
             try:
-                security_manager.raise_for_access(query=self._qc_datasource)
+                security_manager.raise_for_access(
+                    query=self._qc_datasource,
+                    allow_dataset_editorship=False,

Review Comment:
   The Explore GET and the explore form-data step still authorize a `query` 
datasource through `raise_for_access(query=..., 
allow_query_authorship_bypass=True)` with editorship left on. For a user who 
isn't the query's author, a `SELECT 1` decoy dataset named after a table the 
stored query reads still authorizes 
`/api/v1/explore/?datasource_type=query&datasource_id=<id>`, which returns that 
query's SQL. Should those two callers pass `allow_dataset_editorship=False` 
too, so a SQL Lab query is authorized the same way on every path?



##########
superset/commands/dataset/update.py:
##########
@@ -283,6 +291,7 @@ def _validate_sql_access(
                     sql=sql,
                     catalog=catalog,
                     schema=schema,
+                    allow_dataset_editorship=False,

Review Comment:
   This only runs when the SQL text changes, and `_validate_table_access` is 
skipped whenever `sql` is non-empty. So `PUT {"schema": "restricted"}` (or a 
`template_params`-only change) on a virtual dataset whose SQL is unchanged 
re-resolves the same SQL against a different schema with no access check. The 
decoy's editor can then read that table through chart-data. Should the SQL 
check also run when the schema, catalog or template params change, as the 
legacy `/datasource/save/` path now does for repoints?



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