mirror of https://github.com/apache/superset.git
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.
This commit is contained in:
parent
733ab8014b
commit
92aa1a6124
|
@ -52,7 +52,6 @@ from sqlalchemy_utils import EncryptedType
|
||||||
|
|
||||||
from werkzeug.datastructures import ImmutableMultiDict
|
from werkzeug.datastructures import ImmutableMultiDict
|
||||||
|
|
||||||
import superset
|
|
||||||
from superset import app, db, db_engine_specs, get_session, utils, sm
|
from superset import app, db, db_engine_specs, get_session, utils, sm
|
||||||
from superset.source_registry import SourceRegistry
|
from superset.source_registry import SourceRegistry
|
||||||
from superset.viz import viz_types
|
from superset.viz import viz_types
|
||||||
|
@ -70,24 +69,13 @@ FillterPattern = re.compile(r'''((?:[^,"']|"[^"]*"|'[^']*')+)''')
|
||||||
|
|
||||||
|
|
||||||
def set_perm(mapper, connection, target): # noqa
|
def set_perm(mapper, connection, target): # noqa
|
||||||
target.perm = target.get_perm()
|
if target.perm != target.get_perm():
|
||||||
|
link_table = target.__table__
|
||||||
|
connection.execute(
|
||||||
def init_metrics_perm(metrics=None):
|
link_table.update()
|
||||||
"""Create permissions for restricted metrics
|
.where(link_table.c.id == target.id)
|
||||||
|
.values(perm=target.get_perm())
|
||||||
: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)
|
|
||||||
|
|
||||||
|
|
||||||
class JavascriptPostAggregator(Postaggregator):
|
class JavascriptPostAggregator(Postaggregator):
|
||||||
|
@ -860,8 +848,8 @@ class Database(Model, AuditMixinNullable):
|
||||||
return (
|
return (
|
||||||
"[{obj.database_name}].(id:{obj.id})").format(obj=self)
|
"[{obj.database_name}].(id:{obj.id})").format(obj=self)
|
||||||
|
|
||||||
sqla.event.listen(Database, 'before_insert', set_perm)
|
sqla.event.listen(Database, 'after_insert', set_perm)
|
||||||
sqla.event.listen(Database, 'before_update', set_perm)
|
sqla.event.listen(Database, 'after_update', set_perm)
|
||||||
|
|
||||||
|
|
||||||
class SqlaTable(Model, Queryable, AuditMixinNullable, ImportMixin):
|
class SqlaTable(Model, Queryable, AuditMixinNullable, ImportMixin):
|
||||||
|
@ -1340,8 +1328,8 @@ class SqlaTable(Model, Queryable, AuditMixinNullable, ImportMixin):
|
||||||
|
|
||||||
return datasource.id
|
return datasource.id
|
||||||
|
|
||||||
sqla.event.listen(SqlaTable, 'before_insert', set_perm)
|
sqla.event.listen(SqlaTable, 'after_insert', set_perm)
|
||||||
sqla.event.listen(SqlaTable, 'before_update', set_perm)
|
sqla.event.listen(SqlaTable, 'after_update', set_perm)
|
||||||
|
|
||||||
|
|
||||||
class SqlMetric(Model, AuditMixinNullable, ImportMixin):
|
class SqlMetric(Model, AuditMixinNullable, ImportMixin):
|
||||||
|
@ -2238,8 +2226,8 @@ class DruidDatasource(Model, AuditMixinNullable, Queryable):
|
||||||
filters = cond
|
filters = cond
|
||||||
return filters
|
return filters
|
||||||
|
|
||||||
sqla.event.listen(DruidDatasource, 'before_insert', set_perm)
|
sqla.event.listen(DruidDatasource, 'after_insert', set_perm)
|
||||||
sqla.event.listen(DruidDatasource, 'before_update', set_perm)
|
sqla.event.listen(DruidDatasource, 'after_update', set_perm)
|
||||||
|
|
||||||
|
|
||||||
class Log(Model):
|
class Log(Model):
|
||||||
|
@ -2466,8 +2454,6 @@ class DruidColumn(Model, AuditMixinNullable):
|
||||||
session.add(metric)
|
session.add(metric)
|
||||||
session.flush()
|
session.flush()
|
||||||
|
|
||||||
init_metrics_perm(new_metrics)
|
|
||||||
|
|
||||||
|
|
||||||
class FavStar(Model):
|
class FavStar(Model):
|
||||||
__tablename__ = 'favstar'
|
__tablename__ = 'favstar'
|
||||||
|
|
|
@ -3,11 +3,10 @@ from __future__ import division
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from itertools import product
|
|
||||||
import logging
|
import logging
|
||||||
from flask_appbuilder.security.sqla import models as ab_models
|
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 = {
|
READ_ONLY_MODELVIEWS = {
|
||||||
|
@ -17,13 +16,10 @@ READ_ONLY_MODELVIEWS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
GAMMA_READ_ONLY_MODELVIEWS = {
|
GAMMA_READ_ONLY_MODELVIEWS = {
|
||||||
'ColumnInlineView',
|
|
||||||
'SqlMetricInlineView',
|
'SqlMetricInlineView',
|
||||||
'TableColumnInlineView',
|
'TableColumnInlineView',
|
||||||
'TableModelView',
|
'TableModelView',
|
||||||
'DatasourceModelView',
|
|
||||||
'DruidColumnInlineView',
|
'DruidColumnInlineView',
|
||||||
'MetricInlineView',
|
|
||||||
'DruidDatasourceModelView',
|
'DruidDatasourceModelView',
|
||||||
'DruidMetricInlineView',
|
'DruidMetricInlineView',
|
||||||
} | READ_ONLY_MODELVIEWS
|
} | READ_ONLY_MODELVIEWS
|
||||||
|
@ -38,13 +34,11 @@ ADMIN_ONLY_VIEW_MENUES = {
|
||||||
'RoleModelView',
|
'RoleModelView',
|
||||||
'Security',
|
'Security',
|
||||||
'UserDBModelView',
|
'UserDBModelView',
|
||||||
} | READ_ONLY_MODELVIEWS
|
}
|
||||||
|
|
||||||
ADMIN_ONLY_PERMISSIONS = {
|
ADMIN_ONLY_PERMISSIONS = {
|
||||||
'all_database_access',
|
'all_database_access',
|
||||||
'datasource_access',
|
# TODO: move can_sql_json to sql_lab role
|
||||||
'schema_access',
|
|
||||||
'database_access',
|
|
||||||
'can_sql_json',
|
'can_sql_json',
|
||||||
'can_override_role_permissions',
|
'can_override_role_permissions',
|
||||||
'can_sync_druid_source',
|
'can_sync_druid_source',
|
||||||
|
@ -52,24 +46,16 @@ ADMIN_ONLY_PERMISSIONS = {
|
||||||
'can_approve',
|
'can_approve',
|
||||||
'can_update_role',
|
'can_update_role',
|
||||||
}
|
}
|
||||||
|
|
||||||
READ_ONLY_PERMISSION = {
|
READ_ONLY_PERMISSION = {
|
||||||
'can_show',
|
'can_show',
|
||||||
'can_list',
|
'can_list',
|
||||||
}
|
}
|
||||||
|
|
||||||
ALPHA_ONLY_PERMISSIONS = set([
|
ALPHA_ONLY_PERMISSIONS = set([
|
||||||
'datasource_access',
|
|
||||||
'schema_access',
|
|
||||||
'database_access',
|
|
||||||
'muldelete',
|
'muldelete',
|
||||||
'all_datasource_access',
|
'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([
|
OBJECT_SPEC_PERMISSIONS = set([
|
||||||
'database_access',
|
'database_access',
|
||||||
|
@ -81,7 +67,7 @@ OBJECT_SPEC_PERMISSIONS = set([
|
||||||
|
|
||||||
def merge_perm(sm, permission_name, view_menu_name):
|
def merge_perm(sm, permission_name, view_menu_name):
|
||||||
pv = sm.find_permission_view_menu(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)
|
sm.add_permission_view_menu(permission_name, view_menu_name)
|
||||||
|
|
||||||
|
|
||||||
|
@ -107,114 +93,125 @@ def get_or_create_main_db():
|
||||||
return dbobj
|
return dbobj
|
||||||
|
|
||||||
|
|
||||||
def sync_role_definitions():
|
def is_admin_only(pvm):
|
||||||
"""Inits the Superset application with security roles and such"""
|
# not readonly operations on read only model views allowed only for admins
|
||||||
logging.info("Syncing role definition")
|
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
|
# Global perms
|
||||||
merge_perm(sm, 'all_datasource_access', 'all_datasource_access')
|
merge_perm(sm, 'all_datasource_access', 'all_datasource_access')
|
||||||
merge_perm(sm, 'all_database_access', 'all_database_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")
|
def create_missing_datasource_perms(view_menu_set):
|
||||||
for p in perms:
|
logging.info("Creating missing datasource permissions.")
|
||||||
# admin has all_database_access and all_datasource_access
|
datasources = source_registry.SourceRegistry.get_all_datasources(
|
||||||
if is_user_defined_permission(p):
|
db.session)
|
||||||
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()]
|
|
||||||
for datasource in datasources:
|
for datasource in datasources:
|
||||||
perm = datasource.get_perm()
|
if datasource and datasource.perm not in view_menu_set:
|
||||||
merge_perm(sm, 'datasource_access', perm)
|
merge_perm(sm, 'datasource_access', datasource.get_perm())
|
||||||
if datasource.schema:
|
if datasource.schema_perm:
|
||||||
merge_perm(sm, 'schema_access', datasource.schema_perm)
|
merge_perm(sm, 'schema_access', datasource.schema_perm)
|
||||||
if perm != datasource.perm:
|
|
||||||
datasource.perm = 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:
|
for database in databases:
|
||||||
perm = database.get_perm()
|
if database and database.perm not in view_menu_set:
|
||||||
if perm != database.perm:
|
merge_perm(sm, 'database_access', database.perm)
|
||||||
database.perm = perm
|
|
||||||
merge_perm(sm, 'database_access', perm)
|
|
||||||
session.commit()
|
|
||||||
|
|
||||||
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()
|
||||||
|
|
|
@ -333,7 +333,6 @@ def get_datasource_full_name(database_name, datasource_name, schema=None):
|
||||||
def get_schema_perm(database, schema):
|
def get_schema_perm(database, schema):
|
||||||
if schema:
|
if schema:
|
||||||
return "[{}].[{}]".format(database, schema)
|
return "[{}].[{}]".format(database, schema)
|
||||||
return database.perm
|
|
||||||
|
|
||||||
|
|
||||||
def validate_json(obj):
|
def validate_json(obj):
|
||||||
|
|
|
@ -466,10 +466,12 @@ class SqlMetricInlineView(CompactCRUDMixin, SupersetModelView): # noqa
|
||||||
}
|
}
|
||||||
|
|
||||||
def post_add(self, metric):
|
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):
|
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)
|
appbuilder.add_view_no_menu(SqlMetricInlineView)
|
||||||
|
|
||||||
|
@ -702,7 +704,7 @@ class TableModelView(SupersetModelView, DeleteMixin): # noqa
|
||||||
|
|
||||||
def post_add(self, table):
|
def post_add(self, table):
|
||||||
table.fetch_metadata()
|
table.fetch_metadata()
|
||||||
security.merge_perm(sm, 'datasource_access', table.perm)
|
security.merge_perm(sm, 'datasource_access', table.get_perm())
|
||||||
if table.schema:
|
if table.schema:
|
||||||
security.merge_perm(sm, 'schema_access', table.schema_perm)
|
security.merge_perm(sm, 'schema_access', table.schema_perm)
|
||||||
|
|
||||||
|
@ -1069,7 +1071,7 @@ class DruidDatasourceModelView(SupersetModelView, DeleteMixin): # noqa
|
||||||
|
|
||||||
def post_add(self, datasource):
|
def post_add(self, datasource):
|
||||||
datasource.generate_metrics()
|
datasource.generate_metrics()
|
||||||
security.merge_perm(sm, 'datasource_access', datasource.perm)
|
security.merge_perm(sm, 'datasource_access', datasource.get_perm())
|
||||||
if datasource.schema:
|
if datasource.schema:
|
||||||
security.merge_perm(sm, 'schema_access', datasource.schema_perm)
|
security.merge_perm(sm, 'schema_access', datasource.schema_perm)
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,6 @@ class RequestAccessTests(SupersetTestCase):
|
||||||
updated_role = sm.find_role('override_me')
|
updated_role = sm.find_role('override_me')
|
||||||
perms = sorted(
|
perms = sorted(
|
||||||
updated_role.permissions, key=lambda p: p.view_menu.name)
|
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')
|
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(druid_ds_1.perm, perms[0].view_menu.name)
|
||||||
self.assertEquals('datasource_access', perms[0].permission.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(birth_names.perm, perms[2].view_menu.name)
|
||||||
self.assertEquals(
|
self.assertEquals(
|
||||||
'datasource_access', updated_role.permissions[2].permission.name)
|
'datasource_access', updated_role.permissions[2].permission.name)
|
||||||
|
self.assertEquals(3, len(perms))
|
||||||
|
|
||||||
def test_override_role_permissions_drops_absent_perms(self):
|
def test_override_role_permissions_drops_absent_perms(self):
|
||||||
override_me = sm.find_role('override_me')
|
override_me = sm.find_role('override_me')
|
||||||
|
|
|
@ -40,16 +40,16 @@ class SupersetTestCase(unittest.TestCase):
|
||||||
self.client = app.test_client()
|
self.client = app.test_client()
|
||||||
self.maxDiff = None
|
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:
|
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
|
db_perm = self.get_main_database(sm.get_session).perm
|
||||||
security.merge_perm(sm, 'database_access', db_perm)
|
security.merge_perm(sm, 'database_access', db_perm)
|
||||||
db_pvm = sm.find_permission_view_menu(
|
db_pvm = sm.find_permission_view_menu(
|
||||||
view_menu_name=db_perm, permission_name='database_access')
|
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:
|
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')
|
admin = appbuilder.sm.find_user('admin')
|
||||||
if not admin:
|
if not admin:
|
||||||
|
@ -65,12 +65,11 @@ class SupersetTestCase(unittest.TestCase):
|
||||||
appbuilder.sm.find_role('Gamma'),
|
appbuilder.sm.find_role('Gamma'),
|
||||||
password='general')
|
password='general')
|
||||||
|
|
||||||
gamma_sqllab = appbuilder.sm.find_user('gamma_sqllab')
|
gamma_sqllab_user = appbuilder.sm.find_user('gamma_sqllab')
|
||||||
if not gamma_sqllab:
|
if not gamma_sqllab_user:
|
||||||
gamma_sqllab = appbuilder.sm.add_user(
|
appbuilder.sm.add_user(
|
||||||
'gamma_sqllab', 'gamma_sqllab', 'user', 'gamma_sqllab@fab.org',
|
'gamma_sqllab', 'gamma_sqllab', 'user', 'gamma_sqllab@fab.org',
|
||||||
appbuilder.sm.find_role('gamma_sqllab'),
|
gamma_sqllab_role, password='general')
|
||||||
password='general')
|
|
||||||
|
|
||||||
alpha = appbuilder.sm.find_user('alpha')
|
alpha = appbuilder.sm.find_user('alpha')
|
||||||
if not alpha:
|
if not alpha:
|
||||||
|
@ -266,6 +265,3 @@ class SupersetTestCase(unittest.TestCase):
|
||||||
self.assertIn(('can_save_dash', 'Superset'), gamma_perm_set)
|
self.assertIn(('can_save_dash', 'Superset'), gamma_perm_set)
|
||||||
self.assertIn(('can_slice', 'Superset'), gamma_perm_set)
|
self.assertIn(('can_slice', 'Superset'), gamma_perm_set)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import unittest
|
||||||
|
|
||||||
from mock import Mock, patch
|
from mock import Mock, patch
|
||||||
|
|
||||||
from superset import db, sm, utils
|
from superset import db, sm, security
|
||||||
from superset.models import DruidCluster, DruidDatasource
|
from superset.models import DruidCluster, DruidDatasource
|
||||||
|
|
||||||
from .base_tests import SupersetTestCase
|
from .base_tests import SupersetTestCase
|
||||||
|
@ -240,21 +240,21 @@ class DruidTests(SupersetTestCase):
|
||||||
db.session)
|
db.session)
|
||||||
no_gamma_ds.cluster = cluster
|
no_gamma_ds.cluster = cluster
|
||||||
db.session.merge(no_gamma_ds)
|
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()
|
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)
|
sm.add_permission_role(sm.find_role('Gamma'), perm)
|
||||||
db.session.commit()
|
sm.get_session.commit()
|
||||||
|
|
||||||
self.login(username='gamma')
|
self.login(username='gamma')
|
||||||
url = '/druiddatasourcemodelview/list/'
|
url = '/druiddatasourcemodelview/list/'
|
||||||
resp = self.get_resp(url)
|
resp = self.get_resp(url)
|
||||||
assert 'datasource_for_gamma' in resp
|
self.assertIn('datasource_for_gamma', resp)
|
||||||
assert 'datasource_not_for_gamma' not in resp
|
self.assertNotIn('datasource_not_for_gamma', resp)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -18,11 +18,8 @@ class SqlLabTests(SupersetTestCase):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(SqlLabTests, self).__init__(*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):
|
def run_some_queries(self):
|
||||||
self.logout()
|
|
||||||
db.session.query(models.Query).delete()
|
db.session.query(models.Query).delete()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
self.run_sql(
|
self.run_sql(
|
||||||
|
@ -87,6 +84,7 @@ class SqlLabTests(SupersetTestCase):
|
||||||
|
|
||||||
# Not logged in, should error out
|
# Not logged in, should error out
|
||||||
resp = self.client.get('/superset/queries/0')
|
resp = self.client.get('/superset/queries/0')
|
||||||
|
# Redirects to the login page
|
||||||
self.assertEquals(403, resp.status_code)
|
self.assertEquals(403, resp.status_code)
|
||||||
|
|
||||||
# Admin sees queries
|
# Admin sees queries
|
||||||
|
@ -114,6 +112,7 @@ class SqlLabTests(SupersetTestCase):
|
||||||
|
|
||||||
self.logout()
|
self.logout()
|
||||||
resp = self.client.get('/superset/queries/0')
|
resp = self.client.get('/superset/queries/0')
|
||||||
|
# Redirects to the login page
|
||||||
self.assertEquals(403, resp.status_code)
|
self.assertEquals(403, resp.status_code)
|
||||||
|
|
||||||
def test_search_query_on_db_id(self):
|
def test_search_query_on_db_id(self):
|
||||||
|
|
Loading…
Reference in New Issue