2019-01-15 18:53:27 -05:00
|
|
|
# Licensed to the Apache Software Foundation (ASF) under one
|
|
|
|
# or more contributor license agreements. See the NOTICE file
|
|
|
|
# distributed with this work for additional information
|
|
|
|
# regarding copyright ownership. The ASF licenses this file
|
|
|
|
# to you under the Apache License, Version 2.0 (the
|
|
|
|
# "License"); you may not use this file except in compliance
|
|
|
|
# with the License. You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing,
|
|
|
|
# software distributed under the License is distributed on an
|
|
|
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
|
|
# KIND, either express or implied. See the License for the
|
|
|
|
# specific language governing permissions and limitations
|
|
|
|
# under the License.
|
2020-02-06 19:45:37 -05:00
|
|
|
# isort:skip_file
|
2018-12-18 14:57:13 -05:00
|
|
|
import inspect
|
2022-01-25 19:41:32 -05:00
|
|
|
import time
|
2019-08-02 13:01:28 -04:00
|
|
|
import unittest
|
2021-06-30 12:51:11 -04:00
|
|
|
from collections import namedtuple
|
|
|
|
from unittest import mock
|
2022-07-06 04:54:18 -04:00
|
|
|
from unittest.mock import Mock, patch, call, ANY
|
2022-01-25 19:41:32 -05:00
|
|
|
from typing import Any
|
2018-12-18 14:57:13 -05:00
|
|
|
|
2022-01-25 19:41:32 -05:00
|
|
|
import jwt
|
2019-12-03 17:57:24 -05:00
|
|
|
import prison
|
2020-10-07 11:29:37 -04:00
|
|
|
import pytest
|
|
|
|
|
2022-01-25 19:41:32 -05:00
|
|
|
from flask import current_app
|
2022-06-21 07:22:39 -04:00
|
|
|
from superset.datasource.dao import DatasourceDAO
|
2019-12-03 17:57:24 -05:00
|
|
|
|
2021-01-13 17:20:05 -05:00
|
|
|
from superset.models.dashboard import Dashboard
|
|
|
|
|
2022-06-21 07:22:39 -04:00
|
|
|
from superset import app, appbuilder, db, security_manager, viz
|
2022-01-25 19:41:32 -05:00
|
|
|
from superset.connectors.sqla.models import SqlaTable
|
2020-06-23 23:49:39 -04:00
|
|
|
from superset.errors import ErrorLevel, SupersetError, SupersetErrorType
|
2019-10-01 19:52:15 -04:00
|
|
|
from superset.exceptions import SupersetSecurityException
|
2019-12-18 14:40:45 -05:00
|
|
|
from superset.models.core import Database
|
|
|
|
from superset.models.slice import Slice
|
2020-06-23 23:49:39 -04:00
|
|
|
from superset.sql_parse import Table
|
2021-12-15 20:06:40 -05:00
|
|
|
from superset.utils.core import (
|
2022-06-02 19:48:16 -04:00
|
|
|
DatasourceType,
|
2021-12-15 20:06:40 -05:00
|
|
|
backend,
|
|
|
|
get_example_default_schema,
|
|
|
|
)
|
2022-01-16 01:32:50 -05:00
|
|
|
from superset.utils.database import get_example_database
|
2022-02-14 13:43:35 -05:00
|
|
|
from superset.utils.urls import get_url_host
|
2021-05-21 17:29:52 -04:00
|
|
|
from superset.views.access_requests import AccessRequestsModelView
|
2019-10-18 17:44:27 -04:00
|
|
|
|
2016-12-15 08:38:34 -05:00
|
|
|
from .base_tests import SupersetTestCase
|
2021-07-01 11:03:07 -04:00
|
|
|
from tests.integration_tests.fixtures.public_role import (
|
2021-02-23 04:50:22 -05:00
|
|
|
public_role_like_gamma,
|
|
|
|
public_role_like_test_role,
|
|
|
|
)
|
2022-02-24 14:02:01 -05:00
|
|
|
from tests.integration_tests.fixtures.birth_names_dashboard import (
|
|
|
|
load_birth_names_dashboard_with_slices,
|
|
|
|
load_birth_names_data,
|
|
|
|
)
|
2021-07-01 11:03:07 -04:00
|
|
|
from tests.integration_tests.fixtures.world_bank_dashboard import (
|
|
|
|
load_world_bank_dashboard_with_slices,
|
2021-12-16 19:11:47 -05:00
|
|
|
load_world_bank_data,
|
2021-07-01 11:03:07 -04:00
|
|
|
)
|
2022-08-23 21:45:39 -04:00
|
|
|
from .dashboard_utils import get_table
|
2016-12-15 08:38:34 -05:00
|
|
|
|
2020-12-16 06:49:03 -05:00
|
|
|
NEW_SECURITY_CONVERGE_VIEWS = (
|
|
|
|
"Annotation",
|
2020-12-17 07:37:05 -05:00
|
|
|
"Database",
|
2020-12-16 06:49:03 -05:00
|
|
|
"Dataset",
|
2020-12-17 04:53:13 -05:00
|
|
|
"Dashboard",
|
2020-12-16 06:49:03 -05:00
|
|
|
"CssTemplate",
|
|
|
|
"Chart",
|
2020-12-17 09:27:14 -05:00
|
|
|
"Query",
|
2020-12-16 06:49:03 -05:00
|
|
|
"SavedQuery",
|
|
|
|
)
|
2020-12-03 03:45:32 -05:00
|
|
|
|
2022-08-23 21:45:39 -04:00
|
|
|
GAMMA_ROLE_PERMISSIONS = {
|
|
|
|
"Gamma": [
|
|
|
|
["menu_access", "List Users"],
|
|
|
|
["can_read", "SavedQuery"],
|
|
|
|
["can_write", "SavedQuery"],
|
|
|
|
["can_read", "CssTemplate"],
|
|
|
|
["can_write", "CssTemplate"],
|
|
|
|
["can_read", "ReportSchedule"],
|
|
|
|
["can_write", "ReportSchedule"],
|
|
|
|
["can_read", "Chart"],
|
|
|
|
["can_write", "Chart"],
|
|
|
|
["can_read", "Annotation"],
|
|
|
|
["can_write", "Annotation"],
|
|
|
|
["can_read", "Dataset"],
|
|
|
|
["can_read", "Dashboard"],
|
|
|
|
["can_write", "Dashboard"],
|
|
|
|
["can_read", "Database"],
|
|
|
|
["can_read", "Query"],
|
|
|
|
["can_this_form_post", "ResetMyPasswordView"],
|
|
|
|
["can_this_form_get", "ResetMyPasswordView"],
|
|
|
|
["can_this_form_post", "UserInfoEditView"],
|
|
|
|
["can_this_form_get", "UserInfoEditView"],
|
|
|
|
["can_userinfo", "UserDBModelView"],
|
|
|
|
["resetmypassword", "UserDBModelView"],
|
|
|
|
["can_get", "OpenApi"],
|
|
|
|
["can_show", "SwaggerView"],
|
|
|
|
["can_get", "MenuApi"],
|
|
|
|
["can_list", "AsyncEventsRestApi"],
|
|
|
|
["can_read", "AdvancedDataType"],
|
|
|
|
["can_invalidate", "CacheRestApi"],
|
|
|
|
["can_export", "Chart"],
|
|
|
|
["can_read", "DashboardFilterStateRestApi"],
|
|
|
|
["can_write", "DashboardFilterStateRestApi"],
|
|
|
|
["can_read", "DashboardPermalinkRestApi"],
|
|
|
|
["can_write", "DashboardPermalinkRestApi"],
|
|
|
|
["can_delete_embedded", "Dashboard"],
|
|
|
|
["can_get_embedded", "Dashboard"],
|
|
|
|
["can_export", "Dashboard"],
|
|
|
|
["can_read", "EmbeddedDashboard"],
|
|
|
|
["can_read", "Explore"],
|
|
|
|
["can_read", "ExploreFormDataRestApi"],
|
|
|
|
["can_write", "ExploreFormDataRestApi"],
|
|
|
|
["can_read", "ExplorePermalinkRestApi"],
|
|
|
|
["can_write", "ExplorePermalinkRestApi"],
|
|
|
|
["can_delete", "FilterSets"],
|
|
|
|
["can_list", "FilterSets"],
|
|
|
|
["can_edit", "FilterSets"],
|
|
|
|
["can_add", "FilterSets"],
|
|
|
|
["can_import_", "ImportExportRestApi"],
|
|
|
|
["can_export", "ImportExportRestApi"],
|
|
|
|
["can_export", "SavedQuery"],
|
|
|
|
["can_show", "DynamicPlugin"],
|
|
|
|
["can_list", "DynamicPlugin"],
|
|
|
|
["can_time_range", "Api"],
|
|
|
|
["can_query_form_data", "Api"],
|
|
|
|
["can_query", "Api"],
|
|
|
|
["can_this_form_post", "CsvToDatabaseView"],
|
|
|
|
["can_this_form_get", "CsvToDatabaseView"],
|
|
|
|
["can_this_form_post", "ExcelToDatabaseView"],
|
|
|
|
["can_this_form_get", "ExcelToDatabaseView"],
|
|
|
|
["can_this_form_post", "ColumnarToDatabaseView"],
|
|
|
|
["can_this_form_get", "ColumnarToDatabaseView"],
|
|
|
|
["can_get", "Datasource"],
|
|
|
|
["can_external_metadata", "Datasource"],
|
|
|
|
["can_external_metadata_by_name", "Datasource"],
|
|
|
|
["can_get_value", "KV"],
|
|
|
|
["can_store", "KV"],
|
|
|
|
["can_my_queries", "SqlLab"],
|
|
|
|
["can_created_dashboards", "Superset"],
|
|
|
|
["can_testconn", "Superset"],
|
|
|
|
["can_estimate_query_cost", "Superset"],
|
|
|
|
["can_explore", "Superset"],
|
|
|
|
["can_fetch_datasource_metadata", "Superset"],
|
|
|
|
["can_search_queries", "Superset"],
|
|
|
|
["can_save_dash", "Superset"],
|
|
|
|
["can_dashboard_permalink", "Superset"],
|
|
|
|
["can_warm_up_cache", "Superset"],
|
|
|
|
["can_request_access", "Superset"],
|
|
|
|
["can_datasources", "Superset"],
|
|
|
|
["can_available_domains", "Superset"],
|
|
|
|
["can_dashboard", "Superset"],
|
|
|
|
["can_annotation_json", "Superset"],
|
|
|
|
["can_created_slices", "Superset"],
|
|
|
|
["can_slice_json", "Superset"],
|
|
|
|
["can_profile", "Superset"],
|
|
|
|
["can_filter", "Superset"],
|
|
|
|
["can_validate_sql_json", "Superset"],
|
|
|
|
["can_slice", "Superset"],
|
|
|
|
["can_sqllab", "Superset"],
|
|
|
|
["can_log", "Superset"],
|
|
|
|
["can_recent_activity", "Superset"],
|
|
|
|
["can_tables", "Superset"],
|
|
|
|
["can_fave_slices", "Superset"],
|
|
|
|
["can_sqllab_viz", "Superset"],
|
|
|
|
["can_fave_dashboards", "Superset"],
|
|
|
|
["can_results", "Superset"],
|
|
|
|
["can_extra_table_metadata", "Superset"],
|
|
|
|
["can_schemas_access_for_file_upload", "Superset"],
|
|
|
|
["can_fave_dashboards_by_username", "Superset"],
|
|
|
|
["can_csv", "Superset"],
|
|
|
|
["can_add_slices", "Superset"],
|
|
|
|
["can_explore_json", "Superset"],
|
|
|
|
["can_sqllab_history", "Superset"],
|
|
|
|
["can_import_dashboards", "Superset"],
|
|
|
|
["can_sqllab_table_viz", "Superset"],
|
|
|
|
["can_stop_query", "Superset"],
|
|
|
|
["can_favstar", "Superset"],
|
|
|
|
["can_copy_dash", "Superset"],
|
|
|
|
["can_queries", "Superset"],
|
|
|
|
["can_user_slices", "Superset"],
|
|
|
|
["can_delete", "TableSchemaView"],
|
|
|
|
["can_post", "TableSchemaView"],
|
|
|
|
["can_expanded", "TableSchemaView"],
|
|
|
|
["can_get", "TabStateView"],
|
|
|
|
["can_post", "TabStateView"],
|
|
|
|
["can_migrate_query", "TabStateView"],
|
|
|
|
["can_put", "TabStateView"],
|
|
|
|
["can_activate", "TabStateView"],
|
|
|
|
["can_delete", "TabStateView"],
|
|
|
|
["can_delete_query", "TabStateView"],
|
|
|
|
["can_get", "TagView"],
|
|
|
|
["can_tagged_objects", "TagView"],
|
|
|
|
["can_post", "TagView"],
|
|
|
|
["can_delete", "TagView"],
|
|
|
|
["can_suggestions", "TagView"],
|
|
|
|
["can_read", "SecurityRestApi"],
|
|
|
|
["menu_access", "List Roles"],
|
|
|
|
["menu_access", "Action Log"],
|
|
|
|
["menu_access", "Access requests"],
|
|
|
|
["menu_access", "Home"],
|
|
|
|
["menu_access", "Annotation Layers"],
|
|
|
|
["menu_access", "Plugins"],
|
|
|
|
["menu_access", "Import Dashboards"],
|
|
|
|
["menu_access", "Alerts & Report"],
|
|
|
|
["menu_access", "Dashboards"],
|
|
|
|
["menu_access", "Charts"],
|
|
|
|
["menu_access", "SQL Editor"],
|
|
|
|
["menu_access", "Saved Queries"],
|
|
|
|
["menu_access", "Query Search"],
|
|
|
|
["menu_access", "Data"],
|
|
|
|
["menu_access", "Databases"],
|
|
|
|
["menu_access", "Datasets"],
|
|
|
|
["can_share_dashboard", "Superset"],
|
|
|
|
["can_share_chart", "Superset"],
|
|
|
|
],
|
|
|
|
"schema_access_role": [["schema_access", "[examples].[temp_schema]"]],
|
|
|
|
"dummy_role": [
|
|
|
|
["datasource_access", "[examples].[wb_health_population](id:1)"],
|
|
|
|
["database_access", "[examples].(id:1)"],
|
|
|
|
],
|
|
|
|
}
|
|
|
|
|
2016-12-15 08:38:34 -05:00
|
|
|
|
|
|
|
def get_perm_tuples(role_name):
|
|
|
|
perm_set = set()
|
2018-03-27 19:46:02 -04:00
|
|
|
for perm in security_manager.find_role(role_name).permissions:
|
2016-12-15 08:38:34 -05:00
|
|
|
perm_set.add((perm.permission.name, perm.view_menu.name))
|
|
|
|
return perm_set
|
|
|
|
|
|
|
|
|
2019-12-03 17:57:24 -05:00
|
|
|
SCHEMA_ACCESS_ROLE = "schema_access_role"
|
|
|
|
|
|
|
|
|
|
|
|
def create_schema_perm(view_menu_name: str) -> None:
|
|
|
|
permission = "schema_access"
|
|
|
|
security_manager.add_permission_view_menu(permission, view_menu_name)
|
|
|
|
perm_view = security_manager.find_permission_view_menu(permission, view_menu_name)
|
|
|
|
security_manager.add_permission_role(
|
|
|
|
security_manager.find_role(SCHEMA_ACCESS_ROLE), perm_view
|
|
|
|
)
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
def delete_schema_perm(view_menu_name: str) -> None:
|
|
|
|
pv = security_manager.find_permission_view_menu("schema_access", "[examples].[2]")
|
|
|
|
security_manager.del_permission_role(
|
|
|
|
security_manager.find_role(SCHEMA_ACCESS_ROLE), pv
|
|
|
|
)
|
|
|
|
security_manager.del_permission_view_menu("schema_access", "[examples].[2]")
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
2020-06-29 18:36:06 -04:00
|
|
|
class TestRolePermission(SupersetTestCase):
|
2019-12-03 17:57:24 -05:00
|
|
|
"""Testing export role permissions."""
|
|
|
|
|
|
|
|
def setUp(self):
|
2021-11-04 14:09:08 -04:00
|
|
|
schema = get_example_default_schema()
|
2020-08-06 18:33:48 -04:00
|
|
|
session = db.session
|
2019-12-03 17:57:24 -05:00
|
|
|
security_manager.add_role(SCHEMA_ACCESS_ROLE)
|
2020-08-06 18:33:48 -04:00
|
|
|
session.commit()
|
2019-12-03 17:57:24 -05:00
|
|
|
|
|
|
|
ds = (
|
|
|
|
db.session.query(SqlaTable)
|
2021-11-04 14:09:08 -04:00
|
|
|
.filter_by(table_name="wb_health_population", schema=schema)
|
2019-12-03 17:57:24 -05:00
|
|
|
.first()
|
|
|
|
)
|
|
|
|
ds.schema = "temp_schema"
|
|
|
|
ds.schema_perm = ds.get_schema_perm()
|
|
|
|
|
|
|
|
ds_slices = (
|
2020-08-06 18:33:48 -04:00
|
|
|
session.query(Slice)
|
2022-06-02 19:48:16 -04:00
|
|
|
.filter_by(datasource_type=DatasourceType.TABLE)
|
2019-12-03 17:57:24 -05:00
|
|
|
.filter_by(datasource_id=ds.id)
|
|
|
|
.all()
|
|
|
|
)
|
|
|
|
for s in ds_slices:
|
|
|
|
s.schema_perm = ds.schema_perm
|
|
|
|
create_schema_perm("[examples].[temp_schema]")
|
|
|
|
gamma_user = security_manager.find_user(username="gamma")
|
|
|
|
gamma_user.roles.append(security_manager.find_role(SCHEMA_ACCESS_ROLE))
|
2020-08-06 18:33:48 -04:00
|
|
|
session.commit()
|
2019-12-03 17:57:24 -05:00
|
|
|
|
|
|
|
def tearDown(self):
|
2020-08-06 18:33:48 -04:00
|
|
|
session = db.session
|
2019-12-03 17:57:24 -05:00
|
|
|
ds = (
|
2020-08-06 18:33:48 -04:00
|
|
|
session.query(SqlaTable)
|
2021-11-04 14:09:08 -04:00
|
|
|
.filter_by(table_name="wb_health_population", schema="temp_schema")
|
2019-12-03 17:57:24 -05:00
|
|
|
.first()
|
|
|
|
)
|
|
|
|
schema_perm = ds.schema_perm
|
2021-11-04 14:09:08 -04:00
|
|
|
ds.schema = get_example_default_schema()
|
2019-12-03 17:57:24 -05:00
|
|
|
ds.schema_perm = None
|
|
|
|
ds_slices = (
|
2020-08-06 18:33:48 -04:00
|
|
|
session.query(Slice)
|
2022-06-02 19:48:16 -04:00
|
|
|
.filter_by(datasource_type=DatasourceType.TABLE)
|
2019-12-03 17:57:24 -05:00
|
|
|
.filter_by(datasource_id=ds.id)
|
|
|
|
.all()
|
|
|
|
)
|
|
|
|
for s in ds_slices:
|
|
|
|
s.schema_perm = None
|
|
|
|
|
|
|
|
delete_schema_perm(schema_perm)
|
2020-08-06 18:33:48 -04:00
|
|
|
session.delete(security_manager.find_role(SCHEMA_ACCESS_ROLE))
|
|
|
|
session.commit()
|
2019-12-03 17:57:24 -05:00
|
|
|
|
|
|
|
def test_set_perm_sqla_table(self):
|
2022-07-06 04:54:18 -04:00
|
|
|
security_manager.on_view_menu_after_insert = Mock()
|
|
|
|
security_manager.on_permission_view_after_insert = Mock()
|
|
|
|
|
2020-08-06 18:33:48 -04:00
|
|
|
session = db.session
|
2019-12-03 17:57:24 -05:00
|
|
|
table = SqlaTable(
|
|
|
|
schema="tmp_schema",
|
|
|
|
table_name="tmp_perm_table",
|
|
|
|
database=get_example_database(),
|
|
|
|
)
|
2020-08-06 18:33:48 -04:00
|
|
|
session.add(table)
|
|
|
|
session.commit()
|
2019-12-03 17:57:24 -05:00
|
|
|
|
|
|
|
stored_table = (
|
2020-08-06 18:33:48 -04:00
|
|
|
session.query(SqlaTable).filter_by(table_name="tmp_perm_table").one()
|
2019-12-03 17:57:24 -05:00
|
|
|
)
|
2020-06-29 19:38:06 -04:00
|
|
|
self.assertEqual(
|
2019-12-03 17:57:24 -05:00
|
|
|
stored_table.perm, f"[examples].[tmp_perm_table](id:{stored_table.id})"
|
|
|
|
)
|
2022-07-06 04:54:18 -04:00
|
|
|
|
|
|
|
pvm_dataset = security_manager.find_permission_view_menu(
|
|
|
|
"datasource_access", stored_table.perm
|
|
|
|
)
|
|
|
|
pvm_schema = security_manager.find_permission_view_menu(
|
|
|
|
"schema_access", stored_table.schema_perm
|
2019-12-03 17:57:24 -05:00
|
|
|
)
|
2022-07-06 04:54:18 -04:00
|
|
|
|
|
|
|
self.assertIsNotNone(pvm_dataset)
|
2020-06-29 19:38:06 -04:00
|
|
|
self.assertEqual(stored_table.schema_perm, "[examples].[tmp_schema]")
|
2022-07-06 04:54:18 -04:00
|
|
|
self.assertIsNotNone(pvm_schema)
|
|
|
|
|
|
|
|
# assert on permission hooks
|
|
|
|
view_menu_dataset = security_manager.find_view_menu(
|
|
|
|
f"[examples].[tmp_perm_table](id:{stored_table.id})"
|
|
|
|
)
|
|
|
|
view_menu_schema = security_manager.find_view_menu(f"[examples].[tmp_schema]")
|
|
|
|
security_manager.on_view_menu_after_insert.assert_has_calls(
|
|
|
|
[
|
|
|
|
call(ANY, ANY, view_menu_dataset),
|
|
|
|
call(ANY, ANY, view_menu_schema),
|
|
|
|
]
|
|
|
|
)
|
|
|
|
security_manager.on_permission_view_after_insert.assert_has_calls(
|
|
|
|
[
|
|
|
|
call(ANY, ANY, pvm_dataset),
|
|
|
|
call(ANY, ANY, pvm_schema),
|
|
|
|
]
|
2019-12-03 17:57:24 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
# table name change
|
2022-08-02 16:06:53 -04:00
|
|
|
orig_table_perm = stored_table.perm
|
2019-12-03 17:57:24 -05:00
|
|
|
stored_table.table_name = "tmp_perm_table_v2"
|
2020-08-06 18:33:48 -04:00
|
|
|
session.commit()
|
2019-12-03 17:57:24 -05:00
|
|
|
stored_table = (
|
2020-08-06 18:33:48 -04:00
|
|
|
session.query(SqlaTable).filter_by(table_name="tmp_perm_table_v2").one()
|
2019-12-03 17:57:24 -05:00
|
|
|
)
|
2020-06-29 19:38:06 -04:00
|
|
|
self.assertEqual(
|
2019-12-03 17:57:24 -05:00
|
|
|
stored_table.perm, f"[examples].[tmp_perm_table_v2](id:{stored_table.id})"
|
|
|
|
)
|
2022-08-02 16:06:53 -04:00
|
|
|
self.assertIsNone(
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"datasource_access", orig_table_perm
|
|
|
|
)
|
|
|
|
)
|
2019-12-03 17:57:24 -05:00
|
|
|
self.assertIsNotNone(
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"datasource_access", stored_table.perm
|
|
|
|
)
|
|
|
|
)
|
|
|
|
# no changes in schema
|
2020-06-29 19:38:06 -04:00
|
|
|
self.assertEqual(stored_table.schema_perm, "[examples].[tmp_schema]")
|
2019-12-03 17:57:24 -05:00
|
|
|
self.assertIsNotNone(
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"schema_access", stored_table.schema_perm
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
# schema name change
|
|
|
|
stored_table.schema = "tmp_schema_v2"
|
2020-08-06 18:33:48 -04:00
|
|
|
session.commit()
|
2019-12-03 17:57:24 -05:00
|
|
|
stored_table = (
|
2020-08-06 18:33:48 -04:00
|
|
|
session.query(SqlaTable).filter_by(table_name="tmp_perm_table_v2").one()
|
2019-12-03 17:57:24 -05:00
|
|
|
)
|
2020-06-29 19:38:06 -04:00
|
|
|
self.assertEqual(
|
2019-12-03 17:57:24 -05:00
|
|
|
stored_table.perm, f"[examples].[tmp_perm_table_v2](id:{stored_table.id})"
|
|
|
|
)
|
|
|
|
self.assertIsNotNone(
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"datasource_access", stored_table.perm
|
|
|
|
)
|
|
|
|
)
|
|
|
|
# no changes in schema
|
2020-06-29 19:38:06 -04:00
|
|
|
self.assertEqual(stored_table.schema_perm, "[examples].[tmp_schema_v2]")
|
2019-12-03 17:57:24 -05:00
|
|
|
self.assertIsNotNone(
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"schema_access", stored_table.schema_perm
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
# database change
|
2022-02-24 14:02:01 -05:00
|
|
|
new_db = Database(sqlalchemy_uri="sqlite://", database_name="tmp_db")
|
2020-08-06 18:33:48 -04:00
|
|
|
session.add(new_db)
|
2019-12-03 17:57:24 -05:00
|
|
|
stored_table.database = (
|
2020-08-06 18:33:48 -04:00
|
|
|
session.query(Database).filter_by(database_name="tmp_db").one()
|
2019-12-03 17:57:24 -05:00
|
|
|
)
|
2020-08-06 18:33:48 -04:00
|
|
|
session.commit()
|
2019-12-03 17:57:24 -05:00
|
|
|
stored_table = (
|
2020-08-06 18:33:48 -04:00
|
|
|
session.query(SqlaTable).filter_by(table_name="tmp_perm_table_v2").one()
|
2019-12-03 17:57:24 -05:00
|
|
|
)
|
2020-06-29 19:38:06 -04:00
|
|
|
self.assertEqual(
|
2019-12-03 17:57:24 -05:00
|
|
|
stored_table.perm, f"[tmp_db].[tmp_perm_table_v2](id:{stored_table.id})"
|
|
|
|
)
|
|
|
|
self.assertIsNotNone(
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"datasource_access", stored_table.perm
|
|
|
|
)
|
|
|
|
)
|
|
|
|
# no changes in schema
|
2020-06-29 19:38:06 -04:00
|
|
|
self.assertEqual(stored_table.schema_perm, "[tmp_db].[tmp_schema_v2]")
|
2019-12-03 17:57:24 -05:00
|
|
|
self.assertIsNotNone(
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"schema_access", stored_table.schema_perm
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
# no schema
|
|
|
|
stored_table.schema = None
|
2020-08-06 18:33:48 -04:00
|
|
|
session.commit()
|
2019-12-03 17:57:24 -05:00
|
|
|
stored_table = (
|
2020-08-06 18:33:48 -04:00
|
|
|
session.query(SqlaTable).filter_by(table_name="tmp_perm_table_v2").one()
|
2019-12-03 17:57:24 -05:00
|
|
|
)
|
2020-06-29 19:38:06 -04:00
|
|
|
self.assertEqual(
|
2019-12-03 17:57:24 -05:00
|
|
|
stored_table.perm, f"[tmp_db].[tmp_perm_table_v2](id:{stored_table.id})"
|
|
|
|
)
|
|
|
|
self.assertIsNotNone(
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"datasource_access", stored_table.perm
|
|
|
|
)
|
|
|
|
)
|
|
|
|
self.assertIsNone(stored_table.schema_perm)
|
|
|
|
|
2020-08-06 18:33:48 -04:00
|
|
|
session.delete(new_db)
|
|
|
|
session.delete(stored_table)
|
|
|
|
session.commit()
|
2019-12-03 17:57:24 -05:00
|
|
|
|
2022-05-20 04:40:10 -04:00
|
|
|
def test_set_perm_sqla_table_none(self):
|
|
|
|
session = db.session
|
|
|
|
table = SqlaTable(
|
|
|
|
schema="tmp_schema",
|
|
|
|
table_name="tmp_perm_table",
|
|
|
|
# Setting database_id instead of database will skip permission creation
|
|
|
|
database_id=get_example_database().id,
|
|
|
|
)
|
|
|
|
session.add(table)
|
|
|
|
session.commit()
|
|
|
|
|
|
|
|
stored_table = (
|
|
|
|
session.query(SqlaTable).filter_by(table_name="tmp_perm_table").one()
|
|
|
|
)
|
|
|
|
# Assert no permission is created
|
|
|
|
self.assertIsNone(
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"datasource_access", stored_table.perm
|
|
|
|
)
|
|
|
|
)
|
|
|
|
# Assert no bogus permission is created
|
|
|
|
self.assertIsNone(
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"datasource_access", f"[None].[tmp_perm_table](id:{stored_table.id})"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
session.delete(table)
|
|
|
|
session.commit()
|
|
|
|
|
2019-12-03 17:57:24 -05:00
|
|
|
def test_set_perm_database(self):
|
2020-08-06 18:33:48 -04:00
|
|
|
session = db.session
|
2022-02-24 14:02:01 -05:00
|
|
|
database = Database(database_name="tmp_database", sqlalchemy_uri="sqlite://")
|
2020-08-06 18:33:48 -04:00
|
|
|
session.add(database)
|
2019-12-03 17:57:24 -05:00
|
|
|
|
|
|
|
stored_db = (
|
2020-08-06 18:33:48 -04:00
|
|
|
session.query(Database).filter_by(database_name="tmp_database").one()
|
2019-12-03 17:57:24 -05:00
|
|
|
)
|
2020-06-29 19:38:06 -04:00
|
|
|
self.assertEqual(stored_db.perm, f"[tmp_database].(id:{stored_db.id})")
|
2019-12-03 17:57:24 -05:00
|
|
|
self.assertIsNotNone(
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"database_access", stored_db.perm
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
stored_db.database_name = "tmp_database2"
|
2020-08-06 18:33:48 -04:00
|
|
|
session.commit()
|
2019-12-03 17:57:24 -05:00
|
|
|
stored_db = (
|
2020-08-06 18:33:48 -04:00
|
|
|
session.query(Database).filter_by(database_name="tmp_database2").one()
|
2019-12-03 17:57:24 -05:00
|
|
|
)
|
2020-06-29 19:38:06 -04:00
|
|
|
self.assertEqual(stored_db.perm, f"[tmp_database2].(id:{stored_db.id})")
|
2019-12-03 17:57:24 -05:00
|
|
|
self.assertIsNotNone(
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"database_access", stored_db.perm
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2020-08-06 18:33:48 -04:00
|
|
|
session.delete(stored_db)
|
|
|
|
session.commit()
|
2019-12-03 17:57:24 -05:00
|
|
|
|
2022-08-02 13:28:46 -04:00
|
|
|
def test_after_update_database__perm_database_access(self):
|
|
|
|
session = db.session
|
|
|
|
database = Database(database_name="tmp_database", sqlalchemy_uri="sqlite://")
|
|
|
|
session.add(database)
|
|
|
|
session.commit()
|
|
|
|
stored_db = (
|
|
|
|
session.query(Database).filter_by(database_name="tmp_database").one()
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertIsNotNone(
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"database_access", stored_db.perm
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
stored_db.database_name = "tmp_database2"
|
|
|
|
session.commit()
|
|
|
|
|
|
|
|
# Assert that the old permission was updated
|
|
|
|
self.assertIsNone(
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"database_access", f"[tmp_database].(id:{stored_db.id})"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
# Assert that the db permission was updated
|
|
|
|
self.assertIsNotNone(
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"database_access", f"[tmp_database2].(id:{stored_db.id})"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
session.delete(stored_db)
|
|
|
|
session.commit()
|
|
|
|
|
|
|
|
def test_after_update_database__perm_database_access_exists(self):
|
|
|
|
session = db.session
|
|
|
|
# Add a bogus existing permission before the change
|
|
|
|
|
|
|
|
database = Database(database_name="tmp_database", sqlalchemy_uri="sqlite://")
|
|
|
|
session.add(database)
|
|
|
|
session.commit()
|
|
|
|
stored_db = (
|
|
|
|
session.query(Database).filter_by(database_name="tmp_database").one()
|
|
|
|
)
|
|
|
|
security_manager.add_permission_view_menu(
|
|
|
|
"database_access", f"[tmp_database2].(id:{stored_db.id})"
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertIsNotNone(
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"database_access", stored_db.perm
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
stored_db.database_name = "tmp_database2"
|
|
|
|
session.commit()
|
|
|
|
|
|
|
|
# Assert that the old permission was updated
|
|
|
|
self.assertIsNone(
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"database_access", f"[tmp_database].(id:{stored_db.id})"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
# Assert that the db permission was updated
|
|
|
|
self.assertIsNotNone(
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"database_access", f"[tmp_database2].(id:{stored_db.id})"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
session.delete(stored_db)
|
|
|
|
session.commit()
|
|
|
|
|
|
|
|
def test_after_update_database__perm_datasource_access(self):
|
|
|
|
session = db.session
|
|
|
|
database = Database(database_name="tmp_database", sqlalchemy_uri="sqlite://")
|
|
|
|
session.add(database)
|
|
|
|
session.commit()
|
|
|
|
|
|
|
|
table1 = SqlaTable(
|
|
|
|
schema="tmp_schema",
|
|
|
|
table_name="tmp_table1",
|
|
|
|
database=database,
|
|
|
|
)
|
|
|
|
session.add(table1)
|
|
|
|
table2 = SqlaTable(
|
|
|
|
schema="tmp_schema",
|
|
|
|
table_name="tmp_table2",
|
|
|
|
database=database,
|
|
|
|
)
|
|
|
|
session.add(table2)
|
|
|
|
session.commit()
|
|
|
|
slice1 = Slice(
|
|
|
|
datasource_id=table1.id,
|
|
|
|
datasource_type=DatasourceType.TABLE,
|
|
|
|
datasource_name="tmp_table1",
|
|
|
|
slice_name="tmp_slice1",
|
|
|
|
)
|
|
|
|
session.add(slice1)
|
|
|
|
session.commit()
|
|
|
|
slice1 = session.query(Slice).filter_by(slice_name="tmp_slice1").one()
|
|
|
|
table1 = session.query(SqlaTable).filter_by(table_name="tmp_table1").one()
|
|
|
|
table2 = session.query(SqlaTable).filter_by(table_name="tmp_table2").one()
|
|
|
|
|
|
|
|
# assert initial perms
|
|
|
|
self.assertIsNotNone(
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"datasource_access", f"[tmp_database].[tmp_table1](id:{table1.id})"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
self.assertIsNotNone(
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"datasource_access", f"[tmp_database].[tmp_table2](id:{table2.id})"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
self.assertEqual(slice1.perm, f"[tmp_database].[tmp_table1](id:{table1.id})")
|
|
|
|
self.assertEqual(table1.perm, f"[tmp_database].[tmp_table1](id:{table1.id})")
|
|
|
|
self.assertEqual(table2.perm, f"[tmp_database].[tmp_table2](id:{table2.id})")
|
|
|
|
|
|
|
|
stored_db = (
|
|
|
|
session.query(Database).filter_by(database_name="tmp_database").one()
|
|
|
|
)
|
|
|
|
stored_db.database_name = "tmp_database2"
|
|
|
|
session.commit()
|
|
|
|
|
|
|
|
# Assert that the old permissions were updated
|
|
|
|
self.assertIsNone(
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"datasource_access", f"[tmp_database].[tmp_table1](id:{table1.id})"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
self.assertIsNone(
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"datasource_access", f"[tmp_database].[tmp_table2](id:{table2.id})"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
# Assert that the db permission was updated
|
|
|
|
self.assertIsNotNone(
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"datasource_access", f"[tmp_database2].[tmp_table1](id:{table1.id})"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
self.assertIsNotNone(
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"datasource_access", f"[tmp_database2].[tmp_table2](id:{table2.id})"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
self.assertEqual(slice1.perm, f"[tmp_database2].[tmp_table1](id:{table1.id})")
|
|
|
|
self.assertEqual(table1.perm, f"[tmp_database2].[tmp_table1](id:{table1.id})")
|
|
|
|
self.assertEqual(table2.perm, f"[tmp_database2].[tmp_table2](id:{table2.id})")
|
|
|
|
|
|
|
|
session.delete(slice1)
|
|
|
|
session.delete(table1)
|
|
|
|
session.delete(table2)
|
|
|
|
session.delete(stored_db)
|
|
|
|
session.commit()
|
|
|
|
|
|
|
|
def test_after_delete_database__perm_database_access(self):
|
|
|
|
session = db.session
|
|
|
|
database = Database(database_name="tmp_database", sqlalchemy_uri="sqlite://")
|
|
|
|
session.add(database)
|
|
|
|
session.commit()
|
|
|
|
stored_db = (
|
|
|
|
session.query(Database).filter_by(database_name="tmp_database").one()
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertIsNotNone(
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"database_access", stored_db.perm
|
|
|
|
)
|
|
|
|
)
|
|
|
|
session.delete(stored_db)
|
|
|
|
session.commit()
|
|
|
|
|
|
|
|
# Assert that the old permission was updated
|
|
|
|
self.assertIsNone(
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"database_access", f"[tmp_database].(id:{stored_db.id})"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2020-06-24 13:06:25 -04:00
|
|
|
def test_hybrid_perm_database(self):
|
2022-02-24 14:02:01 -05:00
|
|
|
database = Database(database_name="tmp_database3", sqlalchemy_uri="sqlite://")
|
2020-06-24 13:06:25 -04:00
|
|
|
|
|
|
|
db.session.add(database)
|
|
|
|
|
|
|
|
id_ = (
|
|
|
|
db.session.query(Database.id)
|
|
|
|
.filter_by(database_name="tmp_database3")
|
|
|
|
.scalar()
|
|
|
|
)
|
|
|
|
|
|
|
|
record = (
|
|
|
|
db.session.query(Database)
|
|
|
|
.filter_by(perm=f"[tmp_database3].(id:{id_})")
|
|
|
|
.one()
|
|
|
|
)
|
|
|
|
|
2020-06-29 19:38:06 -04:00
|
|
|
self.assertEqual(record.get_perm(), record.perm)
|
|
|
|
self.assertEqual(record.id, id_)
|
|
|
|
self.assertEqual(record.database_name, "tmp_database3")
|
2020-06-24 13:06:25 -04:00
|
|
|
db.session.delete(database)
|
|
|
|
db.session.commit()
|
|
|
|
|
2019-12-03 17:57:24 -05:00
|
|
|
def test_set_perm_slice(self):
|
2020-08-06 18:33:48 -04:00
|
|
|
session = db.session
|
2022-02-24 14:02:01 -05:00
|
|
|
database = Database(database_name="tmp_database", sqlalchemy_uri="sqlite://")
|
2019-12-03 17:57:24 -05:00
|
|
|
table = SqlaTable(table_name="tmp_perm_table", database=database)
|
2020-08-06 18:33:48 -04:00
|
|
|
session.add(database)
|
|
|
|
session.add(table)
|
|
|
|
session.commit()
|
2019-12-03 17:57:24 -05:00
|
|
|
|
|
|
|
# no schema permission
|
|
|
|
slice = Slice(
|
|
|
|
datasource_id=table.id,
|
2022-06-02 19:48:16 -04:00
|
|
|
datasource_type=DatasourceType.TABLE,
|
2019-12-03 17:57:24 -05:00
|
|
|
datasource_name="tmp_perm_table",
|
|
|
|
slice_name="slice_name",
|
|
|
|
)
|
2020-08-06 18:33:48 -04:00
|
|
|
session.add(slice)
|
|
|
|
session.commit()
|
2019-12-03 17:57:24 -05:00
|
|
|
|
2020-08-06 18:33:48 -04:00
|
|
|
slice = session.query(Slice).filter_by(slice_name="slice_name").one()
|
2020-06-29 19:38:06 -04:00
|
|
|
self.assertEqual(slice.perm, table.perm)
|
|
|
|
self.assertEqual(slice.perm, f"[tmp_database].[tmp_perm_table](id:{table.id})")
|
|
|
|
self.assertEqual(slice.schema_perm, table.schema_perm)
|
2019-12-03 17:57:24 -05:00
|
|
|
self.assertIsNone(slice.schema_perm)
|
|
|
|
|
|
|
|
table.schema = "tmp_perm_schema"
|
|
|
|
table.table_name = "tmp_perm_table_v2"
|
2020-08-06 18:33:48 -04:00
|
|
|
session.commit()
|
2019-12-03 17:57:24 -05:00
|
|
|
# TODO(bogdan): modify slice permissions on the table update.
|
2021-11-26 11:21:01 -05:00
|
|
|
self.assertNotEqual(slice.perm, table.perm)
|
2020-06-29 19:38:06 -04:00
|
|
|
self.assertEqual(slice.perm, f"[tmp_database].[tmp_perm_table](id:{table.id})")
|
|
|
|
self.assertEqual(
|
2019-12-03 17:57:24 -05:00
|
|
|
table.perm, f"[tmp_database].[tmp_perm_table_v2](id:{table.id})"
|
|
|
|
)
|
|
|
|
# TODO(bogdan): modify slice schema permissions on the table update.
|
2021-11-26 11:21:01 -05:00
|
|
|
self.assertNotEqual(slice.schema_perm, table.schema_perm)
|
2019-12-03 17:57:24 -05:00
|
|
|
self.assertIsNone(slice.schema_perm)
|
|
|
|
|
|
|
|
# updating slice refreshes the permissions
|
|
|
|
slice.slice_name = "slice_name_v2"
|
2020-08-06 18:33:48 -04:00
|
|
|
session.commit()
|
2020-06-29 19:38:06 -04:00
|
|
|
self.assertEqual(slice.perm, table.perm)
|
|
|
|
self.assertEqual(
|
2019-12-03 17:57:24 -05:00
|
|
|
slice.perm, f"[tmp_database].[tmp_perm_table_v2](id:{table.id})"
|
|
|
|
)
|
2020-06-29 19:38:06 -04:00
|
|
|
self.assertEqual(slice.schema_perm, table.schema_perm)
|
|
|
|
self.assertEqual(slice.schema_perm, "[tmp_database].[tmp_perm_schema]")
|
2019-12-03 17:57:24 -05:00
|
|
|
|
2020-08-06 18:33:48 -04:00
|
|
|
session.delete(slice)
|
|
|
|
session.delete(table)
|
|
|
|
session.delete(database)
|
|
|
|
|
|
|
|
session.commit()
|
2019-12-03 17:57:24 -05:00
|
|
|
|
|
|
|
# TODO test slice permission
|
|
|
|
|
2022-06-24 20:57:04 -04:00
|
|
|
@patch("superset.utils.core.g")
|
2022-07-07 14:04:27 -04:00
|
|
|
@patch("superset.security.manager.g")
|
2022-06-24 20:57:04 -04:00
|
|
|
def test_schemas_accessible_by_user_admin(self, mock_sm_g, mock_g):
|
|
|
|
mock_g.user = mock_sm_g.user = security_manager.find_user("admin")
|
2019-12-03 17:57:24 -05:00
|
|
|
with self.client.application.test_request_context():
|
|
|
|
database = get_example_database()
|
2020-06-11 14:29:43 -04:00
|
|
|
schemas = security_manager.get_schemas_accessible_by_user(
|
2019-12-03 17:57:24 -05:00
|
|
|
database, ["1", "2", "3"]
|
|
|
|
)
|
2020-06-29 19:38:06 -04:00
|
|
|
self.assertEqual(schemas, ["1", "2", "3"]) # no changes
|
2019-12-03 17:57:24 -05:00
|
|
|
|
2022-06-24 20:57:04 -04:00
|
|
|
@patch("superset.utils.core.g")
|
2022-07-07 14:04:27 -04:00
|
|
|
@patch("superset.security.manager.g")
|
2022-06-24 20:57:04 -04:00
|
|
|
def test_schemas_accessible_by_user_schema_access(self, mock_sm_g, mock_g):
|
2019-12-03 17:57:24 -05:00
|
|
|
# User has schema access to the schema 1
|
|
|
|
create_schema_perm("[examples].[1]")
|
2022-06-24 20:57:04 -04:00
|
|
|
mock_g.user = mock_sm_g.user = security_manager.find_user("gamma")
|
2019-12-03 17:57:24 -05:00
|
|
|
with self.client.application.test_request_context():
|
|
|
|
database = get_example_database()
|
2020-06-11 14:29:43 -04:00
|
|
|
schemas = security_manager.get_schemas_accessible_by_user(
|
2019-12-03 17:57:24 -05:00
|
|
|
database, ["1", "2", "3"]
|
|
|
|
)
|
|
|
|
# temp_schema is not passed in the params
|
2020-06-29 19:38:06 -04:00
|
|
|
self.assertEqual(schemas, ["1"])
|
2019-12-03 17:57:24 -05:00
|
|
|
delete_schema_perm("[examples].[1]")
|
|
|
|
|
2022-06-24 20:57:04 -04:00
|
|
|
@patch("superset.utils.core.g")
|
2022-07-07 14:04:27 -04:00
|
|
|
@patch("superset.security.manager.g")
|
2022-06-24 20:57:04 -04:00
|
|
|
def test_schemas_accessible_by_user_datasource_access(self, mock_sm_g, mock_g):
|
2019-12-03 17:57:24 -05:00
|
|
|
# User has schema access to the datasource temp_schema.wb_health_population in examples DB.
|
2022-06-24 20:57:04 -04:00
|
|
|
mock_g.user = mock_sm_g.user = security_manager.find_user("gamma")
|
2019-12-03 17:57:24 -05:00
|
|
|
with self.client.application.test_request_context():
|
|
|
|
database = get_example_database()
|
2020-06-11 14:29:43 -04:00
|
|
|
schemas = security_manager.get_schemas_accessible_by_user(
|
2019-12-03 17:57:24 -05:00
|
|
|
database, ["temp_schema", "2", "3"]
|
|
|
|
)
|
2020-06-29 19:38:06 -04:00
|
|
|
self.assertEqual(schemas, ["temp_schema"])
|
2019-12-03 17:57:24 -05:00
|
|
|
|
2022-06-24 20:57:04 -04:00
|
|
|
@patch("superset.utils.core.g")
|
2022-07-07 14:04:27 -04:00
|
|
|
@patch("superset.security.manager.g")
|
2022-06-24 20:57:04 -04:00
|
|
|
def test_schemas_accessible_by_user_datasource_and_schema_access(
|
|
|
|
self, mock_sm_g, mock_g
|
|
|
|
):
|
2019-12-03 17:57:24 -05:00
|
|
|
# User has schema access to the datasource temp_schema.wb_health_population in examples DB.
|
|
|
|
create_schema_perm("[examples].[2]")
|
2022-06-24 20:57:04 -04:00
|
|
|
mock_g.user = mock_sm_g.user = security_manager.find_user("gamma")
|
2019-12-03 17:57:24 -05:00
|
|
|
with self.client.application.test_request_context():
|
|
|
|
database = get_example_database()
|
2020-06-11 14:29:43 -04:00
|
|
|
schemas = security_manager.get_schemas_accessible_by_user(
|
2019-12-03 17:57:24 -05:00
|
|
|
database, ["temp_schema", "2", "3"]
|
|
|
|
)
|
2020-06-29 19:38:06 -04:00
|
|
|
self.assertEqual(schemas, ["temp_schema", "2"])
|
2019-12-03 17:57:24 -05:00
|
|
|
vm = security_manager.find_permission_view_menu(
|
|
|
|
"schema_access", "[examples].[2]"
|
|
|
|
)
|
|
|
|
self.assertIsNotNone(vm)
|
|
|
|
delete_schema_perm("[examples].[2]")
|
|
|
|
|
2021-01-13 17:20:05 -05:00
|
|
|
@pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
|
2019-12-03 17:57:24 -05:00
|
|
|
def test_gamma_user_schema_access_to_dashboards(self):
|
2021-01-13 17:20:05 -05:00
|
|
|
dash = db.session.query(Dashboard).filter_by(slug="world_health").first()
|
|
|
|
dash.published = True
|
|
|
|
db.session.commit()
|
|
|
|
|
2019-12-03 17:57:24 -05:00
|
|
|
self.login(username="gamma")
|
2020-01-16 00:48:55 -05:00
|
|
|
data = str(self.client.get("api/v1/dashboard/").data)
|
2019-12-03 17:57:24 -05:00
|
|
|
self.assertIn("/superset/dashboard/world_health/", data)
|
|
|
|
self.assertNotIn("/superset/dashboard/births/", data)
|
|
|
|
|
2022-02-24 14:02:01 -05:00
|
|
|
@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
|
2021-02-23 04:50:22 -05:00
|
|
|
@pytest.mark.usefixtures("public_role_like_gamma")
|
2020-08-28 05:49:10 -04:00
|
|
|
def test_public_sync_role_data_perms(self):
|
|
|
|
"""
|
|
|
|
Security: Tests if the sync role method preserves data access permissions
|
|
|
|
if they already exist on a public role.
|
|
|
|
Also check that non data access permissions are removed
|
|
|
|
"""
|
|
|
|
table = db.session.query(SqlaTable).filter_by(table_name="birth_names").one()
|
|
|
|
self.grant_public_access_to_table(table)
|
|
|
|
public_role = security_manager.get_public_role()
|
|
|
|
unwanted_pvm = security_manager.find_permission_view_menu(
|
|
|
|
"menu_access", "Security"
|
|
|
|
)
|
|
|
|
public_role.permissions.append(unwanted_pvm)
|
|
|
|
db.session.commit()
|
|
|
|
|
|
|
|
security_manager.sync_role_definitions()
|
|
|
|
public_role = security_manager.get_public_role()
|
|
|
|
public_role_resource_names = [
|
|
|
|
permission.view_menu.name for permission in public_role.permissions
|
|
|
|
]
|
|
|
|
|
|
|
|
assert table.get_perm() in public_role_resource_names
|
|
|
|
assert "Security" not in public_role_resource_names
|
|
|
|
|
|
|
|
# Cleanup
|
|
|
|
self.revoke_public_access_to_table(table)
|
|
|
|
|
2021-02-23 04:50:22 -05:00
|
|
|
@pytest.mark.usefixtures("public_role_like_test_role")
|
2020-08-28 05:49:10 -04:00
|
|
|
def test_public_sync_role_builtin_perms(self):
|
|
|
|
"""
|
|
|
|
Security: Tests public role creation based on a builtin role
|
|
|
|
"""
|
|
|
|
public_role = security_manager.get_public_role()
|
|
|
|
public_role_resource_names = [
|
|
|
|
[permission.view_menu.name, permission.permission.name]
|
|
|
|
for permission in public_role.permissions
|
|
|
|
]
|
|
|
|
for pvm in current_app.config["FAB_ROLES"]["TestRole"]:
|
|
|
|
assert pvm in public_role_resource_names
|
|
|
|
|
2022-04-11 16:50:59 -04:00
|
|
|
@pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
|
2019-12-03 17:57:24 -05:00
|
|
|
def test_sqllab_gamma_user_schema_access_to_sqllab(self):
|
2020-08-06 18:33:48 -04:00
|
|
|
session = db.session
|
|
|
|
example_db = session.query(Database).filter_by(database_name="examples").one()
|
2019-12-03 17:57:24 -05:00
|
|
|
example_db.expose_in_sqllab = True
|
2020-08-06 18:33:48 -04:00
|
|
|
session.commit()
|
2019-12-03 17:57:24 -05:00
|
|
|
|
|
|
|
arguments = {
|
|
|
|
"keys": ["none"],
|
2022-04-11 16:50:59 -04:00
|
|
|
"columns": ["expose_in_sqllab"],
|
2019-12-03 17:57:24 -05:00
|
|
|
"filters": [{"col": "expose_in_sqllab", "opr": "eq", "value": True}],
|
|
|
|
"order_columns": "database_name",
|
|
|
|
"order_direction": "asc",
|
|
|
|
"page": 0,
|
|
|
|
"page_size": -1,
|
|
|
|
}
|
|
|
|
NEW_FLASK_GET_SQL_DBS_REQUEST = f"/api/v1/database/?q={prison.dumps(arguments)}"
|
|
|
|
self.login(username="gamma")
|
|
|
|
databases_json = self.client.get(NEW_FLASK_GET_SQL_DBS_REQUEST).json
|
2020-06-29 19:38:06 -04:00
|
|
|
self.assertEqual(databases_json["count"], 1)
|
2019-12-03 17:57:24 -05:00
|
|
|
self.logout()
|
2016-12-15 08:38:34 -05:00
|
|
|
|
|
|
|
def assert_can_read(self, view_menu, permissions_set):
|
2020-12-03 03:45:32 -05:00
|
|
|
if view_menu in NEW_SECURITY_CONVERGE_VIEWS:
|
|
|
|
self.assertIn(("can_read", view_menu), permissions_set)
|
|
|
|
else:
|
|
|
|
self.assertIn(("can_list", view_menu), permissions_set)
|
2016-12-15 08:38:34 -05:00
|
|
|
|
|
|
|
def assert_can_write(self, view_menu, permissions_set):
|
2020-12-03 03:45:32 -05:00
|
|
|
if view_menu in NEW_SECURITY_CONVERGE_VIEWS:
|
|
|
|
self.assertIn(("can_write", view_menu), permissions_set)
|
|
|
|
else:
|
|
|
|
self.assertIn(("can_add", view_menu), permissions_set)
|
|
|
|
self.assertIn(("can_delete", view_menu), permissions_set)
|
|
|
|
self.assertIn(("can_edit", view_menu), permissions_set)
|
2016-12-15 08:38:34 -05:00
|
|
|
|
|
|
|
def assert_cannot_write(self, view_menu, permissions_set):
|
2020-12-03 03:45:32 -05:00
|
|
|
if view_menu in NEW_SECURITY_CONVERGE_VIEWS:
|
|
|
|
self.assertNotIn(("can_write", view_menu), permissions_set)
|
|
|
|
else:
|
|
|
|
self.assertNotIn(("can_add", view_menu), permissions_set)
|
|
|
|
self.assertNotIn(("can_delete", view_menu), permissions_set)
|
|
|
|
self.assertNotIn(("can_edit", view_menu), permissions_set)
|
|
|
|
self.assertNotIn(("can_save", view_menu), permissions_set)
|
2016-12-15 08:38:34 -05:00
|
|
|
|
|
|
|
def assert_can_all(self, view_menu, permissions_set):
|
|
|
|
self.assert_can_read(view_menu, permissions_set)
|
|
|
|
self.assert_can_write(view_menu, permissions_set)
|
|
|
|
|
2020-07-27 05:32:30 -04:00
|
|
|
def assert_can_menu(self, view_menu, permissions_set):
|
|
|
|
self.assertIn(("menu_access", view_menu), permissions_set)
|
|
|
|
|
2016-12-15 08:38:34 -05:00
|
|
|
def assert_can_gamma(self, perm_set):
|
2020-12-16 06:49:03 -05:00
|
|
|
self.assert_can_read("Dataset", perm_set)
|
2016-12-15 08:38:34 -05:00
|
|
|
|
|
|
|
# make sure that user can create slices and dashboards
|
2020-12-17 04:53:13 -05:00
|
|
|
self.assert_can_all("Dashboard", perm_set)
|
2020-12-15 06:27:06 -05:00
|
|
|
self.assert_can_all("Chart", perm_set)
|
2019-06-25 16:34:48 -04:00
|
|
|
|
|
|
|
self.assertIn(("can_add_slices", "Superset"), perm_set)
|
|
|
|
self.assertIn(("can_copy_dash", "Superset"), perm_set)
|
|
|
|
self.assertIn(("can_created_dashboards", "Superset"), perm_set)
|
|
|
|
self.assertIn(("can_created_slices", "Superset"), perm_set)
|
|
|
|
self.assertIn(("can_csv", "Superset"), perm_set)
|
|
|
|
self.assertIn(("can_dashboard", "Superset"), perm_set)
|
|
|
|
self.assertIn(("can_explore", "Superset"), perm_set)
|
2021-04-13 06:54:14 -04:00
|
|
|
self.assertIn(("can_share_chart", "Superset"), perm_set)
|
|
|
|
self.assertIn(("can_share_dashboard", "Superset"), perm_set)
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertIn(("can_explore_json", "Superset"), perm_set)
|
|
|
|
self.assertIn(("can_fave_dashboards", "Superset"), perm_set)
|
|
|
|
self.assertIn(("can_fave_slices", "Superset"), perm_set)
|
|
|
|
self.assertIn(("can_save_dash", "Superset"), perm_set)
|
|
|
|
self.assertIn(("can_slice", "Superset"), perm_set)
|
|
|
|
self.assertIn(("can_explore_json", "Superset"), perm_set)
|
|
|
|
self.assertIn(("can_userinfo", "UserDBModelView"), perm_set)
|
2020-07-27 05:32:30 -04:00
|
|
|
self.assert_can_menu("Databases", perm_set)
|
2020-08-29 21:09:47 -04:00
|
|
|
self.assert_can_menu("Datasets", perm_set)
|
|
|
|
self.assert_can_menu("Data", perm_set)
|
2020-07-27 05:32:30 -04:00
|
|
|
self.assert_can_menu("Charts", perm_set)
|
|
|
|
self.assert_can_menu("Dashboards", perm_set)
|
2016-12-15 08:38:34 -05:00
|
|
|
|
|
|
|
def assert_can_alpha(self, perm_set):
|
2020-12-16 04:08:06 -05:00
|
|
|
self.assert_can_all("Annotation", perm_set)
|
2020-12-03 03:45:32 -05:00
|
|
|
self.assert_can_all("CssTemplate", perm_set)
|
2020-12-16 06:49:03 -05:00
|
|
|
self.assert_can_all("Dataset", perm_set)
|
2020-12-17 09:27:14 -05:00
|
|
|
self.assert_can_read("Query", perm_set)
|
2020-12-21 14:17:58 -05:00
|
|
|
self.assert_can_read("Database", perm_set)
|
2020-07-27 05:32:30 -04:00
|
|
|
self.assertIn(("can_import_dashboards", "Superset"), perm_set)
|
|
|
|
self.assertIn(("can_this_form_post", "CsvToDatabaseView"), perm_set)
|
|
|
|
self.assertIn(("can_this_form_get", "CsvToDatabaseView"), perm_set)
|
|
|
|
self.assert_can_menu("Manage", perm_set)
|
|
|
|
self.assert_can_menu("Annotation Layers", perm_set)
|
|
|
|
self.assert_can_menu("CSS Templates", perm_set)
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertIn(("all_datasource_access", "all_datasource_access"), perm_set)
|
2016-12-15 08:38:34 -05:00
|
|
|
|
|
|
|
def assert_cannot_alpha(self, perm_set):
|
2019-10-30 19:19:16 -04:00
|
|
|
if app.config["ENABLE_ACCESS_REQUEST"]:
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assert_cannot_write("AccessRequestsModelView", perm_set)
|
|
|
|
self.assert_can_all("AccessRequestsModelView", perm_set)
|
|
|
|
self.assert_cannot_write("Queries", perm_set)
|
|
|
|
self.assert_cannot_write("RoleModelView", perm_set)
|
|
|
|
self.assert_cannot_write("UserDBModelView", perm_set)
|
2020-12-21 14:17:58 -05:00
|
|
|
self.assert_cannot_write("Database", perm_set)
|
2016-12-15 08:38:34 -05:00
|
|
|
|
|
|
|
def assert_can_admin(self, perm_set):
|
2020-12-17 07:37:05 -05:00
|
|
|
self.assert_can_all("Database", perm_set)
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assert_can_all("RoleModelView", perm_set)
|
|
|
|
self.assert_can_all("UserDBModelView", perm_set)
|
|
|
|
|
|
|
|
self.assertIn(("all_database_access", "all_database_access"), perm_set)
|
|
|
|
self.assertIn(("can_override_role_permissions", "Superset"), perm_set)
|
|
|
|
self.assertIn(("can_override_role_permissions", "Superset"), perm_set)
|
|
|
|
self.assertIn(("can_approve", "Superset"), perm_set)
|
2016-12-15 08:38:34 -05:00
|
|
|
|
2020-07-27 05:32:30 -04:00
|
|
|
self.assert_can_menu("Security", perm_set)
|
|
|
|
self.assert_can_menu("List Users", perm_set)
|
|
|
|
self.assert_can_menu("List Roles", perm_set)
|
|
|
|
|
2016-12-15 08:38:34 -05:00
|
|
|
def test_is_admin_only(self):
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertFalse(
|
2019-08-05 14:24:13 -04:00
|
|
|
security_manager._is_admin_only(
|
2020-12-16 06:49:03 -05:00
|
|
|
security_manager.find_permission_view_menu("can_read", "Dataset")
|
2019-06-25 16:34:48 -04:00
|
|
|
)
|
|
|
|
)
|
|
|
|
self.assertFalse(
|
2019-08-05 14:24:13 -04:00
|
|
|
security_manager._is_admin_only(
|
2018-03-27 19:46:02 -04:00
|
|
|
security_manager.find_permission_view_menu(
|
2019-06-25 16:34:48 -04:00
|
|
|
"all_datasource_access", "all_datasource_access"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2020-12-17 03:50:31 -05:00
|
|
|
log_permissions = ["can_read"]
|
2020-01-26 07:15:57 -05:00
|
|
|
for log_permission in log_permissions:
|
|
|
|
self.assertTrue(
|
|
|
|
security_manager._is_admin_only(
|
2020-12-17 03:50:31 -05:00
|
|
|
security_manager.find_permission_view_menu(log_permission, "Log")
|
2020-01-26 07:15:57 -05:00
|
|
|
)
|
2019-06-25 16:34:48 -04:00
|
|
|
)
|
2020-01-26 07:15:57 -05:00
|
|
|
|
2019-10-30 19:19:16 -04:00
|
|
|
if app.config["ENABLE_ACCESS_REQUEST"]:
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertTrue(
|
2019-08-05 14:24:13 -04:00
|
|
|
security_manager._is_admin_only(
|
2019-06-25 16:34:48 -04:00
|
|
|
security_manager.find_permission_view_menu(
|
2020-01-23 11:25:15 -05:00
|
|
|
"can_list", "AccessRequestsModelView"
|
2019-06-25 16:34:48 -04:00
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
self.assertTrue(
|
2019-08-05 14:24:13 -04:00
|
|
|
security_manager._is_admin_only(
|
2019-06-25 16:34:48 -04:00
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"can_edit", "UserDBModelView"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
self.assertTrue(
|
2019-08-05 14:24:13 -04:00
|
|
|
security_manager._is_admin_only(
|
2019-06-25 16:34:48 -04:00
|
|
|
security_manager.find_permission_view_menu("can_approve", "Superset")
|
|
|
|
)
|
|
|
|
)
|
2016-12-15 08:38:34 -05:00
|
|
|
|
2019-08-02 13:01:28 -04:00
|
|
|
@unittest.skipUnless(
|
|
|
|
SupersetTestCase.is_module_installed("pydruid"), "pydruid not installed"
|
|
|
|
)
|
2016-12-15 08:38:34 -05:00
|
|
|
def test_is_alpha_only(self):
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertFalse(
|
2019-08-05 14:24:13 -04:00
|
|
|
security_manager._is_alpha_only(
|
2020-12-16 06:49:03 -05:00
|
|
|
security_manager.find_permission_view_menu("can_read", "Dataset")
|
2019-06-25 16:34:48 -04:00
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertTrue(
|
2019-08-05 14:24:13 -04:00
|
|
|
security_manager._is_alpha_only(
|
2020-12-16 06:49:03 -05:00
|
|
|
security_manager.find_permission_view_menu("can_write", "Dataset")
|
2019-06-25 16:34:48 -04:00
|
|
|
)
|
|
|
|
)
|
|
|
|
self.assertTrue(
|
2019-08-05 14:24:13 -04:00
|
|
|
security_manager._is_alpha_only(
|
2019-06-25 16:34:48 -04:00
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"all_datasource_access", "all_datasource_access"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
self.assertTrue(
|
2019-08-05 14:24:13 -04:00
|
|
|
security_manager._is_alpha_only(
|
2019-06-25 16:34:48 -04:00
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"all_database_access", "all_database_access"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
2016-12-15 08:38:34 -05:00
|
|
|
|
|
|
|
def test_is_gamma_pvm(self):
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertTrue(
|
2019-08-05 14:24:13 -04:00
|
|
|
security_manager._is_gamma_pvm(
|
2020-12-16 06:49:03 -05:00
|
|
|
security_manager.find_permission_view_menu("can_read", "Dataset")
|
2019-06-25 16:34:48 -04:00
|
|
|
)
|
|
|
|
)
|
2016-12-15 08:38:34 -05:00
|
|
|
|
2018-08-06 18:30:13 -04:00
|
|
|
def test_gamma_permissions_basic(self):
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assert_can_gamma(get_perm_tuples("Gamma"))
|
2020-08-28 05:49:10 -04:00
|
|
|
self.assert_cannot_alpha(get_perm_tuples("Gamma"))
|
|
|
|
|
2021-02-23 04:50:22 -05:00
|
|
|
@pytest.mark.usefixtures("public_role_like_gamma")
|
2020-08-28 05:49:10 -04:00
|
|
|
def test_public_permissions_basic(self):
|
|
|
|
self.assert_can_gamma(get_perm_tuples("Public"))
|
2016-12-15 08:38:34 -05:00
|
|
|
|
2019-08-02 13:01:28 -04:00
|
|
|
@unittest.skipUnless(
|
|
|
|
SupersetTestCase.is_module_installed("pydruid"), "pydruid not installed"
|
|
|
|
)
|
2016-12-15 08:38:34 -05:00
|
|
|
def test_alpha_permissions(self):
|
2020-01-23 11:25:15 -05:00
|
|
|
alpha_perm_tuples = get_perm_tuples("Alpha")
|
|
|
|
self.assert_can_gamma(alpha_perm_tuples)
|
|
|
|
self.assert_can_alpha(alpha_perm_tuples)
|
|
|
|
self.assert_cannot_alpha(alpha_perm_tuples)
|
2016-12-15 08:38:34 -05:00
|
|
|
|
2021-01-13 17:20:05 -05:00
|
|
|
@pytest.mark.usefixtures("load_world_bank_dashboard_with_slices")
|
2016-12-15 08:38:34 -05:00
|
|
|
def test_admin_permissions(self):
|
2021-12-15 20:06:40 -05:00
|
|
|
if backend() == "hive":
|
|
|
|
return
|
|
|
|
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assert_can_gamma(get_perm_tuples("Admin"))
|
|
|
|
self.assert_can_alpha(get_perm_tuples("Admin"))
|
|
|
|
self.assert_can_admin(get_perm_tuples("Admin"))
|
2016-12-15 08:38:34 -05:00
|
|
|
|
|
|
|
def test_sql_lab_permissions(self):
|
2019-06-25 16:34:48 -04:00
|
|
|
sql_lab_set = get_perm_tuples("sql_lab")
|
|
|
|
self.assertIn(("can_csv", "Superset"), sql_lab_set)
|
2021-04-29 10:58:08 -04:00
|
|
|
self.assertIn(("can_read", "Database"), sql_lab_set)
|
|
|
|
self.assertIn(("can_read", "SavedQuery"), sql_lab_set)
|
|
|
|
self.assertIn(("can_sql_json", "Superset"), sql_lab_set)
|
|
|
|
self.assertIn(("can_sqllab_viz", "Superset"), sql_lab_set)
|
|
|
|
self.assertIn(("can_sqllab_table_viz", "Superset"), sql_lab_set)
|
|
|
|
self.assertIn(("can_sqllab", "Superset"), sql_lab_set)
|
|
|
|
|
|
|
|
self.assertIn(("menu_access", "SQL Lab"), sql_lab_set)
|
|
|
|
self.assertIn(("menu_access", "SQL Editor"), sql_lab_set)
|
|
|
|
self.assertIn(("menu_access", "Saved Queries"), sql_lab_set)
|
|
|
|
self.assertIn(("menu_access", "Query Search"), sql_lab_set)
|
2016-12-15 08:38:34 -05:00
|
|
|
|
|
|
|
self.assert_cannot_alpha(sql_lab_set)
|
|
|
|
|
|
|
|
def test_granter_permissions(self):
|
2019-06-25 16:34:48 -04:00
|
|
|
granter_set = get_perm_tuples("granter")
|
|
|
|
self.assertIn(("can_override_role_permissions", "Superset"), granter_set)
|
|
|
|
self.assertIn(("can_approve", "Superset"), granter_set)
|
2016-12-15 08:38:34 -05:00
|
|
|
|
|
|
|
self.assert_cannot_alpha(granter_set)
|
2018-08-06 18:30:13 -04:00
|
|
|
|
|
|
|
def test_gamma_permissions(self):
|
|
|
|
gamma_perm_set = set()
|
2019-06-25 16:34:48 -04:00
|
|
|
for perm in security_manager.find_role("Gamma").permissions:
|
2018-08-06 18:30:13 -04:00
|
|
|
gamma_perm_set.add((perm.permission.name, perm.view_menu.name))
|
|
|
|
|
|
|
|
# check read only perms
|
2020-12-17 04:53:13 -05:00
|
|
|
|
|
|
|
# make sure that user can create slices and dashboards
|
|
|
|
self.assert_can_all("Dashboard", gamma_perm_set)
|
2020-12-16 06:49:03 -05:00
|
|
|
self.assert_can_read("Dataset", gamma_perm_set)
|
2018-08-06 18:30:13 -04:00
|
|
|
|
|
|
|
# make sure that user can create slices and dashboards
|
2020-12-15 06:27:06 -05:00
|
|
|
self.assert_can_all("Chart", gamma_perm_set)
|
2019-06-25 16:34:48 -04:00
|
|
|
|
2020-12-15 06:27:06 -05:00
|
|
|
self.assert_cannot_write("UserDBModelView", gamma_perm_set)
|
|
|
|
self.assert_cannot_write("RoleModelView", gamma_perm_set)
|
2020-08-28 05:49:10 -04:00
|
|
|
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertIn(("can_add_slices", "Superset"), gamma_perm_set)
|
|
|
|
self.assertIn(("can_copy_dash", "Superset"), gamma_perm_set)
|
|
|
|
self.assertIn(("can_created_dashboards", "Superset"), gamma_perm_set)
|
|
|
|
self.assertIn(("can_created_slices", "Superset"), gamma_perm_set)
|
|
|
|
self.assertIn(("can_csv", "Superset"), gamma_perm_set)
|
|
|
|
self.assertIn(("can_dashboard", "Superset"), gamma_perm_set)
|
|
|
|
self.assertIn(("can_explore", "Superset"), gamma_perm_set)
|
2021-04-13 06:54:14 -04:00
|
|
|
self.assertIn(("can_share_chart", "Superset"), gamma_perm_set)
|
|
|
|
self.assertIn(("can_share_dashboard", "Superset"), gamma_perm_set)
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertIn(("can_explore_json", "Superset"), gamma_perm_set)
|
|
|
|
self.assertIn(("can_fave_dashboards", "Superset"), gamma_perm_set)
|
|
|
|
self.assertIn(("can_fave_slices", "Superset"), gamma_perm_set)
|
|
|
|
self.assertIn(("can_save_dash", "Superset"), gamma_perm_set)
|
|
|
|
self.assertIn(("can_slice", "Superset"), gamma_perm_set)
|
|
|
|
self.assertIn(("can_userinfo", "UserDBModelView"), gamma_perm_set)
|
2018-12-18 14:57:13 -05:00
|
|
|
|
|
|
|
def test_views_are_secured(self):
|
|
|
|
"""Preventing the addition of unsecured views without has_access decorator"""
|
|
|
|
# These FAB views are secured in their body as opposed to by decorators
|
2020-07-15 12:22:46 -04:00
|
|
|
method_allowlist = ("action", "action_post")
|
2018-12-18 14:57:13 -05:00
|
|
|
# List of redirect & other benign views
|
2020-07-15 12:22:46 -04:00
|
|
|
views_allowlist = [
|
2019-06-25 16:34:48 -04:00
|
|
|
["MyIndexView", "index"],
|
|
|
|
["UtilView", "back"],
|
|
|
|
["LocaleView", "index"],
|
|
|
|
["AuthDBView", "login"],
|
|
|
|
["AuthDBView", "logout"],
|
2022-03-01 12:47:13 -05:00
|
|
|
["CurrentUserRestApi", "get_me"],
|
2022-05-03 15:58:06 -04:00
|
|
|
["CurrentUserRestApi", "get_my_roles"],
|
2022-03-30 15:34:05 -04:00
|
|
|
# TODO (embedded) remove Dashboard:embedded after uuids have been shipped
|
2022-01-25 19:41:32 -05:00
|
|
|
["Dashboard", "embedded"],
|
2022-03-30 15:34:05 -04:00
|
|
|
["EmbeddedView", "embedded"],
|
2019-06-25 16:34:48 -04:00
|
|
|
["R", "index"],
|
|
|
|
["Superset", "log"],
|
|
|
|
["Superset", "theme"],
|
|
|
|
["Superset", "welcome"],
|
|
|
|
["SecurityApi", "login"],
|
|
|
|
["SecurityApi", "refresh"],
|
2019-11-20 10:47:06 -05:00
|
|
|
["SupersetIndexView", "index"],
|
2018-12-18 14:57:13 -05:00
|
|
|
]
|
|
|
|
unsecured_views = []
|
|
|
|
for view_class in appbuilder.baseviews:
|
|
|
|
class_name = view_class.__class__.__name__
|
2019-06-25 16:34:48 -04:00
|
|
|
for name, value in inspect.getmembers(
|
|
|
|
view_class, predicate=inspect.ismethod
|
|
|
|
):
|
2018-12-18 14:57:13 -05:00
|
|
|
if (
|
2020-07-15 12:22:46 -04:00
|
|
|
name not in method_allowlist
|
|
|
|
and [class_name, name] not in views_allowlist
|
2019-06-25 16:34:48 -04:00
|
|
|
and hasattr(value, "_urls")
|
|
|
|
and not hasattr(value, "_permission_name")
|
2018-12-18 14:57:13 -05:00
|
|
|
):
|
|
|
|
unsecured_views.append((class_name, name))
|
|
|
|
if unsecured_views:
|
2019-06-25 16:34:48 -04:00
|
|
|
view_str = "\n".join([str(v) for v in unsecured_views])
|
|
|
|
raise Exception(f"Some views are not secured:\n{view_str}")
|
2019-10-01 19:52:15 -04:00
|
|
|
|
2022-08-23 21:45:39 -04:00
|
|
|
@patch("superset.utils.core.g")
|
|
|
|
@patch("superset.security.manager.g")
|
|
|
|
def test_get_permissions_gamma_user(self, mock_sm_g, mock_g):
|
|
|
|
session = db.session
|
|
|
|
role_name = "dummy_role"
|
|
|
|
gamma_user = security_manager.find_user(username="gamma")
|
|
|
|
security_manager.add_role(role_name)
|
|
|
|
dummy_role = security_manager.find_role(role_name)
|
|
|
|
gamma_user.roles.append(dummy_role)
|
|
|
|
|
|
|
|
table = (
|
|
|
|
db.session.query(SqlaTable)
|
|
|
|
.filter_by(table_name="wb_health_population")
|
|
|
|
.one()
|
|
|
|
)
|
|
|
|
table_perm = table.perm
|
|
|
|
security_manager.add_permission_role(
|
|
|
|
dummy_role,
|
|
|
|
security_manager.find_permission_view_menu("datasource_access", table_perm),
|
|
|
|
)
|
|
|
|
security_manager.add_permission_role(
|
|
|
|
dummy_role,
|
|
|
|
security_manager.find_permission_view_menu(
|
|
|
|
"database_access", table.database.perm
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
session.commit()
|
|
|
|
|
|
|
|
mock_g.user = mock_sm_g.user = security_manager.find_user("gamma")
|
|
|
|
with self.client.application.test_request_context():
|
|
|
|
roles, permissions = security_manager.get_permissions(mock_g.user)
|
|
|
|
assert "dummy_role" in roles
|
|
|
|
assert "Gamma" in roles
|
|
|
|
assert sorted(roles["Gamma"]) == sorted(GAMMA_ROLE_PERMISSIONS["Gamma"])
|
|
|
|
assert sorted(roles["schema_access_role"]) == sorted(
|
|
|
|
GAMMA_ROLE_PERMISSIONS["schema_access_role"]
|
|
|
|
)
|
|
|
|
|
|
|
|
assert len(permissions) == 2
|
|
|
|
assert "[examples].(id:" in permissions["database_access"][0]
|
|
|
|
assert "[examples].[" in permissions["datasource_access"][0]
|
|
|
|
|
|
|
|
# cleanup
|
|
|
|
gamma_user = security_manager.find_user(username="gamma")
|
|
|
|
gamma_user.roles.remove(security_manager.find_role(role_name))
|
|
|
|
session.commit()
|
|
|
|
|
2019-10-01 19:52:15 -04:00
|
|
|
|
2020-06-29 18:36:06 -04:00
|
|
|
class TestSecurityManager(SupersetTestCase):
|
2019-10-01 19:52:15 -04:00
|
|
|
"""
|
|
|
|
Testing the Security Manager.
|
|
|
|
"""
|
|
|
|
|
2020-06-23 23:49:39 -04:00
|
|
|
@patch("superset.security.SupersetSecurityManager.raise_for_access")
|
|
|
|
def test_can_access_datasource(self, mock_raise_for_access):
|
2019-10-01 19:52:15 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
|
|
|
|
2020-06-23 23:49:39 -04:00
|
|
|
mock_raise_for_access.return_value = None
|
|
|
|
self.assertTrue(security_manager.can_access_datasource(datasource=datasource))
|
2019-10-01 19:52:15 -04:00
|
|
|
|
2020-06-23 23:49:39 -04:00
|
|
|
mock_raise_for_access.side_effect = SupersetSecurityException(
|
|
|
|
SupersetError(
|
|
|
|
"dummy",
|
|
|
|
SupersetErrorType.DATASOURCE_SECURITY_ACCESS_ERROR,
|
|
|
|
ErrorLevel.ERROR,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertFalse(security_manager.can_access_datasource(datasource=datasource))
|
|
|
|
|
|
|
|
@patch("superset.security.SupersetSecurityManager.raise_for_access")
|
|
|
|
def test_can_access_table(self, mock_raise_for_access):
|
|
|
|
database = get_example_database()
|
|
|
|
table = Table("bar", "foo")
|
|
|
|
|
|
|
|
mock_raise_for_access.return_value = None
|
|
|
|
self.assertTrue(security_manager.can_access_table(database, table))
|
|
|
|
|
|
|
|
mock_raise_for_access.side_effect = SupersetSecurityException(
|
|
|
|
SupersetError(
|
2022-01-25 19:41:32 -05:00
|
|
|
"dummy", SupersetErrorType.TABLE_SECURITY_ACCESS_ERROR, ErrorLevel.ERROR
|
2020-06-23 23:49:39 -04:00
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertFalse(security_manager.can_access_table(database, table))
|
|
|
|
|
2022-07-07 14:04:27 -04:00
|
|
|
@patch("superset.security.SupersetSecurityManager.is_owner")
|
2020-06-23 23:49:39 -04:00
|
|
|
@patch("superset.security.SupersetSecurityManager.can_access")
|
|
|
|
@patch("superset.security.SupersetSecurityManager.can_access_schema")
|
2022-07-06 10:27:50 -04:00
|
|
|
def test_raise_for_access_datasource(
|
|
|
|
self, mock_can_access_schema, mock_can_access, mock_is_owner
|
|
|
|
):
|
2020-06-23 23:49:39 -04:00
|
|
|
datasource = self.get_datasource_mock()
|
|
|
|
|
|
|
|
mock_can_access_schema.return_value = True
|
|
|
|
security_manager.raise_for_access(datasource=datasource)
|
|
|
|
|
|
|
|
mock_can_access.return_value = False
|
|
|
|
mock_can_access_schema.return_value = False
|
2022-07-06 10:27:50 -04:00
|
|
|
mock_is_owner.return_value = False
|
2020-06-23 23:49:39 -04:00
|
|
|
|
|
|
|
with self.assertRaises(SupersetSecurityException):
|
|
|
|
security_manager.raise_for_access(datasource=datasource)
|
|
|
|
|
2022-07-07 14:04:27 -04:00
|
|
|
@patch("superset.security.SupersetSecurityManager.is_owner")
|
2020-06-23 23:49:39 -04:00
|
|
|
@patch("superset.security.SupersetSecurityManager.can_access")
|
2022-07-06 10:27:50 -04:00
|
|
|
def test_raise_for_access_query(self, mock_can_access, mock_is_owner):
|
2020-06-23 23:49:39 -04:00
|
|
|
query = Mock(
|
|
|
|
database=get_example_database(), schema="bar", sql="SELECT * FROM foo"
|
|
|
|
)
|
|
|
|
|
|
|
|
mock_can_access.return_value = True
|
|
|
|
security_manager.raise_for_access(query=query)
|
|
|
|
|
|
|
|
mock_can_access.return_value = False
|
2022-07-06 10:27:50 -04:00
|
|
|
mock_is_owner.return_value = False
|
2020-06-23 23:49:39 -04:00
|
|
|
|
|
|
|
with self.assertRaises(SupersetSecurityException):
|
|
|
|
security_manager.raise_for_access(query=query)
|
|
|
|
|
2022-07-07 14:04:27 -04:00
|
|
|
@patch("superset.security.SupersetSecurityManager.is_owner")
|
2020-06-23 23:49:39 -04:00
|
|
|
@patch("superset.security.SupersetSecurityManager.can_access")
|
|
|
|
@patch("superset.security.SupersetSecurityManager.can_access_schema")
|
|
|
|
def test_raise_for_access_query_context(
|
2022-07-07 14:04:27 -04:00
|
|
|
self, mock_can_access_schema, mock_can_access, mock_is_owner
|
2020-06-23 23:49:39 -04:00
|
|
|
):
|
|
|
|
query_context = Mock(datasource=self.get_datasource_mock())
|
|
|
|
|
|
|
|
mock_can_access_schema.return_value = True
|
|
|
|
security_manager.raise_for_access(query_context=query_context)
|
|
|
|
|
|
|
|
mock_can_access.return_value = False
|
|
|
|
mock_can_access_schema.return_value = False
|
2022-07-07 14:04:27 -04:00
|
|
|
mock_is_owner.return_value = False
|
2019-10-01 19:52:15 -04:00
|
|
|
|
|
|
|
with self.assertRaises(SupersetSecurityException):
|
2020-06-23 23:49:39 -04:00
|
|
|
security_manager.raise_for_access(query_context=query_context)
|
2019-10-01 19:52:15 -04:00
|
|
|
|
2020-06-23 23:49:39 -04:00
|
|
|
@patch("superset.security.SupersetSecurityManager.can_access")
|
|
|
|
def test_raise_for_access_table(self, mock_can_access):
|
|
|
|
database = get_example_database()
|
|
|
|
table = Table("bar", "foo")
|
2019-10-01 19:52:15 -04:00
|
|
|
|
2020-06-23 23:49:39 -04:00
|
|
|
mock_can_access.return_value = True
|
|
|
|
security_manager.raise_for_access(database=database, table=table)
|
2019-10-01 19:52:15 -04:00
|
|
|
|
2020-06-23 23:49:39 -04:00
|
|
|
mock_can_access.return_value = False
|
2019-10-01 19:52:15 -04:00
|
|
|
|
|
|
|
with self.assertRaises(SupersetSecurityException):
|
2020-06-23 23:49:39 -04:00
|
|
|
security_manager.raise_for_access(database=database, table=table)
|
2019-10-01 19:52:15 -04:00
|
|
|
|
2022-07-07 14:04:27 -04:00
|
|
|
@patch("superset.security.SupersetSecurityManager.is_owner")
|
2020-06-23 23:49:39 -04:00
|
|
|
@patch("superset.security.SupersetSecurityManager.can_access")
|
|
|
|
@patch("superset.security.SupersetSecurityManager.can_access_schema")
|
2022-07-07 14:04:27 -04:00
|
|
|
def test_raise_for_access_viz(
|
|
|
|
self, mock_can_access_schema, mock_can_access, mock_is_owner
|
|
|
|
):
|
2019-10-01 19:52:15 -04:00
|
|
|
test_viz = viz.TableViz(self.get_datasource_mock(), form_data={})
|
|
|
|
|
2020-06-23 23:49:39 -04:00
|
|
|
mock_can_access_schema.return_value = True
|
|
|
|
security_manager.raise_for_access(viz=test_viz)
|
2019-10-01 19:52:15 -04:00
|
|
|
|
2020-06-23 23:49:39 -04:00
|
|
|
mock_can_access.return_value = False
|
|
|
|
mock_can_access_schema.return_value = False
|
2022-07-07 14:04:27 -04:00
|
|
|
mock_is_owner.return_value = False
|
2019-10-01 19:52:15 -04:00
|
|
|
|
|
|
|
with self.assertRaises(SupersetSecurityException):
|
2020-06-23 23:49:39 -04:00
|
|
|
security_manager.raise_for_access(viz=test_viz)
|
2020-02-22 04:21:31 -05:00
|
|
|
|
2022-01-25 19:41:32 -05:00
|
|
|
@patch("superset.security.manager.g")
|
|
|
|
def test_get_user_roles(self, mock_g):
|
|
|
|
admin = security_manager.find_user("admin")
|
|
|
|
mock_g.user = admin
|
|
|
|
roles = security_manager.get_user_roles()
|
|
|
|
self.assertEqual(admin.roles, roles)
|
2020-02-22 04:21:31 -05:00
|
|
|
|
2022-01-25 19:41:32 -05:00
|
|
|
@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)
|
2021-05-21 17:29:52 -04:00
|
|
|
|
|
|
|
|
|
|
|
class TestAccessRequestEndpoints(SupersetTestCase):
|
|
|
|
def test_access_request_disabled(self):
|
|
|
|
with patch.object(AccessRequestsModelView, "is_enabled", return_value=False):
|
|
|
|
self.login("admin")
|
|
|
|
uri = "/accessrequestsmodelview/list/"
|
|
|
|
rv = self.client.get(uri)
|
|
|
|
self.assertEqual(rv.status_code, 404)
|
|
|
|
|
|
|
|
def test_access_request_enabled(self):
|
|
|
|
with patch.object(AccessRequestsModelView, "is_enabled", return_value=True):
|
|
|
|
self.login("admin")
|
|
|
|
uri = "/accessrequestsmodelview/list/"
|
|
|
|
rv = self.client.get(uri)
|
|
|
|
self.assertLess(rv.status_code, 400)
|
2021-06-30 12:51:11 -04:00
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
):
|
|
|
|
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 = []
|
|
|
|
|
|
|
|
with mock.patch.object(
|
2022-06-21 07:22:39 -04:00
|
|
|
SqlaTable, "get_all_datasources"
|
2021-06-30 12:51:11 -04:00
|
|
|
) as mock_get_all_datasources:
|
|
|
|
mock_get_all_datasources.return_value = [
|
|
|
|
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
|
|
|
|
):
|
|
|
|
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 = []
|
|
|
|
|
|
|
|
with mock.patch.object(
|
2022-06-21 07:22:39 -04:00
|
|
|
SqlaTable, "get_all_datasources"
|
2021-06-30 12:51:11 -04:00
|
|
|
) as mock_get_all_datasources:
|
|
|
|
mock_get_all_datasources.return_value = [
|
|
|
|
Datasource("database1", "schema1", "table1"),
|
|
|
|
Datasource("database1", "schema1", "table2"),
|
|
|
|
Datasource("database2", None, "table1"),
|
|
|
|
]
|
|
|
|
|
|
|
|
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
|
|
|
|
):
|
|
|
|
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 = [
|
|
|
|
Datasource("database1", "schema1", "table1"),
|
|
|
|
Datasource("database1", "schema1", "table2"),
|
|
|
|
]
|
|
|
|
|
|
|
|
with mock.patch.object(
|
2022-06-21 07:22:39 -04:00
|
|
|
SqlaTable, "get_all_datasources"
|
2021-06-30 12:51:11 -04:00
|
|
|
) as mock_get_all_datasources:
|
|
|
|
mock_get_all_datasources.return_value = [
|
|
|
|
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"),
|
|
|
|
]
|
2022-01-25 19:41:32 -05:00
|
|
|
|
|
|
|
|
|
|
|
class FakeRequest:
|
|
|
|
headers: Any = {}
|
2022-06-17 23:01:08 -04:00
|
|
|
form: Any = {}
|
2022-01-25 19:41:32 -05:00
|
|
|
|
|
|
|
|
|
|
|
class TestGuestTokens(SupersetTestCase):
|
|
|
|
def create_guest_token(self):
|
|
|
|
user = {"username": "test_guest"}
|
|
|
|
resources = [{"some": "resource"}]
|
|
|
|
rls = [{"dataset": 1, "clause": "access = 1"}]
|
|
|
|
return security_manager.create_guest_access_token(user, resources, rls)
|
|
|
|
|
|
|
|
@patch("superset.security.SupersetSecurityManager._get_current_epoch_time")
|
|
|
|
def test_create_guest_access_token(self, get_time_mock):
|
|
|
|
now = time.time()
|
|
|
|
get_time_mock.return_value = now # so we know what it should =
|
|
|
|
|
|
|
|
user = {"username": "test_guest"}
|
|
|
|
resources = [{"some": "resource"}]
|
|
|
|
rls = [{"dataset": 1, "clause": "access = 1"}]
|
|
|
|
token = security_manager.create_guest_access_token(user, resources, rls)
|
2022-02-14 13:43:35 -05:00
|
|
|
aud = get_url_host()
|
2022-01-25 19:41:32 -05:00
|
|
|
# unfortunately we cannot mock time in the jwt lib
|
|
|
|
decoded_token = jwt.decode(
|
|
|
|
token,
|
|
|
|
self.app.config["GUEST_TOKEN_JWT_SECRET"],
|
|
|
|
algorithms=[self.app.config["GUEST_TOKEN_JWT_ALGO"]],
|
2022-02-14 13:43:35 -05:00
|
|
|
audience=aud,
|
2022-01-25 19:41:32 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
self.assertEqual(user, decoded_token["user"])
|
|
|
|
self.assertEqual(resources, decoded_token["resources"])
|
|
|
|
self.assertEqual(now, decoded_token["iat"])
|
2022-02-14 13:43:35 -05:00
|
|
|
self.assertEqual(aud, decoded_token["aud"])
|
|
|
|
self.assertEqual("guest", decoded_token["type"])
|
2022-01-25 19:41:32 -05:00
|
|
|
self.assertEqual(
|
2022-03-14 12:32:25 -04:00
|
|
|
now + (self.app.config["GUEST_TOKEN_JWT_EXP_SECONDS"]),
|
2022-01-25 19:41:32 -05:00
|
|
|
decoded_token["exp"],
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_get_guest_user(self):
|
|
|
|
token = self.create_guest_token()
|
|
|
|
fake_request = FakeRequest()
|
|
|
|
fake_request.headers[current_app.config["GUEST_TOKEN_HEADER_NAME"]] = token
|
|
|
|
|
|
|
|
guest_user = security_manager.get_guest_user_from_request(fake_request)
|
|
|
|
|
|
|
|
self.assertIsNotNone(guest_user)
|
|
|
|
self.assertEqual("test_guest", guest_user.username)
|
|
|
|
|
2022-06-17 23:01:08 -04:00
|
|
|
def test_get_guest_user_with_request_form(self):
|
|
|
|
token = self.create_guest_token()
|
|
|
|
fake_request = FakeRequest()
|
|
|
|
fake_request.headers[current_app.config["GUEST_TOKEN_HEADER_NAME"]] = None
|
|
|
|
fake_request.form["guest_token"] = token
|
|
|
|
|
|
|
|
guest_user = security_manager.get_guest_user_from_request(fake_request)
|
|
|
|
|
|
|
|
self.assertIsNotNone(guest_user)
|
|
|
|
self.assertEqual("test_guest", guest_user.username)
|
|
|
|
|
2022-01-25 19:41:32 -05:00
|
|
|
@patch("superset.security.SupersetSecurityManager._get_current_epoch_time")
|
|
|
|
def test_get_guest_user_expired_token(self, get_time_mock):
|
|
|
|
# make a just-expired token
|
|
|
|
get_time_mock.return_value = (
|
|
|
|
time.time() - (self.app.config["GUEST_TOKEN_JWT_EXP_SECONDS"] * 1000) - 1
|
|
|
|
)
|
|
|
|
token = self.create_guest_token()
|
|
|
|
fake_request = FakeRequest()
|
|
|
|
fake_request.headers[current_app.config["GUEST_TOKEN_HEADER_NAME"]] = token
|
|
|
|
|
|
|
|
guest_user = security_manager.get_guest_user_from_request(fake_request)
|
|
|
|
|
|
|
|
self.assertIsNone(guest_user)
|
|
|
|
|
|
|
|
def test_get_guest_user_no_user(self):
|
|
|
|
user = None
|
|
|
|
resources = [{"type": "dashboard", "id": 1}]
|
|
|
|
rls = {}
|
|
|
|
token = security_manager.create_guest_access_token(user, resources, rls)
|
|
|
|
fake_request = FakeRequest()
|
|
|
|
fake_request.headers[current_app.config["GUEST_TOKEN_HEADER_NAME"]] = token
|
|
|
|
guest_user = security_manager.get_guest_user_from_request(fake_request)
|
|
|
|
|
|
|
|
self.assertIsNone(guest_user)
|
|
|
|
self.assertRaisesRegex(ValueError, "Guest token does not contain a user claim")
|
|
|
|
|
|
|
|
def test_get_guest_user_no_resource(self):
|
|
|
|
user = {"username": "test_guest"}
|
|
|
|
resources = []
|
|
|
|
rls = {}
|
|
|
|
token = security_manager.create_guest_access_token(user, resources, rls)
|
|
|
|
fake_request = FakeRequest()
|
|
|
|
fake_request.headers[current_app.config["GUEST_TOKEN_HEADER_NAME"]] = token
|
|
|
|
security_manager.get_guest_user_from_request(fake_request)
|
|
|
|
|
|
|
|
self.assertRaisesRegex(
|
|
|
|
ValueError, "Guest token does not contain a resources claim"
|
|
|
|
)
|
2022-02-14 13:43:35 -05:00
|
|
|
|
|
|
|
def test_get_guest_user_not_guest_type(self):
|
|
|
|
now = time.time()
|
|
|
|
user = {"username": "test_guest"}
|
|
|
|
resources = [{"some": "resource"}]
|
|
|
|
aud = get_url_host()
|
|
|
|
|
|
|
|
claims = {
|
|
|
|
"user": user,
|
|
|
|
"resources": resources,
|
|
|
|
"rls_rules": [],
|
|
|
|
# standard jwt claims:
|
|
|
|
"aud": aud,
|
|
|
|
"iat": now, # issued at
|
|
|
|
"type": "not_guest",
|
|
|
|
}
|
|
|
|
token = jwt.encode(
|
|
|
|
claims,
|
|
|
|
self.app.config["GUEST_TOKEN_JWT_SECRET"],
|
|
|
|
algorithm=self.app.config["GUEST_TOKEN_JWT_ALGO"],
|
|
|
|
)
|
|
|
|
fake_request = FakeRequest()
|
|
|
|
fake_request.headers[current_app.config["GUEST_TOKEN_HEADER_NAME"]] = token
|
|
|
|
guest_user = security_manager.get_guest_user_from_request(fake_request)
|
|
|
|
|
|
|
|
self.assertIsNone(guest_user)
|
|
|
|
self.assertRaisesRegex(ValueError, "This is not a guest token.")
|
|
|
|
|
|
|
|
def test_get_guest_user_bad_audience(self):
|
|
|
|
now = time.time()
|
|
|
|
user = {"username": "test_guest"}
|
|
|
|
resources = [{"some": "resource"}]
|
|
|
|
aud = get_url_host()
|
|
|
|
|
|
|
|
claims = {
|
|
|
|
"user": user,
|
|
|
|
"resources": resources,
|
|
|
|
"rls_rules": [],
|
|
|
|
# standard jwt claims:
|
|
|
|
"aud": "bad_audience",
|
|
|
|
"iat": now, # issued at
|
|
|
|
"type": "guest",
|
|
|
|
}
|
|
|
|
token = jwt.encode(
|
|
|
|
claims,
|
|
|
|
self.app.config["GUEST_TOKEN_JWT_SECRET"],
|
|
|
|
algorithm=self.app.config["GUEST_TOKEN_JWT_ALGO"],
|
|
|
|
)
|
|
|
|
fake_request = FakeRequest()
|
|
|
|
fake_request.headers[current_app.config["GUEST_TOKEN_HEADER_NAME"]] = token
|
|
|
|
guest_user = security_manager.get_guest_user_from_request(fake_request)
|
|
|
|
|
|
|
|
self.assertRaisesRegex(jwt.exceptions.InvalidAudienceError, "Invalid audience")
|
|
|
|
self.assertIsNone(guest_user)
|
2022-02-15 20:47:32 -05:00
|
|
|
|
|
|
|
@patch("superset.security.SupersetSecurityManager._get_current_epoch_time")
|
|
|
|
def test_create_guest_access_token_callable_audience(self, get_time_mock):
|
|
|
|
now = time.time()
|
|
|
|
get_time_mock.return_value = now
|
|
|
|
app.config["GUEST_TOKEN_JWT_AUDIENCE"] = Mock(return_value="cool_code")
|
|
|
|
|
|
|
|
user = {"username": "test_guest"}
|
|
|
|
resources = [{"some": "resource"}]
|
|
|
|
rls = [{"dataset": 1, "clause": "access = 1"}]
|
|
|
|
token = security_manager.create_guest_access_token(user, resources, rls)
|
|
|
|
|
|
|
|
decoded_token = jwt.decode(
|
|
|
|
token,
|
|
|
|
self.app.config["GUEST_TOKEN_JWT_SECRET"],
|
|
|
|
algorithms=[self.app.config["GUEST_TOKEN_JWT_ALGO"]],
|
|
|
|
audience="cool_code",
|
|
|
|
)
|
|
|
|
app.config["GUEST_TOKEN_JWT_AUDIENCE"].assert_called_once()
|
|
|
|
self.assertEqual("cool_code", decoded_token["aud"])
|
|
|
|
self.assertEqual("guest", decoded_token["type"])
|
|
|
|
app.config["GUEST_TOKEN_JWT_AUDIENCE"] = None
|