From 92aa1a612476fdef5f19eb68f961324a333b346c Mon Sep 17 00:00:00 2001 From: Bogdan Date: Thu, 15 Dec 2016 08:38:34 -0500 Subject: [PATCH] Permissions refactoring, optimizations and unit testing. (#1798) * Refactor and speed up superset init * Add unit tests. * Test fixes. * More test updates. * Fix read only perms * Address comments. --- superset/models.py | 40 +++---- superset/security.py | 233 ++++++++++++++++++++-------------------- superset/utils.py | 1 - superset/views.py | 10 +- tests/access_tests.py | 2 +- tests/base_tests.py | 20 ++-- tests/druid_tests.py | 18 ++-- tests/security_tests.py | 173 +++++++++++++++++++++++++++++ tests/sqllab_tests.py | 5 +- 9 files changed, 327 insertions(+), 175 deletions(-) create mode 100644 tests/security_tests.py diff --git a/superset/models.py b/superset/models.py index cc43b00948..10928ff1e6 100644 --- a/superset/models.py +++ b/superset/models.py @@ -52,7 +52,6 @@ from sqlalchemy_utils import EncryptedType from werkzeug.datastructures import ImmutableMultiDict -import superset from superset import app, db, db_engine_specs, get_session, utils, sm from superset.source_registry import SourceRegistry from superset.viz import viz_types @@ -70,24 +69,13 @@ FillterPattern = re.compile(r'''((?:[^,"']|"[^"]*"|'[^']*')+)''') def set_perm(mapper, connection, target): # noqa - target.perm = target.get_perm() - - -def init_metrics_perm(metrics=None): - """Create permissions for restricted metrics - - :param metrics: a list of metrics to be processed, if not specified, - all metrics are processed - :type metrics: models.SqlMetric or models.DruidMetric - """ - if not metrics: - metrics = [] - for model in [SqlMetric, DruidMetric]: - metrics += list(db.session.query(model).all()) - - for metric in metrics: - if metric.is_restricted and metric.perm: - sm.add_permission_view_menu('metric_access', metric.perm) + if target.perm != target.get_perm(): + link_table = target.__table__ + connection.execute( + link_table.update() + .where(link_table.c.id == target.id) + .values(perm=target.get_perm()) + ) class JavascriptPostAggregator(Postaggregator): @@ -860,8 +848,8 @@ class Database(Model, AuditMixinNullable): return ( "[{obj.database_name}].(id:{obj.id})").format(obj=self) -sqla.event.listen(Database, 'before_insert', set_perm) -sqla.event.listen(Database, 'before_update', set_perm) +sqla.event.listen(Database, 'after_insert', set_perm) +sqla.event.listen(Database, 'after_update', set_perm) class SqlaTable(Model, Queryable, AuditMixinNullable, ImportMixin): @@ -1340,8 +1328,8 @@ class SqlaTable(Model, Queryable, AuditMixinNullable, ImportMixin): return datasource.id -sqla.event.listen(SqlaTable, 'before_insert', set_perm) -sqla.event.listen(SqlaTable, 'before_update', set_perm) +sqla.event.listen(SqlaTable, 'after_insert', set_perm) +sqla.event.listen(SqlaTable, 'after_update', set_perm) class SqlMetric(Model, AuditMixinNullable, ImportMixin): @@ -2238,8 +2226,8 @@ class DruidDatasource(Model, AuditMixinNullable, Queryable): filters = cond return filters -sqla.event.listen(DruidDatasource, 'before_insert', set_perm) -sqla.event.listen(DruidDatasource, 'before_update', set_perm) +sqla.event.listen(DruidDatasource, 'after_insert', set_perm) +sqla.event.listen(DruidDatasource, 'after_update', set_perm) class Log(Model): @@ -2466,8 +2454,6 @@ class DruidColumn(Model, AuditMixinNullable): session.add(metric) session.flush() - init_metrics_perm(new_metrics) - class FavStar(Model): __tablename__ = 'favstar' diff --git a/superset/security.py b/superset/security.py index c0de5ba22b..8e5915142d 100644 --- a/superset/security.py +++ b/superset/security.py @@ -3,11 +3,10 @@ from __future__ import division from __future__ import print_function from __future__ import unicode_literals -from itertools import product import logging from flask_appbuilder.security.sqla import models as ab_models -from superset import conf, db, models, sm +from superset import conf, db, models, sm, source_registry READ_ONLY_MODELVIEWS = { @@ -17,13 +16,10 @@ READ_ONLY_MODELVIEWS = { } GAMMA_READ_ONLY_MODELVIEWS = { - 'ColumnInlineView', 'SqlMetricInlineView', 'TableColumnInlineView', 'TableModelView', - 'DatasourceModelView', 'DruidColumnInlineView', - 'MetricInlineView', 'DruidDatasourceModelView', 'DruidMetricInlineView', } | READ_ONLY_MODELVIEWS @@ -38,13 +34,11 @@ ADMIN_ONLY_VIEW_MENUES = { 'RoleModelView', 'Security', 'UserDBModelView', -} | READ_ONLY_MODELVIEWS +} ADMIN_ONLY_PERMISSIONS = { 'all_database_access', - 'datasource_access', - 'schema_access', - 'database_access', + # TODO: move can_sql_json to sql_lab role 'can_sql_json', 'can_override_role_permissions', 'can_sync_druid_source', @@ -52,24 +46,16 @@ ADMIN_ONLY_PERMISSIONS = { 'can_approve', 'can_update_role', } + READ_ONLY_PERMISSION = { 'can_show', 'can_list', } ALPHA_ONLY_PERMISSIONS = set([ - 'datasource_access', - 'schema_access', - 'database_access', 'muldelete', 'all_datasource_access', ]) -READ_ONLY_PRODUCT = set( - product(READ_ONLY_PERMISSION, READ_ONLY_MODELVIEWS)) - -GAMMA_READ_ONLY_PRODUCT = set( - product(READ_ONLY_PERMISSION, GAMMA_READ_ONLY_MODELVIEWS)) - OBJECT_SPEC_PERMISSIONS = set([ 'database_access', @@ -81,7 +67,7 @@ OBJECT_SPEC_PERMISSIONS = set([ def merge_perm(sm, permission_name, view_menu_name): pv = sm.find_permission_view_menu(permission_name, view_menu_name) - if not pv: + if not pv and permission_name and view_menu_name: sm.add_permission_view_menu(permission_name, view_menu_name) @@ -107,114 +93,125 @@ def get_or_create_main_db(): return dbobj -def sync_role_definitions(): - """Inits the Superset application with security roles and such""" - logging.info("Syncing role definition") +def is_admin_only(pvm): + # not readonly operations on read only model views allowed only for admins + if (pvm.view_menu.name in READ_ONLY_MODELVIEWS and + pvm.permission.name not in READ_ONLY_PERMISSION): + return True + return (pvm.view_menu.name in ADMIN_ONLY_VIEW_MENUES or + pvm.permission.name in ADMIN_ONLY_PERMISSIONS) - # Creating default roles - alpha = sm.add_role("Alpha") - admin = sm.add_role("Admin") - gamma = sm.add_role("Gamma") - public = sm.add_role("Public") - sql_lab = sm.add_role("sql_lab") - granter = sm.add_role("granter") - get_or_create_main_db() +def is_alpha_only(pvm): + if (pvm.view_menu.name in GAMMA_READ_ONLY_MODELVIEWS and + pvm.permission.name not in READ_ONLY_PERMISSION): + return True + return pvm.permission.name in ALPHA_ONLY_PERMISSIONS + +def is_admin_pvm(pvm): + return not is_user_defined_permission(pvm) + + +def is_alpha_pvm(pvm): + return not (is_user_defined_permission(pvm) or is_admin_only(pvm)) + + +def is_gamma_pvm(pvm): + return not (is_user_defined_permission(pvm) or is_admin_only(pvm) or + is_alpha_only(pvm)) + + +def is_sql_lab_pvm(pvm): + return pvm.view_menu.name in {'SQL Lab'} or pvm.permission.name in { + 'can_sql_json', 'can_csv', 'can_search_queries'} + + +def is_granter_pvm(pvm): + return pvm.permission.name in {'can_override_role_permissions', + 'can_approve'} + + +def set_role(role_name, pvms, pvm_check): + logging.info("Syncing {} perms".format(role_name)) + role = sm.add_role(role_name) + role_pvms = [p for p in pvms if pvm_check(p)] + role.permissions = role_pvms + + +def create_custom_permissions(): # Global perms merge_perm(sm, 'all_datasource_access', 'all_datasource_access') merge_perm(sm, 'all_database_access', 'all_database_access') - perms = db.session.query(ab_models.PermissionView).all() - perms = [p for p in perms if p.permission and p.view_menu] - logging.info("Syncing admin perms") - for p in perms: - # admin has all_database_access and all_datasource_access - if is_user_defined_permission(p): - sm.del_permission_role(admin, p) - else: - sm.add_permission_role(admin, p) - - logging.info("Syncing alpha perms") - for p in perms: - # alpha has all_database_access and all_datasource_access - if is_user_defined_permission(p): - sm.del_permission_role(alpha, p) - elif ( - ( - p.view_menu.name not in ADMIN_ONLY_VIEW_MENUES and - p.permission.name not in ADMIN_ONLY_PERMISSIONS - ) or - (p.permission.name, p.view_menu.name) in READ_ONLY_PRODUCT - ): - sm.add_permission_role(alpha, p) - else: - sm.del_permission_role(alpha, p) - - logging.info("Syncing gamma perms and public if specified") - PUBLIC_ROLE_LIKE_GAMMA = conf.get('PUBLIC_ROLE_LIKE_GAMMA', False) - for p in perms: - if ( - ( - p.view_menu.name not in ADMIN_ONLY_VIEW_MENUES and - p.view_menu.name not in GAMMA_READ_ONLY_MODELVIEWS and - p.permission.name not in ADMIN_ONLY_PERMISSIONS and - p.permission.name not in ALPHA_ONLY_PERMISSIONS - ) or - (p.permission.name, p.view_menu.name) in - GAMMA_READ_ONLY_PRODUCT - ): - sm.add_permission_role(gamma, p) - if PUBLIC_ROLE_LIKE_GAMMA: - sm.add_permission_role(public, p) - else: - sm.del_permission_role(gamma, p) - sm.del_permission_role(public, p) - - logging.info("Syncing sql_lab perms") - for p in perms: - if ( - p.view_menu.name in {'SQL Lab'} or - p.permission.name in { - 'can_sql_json', 'can_csv', 'can_search_queries'} - ): - sm.add_permission_role(sql_lab, p) - else: - sm.del_permission_role(sql_lab, p) - - logging.info("Syncing granter perms") - for p in perms: - if ( - p.permission.name in { - 'can_override_role_permissions', 'can_aprove'} - ): - sm.add_permission_role(granter, p) - else: - sm.del_permission_role(granter, p) - - logging.info("Making sure all data source perms have been created") - session = db.session() - datasources = [ - o for o in session.query(models.SqlaTable).all()] - datasources += [ - o for o in session.query(models.DruidDatasource).all()] +def create_missing_datasource_perms(view_menu_set): + logging.info("Creating missing datasource permissions.") + datasources = source_registry.SourceRegistry.get_all_datasources( + db.session) for datasource in datasources: - perm = datasource.get_perm() - merge_perm(sm, 'datasource_access', perm) - if datasource.schema: - merge_perm(sm, 'schema_access', datasource.schema_perm) - if perm != datasource.perm: - datasource.perm = perm + if datasource and datasource.perm not in view_menu_set: + merge_perm(sm, 'datasource_access', datasource.get_perm()) + if datasource.schema_perm: + merge_perm(sm, 'schema_access', datasource.schema_perm) - logging.info("Making sure all database perms have been created") - databases = [o for o in session.query(models.Database).all()] + +def create_missing_database_perms(view_menu_set): + logging.info("Creating missing database permissions.") + databases = db.session.query(models.Database).all() for database in databases: - perm = database.get_perm() - if perm != database.perm: - database.perm = perm - merge_perm(sm, 'database_access', perm) - session.commit() + if database and database.perm not in view_menu_set: + merge_perm(sm, 'database_access', database.perm) - logging.info("Making sure all metrics perms exist") - models.init_metrics_perm() + +def create_missing_metrics_perm(view_menu_set): + """Create permissions for restricted metrics + + :param metrics: a list of metrics to be processed, if not specified, + all metrics are processed + :type metrics: models.SqlMetric or models.DruidMetric + """ + logging.info("Creating missing metrics permissions") + metrics = [] + for model in [models.SqlMetric, models.DruidMetric]: + metrics += list(db.session.query(model).all()) + + for metric in metrics: + if (metric.is_restricted and metric.perm and + metric.perm not in view_menu_set): + merge_perm('metric_access', metric.perm) + + +def sync_role_definitions(): + """Inits the Superset application with security roles and such""" + logging.info("Syncing role definition") + + get_or_create_main_db() + create_custom_permissions() + + pvms = db.session.query(ab_models.PermissionView).all() + pvms = [p for p in pvms if p.permission and p.view_menu] + + # cleanup + pvms_to_delete = [p for p in pvms if not (p.permission and p.view_menu)] + + for pvm_to_delete in pvms_to_delete: + sm.get_session.delete(pvm_to_delete) + + # Creating default roles + set_role('Admin', pvms, is_admin_pvm) + set_role('Alpha', pvms, is_alpha_pvm) + set_role('Gamma', pvms, is_gamma_pvm) + set_role('granter', pvms, is_granter_pvm) + set_role('sql_lab', pvms, is_sql_lab_pvm) + + if conf.get('PUBLIC_ROLE_LIKE_GAMMA', False): + set_role('Public', pvms, is_gamma_pvm) + + view_menu_set = db.session.query(models.SqlaTable).all() + create_missing_datasource_perms(view_menu_set) + create_missing_database_perms(view_menu_set) + create_missing_metrics_perm(view_menu_set) + + # commit role and view menu updates + sm.get_session.commit() diff --git a/superset/utils.py b/superset/utils.py index d4dc2dbe5f..9239b71b58 100644 --- a/superset/utils.py +++ b/superset/utils.py @@ -333,7 +333,6 @@ def get_datasource_full_name(database_name, datasource_name, schema=None): def get_schema_perm(database, schema): if schema: return "[{}].[{}]".format(database, schema) - return database.perm def validate_json(obj): diff --git a/superset/views.py b/superset/views.py index 5dc9f570e2..27be04527c 100755 --- a/superset/views.py +++ b/superset/views.py @@ -466,10 +466,12 @@ class SqlMetricInlineView(CompactCRUDMixin, SupersetModelView): # noqa } def post_add(self, metric): - utils.init_metrics_perm(superset, [metric]) + if metric.is_restricted: + security.merge_perm(sm, 'metric_access', metric.get_perm()) def post_update(self, metric): - utils.init_metrics_perm(superset, [metric]) + if metric.is_restricted: + security.merge_perm(sm, 'metric_access', metric.get_perm()) appbuilder.add_view_no_menu(SqlMetricInlineView) @@ -702,7 +704,7 @@ class TableModelView(SupersetModelView, DeleteMixin): # noqa def post_add(self, table): table.fetch_metadata() - security.merge_perm(sm, 'datasource_access', table.perm) + security.merge_perm(sm, 'datasource_access', table.get_perm()) if table.schema: security.merge_perm(sm, 'schema_access', table.schema_perm) @@ -1069,7 +1071,7 @@ class DruidDatasourceModelView(SupersetModelView, DeleteMixin): # noqa def post_add(self, datasource): datasource.generate_metrics() - security.merge_perm(sm, 'datasource_access', datasource.perm) + security.merge_perm(sm, 'datasource_access', datasource.get_perm()) if datasource.schema: security.merge_perm(sm, 'schema_access', datasource.schema_perm) diff --git a/tests/access_tests.py b/tests/access_tests.py index 376da41dc9..383f7c6501 100644 --- a/tests/access_tests.py +++ b/tests/access_tests.py @@ -107,7 +107,6 @@ class RequestAccessTests(SupersetTestCase): updated_role = sm.find_role('override_me') perms = sorted( updated_role.permissions, key=lambda p: p.view_menu.name) - self.assertEquals(3, len(perms)) druid_ds_1 = self.get_druid_ds_by_name('druid_ds_1') self.assertEquals(druid_ds_1.perm, perms[0].view_menu.name) self.assertEquals('datasource_access', perms[0].permission.name) @@ -121,6 +120,7 @@ class RequestAccessTests(SupersetTestCase): self.assertEquals(birth_names.perm, perms[2].view_menu.name) self.assertEquals( 'datasource_access', updated_role.permissions[2].permission.name) + self.assertEquals(3, len(perms)) def test_override_role_permissions_drops_absent_perms(self): override_me = sm.find_role('override_me') diff --git a/tests/base_tests.py b/tests/base_tests.py index 3ff744fc9b..2dbb7c2520 100644 --- a/tests/base_tests.py +++ b/tests/base_tests.py @@ -40,16 +40,16 @@ class SupersetTestCase(unittest.TestCase): self.client = app.test_client() self.maxDiff = None - gamma_sqllab = sm.add_role("gamma_sqllab") + gamma_sqllab_role = sm.add_role("gamma_sqllab") for perm in sm.find_role('Gamma').permissions: - sm.add_permission_role(gamma_sqllab, perm) + sm.add_permission_role(gamma_sqllab_role, perm) db_perm = self.get_main_database(sm.get_session).perm security.merge_perm(sm, 'database_access', db_perm) db_pvm = sm.find_permission_view_menu( view_menu_name=db_perm, permission_name='database_access') - gamma_sqllab.permissions.append(db_pvm) + gamma_sqllab_role.permissions.append(db_pvm) for perm in sm.find_role('sql_lab').permissions: - sm.add_permission_role(gamma_sqllab, perm) + sm.add_permission_role(gamma_sqllab_role, perm) admin = appbuilder.sm.find_user('admin') if not admin: @@ -65,12 +65,11 @@ class SupersetTestCase(unittest.TestCase): appbuilder.sm.find_role('Gamma'), password='general') - gamma_sqllab = appbuilder.sm.find_user('gamma_sqllab') - if not gamma_sqllab: - gamma_sqllab = appbuilder.sm.add_user( + gamma_sqllab_user = appbuilder.sm.find_user('gamma_sqllab') + if not gamma_sqllab_user: + appbuilder.sm.add_user( 'gamma_sqllab', 'gamma_sqllab', 'user', 'gamma_sqllab@fab.org', - appbuilder.sm.find_role('gamma_sqllab'), - password='general') + gamma_sqllab_role, password='general') alpha = appbuilder.sm.find_user('alpha') if not alpha: @@ -266,6 +265,3 @@ class SupersetTestCase(unittest.TestCase): self.assertIn(('can_save_dash', 'Superset'), gamma_perm_set) self.assertIn(('can_slice', 'Superset'), gamma_perm_set) - - - diff --git a/tests/druid_tests.py b/tests/druid_tests.py index 96a63fb1b1..0da4b848f6 100644 --- a/tests/druid_tests.py +++ b/tests/druid_tests.py @@ -10,7 +10,7 @@ import unittest from mock import Mock, patch -from superset import db, sm, utils +from superset import db, sm, security from superset.models import DruidCluster, DruidDatasource from .base_tests import SupersetTestCase @@ -240,21 +240,21 @@ class DruidTests(SupersetTestCase): db.session) no_gamma_ds.cluster = cluster db.session.merge(no_gamma_ds) - - sm.add_permission_view_menu('datasource_access', gamma_ds.perm) - sm.add_permission_view_menu('datasource_access', no_gamma_ds.perm) - db.session.commit() - perm = sm.find_permission_view_menu('datasource_access', gamma_ds.perm) + security.merge_perm(sm, 'datasource_access', gamma_ds.perm) + security.merge_perm(sm, 'datasource_access', no_gamma_ds.perm) + + perm = sm.find_permission_view_menu( + 'datasource_access', gamma_ds.get_perm()) sm.add_permission_role(sm.find_role('Gamma'), perm) - db.session.commit() + sm.get_session.commit() self.login(username='gamma') url = '/druiddatasourcemodelview/list/' resp = self.get_resp(url) - assert 'datasource_for_gamma' in resp - assert 'datasource_not_for_gamma' not in resp + self.assertIn('datasource_for_gamma', resp) + self.assertNotIn('datasource_not_for_gamma', resp) if __name__ == '__main__': diff --git a/tests/security_tests.py b/tests/security_tests.py new file mode 100644 index 0000000000..bfa9d71dbb --- /dev/null +++ b/tests/security_tests.py @@ -0,0 +1,173 @@ +from superset import security, sm + +from .base_tests import SupersetTestCase + + +def get_perm_tuples(role_name): + perm_set = set() + for perm in sm.find_role(role_name).permissions: + perm_set.add((perm.permission.name, perm.view_menu.name)) + return perm_set + + +class RolePermissionTests(SupersetTestCase): + """Testing export import functionality for dashboards""" + + def __init__(self, *args, **kwargs): + super(RolePermissionTests, self).__init__(*args, **kwargs) + + def assert_can_read(self, view_menu, permissions_set): + self.assertIn(('can_show', view_menu), permissions_set) + self.assertIn(('can_list', view_menu), permissions_set) + + def assert_can_write(self, view_menu, permissions_set): + self.assertIn(('can_add', view_menu), permissions_set) + self.assertIn(('can_download', view_menu), permissions_set) + self.assertIn(('can_delete', view_menu), permissions_set) + self.assertIn(('can_edit', view_menu), permissions_set) + + def assert_cannot_write(self, view_menu, permissions_set): + self.assertNotIn(('can_add', view_menu), permissions_set) + self.assertNotIn(('can_download', 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) + + 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) + + def assert_cannot_gamma(self, perm_set): + self.assert_cannot_write('DruidColumnInlineView', perm_set) + + def assert_can_gamma(self, perm_set): + self.assert_can_read('DatabaseAsync', perm_set) + self.assert_can_read('TableModelView', perm_set) + + # make sure that user can create slices and dashboards + self.assert_can_all('SliceModelView', perm_set) + self.assert_can_all('DashboardModelView', perm_set) + + self.assertIn(('can_add_slices', 'Superset'), perm_set) + self.assertIn(('can_copy_dash', 'Superset'), perm_set) + self.assertIn(('can_activity_per_day', '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) + 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', 'Superset'), perm_set) + self.assertIn(('can_explore_json', 'Superset'), perm_set) + self.assertIn(('can_queries', 'Superset'), perm_set) + + def assert_can_alpha(self, perm_set): + self.assert_can_all('SqlMetricInlineView', perm_set) + self.assert_can_all('TableColumnInlineView', perm_set) + self.assert_can_all('TableModelView', perm_set) + self.assert_can_all('DruidColumnInlineView', perm_set) + self.assert_can_all('DruidDatasourceModelView', perm_set) + self.assert_can_all('DruidMetricInlineView', perm_set) + + self.assertIn( + ('all_datasource_access', 'all_datasource_access'), perm_set) + self.assertIn(('muldelete', 'DruidDatasourceModelView'), perm_set) + + def assert_cannot_alpha(self, perm_set): + self.assert_cannot_write('AccessRequestsModelView', perm_set) + self.assert_cannot_write('Queries', perm_set) + self.assert_cannot_write('RoleModelView', perm_set) + self.assert_cannot_write('UserDBModelView', perm_set) + + def assert_can_admin(self, perm_set): + self.assert_can_all('DatabaseAsync', perm_set) + self.assert_can_all('DatabaseView', perm_set) + self.assert_can_all('DruidClusterModelView', perm_set) + self.assert_can_all('AccessRequestsModelView', perm_set) + 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_sync_druid_source', 'Superset'), perm_set) + self.assertIn(('can_override_role_permissions', 'Superset'), perm_set) + self.assertIn(('can_approve', 'Superset'), perm_set) + self.assertIn(('can_update_role', 'Superset'), perm_set) + + def test_is_admin_only(self): + self.assertFalse(security.is_admin_only( + sm.find_permission_view_menu('can_show', 'TableModelView'))) + self.assertFalse(security.is_admin_only( + sm.find_permission_view_menu( + 'all_datasource_access', 'all_datasource_access'))) + + self.assertTrue(security.is_admin_only( + sm.find_permission_view_menu('can_delete', 'DatabaseView'))) + self.assertTrue(security.is_admin_only( + sm.find_permission_view_menu( + 'can_show', 'AccessRequestsModelView'))) + self.assertTrue(security.is_admin_only( + sm.find_permission_view_menu( + 'can_edit', 'UserDBModelView'))) + self.assertTrue(security.is_admin_only( + sm.find_permission_view_menu( + 'can_approve', 'Superset'))) + self.assertTrue(security.is_admin_only( + sm.find_permission_view_menu( + 'all_database_access', 'all_database_access'))) + + def test_is_alpha_only(self): + self.assertFalse(security.is_alpha_only( + sm.find_permission_view_menu('can_show', 'TableModelView'))) + + self.assertTrue(security.is_alpha_only( + sm.find_permission_view_menu('muldelete', 'TableModelView'))) + self.assertTrue(security.is_alpha_only( + sm.find_permission_view_menu( + 'all_datasource_access', 'all_datasource_access'))) + self.assertTrue(security.is_alpha_only( + sm.find_permission_view_menu('can_edit', 'SqlMetricInlineView'))) + self.assertTrue(security.is_alpha_only( + sm.find_permission_view_menu( + 'can_delete', 'DruidMetricInlineView'))) + + def test_is_gamma_pvm(self): + self.assertTrue(security.is_gamma_pvm( + sm.find_permission_view_menu('can_show', 'TableModelView'))) + + def test_gamma_permissions(self): + self.assert_can_gamma(get_perm_tuples('Gamma')) + self.assert_cannot_gamma(get_perm_tuples('Gamma')) + self.assert_cannot_alpha(get_perm_tuples('Alpha')) + + def test_alpha_permissions(self): + self.assert_can_gamma(get_perm_tuples('Alpha')) + self.assert_can_alpha(get_perm_tuples('Alpha')) + self.assert_cannot_alpha(get_perm_tuples('Alpha')) + + def test_admin_permissions(self): + self.assert_can_gamma(get_perm_tuples('Admin')) + self.assert_can_alpha(get_perm_tuples('Admin')) + self.assert_can_admin(get_perm_tuples('Admin')) + + def test_sql_lab_permissions(self): + sql_lab_set = get_perm_tuples('sql_lab') + self.assertIn(('can_sql_json', 'Superset'), sql_lab_set) + self.assertIn(('can_csv', 'Superset'), sql_lab_set) + self.assertIn(('can_search_queries', 'Superset'), sql_lab_set) + + self.assert_cannot_gamma(sql_lab_set) + self.assert_cannot_alpha(sql_lab_set) + + def test_granter_permissions(self): + granter_set = get_perm_tuples('granter') + self.assertIn(('can_override_role_permissions', 'Superset'), granter_set) + self.assertIn(('can_approve', 'Superset'), granter_set) + + self.assert_cannot_gamma(granter_set) + self.assert_cannot_alpha(granter_set) + diff --git a/tests/sqllab_tests.py b/tests/sqllab_tests.py index d88233471b..22c06d4e1f 100644 --- a/tests/sqllab_tests.py +++ b/tests/sqllab_tests.py @@ -18,11 +18,8 @@ class SqlLabTests(SupersetTestCase): def __init__(self, *args, **kwargs): super(SqlLabTests, self).__init__(*args, **kwargs) - gamma_sqllab = appbuilder.sm.find_role('gamma_sqllab') - security.merge_perm(sm, 'database_access', self.get_main_database(db.session).perm) def run_some_queries(self): - self.logout() db.session.query(models.Query).delete() db.session.commit() self.run_sql( @@ -87,6 +84,7 @@ class SqlLabTests(SupersetTestCase): # Not logged in, should error out resp = self.client.get('/superset/queries/0') + # Redirects to the login page self.assertEquals(403, resp.status_code) # Admin sees queries @@ -114,6 +112,7 @@ class SqlLabTests(SupersetTestCase): self.logout() resp = self.client.get('/superset/queries/0') + # Redirects to the login page self.assertEquals(403, resp.status_code) def test_search_query_on_db_id(self):