mirror of
https://github.com/apache/superset.git
synced 2026-04-19 16:14:52 +00:00
feat(dashboard_rbac): dashboard_view access enforcement (#12875)
* test: dashboard_view_test failing * test: tests works first time * fix: pre-commit and some refactoring * fix: after CR * fix: replace not_published with draft * fix: after CR * fix: pre-commit fixes * fix: pre-commit and lint fixes * fix: remove unused * fix: remove unused import * fix: wrap the decorator to not block others * chore: reuse dashboard from decorator into function
This commit is contained in:
@@ -160,7 +160,7 @@ class TestDashboardDatasetSecurity(DashboardTestCase):
|
||||
# arrange
|
||||
admin_user = security_manager.find_user(ADMIN_USERNAME)
|
||||
gamma_user = security_manager.find_user(GAMMA_USERNAME)
|
||||
admin_and_not_published_dashboard = create_dashboard_to_db(
|
||||
admin_and_draft_dashboard = create_dashboard_to_db(
|
||||
dashboard_title="admin_owned_unpublished_dash", owners=[admin_user]
|
||||
)
|
||||
|
||||
@@ -171,7 +171,7 @@ class TestDashboardDatasetSecurity(DashboardTestCase):
|
||||
|
||||
# assert
|
||||
self.assertNotIn(
|
||||
admin_and_not_published_dashboard.url, get_dashboards_response_as_gamma
|
||||
admin_and_draft_dashboard.url, get_dashboards_response_as_gamma
|
||||
)
|
||||
|
||||
@pytest.mark.usefixtures("load_energy_table_with_slice", "load_dashboard")
|
||||
|
||||
@@ -31,6 +31,136 @@ from tests.dashboards.superset_factory_util import (
|
||||
"superset.extensions.feature_flag_manager._feature_flags", DASHBOARD_RBAC=True,
|
||||
)
|
||||
class TestDashboardRoleBasedSecurity(BaseTestDashboardSecurity):
|
||||
def test_get_dashboard_view__admin_can_access(self):
|
||||
# arrange
|
||||
dashboard_to_access = create_dashboard_to_db(
|
||||
owners=[], slices=[create_slice_to_db()], published=False
|
||||
)
|
||||
self.login("admin")
|
||||
|
||||
# act
|
||||
response = self.get_dashboard_view_response(dashboard_to_access)
|
||||
|
||||
# assert
|
||||
self.assert_dashboard_view_response(response, dashboard_to_access)
|
||||
|
||||
def test_get_dashboard_view__owner_can_access(self):
|
||||
# arrange
|
||||
username = random_str()
|
||||
new_role = f"role_{random_str()}"
|
||||
owner = self.create_user_with_roles(
|
||||
username, [new_role], should_create_roles=True
|
||||
)
|
||||
dashboard_to_access = create_dashboard_to_db(
|
||||
owners=[owner], slices=[create_slice_to_db()], published=False
|
||||
)
|
||||
self.login(username)
|
||||
|
||||
# act
|
||||
response = self.get_dashboard_view_response(dashboard_to_access)
|
||||
|
||||
# assert
|
||||
self.assert_dashboard_view_response(response, dashboard_to_access)
|
||||
|
||||
def test_get_dashboard_view__user_can_not_access_without_permission(self):
|
||||
username = random_str()
|
||||
new_role = f"role_{random_str()}"
|
||||
self.create_user_with_roles(username, [new_role], should_create_roles=True)
|
||||
dashboard_to_access = create_dashboard_to_db(published=True)
|
||||
self.login(username)
|
||||
|
||||
# act
|
||||
response = self.get_dashboard_view_response(dashboard_to_access)
|
||||
|
||||
# assert
|
||||
self.assert403(response)
|
||||
|
||||
def test_get_dashboard_view__user_with_dashboard_permission_can_not_access_draft(
|
||||
self,
|
||||
):
|
||||
# arrange
|
||||
dashboard_to_access = create_dashboard_to_db(published=False)
|
||||
username = random_str()
|
||||
new_role = f"role_{random_str()}"
|
||||
self.create_user_with_roles(username, [new_role], should_create_roles=True)
|
||||
grant_access_to_dashboard(dashboard_to_access, new_role)
|
||||
self.login(username)
|
||||
|
||||
# act
|
||||
response = self.get_dashboard_view_response(dashboard_to_access)
|
||||
|
||||
# assert
|
||||
self.assert403(response)
|
||||
|
||||
# post
|
||||
revoke_access_to_dashboard(dashboard_to_access, new_role)
|
||||
|
||||
def test_get_dashboard_view__user_access_with_dashboard_permission(self):
|
||||
# arrange
|
||||
|
||||
username = random_str()
|
||||
new_role = f"role_{random_str()}"
|
||||
self.create_user_with_roles(username, [new_role], should_create_roles=True)
|
||||
|
||||
dashboard_to_access = create_dashboard_to_db(
|
||||
published=True, slices=[create_slice_to_db()]
|
||||
)
|
||||
self.login(username)
|
||||
grant_access_to_dashboard(dashboard_to_access, new_role)
|
||||
|
||||
# act
|
||||
response = self.get_dashboard_view_response(dashboard_to_access)
|
||||
|
||||
# assert
|
||||
self.assert_dashboard_view_response(response, dashboard_to_access)
|
||||
|
||||
# post
|
||||
revoke_access_to_dashboard(dashboard_to_access, new_role)
|
||||
|
||||
def test_get_dashboard_view__public_user_can_not_access_without_permission(self):
|
||||
dashboard_to_access = create_dashboard_to_db(published=True)
|
||||
self.logout()
|
||||
|
||||
# act
|
||||
response = self.get_dashboard_view_response(dashboard_to_access)
|
||||
|
||||
# assert
|
||||
self.assert403(response)
|
||||
|
||||
def test_get_dashboard_view__public_user_with_dashboard_permission_can_not_access_draft(
|
||||
self,
|
||||
):
|
||||
# arrange
|
||||
dashboard_to_access = create_dashboard_to_db(published=False)
|
||||
grant_access_to_dashboard(dashboard_to_access, "Public")
|
||||
self.logout()
|
||||
# act
|
||||
response = self.get_dashboard_view_response(dashboard_to_access)
|
||||
|
||||
# assert
|
||||
self.assert403(response)
|
||||
|
||||
# post
|
||||
revoke_access_to_dashboard(dashboard_to_access, "Public")
|
||||
|
||||
def test_get_dashboard_view__public_user_access_with_dashboard_permission(self):
|
||||
# arrange
|
||||
dashboard_to_access = create_dashboard_to_db(
|
||||
published=True, slices=[create_slice_to_db()]
|
||||
)
|
||||
grant_access_to_dashboard(dashboard_to_access, "Public")
|
||||
|
||||
self.logout()
|
||||
|
||||
# act
|
||||
response = self.get_dashboard_view_response(dashboard_to_access)
|
||||
|
||||
# assert
|
||||
self.assert_dashboard_view_response(response, dashboard_to_access)
|
||||
|
||||
# post
|
||||
revoke_access_to_dashboard(dashboard_to_access, "Public")
|
||||
|
||||
def test_get_dashboards_list__admin_get_all_dashboards(self):
|
||||
# arrange
|
||||
create_dashboard_to_db(
|
||||
@@ -48,6 +178,20 @@ class TestDashboardRoleBasedSecurity(BaseTestDashboardSecurity):
|
||||
|
||||
def test_get_dashboards_list__owner_get_all_owned_dashboards(self):
|
||||
# arrange
|
||||
(
|
||||
not_owned_dashboards,
|
||||
owned_dashboards,
|
||||
) = self._create_sample_dashboards_with_owner_access()
|
||||
|
||||
# act
|
||||
response = self.get_dashboards_list_response()
|
||||
|
||||
# assert
|
||||
self.assert_dashboards_list_view_response(
|
||||
response, 2, owned_dashboards, not_owned_dashboards
|
||||
)
|
||||
|
||||
def _create_sample_dashboards_with_owner_access(self):
|
||||
username = random_str()
|
||||
new_role = f"role_{random_str()}"
|
||||
owner = self.create_user_with_roles(
|
||||
@@ -67,16 +211,8 @@ class TestDashboardRoleBasedSecurity(BaseTestDashboardSecurity):
|
||||
slices=[create_slice_to_db(datasource_id=table.id)], published=True
|
||||
)
|
||||
]
|
||||
|
||||
self.login(username)
|
||||
|
||||
# act
|
||||
response = self.get_dashboards_list_response()
|
||||
|
||||
# assert
|
||||
self.assert_dashboards_list_view_response(
|
||||
response, 2, owned_dashboards, not_owned_dashboards
|
||||
)
|
||||
return not_owned_dashboards, owned_dashboards
|
||||
|
||||
def test_get_dashboards_list__user_without_any_permissions_get_empty_list(self):
|
||||
|
||||
@@ -96,39 +232,41 @@ class TestDashboardRoleBasedSecurity(BaseTestDashboardSecurity):
|
||||
|
||||
def test_get_dashboards_list__user_get_only_published_permitted_dashboards(self):
|
||||
# arrange
|
||||
username = random_str()
|
||||
new_role = f"role_{random_str()}"
|
||||
self.create_user_with_roles(username, [new_role], should_create_roles=True)
|
||||
|
||||
published_dashboards = [
|
||||
create_dashboard_to_db(published=True),
|
||||
create_dashboard_to_db(published=True),
|
||||
]
|
||||
not_published_dashboards = [
|
||||
create_dashboard_to_db(published=False),
|
||||
create_dashboard_to_db(published=False),
|
||||
]
|
||||
|
||||
for dash in published_dashboards + not_published_dashboards:
|
||||
grant_access_to_dashboard(dash, new_role)
|
||||
|
||||
self.login(username)
|
||||
(
|
||||
new_role,
|
||||
draft_dashboards,
|
||||
published_dashboards,
|
||||
) = self._create_sample_only_published_dashboard_with_roles()
|
||||
|
||||
# act
|
||||
response = self.get_dashboards_list_response()
|
||||
|
||||
# assert
|
||||
self.assert_dashboards_list_view_response(
|
||||
response,
|
||||
len(published_dashboards),
|
||||
published_dashboards,
|
||||
not_published_dashboards,
|
||||
response, len(published_dashboards), published_dashboards, draft_dashboards,
|
||||
)
|
||||
|
||||
# post
|
||||
for dash in published_dashboards + not_published_dashboards:
|
||||
for dash in published_dashboards + draft_dashboards:
|
||||
revoke_access_to_dashboard(dash, new_role)
|
||||
|
||||
def _create_sample_only_published_dashboard_with_roles(self):
|
||||
username = random_str()
|
||||
new_role = f"role_{random_str()}"
|
||||
self.create_user_with_roles(username, [new_role], should_create_roles=True)
|
||||
published_dashboards = [
|
||||
create_dashboard_to_db(published=True),
|
||||
create_dashboard_to_db(published=True),
|
||||
]
|
||||
draft_dashboards = [
|
||||
create_dashboard_to_db(published=False),
|
||||
create_dashboard_to_db(published=False),
|
||||
]
|
||||
for dash in published_dashboards + draft_dashboards:
|
||||
grant_access_to_dashboard(dash, new_role)
|
||||
self.login(username)
|
||||
return new_role, draft_dashboards, published_dashboards
|
||||
|
||||
def test_get_dashboards_list__public_user_without_any_permissions_get_empty_list(
|
||||
self,
|
||||
):
|
||||
@@ -148,27 +286,26 @@ class TestDashboardRoleBasedSecurity(BaseTestDashboardSecurity):
|
||||
create_dashboard_to_db(published=True),
|
||||
create_dashboard_to_db(published=True),
|
||||
]
|
||||
not_published_dashboards = [
|
||||
draft_dashboards = [
|
||||
create_dashboard_to_db(published=False),
|
||||
create_dashboard_to_db(published=False),
|
||||
]
|
||||
|
||||
for dash in published_dashboards + not_published_dashboards:
|
||||
for dash in published_dashboards + draft_dashboards:
|
||||
grant_access_to_dashboard(dash, "Public")
|
||||
|
||||
self.logout()
|
||||
|
||||
# act
|
||||
response = self.get_dashboards_list_response()
|
||||
|
||||
# assert
|
||||
self.assert_dashboards_list_view_response(
|
||||
response,
|
||||
len(published_dashboards),
|
||||
published_dashboards,
|
||||
not_published_dashboards,
|
||||
response, len(published_dashboards), published_dashboards, draft_dashboards,
|
||||
)
|
||||
|
||||
# post
|
||||
for dash in published_dashboards + not_published_dashboards:
|
||||
for dash in published_dashboards + draft_dashboards:
|
||||
revoke_access_to_dashboard(dash, "Public")
|
||||
|
||||
def test_get_dashboards_api__admin_get_all_dashboards(self):
|
||||
@@ -188,27 +325,10 @@ class TestDashboardRoleBasedSecurity(BaseTestDashboardSecurity):
|
||||
|
||||
def test_get_dashboards_api__owner_get_all_owned_dashboards(self):
|
||||
# arrange
|
||||
username = random_str()
|
||||
new_role = f"role_{random_str()}"
|
||||
owner = self.create_user_with_roles(
|
||||
username, [new_role], should_create_roles=True
|
||||
)
|
||||
database = create_database_to_db()
|
||||
table = create_datasource_table_to_db(db_id=database.id, owners=[owner])
|
||||
first_dash = create_dashboard_to_db(
|
||||
owners=[owner], slices=[create_slice_to_db(datasource_id=table.id)]
|
||||
)
|
||||
second_dash = create_dashboard_to_db(
|
||||
owners=[owner], slices=[create_slice_to_db(datasource_id=table.id)]
|
||||
)
|
||||
owned_dashboards = [first_dash, second_dash]
|
||||
not_owned_dashboards = [
|
||||
create_dashboard_to_db(
|
||||
slices=[create_slice_to_db(datasource_id=table.id)], published=True
|
||||
)
|
||||
]
|
||||
|
||||
self.login(username)
|
||||
(
|
||||
not_owned_dashboards,
|
||||
owned_dashboards,
|
||||
) = self._create_sample_dashboards_with_owner_access()
|
||||
|
||||
# act
|
||||
response = self.get_dashboards_api_response()
|
||||
@@ -232,43 +352,29 @@ class TestDashboardRoleBasedSecurity(BaseTestDashboardSecurity):
|
||||
self.assert_dashboards_api_response(response, 0)
|
||||
|
||||
def test_get_dashboards_api__user_get_only_published_permitted_dashboards(self):
|
||||
username = random_str()
|
||||
new_role = f"role_{random_str()}"
|
||||
self.create_user_with_roles(username, [new_role], should_create_roles=True)
|
||||
# arrange
|
||||
published_dashboards = [
|
||||
create_dashboard_to_db(published=True),
|
||||
create_dashboard_to_db(published=True),
|
||||
]
|
||||
not_published_dashboards = [
|
||||
create_dashboard_to_db(published=False),
|
||||
create_dashboard_to_db(published=False),
|
||||
]
|
||||
|
||||
for dash in published_dashboards + not_published_dashboards:
|
||||
grant_access_to_dashboard(dash, new_role)
|
||||
|
||||
self.login(username)
|
||||
(
|
||||
new_role,
|
||||
draft_dashboards,
|
||||
published_dashboards,
|
||||
) = self._create_sample_only_published_dashboard_with_roles()
|
||||
|
||||
# act
|
||||
response = self.get_dashboards_api_response()
|
||||
|
||||
# assert
|
||||
self.assert_dashboards_api_response(
|
||||
response,
|
||||
len(published_dashboards),
|
||||
published_dashboards,
|
||||
not_published_dashboards,
|
||||
response, len(published_dashboards), published_dashboards, draft_dashboards,
|
||||
)
|
||||
|
||||
# post
|
||||
for dash in published_dashboards + not_published_dashboards:
|
||||
for dash in published_dashboards + draft_dashboards:
|
||||
revoke_access_to_dashboard(dash, new_role)
|
||||
|
||||
def test_get_dashboards_api__public_user_without_any_permissions_get_empty_list(
|
||||
self,
|
||||
):
|
||||
create_dashboard_to_db(published=True)
|
||||
self.logout()
|
||||
|
||||
# act
|
||||
response = self.get_dashboards_api_response()
|
||||
@@ -284,25 +390,24 @@ class TestDashboardRoleBasedSecurity(BaseTestDashboardSecurity):
|
||||
create_dashboard_to_db(published=True),
|
||||
create_dashboard_to_db(published=True),
|
||||
]
|
||||
not_published_dashboards = [
|
||||
draft_dashboards = [
|
||||
create_dashboard_to_db(published=False),
|
||||
create_dashboard_to_db(published=False),
|
||||
]
|
||||
|
||||
for dash in published_dashboards + not_published_dashboards:
|
||||
for dash in published_dashboards + draft_dashboards:
|
||||
grant_access_to_dashboard(dash, "Public")
|
||||
|
||||
self.logout()
|
||||
|
||||
# act
|
||||
response = self.get_dashboards_api_response()
|
||||
|
||||
# assert
|
||||
self.assert_dashboards_api_response(
|
||||
response,
|
||||
len(published_dashboards),
|
||||
published_dashboards,
|
||||
not_published_dashboards,
|
||||
response, len(published_dashboards), published_dashboards, draft_dashboards,
|
||||
)
|
||||
|
||||
# post
|
||||
for dash in published_dashboards + not_published_dashboards:
|
||||
for dash in published_dashboards + draft_dashboards:
|
||||
revoke_access_to_dashboard(dash, "Public")
|
||||
|
||||
Reference in New Issue
Block a user