[security] Refactor security code into SupersetSecurityManager (#4565)

* move access permissions methods to security manager

* consolidate all security methods into SupersetSecurityManager

* update security method calls

* update calls from tests

* move get_or_create_main_db to utils

* raise if supersetsecuritymanager is not extended

* rename sm to security_manager
This commit is contained in:
timifasubaa 2018-03-27 16:46:02 -07:00 committed by John Bodley
parent f510956da2
commit 8dd052de4b
23 changed files with 560 additions and 546 deletions

8
UPDATING.MD Normal file
View File

@ -0,0 +1,8 @@
# Updating Superset
This file documents any backwards-incompatible changes in Superset and
assists people when migrating to a new version.
## Superset 0.23.0
* [4565](https://github.com/apache/incubator-superset/pull/4565)

View File

@ -18,8 +18,9 @@ from flask_migrate import Migrate
from flask_wtf.csrf import CSRFProtect
from werkzeug.contrib.fixers import ProxyFix
from superset import config, utils
from superset.connectors.connector_registry import ConnectorRegistry
from superset import utils, config # noqa
from superset.security import SupersetSecurityManager
APP_DIR = os.path.dirname(__file__)
CONFIG_MODULE = os.environ.get('SUPERSET_CONFIG', 'superset.config')
@ -149,16 +150,23 @@ class MyIndexView(IndexView):
return redirect('/superset/welcome')
custom_sm = app.config.get('CUSTOM_SECURITY_MANAGER') or SupersetSecurityManager
if not issubclass(custom_sm, SupersetSecurityManager):
raise Exception(
"""Your CUSTOM_SECURITY_MANAGER must now extend SupersetSecurityManager,
not FAB's security manager.
See [4565] in UPDATING.md""")
appbuilder = AppBuilder(
app,
db.session,
base_template='superset/base.html',
indexview=MyIndexView,
security_manager_class=app.config.get('CUSTOM_SECURITY_MANAGER'),
security_manager_class=custom_sm,
update_perms=utils.get_update_perms_flag(),
)
sm = appbuilder.sm
security_manager = appbuilder.sm
results_backend = app.config.get('RESULTS_BACKEND')

View File

@ -16,7 +16,7 @@ from flask_script import Manager
from pathlib2 import Path
import yaml
from superset import app, db, dict_import_export_util, security, utils
from superset import app, data, db, dict_import_export_util, security_manager, utils
config = app.config
celery_app = utils.get_celery_app(config)
@ -28,7 +28,8 @@ manager.add_command('db', MigrateCommand)
@manager.command
def init():
"""Inits the Superset application"""
security.sync_role_definitions()
utils.get_or_create_main_db()
security_manager.sync_role_definitions()
@manager.option(
@ -108,7 +109,6 @@ def version(verbose):
help='Load additional test data')
def load_examples(load_test_data):
"""Loads a set of Slices and Dashboards and a supporting dataset """
from superset import data
print('Loading examples into {}'.format(db))
data.load_css_templates()

View File

@ -33,7 +33,7 @@ from sqlalchemy import (
)
from sqlalchemy.orm import backref, relationship
from superset import conf, db, import_util, sm, utils
from superset import conf, db, import_util, security_manager, utils
from superset.connectors.base.models import BaseColumn, BaseDatasource, BaseMetric
from superset.exceptions import MetricPermException
from superset.models.helpers import (
@ -465,7 +465,7 @@ class DruidDatasource(Model, BaseDatasource):
'DruidCluster', backref='datasources', foreign_keys=[cluster_name])
user_id = Column(Integer, ForeignKey('ab_user.id'))
owner = relationship(
sm.user_model,
security_manager.user_model,
backref=backref('datasources', cascade='all, delete-orphan'),
foreign_keys=[user_id])
UniqueConstraint('cluster_name', 'datasource_name')
@ -506,7 +506,7 @@ class DruidDatasource(Model, BaseDatasource):
@property
def schema_perm(self):
"""Returns schema permission if present, cluster one otherwise."""
return utils.get_schema_perm(self.cluster, self.schema)
return security_manager.get_schema_perm(self.cluster, self.schema)
def get_perm(self):
return (
@ -980,7 +980,7 @@ class DruidDatasource(Model, BaseDatasource):
m.metric_name for m in self.metrics
if m.is_restricted and
m.metric_name in aggregations.keys() and
not sm.has_access('metric_access', m.perm)
not security_manager.has_access('metric_access', m.perm)
]
if rejected_metrics:
raise MetricPermException(

View File

@ -14,7 +14,7 @@ from flask_appbuilder.models.sqla.interface import SQLAInterface
from flask_babel import gettext as __
from flask_babel import lazy_gettext as _
from superset import appbuilder, db, security, sm, utils
from superset import appbuilder, db, security_manager, utils
from superset.connectors.base.views import DatasourceModelView
from superset.connectors.connector_registry import ConnectorRegistry
from superset.utils import has_access
@ -140,11 +140,11 @@ class DruidMetricInlineView(CompactCRUDMixin, SupersetModelView): # noqa
def post_add(self, metric):
if metric.is_restricted:
security.merge_perm(sm, 'metric_access', metric.get_perm())
security_manager.merge_perm('metric_access', metric.get_perm())
def post_update(self, metric):
if metric.is_restricted:
security.merge_perm(sm, 'metric_access', metric.get_perm())
security_manager.merge_perm('metric_access', metric.get_perm())
appbuilder.add_view_no_menu(DruidMetricInlineView)
@ -177,7 +177,7 @@ class DruidClusterModelView(SupersetModelView, DeleteMixin, YamlExportMixin): #
}
def pre_add(self, cluster):
security.merge_perm(sm, 'database_access', cluster.perm)
security_manager.merge_perm('database_access', cluster.perm)
def pre_update(self, cluster):
self.pre_add(cluster)
@ -278,9 +278,9 @@ class DruidDatasourceModelView(DatasourceModelView, DeleteMixin, YamlExportMixin
def post_add(self, datasource):
datasource.refresh_metrics()
security.merge_perm(sm, 'datasource_access', datasource.get_perm())
security_manager.merge_perm('datasource_access', datasource.get_perm())
if datasource.schema:
security.merge_perm(sm, 'schema_access', datasource.schema_perm)
security_manager.merge_perm('schema_access', datasource.schema_perm)
def post_update(self, datasource):
self.post_add(datasource)

View File

@ -24,7 +24,7 @@ from sqlalchemy.sql import column, literal_column, table, text
from sqlalchemy.sql.expression import TextAsFrom
import sqlparse
from superset import db, import_util, sm, utils
from superset import db, import_util, security_manager, utils
from superset.connectors.base.models import BaseColumn, BaseDatasource, BaseMetric
from superset.jinja_context import get_template_processor
from superset.models.annotations import Annotation
@ -259,7 +259,7 @@ class SqlaTable(Model, BaseDatasource):
fetch_values_predicate = Column(String(1000))
user_id = Column(Integer, ForeignKey('ab_user.id'))
owner = relationship(
sm.user_model,
security_manager.user_model,
backref='tables',
foreign_keys=[user_id])
database = relationship(
@ -298,7 +298,7 @@ class SqlaTable(Model, BaseDatasource):
@property
def schema_perm(self):
"""Returns schema permission if present, database one otherwise."""
return utils.get_schema_perm(self.database, self.schema)
return security_manager.get_schema_perm(self.database, self.schema)
def get_perm(self):
return (

View File

@ -13,7 +13,7 @@ from flask_babel import gettext as __
from flask_babel import lazy_gettext as _
from past.builtins import basestring
from superset import appbuilder, db, security, sm, utils
from superset import appbuilder, db, security_manager, utils
from superset.connectors.base.views import DatasourceModelView
from superset.utils import has_access
from superset.views.base import (
@ -144,11 +144,11 @@ class SqlMetricInlineView(CompactCRUDMixin, SupersetModelView): # noqa
def post_add(self, metric):
if metric.is_restricted:
security.merge_perm(sm, 'metric_access', metric.get_perm())
security_manager.merge_perm('metric_access', metric.get_perm())
def post_update(self, metric):
if metric.is_restricted:
security.merge_perm(sm, 'metric_access', metric.get_perm())
security_manager.merge_perm('metric_access', metric.get_perm())
appbuilder.add_view_no_menu(SqlMetricInlineView)
@ -253,9 +253,9 @@ class TableModelView(DatasourceModelView, DeleteMixin, YamlExportMixin): # noqa
def post_add(self, table, flash_message=True):
table.fetch_metadata()
security.merge_perm(sm, 'datasource_access', table.get_perm())
security_manager.merge_perm('datasource_access', table.get_perm())
if table.schema:
security.merge_perm(sm, 'schema_access', table.schema_perm)
security_manager.merge_perm('schema_access', table.schema_perm)
if flash_message:
flash(_(

View File

@ -16,10 +16,9 @@ from sqlalchemy import BigInteger, Date, DateTime, Float, String, Text
import geohash
import polyline
from superset import app, db, utils
from superset import app, db, security_manager, utils
from superset.connectors.connector_registry import ConnectorRegistry
from superset.models import core as models
from superset.security import get_or_create_main_db
# Shortcuts
DB = models.Database
@ -71,7 +70,7 @@ def load_energy():
if not tbl:
tbl = TBL(table_name=tbl_name)
tbl.description = "Energy consumption"
tbl.database = get_or_create_main_db()
tbl.database = utils.get_or_create_main_db()
db.session.merge(tbl)
db.session.commit()
tbl.fetch_metadata()
@ -179,7 +178,7 @@ def load_world_bank_health_n_pop():
tbl = TBL(table_name=tbl_name)
tbl.description = utils.readfile(os.path.join(DATA_FOLDER, 'countries.md'))
tbl.main_dttm_col = 'year'
tbl.database = get_or_create_main_db()
tbl.database = utils.get_or_create_main_db()
tbl.filter_select_enabled = True
db.session.merge(tbl)
db.session.commit()
@ -583,7 +582,7 @@ def load_birth_names():
if not obj:
obj = TBL(table_name='birth_names')
obj.main_dttm_col = 'ds'
obj.database = get_or_create_main_db()
obj.database = utils.get_or_create_main_db()
obj.filter_select_enabled = True
db.session.merge(obj)
db.session.commit()
@ -870,7 +869,7 @@ def load_unicode_test_data():
if not obj:
obj = TBL(table_name='unicode_test')
obj.main_dttm_col = 'dttm'
obj.database = get_or_create_main_db()
obj.database = utils.get_or_create_main_db()
db.session.merge(obj)
db.session.commit()
obj.fetch_metadata()
@ -948,7 +947,7 @@ def load_random_time_series_data():
if not obj:
obj = TBL(table_name='random_time_series')
obj.main_dttm_col = 'ds'
obj.database = get_or_create_main_db()
obj.database = utils.get_or_create_main_db()
db.session.merge(obj)
db.session.commit()
obj.fetch_metadata()
@ -1011,7 +1010,7 @@ def load_country_map_data():
if not obj:
obj = TBL(table_name='birth_france_by_region')
obj.main_dttm_col = 'dttm'
obj.database = get_or_create_main_db()
obj.database = utils.get_or_create_main_db()
db.session.merge(obj)
db.session.commit()
obj.fetch_metadata()
@ -1086,7 +1085,7 @@ def load_long_lat_data():
if not obj:
obj = TBL(table_name='long_lat')
obj.main_dttm_col = 'datetime'
obj.database = get_or_create_main_db()
obj.database = utils.get_or_create_main_db()
db.session.merge(obj)
db.session.commit()
obj.fetch_metadata()
@ -1147,7 +1146,7 @@ def load_multiformat_time_series_data():
if not obj:
obj = TBL(table_name='multiformat_time_series')
obj.main_dttm_col = 'ds'
obj.database = get_or_create_main_db()
obj.database = utils.get_or_create_main_db()
dttm_and_expr_dict = {
'ds': [None, None],
'ds2': [None, None],
@ -1769,7 +1768,7 @@ def load_flights():
if not tbl:
tbl = TBL(table_name=tbl_name)
tbl.description = "Random set of flights in the US"
tbl.database = get_or_create_main_db()
tbl.database = utils.get_or_create_main_db()
db.session.merge(tbl)
db.session.commit()
tbl.fetch_metadata()
@ -1800,7 +1799,7 @@ def load_paris_iris_geojson():
if not tbl:
tbl = TBL(table_name=tbl_name)
tbl.description = "Map of Paris"
tbl.database = get_or_create_main_db()
tbl.database = utils.get_or_create_main_db()
db.session.merge(tbl)
db.session.commit()
tbl.fetch_metadata()
@ -1830,7 +1829,7 @@ def load_sf_population_polygons():
if not tbl:
tbl = TBL(table_name=tbl_name)
tbl.description = "Population density of San Francisco"
tbl.database = get_or_create_main_db()
tbl.database = utils.get_or_create_main_db()
db.session.merge(tbl)
db.session.commit()
tbl.fetch_metadata()
@ -1860,7 +1859,7 @@ def load_bart_lines():
if not tbl:
tbl = TBL(table_name=tbl_name)
tbl.description = "BART lines"
tbl.database = get_or_create_main_db()
tbl.database = utils.get_or_create_main_db()
db.session.merge(tbl)
db.session.commit()
tbl.fetch_metadata()

View File

@ -33,7 +33,7 @@ from sqlalchemy.sql import text
from sqlalchemy.sql.expression import TextAsFrom
from sqlalchemy_utils import EncryptedType
from superset import app, db, db_engine_specs, sm, utils
from superset import app, db, db_engine_specs, security_manager, utils
from superset.connectors.connector_registry import ConnectorRegistry
from superset.models.helpers import AuditMixinNullable, ImportMixin, set_perm
from superset.viz import viz_types
@ -104,7 +104,7 @@ class Slice(Model, AuditMixinNullable, ImportMixin):
description = Column(Text)
cache_timeout = Column(Integer)
perm = Column(String(1000))
owners = relationship(sm.user_model, secondary=slice_user)
owners = relationship(security_manager.user_model, secondary=slice_user)
export_fields = ('slice_name', 'datasource_type', 'datasource_name',
'viz_type', 'params', 'cache_timeout')
@ -322,7 +322,7 @@ class Dashboard(Model, AuditMixinNullable, ImportMixin):
slug = Column(String(255), unique=True)
slices = relationship(
'Slice', secondary=dashboard_slices, backref='dashboards')
owners = relationship(sm.user_model, secondary=dashboard_user)
owners = relationship(security_manager.user_model, secondary=dashboard_user)
export_fields = ('dashboard_title', 'position_json', 'json_metadata',
'description', 'css', 'slug')
@ -681,7 +681,7 @@ class Database(Model, AuditMixinNullable, ImportMixin):
DB_CONNECTION_MUTATOR = config.get('DB_CONNECTION_MUTATOR')
if DB_CONNECTION_MUTATOR:
url, params = DB_CONNECTION_MUTATOR(
url, params, effective_username, sm)
url, params, effective_username, security_manager)
return create_engine(url, **params)
def get_reserved_words(self):
@ -862,7 +862,8 @@ class Log(Model):
dashboard_id = Column(Integer)
slice_id = Column(Integer)
json = Column(Text)
user = relationship(sm.user_model, backref='logs', foreign_keys=[user_id])
user = relationship(
security_manager.user_model, backref='logs', foreign_keys=[user_id])
dttm = Column(DateTime, default=datetime.utcnow)
dt = Column(Date, default=date.today())
duration_ms = Column(Integer)
@ -961,7 +962,7 @@ class DatasourceAccessRequest(Model, AuditMixinNullable):
def roles_with_datasource(self):
action_list = ''
perm = self.datasource.perm # pylint: disable=no-member
pv = sm.find_permission_view_menu('datasource_access', perm)
pv = security_manager.find_permission_view_menu('datasource_access', perm)
for r in pv.role:
if r.name in self.ROLES_BLACKLIST:
continue

View File

@ -20,7 +20,7 @@ from sqlalchemy.ext.declarative import declared_attr
from sqlalchemy.orm.exc import MultipleResultsFound
import yaml
from superset import sm
from superset import security_manager
from superset.utils import QueryStatus
@ -353,4 +353,4 @@ def set_perm(mapper, connection, target): # noqa
)
# add to view menu if not already exists
merge_perm(sm, 'datasource_access', target.get_perm(), connection)
merge_perm(security_manager, 'datasource_access', target.get_perm(), connection)

View File

@ -17,7 +17,7 @@ from sqlalchemy import (
)
from sqlalchemy.orm import backref, relationship
from superset import sm
from superset import security_manager
from superset.models.helpers import AuditMixinNullable
from superset.utils import QueryStatus, user_label
@ -76,7 +76,7 @@ class Query(Model):
'Database',
foreign_keys=[database_id],
backref=backref('queries', cascade='all, delete-orphan'))
user = relationship(sm.user_model, foreign_keys=[user_id])
user = relationship(security_manager.user_model, foreign_keys=[user_id])
__table_args__ = (
sqla.Index('ti_user_id_changed_on', user_id, changed_on),
@ -138,7 +138,7 @@ class SavedQuery(Model, AuditMixinNullable):
description = Column(Text)
sql = Column(Text)
user = relationship(
sm.user_model,
security_manager.user_model,
backref=backref('saved_queries', cascade='all, delete-orphan'),
foreign_keys=[user_id])
database = relationship(

View File

@ -7,12 +7,13 @@ from __future__ import unicode_literals
import logging
from flask import g
from flask_appbuilder.security.sqla import models as ab_models
from flask_appbuilder.security.sqla.manager import SecurityManager
from sqlalchemy import or_
from superset import conf, db, sm
from superset import sql_parse
from superset.connectors.connector_registry import ConnectorRegistry
from superset.models import core as models
READ_ONLY_MODEL_VIEWS = {
'DatabaseAsync',
@ -77,177 +78,282 @@ OBJECT_SPEC_PERMISSIONS = set([
])
def merge_perm(sm, permission_name, view_menu_name):
# Implementation copied from sm.find_permission_view_menu.
# TODO: use sm.find_permission_view_menu once issue
# https://github.com/airbnb/superset/issues/1944 is resolved.
permission = sm.find_permission(permission_name)
view_menu = sm.find_view_menu(view_menu_name)
pv = None
if permission and view_menu:
pv = sm.get_session.query(sm.permissionview_model).filter_by(
permission=permission, view_menu=view_menu).first()
if not pv and permission_name and view_menu_name:
sm.add_permission_view_menu(permission_name, view_menu_name)
class SupersetSecurityManager(SecurityManager):
def get_schema_perm(self, database, schema):
if schema:
return '[{}].[{}]'.format(database, schema)
def is_user_defined_permission(perm):
return perm.permission.name in OBJECT_SPEC_PERMISSIONS
def can_access(self, permission_name, view_name, user=None):
"""Protecting from has_access failing from missing perms/view"""
if not user:
user = g.user
if user.is_anonymous():
return self.is_item_public(permission_name, view_name)
return self._has_view_access(user, permission_name, view_name)
def all_datasource_access(self, user=None):
return self.can_access(
'all_datasource_access', 'all_datasource_access', user=user)
def get_or_create_main_db():
logging.info('Creating database reference')
dbobj = (
db.session.query(models.Database)
.filter_by(database_name='main')
.first()
)
if not dbobj:
dbobj = models.Database(database_name='main')
dbobj.set_sqlalchemy_uri(conf.get('SQLALCHEMY_DATABASE_URI'))
dbobj.expose_in_sqllab = True
dbobj.allow_run_sync = True
db.session.add(dbobj)
db.session.commit()
return dbobj
def database_access(self, database, user=None):
return (
self.can_access(
'all_database_access', 'all_database_access', user=user) or
self.can_access('database_access', database.perm, user=user)
)
def schema_access(self, datasource, user=None):
return (
self.database_access(datasource.database, user=user) or
self.all_datasource_access(user=user) or
self.can_access('schema_access', datasource.schema_perm, user=user)
)
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_MODEL_VIEWS and
pvm.permission.name not in READ_ONLY_PERMISSION):
return True
return (
pvm.view_menu.name in ADMIN_ONLY_VIEW_MENUS or
pvm.permission.name in ADMIN_ONLY_PERMISSIONS
)
def datasource_access(self, datasource, user=None):
return (
self.schema_access(datasource, user=user) or
self.can_access('datasource_access', datasource.perm, user=user)
)
def datasource_access_by_name(
self, database, datasource_name, schema=None):
from superset import db
def is_alpha_only(pvm):
if (pvm.view_menu.name in GAMMA_READ_ONLY_MODEL_VIEWS and
pvm.permission.name not in READ_ONLY_PERMISSION):
return True
return (
pvm.view_menu.name in ALPHA_ONLY_VIEW_MENUS or
pvm.permission.name in ALPHA_ONLY_PERMISSIONS
)
if self.database_access(database) or self.all_datasource_access():
return True
schema_perm = self.get_schema_perm(database, schema)
if schema and self.can_access('schema_access', schema_perm):
return True
def is_admin_pvm(pvm):
return not is_user_defined_permission(pvm)
datasources = ConnectorRegistry.query_datasources_by_name(
db.session, database, datasource_name, schema=schema)
for datasource in datasources:
if self.can_access('datasource_access', datasource.perm):
return True
return False
def datasource_access_by_fullname(
self, database, full_table_name, schema):
table_name_pieces = full_table_name.split('.')
if len(table_name_pieces) == 2:
table_schema = table_name_pieces[0]
table_name = table_name_pieces[1]
else:
table_schema = schema
table_name = table_name_pieces[0]
return self.datasource_access_by_name(
database, table_name, schema=table_schema)
def is_alpha_pvm(pvm):
return not (is_user_defined_permission(pvm) or is_admin_only(pvm))
def rejected_datasources(self, sql, database, schema):
superset_query = sql_parse.SupersetQuery(sql)
return [
t for t in superset_query.tables if not
self.datasource_access_by_fullname(database, t, schema)]
def user_datasource_perms(self):
datasource_perms = set()
for r in g.user.roles:
for perm in r.permissions:
if (
perm.permission and
'datasource_access' == perm.permission.name):
datasource_perms.add(perm.view_menu.name)
return datasource_perms
def is_gamma_pvm(pvm):
return not (is_user_defined_permission(pvm) or is_admin_only(pvm) or
is_alpha_only(pvm))
def schemas_accessible_by_user(self, database, schemas):
from superset import db
from superset.connectors.sqla.models import SqlaTable
if self.database_access(database) or self.all_datasource_access():
return schemas
subset = set()
for schema in schemas:
schema_perm = self.get_schema_perm(database, schema)
if self.can_access('schema_access', schema_perm):
subset.add(schema)
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',
}
perms = self.user_datasource_perms()
if perms:
tables = (
db.session.query(SqlaTable)
.filter(
SqlaTable.perm.in_(perms),
SqlaTable.database_id == database.id,
)
.all()
)
for t in tables:
if t.schema:
subset.add(t.schema)
return sorted(list(subset))
def accessible_by_user(self, database, datasource_names, schema=None):
from superset import db
if self.database_access(database) or self.all_datasource_access():
return datasource_names
def is_granter_pvm(pvm):
return pvm.permission.name in {
'can_override_role_permissions', 'can_approve',
}
if schema:
schema_perm = self.get_schema_perm(database, schema)
if self.can_access('schema_access', schema_perm):
return datasource_names
user_perms = self.user_datasource_perms()
user_datasources = ConnectorRegistry.query_datasources_by_permissions(
db.session, database, user_perms)
if schema:
names = {
d.table_name
for d in user_datasources if d.schema == schema}
return [d for d in datasource_names if d in names]
else:
full_names = {d.full_name for d in user_datasources}
return [d for d in datasource_names if d in full_names]
def set_role(role_name, pvm_check):
logging.info('Syncing {} perms'.format(role_name))
sesh = sm.get_session()
pvms = sesh.query(ab_models.PermissionView).all()
pvms = [p for p in pvms if p.permission and p.view_menu]
role = sm.add_role(role_name)
role_pvms = [p for p in pvms if pvm_check(p)]
role.permissions = role_pvms
sesh.merge(role)
sesh.commit()
def merge_perm(self, permission_name, view_menu_name):
# Implementation copied from sm.find_permission_view_menu.
# TODO: use sm.find_permission_view_menu once issue
# https://github.com/airbnb/superset/issues/1944 is resolved.
permission = self.find_permission(permission_name)
view_menu = self.find_view_menu(view_menu_name)
pv = None
if permission and view_menu:
pv = self.get_session.query(self.permissionview_model).filter_by(
permission=permission, view_menu=view_menu).first()
if not pv and permission_name and view_menu_name:
self.add_permission_view_menu(permission_name, view_menu_name)
def is_user_defined_permission(self, perm):
return perm.permission.name in OBJECT_SPEC_PERMISSIONS
def create_custom_permissions():
# Global perms
merge_perm(sm, 'all_datasource_access', 'all_datasource_access')
merge_perm(sm, 'all_database_access', 'all_database_access')
def create_custom_permissions(self):
# Global perms
self.merge_perm('all_datasource_access', 'all_datasource_access')
self.merge_perm('all_database_access', 'all_database_access')
def create_missing_perms(self):
"""Creates missing perms for datasources, schemas and metrics"""
from superset import db
from superset.models import core as models
def create_missing_perms():
"""Creates missing perms for datasources, schemas and metrics"""
logging.info(
'Fetching a set of all perms to lookup which ones are missing')
all_pvs = set()
for pv in self.get_session.query(self.permissionview_model).all():
if pv.permission and pv.view_menu:
all_pvs.add((pv.permission.name, pv.view_menu.name))
logging.info(
'Fetching a set of all perms to lookup which ones are missing')
all_pvs = set()
for pv in sm.get_session.query(sm.permissionview_model).all():
if pv.permission and pv.view_menu:
all_pvs.add((pv.permission.name, pv.view_menu.name))
def merge_pv(view_menu, perm):
"""Create permission view menu only if it doesn't exist"""
if view_menu and perm and (view_menu, perm) not in all_pvs:
self.merge_perm(view_menu, perm)
def merge_pv(view_menu, perm):
"""Create permission view menu only if it doesn't exist"""
if view_menu and perm and (view_menu, perm) not in all_pvs:
merge_perm(sm, view_menu, perm)
logging.info('Creating missing datasource permissions.')
datasources = ConnectorRegistry.get_all_datasources(db.session)
for datasource in datasources:
merge_pv('datasource_access', datasource.get_perm())
merge_pv('schema_access', datasource.schema_perm)
logging.info('Creating missing datasource permissions.')
datasources = ConnectorRegistry.get_all_datasources(db.session)
for datasource in datasources:
merge_pv('datasource_access', datasource.get_perm())
merge_pv('schema_access', datasource.schema_perm)
logging.info('Creating missing database permissions.')
databases = db.session.query(models.Database).all()
for database in databases:
merge_pv('database_access', database.perm)
logging.info('Creating missing database permissions.')
databases = db.session.query(models.Database).all()
for database in databases:
merge_pv('database_access', database.perm)
logging.info('Creating missing metrics permissions')
metrics = []
for datasource_class in ConnectorRegistry.sources.values():
metrics += list(db.session.query(datasource_class.metric_class).all())
logging.info('Creating missing metrics permissions')
metrics = []
for datasource_class in ConnectorRegistry.sources.values():
metrics += list(db.session.query(datasource_class.metric_class).all())
for metric in metrics:
if metric.is_restricted:
merge_pv('metric_access', metric.perm)
for metric in metrics:
if metric.is_restricted:
merge_pv('metric_access', metric.perm)
def clean_perms(self):
"""FAB leaves faulty permissions that need to be cleaned up"""
logging.info('Cleaning faulty perms')
sesh = self.get_session
pvms = (
sesh.query(ab_models.PermissionView)
.filter(or_(
ab_models.PermissionView.permission == None, # NOQA
ab_models.PermissionView.view_menu == None, # NOQA
))
)
deleted_count = pvms.delete()
sesh.commit()
if deleted_count:
logging.info('Deleted {} faulty permissions'.format(deleted_count))
def sync_role_definitions(self):
"""Inits the Superset application with security roles and such"""
from superset import conf
logging.info('Syncing role definition')
def clean_perms():
"""FAB leaves faulty permissions that need to be cleaned up"""
logging.info('Cleaning faulty perms')
sesh = sm.get_session()
pvms = (
sesh.query(ab_models.PermissionView)
.filter(or_(
ab_models.PermissionView.permission == None, # NOQA
ab_models.PermissionView.view_menu == None, # NOQA
))
)
deleted_count = pvms.delete()
sesh.commit()
if deleted_count:
logging.info('Deleted {} faulty permissions'.format(deleted_count))
self.create_custom_permissions()
# Creating default roles
self.set_role('Admin', self.is_admin_pvm)
self.set_role('Alpha', self.is_alpha_pvm)
self.set_role('Gamma', self.is_gamma_pvm)
self.set_role('granter', self.is_granter_pvm)
self.set_role('sql_lab', self.is_sql_lab_pvm)
def sync_role_definitions():
"""Inits the Superset application with security roles and such"""
logging.info('Syncing role definition')
if conf.get('PUBLIC_ROLE_LIKE_GAMMA', False):
self.set_role('Public', self.is_gamma_pvm)
get_or_create_main_db()
create_custom_permissions()
self.create_missing_perms()
# Creating default roles
set_role('Admin', is_admin_pvm)
set_role('Alpha', is_alpha_pvm)
set_role('Gamma', is_gamma_pvm)
set_role('granter', is_granter_pvm)
set_role('sql_lab', is_sql_lab_pvm)
# commit role and view menu updates
self.get_session.commit()
self.clean_perms()
if conf.get('PUBLIC_ROLE_LIKE_GAMMA', False):
set_role('Public', is_gamma_pvm)
def set_role(self, role_name, pvm_check):
logging.info('Syncing {} perms'.format(role_name))
sesh = self.get_session
pvms = sesh.query(ab_models.PermissionView).all()
pvms = [p for p in pvms if p.permission and p.view_menu]
role = self.add_role(role_name)
role_pvms = [p for p in pvms if pvm_check(p)]
role.permissions = role_pvms
sesh.merge(role)
sesh.commit()
create_missing_perms()
def is_admin_only(self, pvm):
# not readonly operations on read only model views allowed only for admins
if (pvm.view_menu.name in READ_ONLY_MODEL_VIEWS and
pvm.permission.name not in READ_ONLY_PERMISSION):
return True
return (
pvm.view_menu.name in ADMIN_ONLY_VIEW_MENUS or
pvm.permission.name in ADMIN_ONLY_PERMISSIONS
)
# commit role and view menu updates
sm.get_session.commit()
clean_perms()
def is_alpha_only(self, pvm):
if (pvm.view_menu.name in GAMMA_READ_ONLY_MODEL_VIEWS and
pvm.permission.name not in READ_ONLY_PERMISSION):
return True
return (
pvm.view_menu.name in ALPHA_ONLY_VIEW_MENUS or
pvm.permission.name in ALPHA_ONLY_PERMISSIONS
)
def is_admin_pvm(self, pvm):
return not self.is_user_defined_permission(pvm)
def is_alpha_pvm(self, pvm):
return not (self.is_user_defined_permission(pvm) or self.is_admin_only(pvm))
def is_gamma_pvm(self, pvm):
return not (self.is_user_defined_permission(pvm) or self.is_admin_only(pvm) or
self.is_alpha_only(pvm))
def is_sql_lab_pvm(self, 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(self, pvm):
return pvm.permission.name in {
'can_override_role_permissions', 'can_approve',
}

View File

@ -17,7 +17,7 @@ import sqlalchemy
from sqlalchemy.orm import sessionmaker
from sqlalchemy.pool import NullPool
from superset import app, dataframe, db, results_backend, sm, utils
from superset import app, dataframe, db, results_backend, security_manager, utils
from superset.db_engine_specs import LimitMethod
from superset.jinja_context import get_template_processor
from superset.models.sql_lab import Query
@ -196,7 +196,8 @@ def execute_sql(
# Hook to allow environment-specific mutation (usually comments) to the SQL
SQL_QUERY_MUTATOR = config.get('SQL_QUERY_MUTATOR')
if SQL_QUERY_MUTATOR:
executed_sql = SQL_QUERY_MUTATOR(executed_sql, user_name, sm, database)
executed_sql = SQL_QUERY_MUTATOR(
executed_sql, user_name, security_manager, database)
query.executed_sql = executed_sql
query.status = QueryStatus.RUNNING

View File

@ -55,13 +55,6 @@ EPOCH = datetime(1970, 1, 1)
DTTM_ALIAS = '__timestamp'
def can_access(sm, permission_name, view_name, user):
"""Protecting from has_access failing from missing perms/view"""
if user.is_anonymous():
return sm.is_item_public(permission_name, view_name)
return sm._has_view_access(user, permission_name, view_name)
def flasher(msg, severity=None):
"""Flask's flash if available, logging call if not"""
try:
@ -477,11 +470,6 @@ def get_datasource_full_name(database_name, datasource_name, schema=None):
return '[{}].[{}].[{}]'.format(database_name, schema, datasource_name)
def get_schema_perm(database, schema):
if schema:
return '[{}].[{}]'.format(database, schema)
def validate_json(obj):
if obj:
try:
@ -834,3 +822,23 @@ def user_label(user):
return user.first_name + ' ' + user.last_name
else:
return user.username
def get_or_create_main_db():
from superset import conf, db
from superset.models import core as models
logging.info('Creating database reference')
dbobj = (
db.session.query(models.Database)
.filter_by(database_name='main')
.first()
)
if not dbobj:
dbobj = models.Database(database_name='main')
dbobj.set_sqlalchemy_uri(conf.get('SQLALCHEMY_DATABASE_URI'))
dbobj.expose_in_sqllab = True
dbobj.allow_run_sync = True
db.session.add(dbobj)
db.session.commit()
return dbobj

View File

@ -20,9 +20,7 @@ from flask_babel import gettext as __
from flask_babel import lazy_gettext as _
import yaml
from superset import appbuilder, conf, db, sm, sql_parse, utils
from superset.connectors.connector_registry import ConnectorRegistry
from superset.connectors.sqla.models import SqlaTable
from superset import conf, security_manager, utils
from superset.translations.utils import get_language_pack
FRONTEND_CONF_KEYS = (
@ -83,131 +81,11 @@ def get_datasource_exist_error_mgs(full_name):
def get_user_roles():
if g.user.is_anonymous():
public_role = conf.get('AUTH_ROLE_PUBLIC')
return [appbuilder.sm.find_role(public_role)] if public_role else []
return [security_manager.find_role(public_role)] if public_role else []
return g.user.roles
class BaseSupersetView(BaseView):
def can_access(self, permission_name, view_name, user=None):
if not user:
user = g.user
return utils.can_access(
appbuilder.sm, permission_name, view_name, user)
def all_datasource_access(self, user=None):
return self.can_access(
'all_datasource_access', 'all_datasource_access', user=user)
def database_access(self, database, user=None):
return (
self.can_access(
'all_database_access', 'all_database_access', user=user) or
self.can_access('database_access', database.perm, user=user)
)
def schema_access(self, datasource, user=None):
return (
self.database_access(datasource.database, user=user) or
self.all_datasource_access(user=user) or
self.can_access('schema_access', datasource.schema_perm, user=user)
)
def datasource_access(self, datasource, user=None):
return (
self.schema_access(datasource, user=user) or
self.can_access('datasource_access', datasource.perm, user=user)
)
def datasource_access_by_name(
self, database, datasource_name, schema=None):
if self.database_access(database) or self.all_datasource_access():
return True
schema_perm = utils.get_schema_perm(database, schema)
if schema and self.can_access('schema_access', schema_perm):
return True
datasources = ConnectorRegistry.query_datasources_by_name(
db.session, database, datasource_name, schema=schema)
for datasource in datasources:
if self.can_access('datasource_access', datasource.perm):
return True
return False
def datasource_access_by_fullname(
self, database, full_table_name, schema):
table_name_pieces = full_table_name.split('.')
if len(table_name_pieces) == 2:
table_schema = table_name_pieces[0]
table_name = table_name_pieces[1]
else:
table_schema = schema
table_name = table_name_pieces[0]
return self.datasource_access_by_name(
database, table_name, schema=table_schema)
def rejected_datasources(self, sql, database, schema):
superset_query = sql_parse.SupersetQuery(sql)
return [
t for t in superset_query.tables if not
self.datasource_access_by_fullname(database, t, schema)]
def user_datasource_perms(self):
datasource_perms = set()
for r in g.user.roles:
for perm in r.permissions:
if (
perm.permission and
'datasource_access' == perm.permission.name):
datasource_perms.add(perm.view_menu.name)
return datasource_perms
def schemas_accessible_by_user(self, database, schemas):
if self.database_access(database) or self.all_datasource_access():
return schemas
subset = set()
for schema in schemas:
schema_perm = utils.get_schema_perm(database, schema)
if self.can_access('schema_access', schema_perm):
subset.add(schema)
perms = self.user_datasource_perms()
if perms:
tables = (
db.session.query(SqlaTable)
.filter(
SqlaTable.perm.in_(perms),
SqlaTable.database_id == database.id,
)
.all()
)
for t in tables:
if t.schema:
subset.add(t.schema)
return sorted(list(subset))
def accessible_by_user(self, database, datasource_names, schema=None):
if self.database_access(database) or self.all_datasource_access():
return datasource_names
if schema:
schema_perm = utils.get_schema_perm(database, schema)
if self.can_access('schema_access', schema_perm):
return datasource_names
user_perms = self.user_datasource_perms()
user_datasources = ConnectorRegistry.query_datasources_by_permissions(
db.session, database, user_perms)
if schema:
names = {
d.table_name
for d in user_datasources if d.schema == schema}
return [d for d in datasource_names if d in names]
else:
full_names = {d.full_name for d in user_datasources}
return [d for d in datasource_names if d in full_names]
def common_bootsrap_payload(self):
"""Common data always sent to the client"""
messages = get_flashed_messages(with_categories=True)
@ -274,31 +152,32 @@ class DeleteMixin(object):
except Exception as e:
flash(str(e), 'danger')
else:
view_menu = sm.find_view_menu(item.get_perm())
pvs = sm.get_session.query(sm.permissionview_model).filter_by(
view_menu = security_manager.find_view_menu(item.get_perm())
pvs = security_manager.get_session.query(
security_manager.permissionview_model).filter_by(
view_menu=view_menu).all()
schema_view_menu = None
if hasattr(item, 'schema_perm'):
schema_view_menu = sm.find_view_menu(item.schema_perm)
schema_view_menu = security_manager.find_view_menu(item.schema_perm)
pvs.extend(sm.get_session.query(
sm.permissionview_model).filter_by(
pvs.extend(security_manager.get_session.query(
security_manager.permissionview_model).filter_by(
view_menu=schema_view_menu).all())
if self.datamodel.delete(item):
self.post_delete(item)
for pv in pvs:
sm.get_session.delete(pv)
security_manager.get_session.delete(pv)
if view_menu:
sm.get_session.delete(view_menu)
security_manager.get_session.delete(view_menu)
if schema_view_menu:
sm.get_session.delete(schema_view_menu)
security_manager.get_session.delete(schema_view_menu)
sm.get_session.commit()
security_manager.get_session.commit()
flash(*self.datamodel.message)
self.update_redirect()

View File

@ -33,7 +33,7 @@ from werkzeug.routing import BaseConverter
from werkzeug.utils import secure_filename
from superset import (
app, appbuilder, cache, db, results_backend, security, sm, sql_lab, utils,
app, appbuilder, cache, db, results_backend, security_manager, sql_lab, utils,
viz,
)
from superset.connectors.connector_registry import ConnectorRegistry
@ -57,7 +57,6 @@ from .utils import bootstrap_user_data
config = app.config
stats_logger = config.get('STATS_LOGGER')
log_this = models.Log.log_this
can_access = utils.can_access
DAR = models.DatasourceAccessRequest
@ -284,10 +283,10 @@ class DatabaseView(SupersetModelView, DeleteMixin, YamlExportMixin): # noqa
def pre_add(self, db):
db.set_sqlalchemy_uri(db.sqlalchemy_uri)
security.merge_perm(sm, 'database_access', db.perm)
security_manager.merge_perm('database_access', db.perm)
for schema in db.all_schema_names():
security.merge_perm(
sm, 'schema_access', utils.get_schema_perm(db, schema))
security_manager.merge_perm(
'schema_access', security_manager.get_schema_perm(db, schema))
def pre_update(self, db):
self.pre_add(db)
@ -809,13 +808,13 @@ class Superset(BaseSupersetView):
existing_datasources = ConnectorRegistry.get_all_datasources(db.session)
datasources = [
d for d in existing_datasources if d.full_name in db_ds_names]
role = sm.find_role(role_name)
role = security_manager.find_role(role_name)
# remove all permissions
role.permissions = []
# grant permissions to the list of datasources
granted_perms = []
for datasource in datasources:
view_menu_perm = sm.find_permission_view_menu(
view_menu_perm = security_manager.find_permission_view_menu(
view_menu_name=datasource.perm,
permission_name='datasource_access')
# prevent creating empty permissions
@ -854,7 +853,7 @@ class Superset(BaseSupersetView):
has_access = all(
(
datasource and self.datasource_access(datasource)
datasource and security_manager.datasource_access(datasource)
for datasource in datasources
))
if has_access:
@ -884,9 +883,9 @@ class Superset(BaseSupersetView):
for r in session.query(DAR).all():
datasource = ConnectorRegistry.get_datasource(
r.datasource_type, r.datasource_id, session)
user = sm.get_user_by_id(r.created_by_fk)
user = security_manager.get_user_by_id(r.created_by_fk)
if not datasource or \
self.datasource_access(datasource, user):
security_manager.datasource_access(datasource, user):
# datasource does not exist anymore
session.delete(r)
session.commit()
@ -904,7 +903,7 @@ class Superset(BaseSupersetView):
flash(DATASOURCE_MISSING_ERR, 'alert')
return json_error_response(DATASOURCE_MISSING_ERR)
requested_by = sm.find_user(username=created_by_username)
requested_by = security_manager.find_user(username=created_by_username)
if not requested_by:
flash(USER_MISSING_ERR, 'alert')
return json_error_response(USER_MISSING_ERR)
@ -923,10 +922,10 @@ class Superset(BaseSupersetView):
return json_error_response(ACCESS_REQUEST_MISSING_ERR)
# check if you can approve
if self.all_datasource_access() or g.user.id == datasource.owner_id:
if security_manager.all_datasource_access() or g.user.id == datasource.owner_id:
# can by done by admin only
if role_to_grant:
role = sm.find_role(role_to_grant)
role = security_manager.find_role(role_to_grant)
requested_by.roles.append(role)
msg = __(
'%(user)s was granted the role %(role)s that gives access '
@ -940,10 +939,10 @@ class Superset(BaseSupersetView):
flash(msg, 'info')
if role_to_extend:
perm_view = sm.find_permission_view_menu(
perm_view = security_manager.find_permission_view_menu(
'email/datasource_access', datasource.perm)
role = sm.find_role(role_to_extend)
sm.add_permission_role(role, perm_view)
role = security_manager.find_role(role_to_extend)
security_manager.add_permission_role(role, perm_view)
msg = __('Role %(r)s was extended to provide the access to '
'the datasource %(ds)s', r=role_to_extend,
ds=datasource.full_name)
@ -1085,7 +1084,7 @@ class Superset(BaseSupersetView):
utils.error_msg_from_exception(e),
stacktrace=traceback.format_exc())
if not self.datasource_access(viz_obj.datasource):
if not security_manager.datasource_access(viz_obj.datasource, g.user):
return json_error_response(DATASOURCE_ACCESS_ERR, status=404)
if csv:
@ -1245,7 +1244,7 @@ class Superset(BaseSupersetView):
flash(DATASOURCE_MISSING_ERR, 'danger')
return redirect(error_redirect)
if not self.datasource_access(datasource):
if not security_manager.datasource_access(datasource):
flash(
__(get_datasource_access_error_msg(datasource.name)),
'danger')
@ -1260,9 +1259,10 @@ class Superset(BaseSupersetView):
return redirect(datasource.default_endpoint)
# slc perms
slice_add_perm = self.can_access('can_add', 'SliceModelView')
slice_add_perm = security_manager.can_access('can_add', 'SliceModelView')
slice_overwrite_perm = is_owner(slc, g.user)
slice_download_perm = self.can_access('can_download', 'SliceModelView')
slice_download_perm = security_manager.can_access(
'can_download', 'SliceModelView')
form_data['datasource'] = str(datasource_id) + '__' + datasource_type
@ -1342,7 +1342,7 @@ class Superset(BaseSupersetView):
datasource_type, datasource_id, db.session)
if not datasource:
return json_error_response(DATASOURCE_MISSING_ERR)
if not self.datasource_access(datasource):
if not security_manager.datasource_access(datasource):
return json_error_response(DATASOURCE_ACCESS_ERR)
payload = json.dumps(
@ -1402,7 +1402,7 @@ class Superset(BaseSupersetView):
'info')
elif request.args.get('add_to_dash') == 'new':
# check create dashboard permissions
dash_add_perm = self.can_access('can_add', 'DashboardModelView')
dash_add_perm = security_manager.can_access('can_add', 'DashboardModelView')
if not dash_add_perm:
return json_error_response(
_('You don\'t have the rights to ') + _('create a ') + _('dashboard'),
@ -1501,7 +1501,7 @@ class Superset(BaseSupersetView):
.one()
)
schemas = database.all_schema_names()
schemas = self.schemas_accessible_by_user(database, schemas)
schemas = security_manager.schemas_accessible_by_user(database, schemas)
return Response(
json.dumps({'schemas': schemas}),
mimetype='application/json')
@ -1515,9 +1515,9 @@ class Superset(BaseSupersetView):
schema = utils.js_string_to_python(schema)
substr = utils.js_string_to_python(substr)
database = db.session.query(models.Database).filter_by(id=db_id).one()
table_names = self.accessible_by_user(
table_names = security_manager.accessible_by_user(
database, database.all_table_names(schema), schema)
view_names = self.accessible_by_user(
view_names = security_manager.accessible_by_user(
database, database.all_view_names(schema), schema)
if substr:
@ -1761,7 +1761,7 @@ class Superset(BaseSupersetView):
@expose('/fave_dashboards_by_username/<username>/', methods=['GET'])
def fave_dashboards_by_username(self, username):
"""This lets us use a user's username to pull favourite dashboards"""
user = sm.find_user(username=username)
user = security_manager.find_user(username=username)
return self.fave_dashboards(user.get_id())
@api
@ -2041,7 +2041,7 @@ class Superset(BaseSupersetView):
if config.get('ENABLE_ACCESS_REQUEST'):
for datasource in datasources:
if datasource and not self.datasource_access(datasource):
if datasource and not security_manager.datasource_access(datasource):
flash(
__(get_datasource_access_error_msg(datasource.name)),
'danger')
@ -2057,7 +2057,7 @@ class Superset(BaseSupersetView):
dash_edit_perm = check_ownership(dash, raise_if_false=False)
dash_save_perm = \
dash_edit_perm and self.can_access('can_save_dash', 'Superset')
dash_edit_perm and security_manager.can_access('can_save_dash', 'Superset')
standalone_mode = request.args.get('standalone') == 'true'
@ -2108,7 +2108,7 @@ class Superset(BaseSupersetView):
metrics_spec: list of metrics (dictionary). Metric consists of
2 attributes: type and name. Type can be count,
etc. `count` type is stored internally as longSum
other fields will be ignored.
other fields will be ignored.
Example: {
'name': 'test_click',
@ -2121,7 +2121,7 @@ class Superset(BaseSupersetView):
user_name = payload['user']
cluster_name = payload['cluster']
user = sm.find_user(username=user_name)
user = security_manager.find_user(username=user_name)
DruidDatasource = ConnectorRegistry.sources['druid']
DruidCluster = DruidDatasource.cluster_class
if not user:
@ -2324,7 +2324,7 @@ class Superset(BaseSupersetView):
)
query = db.session.query(Query).filter_by(results_key=key).one()
rejected_tables = self.rejected_datasources(
rejected_tables = security_manager.rejected_datasources(
query.sql, query.database, query.schema)
if rejected_tables:
return json_error_response(get_datasource_access_error_msg(
@ -2373,7 +2373,7 @@ class Superset(BaseSupersetView):
json_error_response(
'Database with id {} is missing.'.format(database_id))
rejected_tables = self.rejected_datasources(sql, mydb, schema)
rejected_tables = security_manager.rejected_datasources(sql, mydb, schema)
if rejected_tables:
return json_error_response(get_datasource_access_error_msg(
'{}'.format(rejected_tables)))
@ -2470,7 +2470,7 @@ class Superset(BaseSupersetView):
.one()
)
rejected_tables = self.rejected_datasources(
rejected_tables = security_manager.rejected_datasources(
query.sql, query.database, query.schema)
if rejected_tables:
flash(get_datasource_access_error_msg('{}'.format(rejected_tables)))
@ -2514,7 +2514,7 @@ class Superset(BaseSupersetView):
return json_error_response(DATASOURCE_MISSING_ERR)
# Check permission for datasource
if not self.datasource_access(datasource):
if not security_manager.datasource_access(datasource):
return json_error_response(DATASOURCE_ACCESS_ERR)
return json_success(json.dumps(datasource.data))
@ -2662,7 +2662,7 @@ class Superset(BaseSupersetView):
get the database query string for this slice
"""
viz_obj = self.get_viz(slice_id)
if not self.datasource_access(viz_obj.datasource):
if not security_manager.datasource_access(viz_obj.datasource):
return json_error_response(DATASOURCE_ACCESS_ERR, status=401)
return self.get_query_string_response(viz_obj)

View File

@ -10,7 +10,7 @@ import unittest
import mock
from superset import app, db, security, sm
from superset import app, db, security_manager
from superset.connectors.connector_registry import ConnectorRegistry
from superset.connectors.druid.models import DruidDatasource
from superset.connectors.sqla.models import SqlaTable
@ -70,13 +70,14 @@ def create_access_request(session, ds_type, ds_name, role_name, user_name):
else:
ds = session.query(ds_class).filter(
ds_class.datasource_name == ds_name).first()
ds_perm_view = sm.find_permission_view_menu(
ds_perm_view = security_manager.find_permission_view_menu(
'datasource_access', ds.perm)
sm.add_permission_role(sm.find_role(role_name), ds_perm_view)
security_manager.add_permission_role(
security_manager.find_role(role_name), ds_perm_view)
access_request = models.DatasourceAccessRequest(
datasource_id=ds.id,
datasource_type=ds_type,
created_by_fk=sm.find_user(username=user_name).id,
created_by_fk=security_manager.find_user(username=user_name).id,
)
session.add(access_request)
session.commit()
@ -89,21 +90,21 @@ class RequestAccessTests(SupersetTestCase):
@classmethod
def setUpClass(cls):
sm.add_role('override_me')
sm.add_role(TEST_ROLE_1)
sm.add_role(TEST_ROLE_2)
sm.add_role(DB_ACCESS_ROLE)
sm.add_role(SCHEMA_ACCESS_ROLE)
security_manager.add_role('override_me')
security_manager.add_role(TEST_ROLE_1)
security_manager.add_role(TEST_ROLE_2)
security_manager.add_role(DB_ACCESS_ROLE)
security_manager.add_role(SCHEMA_ACCESS_ROLE)
db.session.commit()
@classmethod
def tearDownClass(cls):
override_me = sm.find_role('override_me')
override_me = security_manager.find_role('override_me')
db.session.delete(override_me)
db.session.delete(sm.find_role(TEST_ROLE_1))
db.session.delete(sm.find_role(TEST_ROLE_2))
db.session.delete(sm.find_role(DB_ACCESS_ROLE))
db.session.delete(sm.find_role(SCHEMA_ACCESS_ROLE))
db.session.delete(security_manager.find_role(TEST_ROLE_1))
db.session.delete(security_manager.find_role(TEST_ROLE_2))
db.session.delete(security_manager.find_role(DB_ACCESS_ROLE))
db.session.delete(security_manager.find_role(SCHEMA_ACCESS_ROLE))
db.session.commit()
def setUp(self):
@ -111,7 +112,7 @@ class RequestAccessTests(SupersetTestCase):
def tearDown(self):
self.logout()
override_me = sm.find_role('override_me')
override_me = security_manager.find_role('override_me')
override_me.permissions = []
db.session.commit()
db.session.close()
@ -133,7 +134,7 @@ class RequestAccessTests(SupersetTestCase):
content_type='application/json')
self.assertEquals(201, response.status_code)
updated_override_me = sm.find_role('override_me')
updated_override_me = security_manager.find_role('override_me')
self.assertEquals(1, len(updated_override_me.permissions))
birth_names = self.get_table_by_name('birth_names')
self.assertEquals(
@ -150,7 +151,7 @@ class RequestAccessTests(SupersetTestCase):
content_type='application/json')
self.assertEquals(201, response.status_code)
updated_role = sm.find_role('override_me')
updated_role = security_manager.find_role('override_me')
perms = sorted(
updated_role.permissions, key=lambda p: p.view_menu.name)
druid_ds_1 = self.get_druid_ds_by_name('druid_ds_1')
@ -169,9 +170,9 @@ class RequestAccessTests(SupersetTestCase):
self.assertEquals(3, len(perms))
def test_override_role_permissions_drops_absent_perms(self):
override_me = sm.find_role('override_me')
override_me = security_manager.find_role('override_me')
override_me.permissions.append(
sm.find_permission_view_menu(
security_manager.find_permission_view_menu(
view_menu_name=self.get_table_by_name('long_lat').perm,
permission_name='datasource_access'),
)
@ -182,7 +183,7 @@ class RequestAccessTests(SupersetTestCase):
data=json.dumps(ROLE_TABLES_PERM_DATA),
content_type='application/json')
self.assertEquals(201, response.status_code)
updated_override_me = sm.find_role('override_me')
updated_override_me = security_manager.find_role('override_me')
self.assertEquals(1, len(updated_override_me.permissions))
birth_names = self.get_table_by_name('birth_names')
self.assertEquals(
@ -218,8 +219,8 @@ class RequestAccessTests(SupersetTestCase):
access_requests = self.get_access_requests('gamma', 'table', ds_1_id)
self.assertFalse(access_requests)
gamma_user = sm.find_user(username='gamma')
gamma_user.roles.remove(sm.find_role('test_role1'))
gamma_user = security_manager.find_user(username='gamma')
gamma_user.roles.remove(security_manager.find_role('test_role1'))
def test_clean_requests_after_alpha_grant(self):
session = db.session
@ -234,8 +235,8 @@ class RequestAccessTests(SupersetTestCase):
session, 'table', 'birth_names', TEST_ROLE_2, 'gamma2')
ds_1_id = access_request1.datasource_id
# gamma becomes alpha
alpha_role = sm.find_role('Alpha')
gamma_user = sm.find_user(username='gamma')
alpha_role = security_manager.find_role('Alpha')
gamma_user = security_manager.find_user(username='gamma')
gamma_user.roles.append(alpha_role)
session.commit()
access_requests = self.get_access_requests('gamma', 'table', ds_1_id)
@ -245,8 +246,8 @@ class RequestAccessTests(SupersetTestCase):
access_requests = self.get_access_requests('gamma', 'table', ds_1_id)
self.assertFalse(access_requests)
gamma_user = sm.find_user(username='gamma')
gamma_user.roles.remove(sm.find_role('Alpha'))
gamma_user = security_manager.find_user(username='gamma')
gamma_user.roles.remove(security_manager.find_role('Alpha'))
session.commit()
def test_clean_requests_after_db_grant(self):
@ -256,7 +257,7 @@ class RequestAccessTests(SupersetTestCase):
# Gamma gets database access, gamma2 access request granted
# Check if request by gamma has been deleted
gamma_user = sm.find_user(username='gamma')
gamma_user = security_manager.find_user(username='gamma')
access_request1 = create_access_request(
session, 'table', 'long_lat', TEST_ROLE_1, 'gamma')
create_access_request(
@ -265,13 +266,12 @@ class RequestAccessTests(SupersetTestCase):
# gamma gets granted database access
database = session.query(models.Database).first()
security.merge_perm(
sm, 'database_access', database.perm)
ds_perm_view = sm.find_permission_view_menu(
security_manager.merge_perm('database_access', database.perm)
ds_perm_view = security_manager.find_permission_view_menu(
'database_access', database.perm)
sm.add_permission_role(
sm.find_role(DB_ACCESS_ROLE), ds_perm_view)
gamma_user.roles.append(sm.find_role(DB_ACCESS_ROLE))
security_manager.add_permission_role(
security_manager.find_role(DB_ACCESS_ROLE), ds_perm_view)
gamma_user.roles.append(security_manager.find_role(DB_ACCESS_ROLE))
session.commit()
access_requests = self.get_access_requests('gamma', 'table', ds_1_id)
self.assertTrue(access_requests)
@ -281,8 +281,8 @@ class RequestAccessTests(SupersetTestCase):
access_requests = self.get_access_requests('gamma', 'table', ds_1_id)
self.assertFalse(access_requests)
gamma_user = sm.find_user(username='gamma')
gamma_user.roles.remove(sm.find_role(DB_ACCESS_ROLE))
gamma_user = security_manager.find_user(username='gamma')
gamma_user.roles.remove(security_manager.find_role(DB_ACCESS_ROLE))
session.commit()
def test_clean_requests_after_schema_grant(self):
@ -292,7 +292,7 @@ class RequestAccessTests(SupersetTestCase):
# Gamma gets schema access, gamma2 access request granted
# Check if request by gamma has been deleted
gamma_user = sm.find_user(username='gamma')
gamma_user = security_manager.find_user(username='gamma')
access_request1 = create_access_request(
session, 'table', 'wb_health_population', TEST_ROLE_1, 'gamma')
create_access_request(
@ -302,21 +302,20 @@ class RequestAccessTests(SupersetTestCase):
table_name='wb_health_population').first()
ds.schema = 'temp_schema'
security.merge_perm(
sm, 'schema_access', ds.schema_perm)
schema_perm_view = sm.find_permission_view_menu(
security_manager.merge_perm('schema_access', ds.schema_perm)
schema_perm_view = security_manager.find_permission_view_menu(
'schema_access', ds.schema_perm)
sm.add_permission_role(
sm.find_role(SCHEMA_ACCESS_ROLE), schema_perm_view)
gamma_user.roles.append(sm.find_role(SCHEMA_ACCESS_ROLE))
security_manager.add_permission_role(
security_manager.find_role(SCHEMA_ACCESS_ROLE), schema_perm_view)
gamma_user.roles.append(security_manager.find_role(SCHEMA_ACCESS_ROLE))
session.commit()
# gamma2 request gets fulfilled
self.client.get(EXTEND_ROLE_REQUEST.format(
'table', ds_1_id, 'gamma2', TEST_ROLE_2))
access_requests = self.get_access_requests('gamma', 'table', ds_1_id)
self.assertFalse(access_requests)
gamma_user = sm.find_user(username='gamma')
gamma_user.roles.remove(sm.find_role(SCHEMA_ACCESS_ROLE))
gamma_user = security_manager.find_user(username='gamma')
gamma_user.roles.remove(security_manager.find_role(SCHEMA_ACCESS_ROLE))
ds = session.query(SqlaTable).filter_by(
table_name='wb_health_population').first()
@ -329,7 +328,7 @@ class RequestAccessTests(SupersetTestCase):
if app.config.get('ENABLE_ACCESS_REQUEST'):
session = db.session
TEST_ROLE_NAME = 'table_role'
sm.add_role(TEST_ROLE_NAME)
security_manager.add_role(TEST_ROLE_NAME)
# Case 1. Grant new role to the user.
@ -341,8 +340,8 @@ class RequestAccessTests(SupersetTestCase):
# Test email content.
self.assertTrue(mock_send_mime.called)
call_args = mock_send_mime.call_args[0]
self.assertEqual([sm.find_user(username='gamma').email,
sm.find_user(username='admin').email],
self.assertEqual([security_manager.find_user(username='gamma').email,
security_manager.find_user(username='admin').email],
call_args[1])
self.assertEqual(
'[Superset] Access to the datasource {} was granted'.format(
@ -354,7 +353,7 @@ class RequestAccessTests(SupersetTestCase):
# request was removed
self.assertFalse(access_requests)
# user was granted table_role
user_roles = [r.name for r in sm.find_user('gamma').roles]
user_roles = [r.name for r in security_manager.find_user('gamma').roles]
self.assertIn(TEST_ROLE_NAME, user_roles)
# Case 2. Extend the role to have access to the table
@ -371,8 +370,8 @@ class RequestAccessTests(SupersetTestCase):
# Test email content.
self.assertTrue(mock_send_mime.called)
call_args = mock_send_mime.call_args[0]
self.assertEqual([sm.find_user(username='gamma').email,
sm.find_user(username='admin').email],
self.assertEqual([security_manager.find_user(username='gamma').email,
security_manager.find_user(username='admin').email],
call_args[1])
self.assertEqual(
'[Superset] Access to the datasource {} was granted'.format(
@ -383,21 +382,21 @@ class RequestAccessTests(SupersetTestCase):
# request was removed
self.assertFalse(access_requests)
# table_role was extended to grant access to the long_lat table/
perm_view = sm.find_permission_view_menu(
perm_view = security_manager.find_permission_view_menu(
'datasource_access', long_lat_perm)
TEST_ROLE = sm.find_role(TEST_ROLE_NAME)
TEST_ROLE = security_manager.find_role(TEST_ROLE_NAME)
self.assertIn(perm_view, TEST_ROLE.permissions)
# Case 3. Grant new role to the user to access the druid datasource.
sm.add_role('druid_role')
security_manager.add_role('druid_role')
access_request3 = create_access_request(
session, 'druid', 'druid_ds_1', 'druid_role', 'gamma')
self.get_resp(GRANT_ROLE_REQUEST.format(
'druid', access_request3.datasource_id, 'gamma', 'druid_role'))
# user was granted table_role
user_roles = [r.name for r in sm.find_user('gamma').roles]
user_roles = [r.name for r in security_manager.find_user('gamma').roles]
self.assertIn('druid_role', user_roles)
# Case 4. Extend the role to have access to the druid datasource
@ -409,17 +408,17 @@ class RequestAccessTests(SupersetTestCase):
self.client.get(EXTEND_ROLE_REQUEST.format(
'druid', access_request4.datasource_id, 'gamma', 'druid_role'))
# druid_role was extended to grant access to the druid_access_ds_2
druid_role = sm.find_role('druid_role')
perm_view = sm.find_permission_view_menu(
druid_role = security_manager.find_role('druid_role')
perm_view = security_manager.find_permission_view_menu(
'datasource_access', druid_ds_2_perm)
self.assertIn(perm_view, druid_role.permissions)
# cleanup
gamma_user = sm.find_user(username='gamma')
gamma_user.roles.remove(sm.find_role('druid_role'))
gamma_user.roles.remove(sm.find_role(TEST_ROLE_NAME))
session.delete(sm.find_role('druid_role'))
session.delete(sm.find_role(TEST_ROLE_NAME))
gamma_user = security_manager.find_user(username='gamma')
gamma_user.roles.remove(security_manager.find_role('druid_role'))
gamma_user.roles.remove(security_manager.find_role(TEST_ROLE_NAME))
session.delete(security_manager.find_role('druid_role'))
session.delete(security_manager.find_role(TEST_ROLE_NAME))
session.commit()
def test_request_access(self):
@ -427,9 +426,9 @@ class RequestAccessTests(SupersetTestCase):
session = db.session
self.logout()
self.login(username='gamma')
gamma_user = sm.find_user(username='gamma')
sm.add_role('dummy_role')
gamma_user.roles.append(sm.find_role('dummy_role'))
gamma_user = security_manager.find_user(username='gamma')
security_manager.add_role('dummy_role')
gamma_user.roles.append(security_manager.find_role('dummy_role'))
session.commit()
ACCESS_REQUEST = (
@ -461,14 +460,16 @@ class RequestAccessTests(SupersetTestCase):
table_3_id = table3.id
table3_perm = table3.perm
sm.add_role('energy_usage_role')
alpha_role = sm.find_role('Alpha')
sm.add_permission_role(
security_manager.add_role('energy_usage_role')
alpha_role = security_manager.find_role('Alpha')
security_manager.add_permission_role(
alpha_role,
sm.find_permission_view_menu('datasource_access', table3_perm))
sm.add_permission_role(
sm.find_role('energy_usage_role'),
sm.find_permission_view_menu('datasource_access', table3_perm))
security_manager.find_permission_view_menu(
'datasource_access', table3_perm))
security_manager.add_permission_role(
security_manager.find_role('energy_usage_role'),
security_manager.find_permission_view_menu(
'datasource_access', table3_perm))
session.commit()
self.get_resp(
@ -500,14 +501,16 @@ class RequestAccessTests(SupersetTestCase):
druid_ds_5_id = druid_ds_5.id
druid_ds_5_perm = druid_ds_5.perm
druid_ds_2_role = sm.add_role('druid_ds_2_role')
admin_role = sm.find_role('Admin')
sm.add_permission_role(
druid_ds_2_role = security_manager.add_role('druid_ds_2_role')
admin_role = security_manager.find_role('Admin')
security_manager.add_permission_role(
admin_role,
sm.find_permission_view_menu('datasource_access', druid_ds_5_perm))
sm.add_permission_role(
security_manager.find_permission_view_menu(
'datasource_access', druid_ds_5_perm))
security_manager.add_permission_role(
druid_ds_2_role,
sm.find_permission_view_menu('datasource_access', druid_ds_5_perm))
security_manager.find_permission_view_menu(
'datasource_access', druid_ds_5_perm))
session.commit()
self.get_resp(ACCESS_REQUEST.format('druid', druid_ds_5_id, 'go'))
@ -520,8 +523,8 @@ class RequestAccessTests(SupersetTestCase):
'<ul><li>{}</li></ul>'.format(approve_link_5))
# cleanup
gamma_user = sm.find_user(username='gamma')
gamma_user.roles.remove(sm.find_role('dummy_role'))
gamma_user = security_manager.find_user(username='gamma')
gamma_user.roles.remove(security_manager.find_role('dummy_role'))
session.commit()

View File

@ -12,11 +12,10 @@ import unittest
from flask_appbuilder.security.sqla import models as ab_models
from superset import app, appbuilder, cli, db, security, sm
from superset import app, cli, db, security_manager, utils
from superset.connectors.druid.models import DruidCluster, DruidDatasource
from superset.connectors.sqla.models import SqlaTable
from superset.models import core as models
from superset.security import sync_role_definitions
os.environ['SUPERSET_CONFIG'] = 'tests.superset_test_config'
@ -36,59 +35,60 @@ class SupersetTestCase(unittest.TestCase):
logging.info('Loading examples')
cli.load_examples(load_test_data=True)
logging.info('Done loading examples')
sync_role_definitions()
security_manager.sync_role_definitions()
os.environ['examples_loaded'] = '1'
else:
sync_role_definitions()
security_manager.sync_role_definitions()
super(SupersetTestCase, self).__init__(*args, **kwargs)
self.client = app.test_client()
self.maxDiff = None
gamma_sqllab_role = sm.add_role('gamma_sqllab')
for perm in sm.find_role('Gamma').permissions:
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(
gamma_sqllab_role = security_manager.add_role('gamma_sqllab')
for perm in security_manager.find_role('Gamma').permissions:
security_manager.add_permission_role(gamma_sqllab_role, perm)
utils.get_or_create_main_db()
db_perm = self.get_main_database(security_manager.get_session).perm
security_manager.merge_perm('database_access', db_perm)
db_pvm = security_manager.find_permission_view_menu(
view_menu_name=db_perm, permission_name='database_access')
gamma_sqllab_role.permissions.append(db_pvm)
for perm in sm.find_role('sql_lab').permissions:
sm.add_permission_role(gamma_sqllab_role, perm)
for perm in security_manager.find_role('sql_lab').permissions:
security_manager.add_permission_role(gamma_sqllab_role, perm)
admin = appbuilder.sm.find_user('admin')
admin = security_manager.find_user('admin')
if not admin:
appbuilder.sm.add_user(
security_manager.add_user(
'admin', 'admin', ' user', 'admin@fab.org',
appbuilder.sm.find_role('Admin'),
security_manager.find_role('Admin'),
password='general')
gamma = appbuilder.sm.find_user('gamma')
gamma = security_manager.find_user('gamma')
if not gamma:
appbuilder.sm.add_user(
security_manager.add_user(
'gamma', 'gamma', 'user', 'gamma@fab.org',
appbuilder.sm.find_role('Gamma'),
security_manager.find_role('Gamma'),
password='general')
gamma2 = appbuilder.sm.find_user('gamma2')
gamma2 = security_manager.find_user('gamma2')
if not gamma2:
appbuilder.sm.add_user(
security_manager.add_user(
'gamma2', 'gamma2', 'user', 'gamma2@fab.org',
appbuilder.sm.find_role('Gamma'),
security_manager.find_role('Gamma'),
password='general')
gamma_sqllab_user = appbuilder.sm.find_user('gamma_sqllab')
gamma_sqllab_user = security_manager.find_user('gamma_sqllab')
if not gamma_sqllab_user:
appbuilder.sm.add_user(
security_manager.add_user(
'gamma_sqllab', 'gamma_sqllab', 'user', 'gamma_sqllab@fab.org',
gamma_sqllab_role, password='general')
alpha = appbuilder.sm.find_user('alpha')
alpha = security_manager.find_user('alpha')
if not alpha:
appbuilder.sm.add_user(
security_manager.add_user(
'alpha', 'alpha', 'user', 'alpha@fab.org',
appbuilder.sm.find_role('Alpha'),
security_manager.find_role('Alpha'),
password='general')
sm.get_session.commit()
security_manager.get_session.commit()
# create druid cluster and druid datasources
session = db.session
cluster = (
@ -177,7 +177,7 @@ class SupersetTestCase(unittest.TestCase):
return (
db.session.query(DAR)
.filter(
DAR.created_by == sm.find_user(username=username),
DAR.created_by == security_manager.find_user(username=username),
DAR.datasource_type == ds_type,
DAR.datasource_id == ds_id,
)
@ -188,20 +188,20 @@ class SupersetTestCase(unittest.TestCase):
self.client.get('/logout/', follow_redirects=True)
def grant_public_access_to_table(self, table):
public_role = appbuilder.sm.find_role('Public')
public_role = security_manager.find_role('Public')
perms = db.session.query(ab_models.PermissionView).all()
for perm in perms:
if (perm.permission.name == 'datasource_access' and
perm.view_menu and table.perm in perm.view_menu.name):
appbuilder.sm.add_permission_role(public_role, perm)
security_manager.add_permission_role(public_role, perm)
def revoke_public_access_to_table(self, table):
public_role = appbuilder.sm.find_role('Public')
public_role = security_manager.find_role('Public')
perms = db.session.query(ab_models.PermissionView).all()
for perm in perms:
if (perm.permission.name == 'datasource_access' and
perm.view_menu and table.perm in perm.view_menu.name):
appbuilder.sm.del_permission_role(public_role, perm)
security_manager.del_permission_role(public_role, perm)
def run_sql(self, sql, client_id, user_name=None, raise_on_error=False):
if user_name:
@ -241,7 +241,7 @@ class SupersetTestCase(unittest.TestCase):
assert_can_write(view_menu)
gamma_perm_set = set()
for perm in sm.find_role('Gamma').permissions:
for perm in security_manager.find_role('Gamma').permissions:
gamma_perm_set.add((perm.permission.name, perm.view_menu.name))
# check read only perms

View File

@ -14,10 +14,9 @@ import unittest
import pandas as pd
from past.builtins import basestring
from superset import app, appbuilder, cli, dataframe, db
from superset import app, cli, dataframe, db, security_manager
from superset.models.helpers import QueryStatus
from superset.models.sql_lab import Query
from superset.security import sync_role_definitions
from superset.sql_parse import SupersetQuery
from .base_tests import SupersetTestCase
@ -98,17 +97,17 @@ class CeleryTestCase(SupersetTestCase):
except OSError as e:
app.logger.warn(str(e))
sync_role_definitions()
security_manager.sync_role_definitions()
worker_command = BASE_DIR + '/bin/superset worker'
subprocess.Popen(
worker_command, shell=True, stdout=subprocess.PIPE)
admin = appbuilder.sm.find_user('admin')
admin = security_manager.find_user('admin')
if not admin:
appbuilder.sm.add_user(
security_manager.add_user(
'admin', 'admin', ' user', 'admin@fab.org',
appbuilder.sm.find_role('Admin'),
security_manager.find_role('Admin'),
password='general')
cli.load_examples(load_test_data=True)

View File

@ -22,7 +22,7 @@ import psycopg2
from six import text_type
import sqlalchemy as sqla
from superset import appbuilder, dataframe, db, jinja_context, sm, sql_lab, utils
from superset import dataframe, db, jinja_context, security_manager, sql_lab, utils
from superset.connectors.sqla.models import SqlaTable
from superset.models import core as models
from superset.models.sql_lab import Query
@ -136,7 +136,7 @@ class CoreTests(SupersetTestCase):
def test_admin_only_permissions(self):
def assert_admin_permission_in(role_name, assert_func):
role = sm.find_role(role_name)
role = security_manager.find_role(role_name)
permissions = [p.permission.name for p in role.permissions]
assert_func('can_sync_druid_source', permissions)
assert_func('can_approve', permissions)
@ -147,7 +147,7 @@ class CoreTests(SupersetTestCase):
def test_admin_only_menu_views(self):
def assert_admin_view_menus_in(role_name, assert_func):
role = sm.find_role(role_name)
role = security_manager.find_role(role_name)
view_menus = [p.view_menu.name for p in role.permissions]
assert_func('ResetPasswordView', view_menus)
assert_func('RoleModelView', view_menus)
@ -267,7 +267,7 @@ class CoreTests(SupersetTestCase):
def test_get_user_slices(self):
self.login(username='admin')
userid = appbuilder.sm.find_user('admin').id
userid = security_manager.find_user('admin').id
url = '/sliceaddview/api/read?_flt_0_created_by={}'.format(userid)
resp = self.client.get(url)
self.assertEqual(resp.status_code, 200)
@ -275,11 +275,11 @@ class CoreTests(SupersetTestCase):
def test_slices_V2(self):
# Add explore-v2-beta role to admin user
# Test all slice urls as user with with explore-v2-beta role
sm.add_role('explore-v2-beta')
security_manager.add_role('explore-v2-beta')
appbuilder.sm.add_user(
security_manager.add_user(
'explore_beta', 'explore_beta', ' user', 'explore_beta@airbnb.com',
appbuilder.sm.find_role('explore-v2-beta'),
security_manager.find_role('explore-v2-beta'),
password='general')
self.login(username='explore_beta', password='general')
@ -651,8 +651,8 @@ class CoreTests(SupersetTestCase):
dash = db.session.query(models.Dashboard).filter_by(
slug='births').first()
dash.owners = [appbuilder.sm.find_user('admin')]
dash.created_by = appbuilder.sm.find_user('admin')
dash.owners = [security_manager.find_user('admin')]
dash.created_by = security_manager.find_user('admin')
db.session.merge(dash)
db.session.commit()
@ -674,7 +674,7 @@ class CoreTests(SupersetTestCase):
self.assertRaises(
Exception, self.test_save_dash, 'alpha')
alpha = appbuilder.sm.find_user('alpha')
alpha = security_manager.find_user('alpha')
dash = (
db.session
@ -775,7 +775,7 @@ class CoreTests(SupersetTestCase):
resp = self.get_json_resp(url)
self.assertEqual(resp['count'], 1)
userid = appbuilder.sm.find_user('admin').id
userid = security_manager.find_user('admin').id
resp = self.get_resp('/superset/profile/admin/')
self.assertIn('"app"', resp)
data = self.get_json_resp('/superset/recent_activity/{}/'.format(userid))

View File

@ -11,7 +11,7 @@ import unittest
from mock import Mock, patch
from superset import db, security, sm
from superset import db, security_manager
from superset.connectors.druid.models import (
DruidCluster, DruidColumn, DruidDatasource, DruidMetric,
)
@ -278,13 +278,13 @@ class DruidTests(SupersetTestCase):
db.session.merge(no_gamma_ds)
db.session.commit()
security.merge_perm(sm, 'datasource_access', gamma_ds.perm)
security.merge_perm(sm, 'datasource_access', no_gamma_ds.perm)
security_manager.merge_perm('datasource_access', gamma_ds.perm)
security_manager.merge_perm('datasource_access', no_gamma_ds.perm)
perm = sm.find_permission_view_menu(
perm = security_manager.find_permission_view_menu(
'datasource_access', gamma_ds.get_perm())
sm.add_permission_role(sm.find_role('Gamma'), perm)
sm.get_session.commit()
security_manager.add_permission_role(security_manager.find_role('Gamma'), perm)
security_manager.get_session.commit()
self.login(username='gamma')
url = '/druiddatasourcemodelview/list/'
@ -331,10 +331,11 @@ class DruidTests(SupersetTestCase):
db.session.commit()
view_menu_name = cluster.datasources[0].get_perm()
view_menu = sm.find_view_menu(view_menu_name)
permission = sm.find_permission('datasource_access')
view_menu = security_manager.find_view_menu(view_menu_name)
permission = security_manager.find_permission('datasource_access')
pv = sm.get_session.query(sm.permissionview_model).filter_by(
pv = security_manager.get_session.query(
security_manager.permissionview_model).filter_by(
permission=permission, view_menu=view_menu).first()
assert pv is not None

View File

@ -4,13 +4,13 @@ from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from superset import app, security, sm
from superset import app, security_manager
from .base_tests import SupersetTestCase
def get_perm_tuples(role_name):
perm_set = set()
for perm in sm.find_role(role_name).permissions:
for perm in security_manager.find_role(role_name).permissions:
perm_set.add((perm.permission.name, perm.view_menu.name))
return perm_set
@ -103,46 +103,47 @@ class RolePermissionTests(SupersetTestCase):
self.assertIn(('can_approve', '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(
self.assertFalse(security_manager.is_admin_only(
security_manager.find_permission_view_menu('can_show', 'TableModelView')))
self.assertFalse(security_manager.is_admin_only(
security_manager.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_manager.is_admin_only(
security_manager.find_permission_view_menu('can_delete', 'DatabaseView')))
if app.config.get('ENABLE_ACCESS_REQUEST'):
self.assertTrue(security.is_admin_only(
sm.find_permission_view_menu(
self.assertTrue(security_manager.is_admin_only(
security_manager.find_permission_view_menu(
'can_show', 'AccessRequestsModelView')))
self.assertTrue(security.is_admin_only(
sm.find_permission_view_menu(
self.assertTrue(security_manager.is_admin_only(
security_manager.find_permission_view_menu(
'can_edit', 'UserDBModelView')))
self.assertTrue(security.is_admin_only(
sm.find_permission_view_menu(
self.assertTrue(security_manager.is_admin_only(
security_manager.find_permission_view_menu(
'can_approve', 'Superset')))
self.assertTrue(security.is_admin_only(
sm.find_permission_view_menu(
self.assertTrue(security_manager.is_admin_only(
security_manager.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.assertFalse(security_manager.is_alpha_only(
security_manager.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(
self.assertTrue(security_manager.is_alpha_only(
security_manager.find_permission_view_menu('muldelete', 'TableModelView')))
self.assertTrue(security_manager.is_alpha_only(
security_manager.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(
self.assertTrue(security_manager.is_alpha_only(
security_manager.find_permission_view_menu(
'can_edit', 'SqlMetricInlineView')))
self.assertTrue(security_manager.is_alpha_only(
security_manager.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')))
self.assertTrue(security_manager.is_gamma_pvm(
security_manager.find_permission_view_menu('can_show', 'TableModelView')))
def test_gamma_permissions(self):
self.assert_can_gamma(get_perm_tuples('Gamma'))

View File

@ -11,7 +11,7 @@ import unittest
from flask_appbuilder.security.sqla import models as ab_models
from superset import appbuilder, db, sm, utils
from superset import db, security_manager, utils
from superset.models.sql_lab import Query
from superset.sql_lab import convert_results_to_df
from .base_tests import SupersetTestCase
@ -56,7 +56,7 @@ class SqlLabTests(SupersetTestCase):
def test_sql_json_has_access(self):
main_db = self.get_main_database(db.session)
sm.add_permission_view_menu('database_access', main_db.perm)
security_manager.add_permission_view_menu('database_access', main_db.perm)
db.session.commit()
main_db_permission_view = (
db.session.query(ab_models.PermissionView)
@ -66,17 +66,17 @@ class SqlLabTests(SupersetTestCase):
.filter(ab_models.Permission.name == 'database_access')
.first()
)
astronaut = sm.add_role('Astronaut')
sm.add_permission_role(astronaut, main_db_permission_view)
astronaut = security_manager.add_role('Astronaut')
security_manager.add_permission_role(astronaut, main_db_permission_view)
# Astronaut role is Gamma + sqllab + main db permissions
for perm in sm.find_role('Gamma').permissions:
sm.add_permission_role(astronaut, perm)
for perm in sm.find_role('sql_lab').permissions:
sm.add_permission_role(astronaut, perm)
for perm in security_manager.find_role('Gamma').permissions:
security_manager.add_permission_role(astronaut, perm)
for perm in security_manager.find_role('sql_lab').permissions:
security_manager.add_permission_role(astronaut, perm)
gagarin = appbuilder.sm.find_user('gagarin')
gagarin = security_manager.find_user('gagarin')
if not gagarin:
appbuilder.sm.add_user(
security_manager.add_user(
'gagarin', 'Iurii', 'Gagarin', 'gagarin@cosmos.ussr',
astronaut,
password='general')
@ -139,14 +139,14 @@ class SqlLabTests(SupersetTestCase):
self.login('admin')
# Test search queries on user Id
user_id = appbuilder.sm.find_user('admin').id
user_id = security_manager.find_user('admin').id
data = self.get_json_resp(
'/superset/search_queries?user_id={}'.format(user_id))
self.assertEquals(2, len(data))
user_ids = {k['userId'] for k in data}
self.assertEquals(set([user_id]), user_ids)
user_id = appbuilder.sm.find_user('gamma_sqllab').id
user_id = security_manager.find_user('gamma_sqllab').id
resp = self.get_resp(
'/superset/search_queries?user_id={}'.format(user_id))
data = json.loads(resp)