diff --git a/superset/commands/dataset/importers/v1/utils.py b/superset/commands/dataset/importers/v1/utils.py index f96717c0bbe..4841922a5cd 100644 --- a/superset/commands/dataset/importers/v1/utils.py +++ b/superset/commands/dataset/importers/v1/utils.py @@ -27,9 +27,13 @@ from sqlalchemy.exc import MultipleResultsFound from sqlalchemy.sql.visitors import VisitableType from superset import db, security_manager -from superset.commands.dataset.exceptions import DatasetForbiddenDataURI +from superset.commands.dataset.exceptions import ( + DatasetAccessDeniedError, + DatasetForbiddenDataURI, +) from superset.commands.exceptions import ImportFailedError from superset.connectors.sqla.models import SqlaTable +from superset.exceptions import SupersetSecurityException from superset.models.core import Database from superset.sql.parse import Table from superset.utils import json @@ -172,6 +176,12 @@ def import_dataset( # noqa: C901 if dataset.id is None: db.session.flush() + if not ignore_permissions: + try: + security_manager.raise_for_access(datasource=dataset) + except SupersetSecurityException as ex: + raise DatasetAccessDeniedError() from ex + try: table_exists = dataset.database.has_table( Table(dataset.table_name, dataset.schema, dataset.catalog), diff --git a/tests/unit_tests/datasets/commands/importers/v1/import_test.py b/tests/unit_tests/datasets/commands/importers/v1/import_test.py index 81980ec149b..79f2400c7c3 100644 --- a/tests/unit_tests/datasets/commands/importers/v1/import_test.py +++ b/tests/unit_tests/datasets/commands/importers/v1/import_test.py @@ -31,6 +31,7 @@ from sqlalchemy.orm.session import Session from superset import db, security_manager from superset.commands.dataset.exceptions import ( + DatasetAccessDeniedError, DatasetForbiddenDataURI, ) from superset.commands.dataset.importers.v1.utils import ( @@ -744,6 +745,44 @@ def test_import_dataset_without_owner_permission( mock_can_access.assert_called_with("can_write", "Dataset") +def test_import_dataset_access_check( + mocker: MockerFixture, + session: Session, +) -> None: + """ + Test that import_dataset raises DatasetAccessDeniedError when the user does not + have datasource-level access to the target dataset. + """ + from superset.errors import ErrorLevel, SupersetError, SupersetErrorType + from superset.exceptions import SupersetSecurityException + + mocker.patch.object(security_manager, "can_access", return_value=True) + mocker.patch.object( + security_manager, + "raise_for_access", + side_effect=SupersetSecurityException( + SupersetError( + error_type=SupersetErrorType.DATASOURCE_SECURITY_ACCESS_ERROR, + message="User does not have access to this datasource", + level=ErrorLevel.ERROR, + ) + ), + ) + + engine = db.session.get_bind() + SqlaTable.metadata.create_all(engine) # pylint: disable=no-member + + database = Database(database_name="my_database", sqlalchemy_uri="sqlite://") + db.session.add(database) + db.session.flush() + + config = copy.deepcopy(dataset_fixture) + config["database_id"] = database.id + + with pytest.raises(DatasetAccessDeniedError): + import_dataset(config) + + @pytest.mark.parametrize( "allowed_urls, data_uri, expected, exception_class", [