mirror of
https://github.com/apache/superset.git
synced 2026-05-12 19:35:17 +00:00
fix: create virtual dataset validation (#26625)
(cherry picked from commit 8e19f59dd2)
This commit is contained in:
committed by
Michael S. Molina
parent
c2cd05ee4a
commit
0c569108da
@@ -43,6 +43,7 @@ from superset.utils.core import (
|
||||
DatasourceType,
|
||||
backend,
|
||||
get_example_default_schema,
|
||||
override_user,
|
||||
)
|
||||
from superset.utils.database import get_example_database
|
||||
from superset.utils.urls import get_url_host
|
||||
@@ -1192,37 +1193,31 @@ class TestRolePermission(SupersetTestCase):
|
||||
self.assertEqual(schemas, ["1"])
|
||||
delete_schema_perm("[examples].[1]")
|
||||
|
||||
@patch("superset.utils.core.g")
|
||||
@patch("superset.security.manager.g")
|
||||
def test_schemas_accessible_by_user_datasource_access(self, mock_sm_g, mock_g):
|
||||
def test_schemas_accessible_by_user_datasource_access(self):
|
||||
# User has schema access to the datasource temp_schema.wb_health_population in examples DB.
|
||||
mock_g.user = mock_sm_g.user = security_manager.find_user("gamma")
|
||||
database = get_example_database()
|
||||
with self.client.application.test_request_context():
|
||||
database = get_example_database()
|
||||
schemas = security_manager.get_schemas_accessible_by_user(
|
||||
database, ["temp_schema", "2", "3"]
|
||||
)
|
||||
self.assertEqual(schemas, ["temp_schema"])
|
||||
with override_user(security_manager.find_user("gamma")):
|
||||
schemas = security_manager.get_schemas_accessible_by_user(
|
||||
database, ["temp_schema", "2", "3"]
|
||||
)
|
||||
self.assertEqual(schemas, ["temp_schema"])
|
||||
|
||||
@patch("superset.utils.core.g")
|
||||
@patch("superset.security.manager.g")
|
||||
def test_schemas_accessible_by_user_datasource_and_schema_access(
|
||||
self, mock_sm_g, mock_g
|
||||
):
|
||||
def test_schemas_accessible_by_user_datasource_and_schema_access(self):
|
||||
# User has schema access to the datasource temp_schema.wb_health_population in examples DB.
|
||||
create_schema_perm("[examples].[2]")
|
||||
mock_g.user = mock_sm_g.user = security_manager.find_user("gamma")
|
||||
with self.client.application.test_request_context():
|
||||
database = get_example_database()
|
||||
schemas = security_manager.get_schemas_accessible_by_user(
|
||||
database, ["temp_schema", "2", "3"]
|
||||
)
|
||||
self.assertEqual(schemas, ["temp_schema", "2"])
|
||||
vm = security_manager.find_permission_view_menu(
|
||||
"schema_access", "[examples].[2]"
|
||||
)
|
||||
self.assertIsNotNone(vm)
|
||||
delete_schema_perm("[examples].[2]")
|
||||
with override_user(security_manager.find_user("gamma")):
|
||||
schemas = security_manager.get_schemas_accessible_by_user(
|
||||
database, ["temp_schema", "2", "3"]
|
||||
)
|
||||
self.assertEqual(schemas, ["temp_schema", "2"])
|
||||
vm = security_manager.find_permission_view_menu(
|
||||
"schema_access", "[examples].[2]"
|
||||
)
|
||||
self.assertIsNotNone(vm)
|
||||
delete_schema_perm("[examples].[2]")
|
||||
|
||||
@pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
|
||||
def test_gamma_user_schema_access_to_dashboards(self):
|
||||
@@ -1642,25 +1637,42 @@ class TestSecurityManager(SupersetTestCase):
|
||||
with self.assertRaises(SupersetSecurityException):
|
||||
security_manager.raise_for_access(query=query)
|
||||
|
||||
@patch("superset.security.manager.g")
|
||||
def test_raise_for_access_sql_fails(self):
|
||||
with override_user(security_manager.find_user("gamma")):
|
||||
with self.assertRaises(SupersetSecurityException):
|
||||
security_manager.raise_for_access(
|
||||
database=get_example_database(),
|
||||
schema="bar",
|
||||
sql="SELECT * FROM foo",
|
||||
)
|
||||
|
||||
@patch("superset.security.SupersetSecurityManager.is_owner")
|
||||
@patch("superset.security.SupersetSecurityManager.can_access")
|
||||
def test_raise_for_access_sql(self, mock_can_access, mock_is_owner):
|
||||
mock_can_access.return_value = True
|
||||
mock_is_owner.return_value = True
|
||||
with override_user(security_manager.find_user("gamma")):
|
||||
security_manager.raise_for_access(
|
||||
database=get_example_database(), schema="bar", sql="SELECT * FROM foo"
|
||||
)
|
||||
|
||||
@patch("superset.security.SupersetSecurityManager.is_owner")
|
||||
@patch("superset.security.SupersetSecurityManager.can_access")
|
||||
@patch("superset.security.SupersetSecurityManager.can_access_schema")
|
||||
def test_raise_for_access_query_context(
|
||||
self, mock_can_access_schema, mock_can_access, mock_is_owner, mock_g
|
||||
self, mock_can_access_schema, mock_can_access, mock_is_owner
|
||||
):
|
||||
query_context = Mock(datasource=self.get_datasource_mock(), form_data={})
|
||||
|
||||
mock_can_access_schema.return_value = True
|
||||
security_manager.raise_for_access(query_context=query_context)
|
||||
|
||||
mock_g.user = security_manager.find_user("gamma")
|
||||
mock_can_access.return_value = False
|
||||
mock_can_access_schema.return_value = False
|
||||
mock_is_owner.return_value = False
|
||||
|
||||
with self.assertRaises(SupersetSecurityException):
|
||||
security_manager.raise_for_access(query_context=query_context)
|
||||
with override_user(security_manager.find_user("gamma")):
|
||||
with self.assertRaises(SupersetSecurityException):
|
||||
security_manager.raise_for_access(query_context=query_context)
|
||||
|
||||
@patch("superset.security.SupersetSecurityManager.can_access")
|
||||
def test_raise_for_access_table(self, mock_can_access):
|
||||
@@ -1675,30 +1687,27 @@ class TestSecurityManager(SupersetTestCase):
|
||||
with self.assertRaises(SupersetSecurityException):
|
||||
security_manager.raise_for_access(database=database, table=table)
|
||||
|
||||
@patch("superset.security.manager.g")
|
||||
@patch("superset.security.SupersetSecurityManager.is_owner")
|
||||
@patch("superset.security.SupersetSecurityManager.can_access")
|
||||
@patch("superset.security.SupersetSecurityManager.can_access_schema")
|
||||
def test_raise_for_access_viz(
|
||||
self, mock_can_access_schema, mock_can_access, mock_is_owner, mock_g
|
||||
self, mock_can_access_schema, mock_can_access, mock_is_owner
|
||||
):
|
||||
test_viz = viz.TimeTableViz(self.get_datasource_mock(), form_data={})
|
||||
|
||||
mock_can_access_schema.return_value = True
|
||||
security_manager.raise_for_access(viz=test_viz)
|
||||
|
||||
mock_g.user = security_manager.find_user("gamma")
|
||||
mock_can_access.return_value = False
|
||||
mock_can_access_schema.return_value = False
|
||||
mock_is_owner.return_value = False
|
||||
|
||||
with self.assertRaises(SupersetSecurityException):
|
||||
security_manager.raise_for_access(viz=test_viz)
|
||||
with override_user(security_manager.find_user("gamma")):
|
||||
with self.assertRaises(SupersetSecurityException):
|
||||
security_manager.raise_for_access(viz=test_viz)
|
||||
|
||||
@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
|
||||
@pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
|
||||
@with_feature_flags(DASHBOARD_RBAC=True)
|
||||
@patch("superset.security.manager.g")
|
||||
@patch("superset.security.SupersetSecurityManager.is_owner")
|
||||
@patch("superset.security.SupersetSecurityManager.can_access")
|
||||
@patch("superset.security.SupersetSecurityManager.can_access_schema")
|
||||
@@ -1707,7 +1716,6 @@ class TestSecurityManager(SupersetTestCase):
|
||||
mock_can_access_schema,
|
||||
mock_can_access,
|
||||
mock_is_owner,
|
||||
mock_g,
|
||||
):
|
||||
births = self.get_dash_by_slug("births")
|
||||
girls = self.get_slice("Girls", db.session, expunge_from_session=False)
|
||||
@@ -1731,16 +1739,80 @@ class TestSecurityManager(SupersetTestCase):
|
||||
}
|
||||
)
|
||||
|
||||
mock_g.user = security_manager.find_user("gamma")
|
||||
mock_is_owner.return_value = False
|
||||
mock_can_access.return_value = False
|
||||
mock_can_access_schema.return_value = False
|
||||
with override_user(security_manager.find_user("gamma")):
|
||||
for kwarg in ["query_context", "viz"]:
|
||||
births.roles = []
|
||||
|
||||
for kwarg in ["query_context", "viz"]:
|
||||
births.roles = []
|
||||
# No dashboard roles.
|
||||
with self.assertRaises(SupersetSecurityException):
|
||||
security_manager.raise_for_access(
|
||||
**{
|
||||
kwarg: Mock(
|
||||
datasource=birth_names,
|
||||
form_data={
|
||||
"dashboardId": births.id,
|
||||
"slice_id": girls.id,
|
||||
},
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
# No dashboard roles.
|
||||
with self.assertRaises(SupersetSecurityException):
|
||||
births.roles = [self.get_role("Gamma")]
|
||||
|
||||
# Undefined dashboard.
|
||||
with self.assertRaises(SupersetSecurityException):
|
||||
security_manager.raise_for_access(
|
||||
**{
|
||||
kwarg: Mock(
|
||||
datasource=birth_names,
|
||||
form_data={},
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
# Undefined dashboard chart.
|
||||
with self.assertRaises(SupersetSecurityException):
|
||||
security_manager.raise_for_access(
|
||||
**{
|
||||
kwarg: Mock(
|
||||
datasource=birth_names,
|
||||
form_data={"dashboardId": births.id},
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
# Ill-defined dashboard chart.
|
||||
with self.assertRaises(SupersetSecurityException):
|
||||
security_manager.raise_for_access(
|
||||
**{
|
||||
kwarg: Mock(
|
||||
datasource=birth_names,
|
||||
form_data={
|
||||
"dashboardId": births.id,
|
||||
"slice_id": treemap.id,
|
||||
},
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
# Dashboard chart not associated with said datasource.
|
||||
with self.assertRaises(SupersetSecurityException):
|
||||
security_manager.raise_for_access(
|
||||
**{
|
||||
kwarg: Mock(
|
||||
datasource=birth_names,
|
||||
form_data={
|
||||
"dashboardId": world_health.id,
|
||||
"slice_id": treemap.id,
|
||||
},
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
# Dashboard chart associated with said datasource.
|
||||
security_manager.raise_for_access(
|
||||
**{
|
||||
kwarg: Mock(
|
||||
@@ -1753,139 +1825,70 @@ class TestSecurityManager(SupersetTestCase):
|
||||
}
|
||||
)
|
||||
|
||||
births.roles = [self.get_role("Gamma")]
|
||||
|
||||
# Undefined dashboard.
|
||||
with self.assertRaises(SupersetSecurityException):
|
||||
security_manager.raise_for_access(
|
||||
**{
|
||||
kwarg: Mock(
|
||||
datasource=birth_names,
|
||||
form_data={},
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
# Undefined dashboard chart.
|
||||
with self.assertRaises(SupersetSecurityException):
|
||||
security_manager.raise_for_access(
|
||||
**{
|
||||
kwarg: Mock(
|
||||
datasource=birth_names,
|
||||
form_data={"dashboardId": births.id},
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
# Ill-defined dashboard chart.
|
||||
with self.assertRaises(SupersetSecurityException):
|
||||
security_manager.raise_for_access(
|
||||
**{
|
||||
kwarg: Mock(
|
||||
datasource=birth_names,
|
||||
form_data={
|
||||
"dashboardId": births.id,
|
||||
"slice_id": treemap.id,
|
||||
},
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
# Dashboard chart not associated with said datasource.
|
||||
with self.assertRaises(SupersetSecurityException):
|
||||
security_manager.raise_for_access(
|
||||
**{
|
||||
kwarg: Mock(
|
||||
datasource=birth_names,
|
||||
form_data={
|
||||
"dashboardId": world_health.id,
|
||||
"slice_id": treemap.id,
|
||||
},
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
# Dashboard chart associated with said datasource.
|
||||
security_manager.raise_for_access(
|
||||
**{
|
||||
kwarg: Mock(
|
||||
datasource=birth_names,
|
||||
form_data={
|
||||
"dashboardId": births.id,
|
||||
"slice_id": girls.id,
|
||||
},
|
||||
# Ill-defined native filter.
|
||||
with self.assertRaises(SupersetSecurityException):
|
||||
security_manager.raise_for_access(
|
||||
**{
|
||||
kwarg: Mock(
|
||||
datasource=birth_names,
|
||||
form_data={
|
||||
"dashboardId": births.id,
|
||||
"type": "NATIVE_FILTER",
|
||||
},
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
# Ill-defined native filter.
|
||||
with self.assertRaises(SupersetSecurityException):
|
||||
# Native filter not associated with said datasource.
|
||||
with self.assertRaises(SupersetSecurityException):
|
||||
security_manager.raise_for_access(
|
||||
**{
|
||||
kwarg: Mock(
|
||||
datasource=birth_names,
|
||||
form_data={
|
||||
"dashboardId": births.id,
|
||||
"native_filter_id": "NATIVE_FILTER-IJKLMNOP",
|
||||
"type": "NATIVE_FILTER",
|
||||
},
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
# Native filter associated with said datasource.
|
||||
security_manager.raise_for_access(
|
||||
**{
|
||||
kwarg: Mock(
|
||||
datasource=birth_names,
|
||||
form_data={
|
||||
"dashboardId": births.id,
|
||||
"native_filter_id": "NATIVE_FILTER-ABCDEFGH",
|
||||
"type": "NATIVE_FILTER",
|
||||
},
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
# Native filter not associated with said datasource.
|
||||
with self.assertRaises(SupersetSecurityException):
|
||||
security_manager.raise_for_access(
|
||||
**{
|
||||
kwarg: Mock(
|
||||
datasource=birth_names,
|
||||
form_data={
|
||||
"dashboardId": births.id,
|
||||
"native_filter_id": "NATIVE_FILTER-IJKLMNOP",
|
||||
"type": "NATIVE_FILTER",
|
||||
},
|
||||
)
|
||||
}
|
||||
)
|
||||
db.session.expunge_all()
|
||||
|
||||
# Native filter associated with said datasource.
|
||||
security_manager.raise_for_access(
|
||||
**{
|
||||
kwarg: Mock(
|
||||
datasource=birth_names,
|
||||
form_data={
|
||||
"dashboardId": births.id,
|
||||
"native_filter_id": "NATIVE_FILTER-ABCDEFGH",
|
||||
"type": "NATIVE_FILTER",
|
||||
},
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
db.session.expunge_all()
|
||||
|
||||
@patch("superset.security.manager.g")
|
||||
def test_get_user_roles(self, mock_g):
|
||||
def test_get_user_roles(self):
|
||||
admin = security_manager.find_user("admin")
|
||||
mock_g.user = admin
|
||||
roles = security_manager.get_user_roles()
|
||||
self.assertEqual(admin.roles, roles)
|
||||
with override_user(admin):
|
||||
roles = security_manager.get_user_roles()
|
||||
self.assertEqual(admin.roles, roles)
|
||||
|
||||
@patch("superset.security.manager.g")
|
||||
def test_get_anonymous_roles(self, mock_g):
|
||||
mock_g.user = security_manager.get_anonymous_user()
|
||||
roles = security_manager.get_user_roles()
|
||||
self.assertEqual([security_manager.get_public_role()], roles)
|
||||
def test_get_anonymous_roles(self):
|
||||
with override_user(security_manager.get_anonymous_user()):
|
||||
roles = security_manager.get_user_roles()
|
||||
self.assertEqual([security_manager.get_public_role()], roles)
|
||||
|
||||
|
||||
class TestDatasources(SupersetTestCase):
|
||||
@patch("superset.security.manager.g")
|
||||
@patch("superset.security.SupersetSecurityManager.can_access_database")
|
||||
@patch("superset.security.SupersetSecurityManager.get_session")
|
||||
def test_get_user_datasources_admin(
|
||||
self, mock_get_session, mock_can_access_database, mock_g
|
||||
self, mock_get_session, mock_can_access_database
|
||||
):
|
||||
Datasource = namedtuple("Datasource", ["database", "schema", "name"])
|
||||
mock_g.user = security_manager.find_user("admin")
|
||||
mock_can_access_database.return_value = True
|
||||
mock_get_session.query.return_value.filter.return_value.all.return_value = []
|
||||
|
||||
@@ -1897,23 +1900,20 @@ class TestDatasources(SupersetTestCase):
|
||||
Datasource("database1", "schema1", "table2"),
|
||||
Datasource("database2", None, "table1"),
|
||||
]
|
||||
with override_user(security_manager.find_user("admin")):
|
||||
datasources = security_manager.get_user_datasources()
|
||||
assert sorted(datasources) == [
|
||||
Datasource("database1", "schema1", "table1"),
|
||||
Datasource("database1", "schema1", "table2"),
|
||||
Datasource("database2", None, "table1"),
|
||||
]
|
||||
|
||||
datasources = security_manager.get_user_datasources()
|
||||
|
||||
assert sorted(datasources) == [
|
||||
Datasource("database1", "schema1", "table1"),
|
||||
Datasource("database1", "schema1", "table2"),
|
||||
Datasource("database2", None, "table1"),
|
||||
]
|
||||
|
||||
@patch("superset.security.manager.g")
|
||||
@patch("superset.security.SupersetSecurityManager.can_access_database")
|
||||
@patch("superset.security.SupersetSecurityManager.get_session")
|
||||
def test_get_user_datasources_gamma(
|
||||
self, mock_get_session, mock_can_access_database, mock_g
|
||||
self, mock_get_session, mock_can_access_database
|
||||
):
|
||||
Datasource = namedtuple("Datasource", ["database", "schema", "name"])
|
||||
mock_g.user = security_manager.find_user("gamma")
|
||||
mock_can_access_database.return_value = False
|
||||
mock_get_session.query.return_value.filter.return_value.all.return_value = []
|
||||
|
||||
@@ -1925,19 +1925,16 @@ class TestDatasources(SupersetTestCase):
|
||||
Datasource("database1", "schema1", "table2"),
|
||||
Datasource("database2", None, "table1"),
|
||||
]
|
||||
with override_user(security_manager.find_user("gamma")):
|
||||
datasources = security_manager.get_user_datasources()
|
||||
assert datasources == []
|
||||
|
||||
datasources = security_manager.get_user_datasources()
|
||||
|
||||
assert datasources == []
|
||||
|
||||
@patch("superset.security.manager.g")
|
||||
@patch("superset.security.SupersetSecurityManager.can_access_database")
|
||||
@patch("superset.security.SupersetSecurityManager.get_session")
|
||||
def test_get_user_datasources_gamma_with_schema(
|
||||
self, mock_get_session, mock_can_access_database, mock_g
|
||||
self, mock_get_session, mock_can_access_database
|
||||
):
|
||||
Datasource = namedtuple("Datasource", ["database", "schema", "name"])
|
||||
mock_g.user = security_manager.find_user("gamma")
|
||||
mock_can_access_database.return_value = False
|
||||
|
||||
mock_get_session.query.return_value.filter.return_value.all.return_value = [
|
||||
@@ -1953,13 +1950,12 @@ class TestDatasources(SupersetTestCase):
|
||||
Datasource("database1", "schema1", "table2"),
|
||||
Datasource("database2", None, "table1"),
|
||||
]
|
||||
|
||||
datasources = security_manager.get_user_datasources()
|
||||
|
||||
assert sorted(datasources) == [
|
||||
Datasource("database1", "schema1", "table1"),
|
||||
Datasource("database1", "schema1", "table2"),
|
||||
]
|
||||
with override_user(security_manager.find_user("gamma")):
|
||||
datasources = security_manager.get_user_datasources()
|
||||
assert sorted(datasources) == [
|
||||
Datasource("database1", "schema1", "table1"),
|
||||
Datasource("database1", "schema1", "table2"),
|
||||
]
|
||||
|
||||
|
||||
class FakeRequest:
|
||||
|
||||
Reference in New Issue
Block a user