You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by jo...@apache.org on 2018/03/27 23:46:06 UTC
[incubator-superset] branch master updated: [security] Refactor
security code into SupersetSecurityManager (#4565)
This is an automated email from the ASF dual-hosted git repository.
johnbodley pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git
The following commit(s) were added to refs/heads/master by this push:
new 8dd052d [security] Refactor security code into SupersetSecurityManager (#4565)
8dd052d is described below
commit 8dd052de4bbd8176f78318e3beb81526b1ecddd4
Author: timifasubaa <30...@users.noreply.github.com>
AuthorDate: Tue Mar 27 16:46:02 2018 -0700
[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
---
UPDATING.MD | 8 +
superset/__init__.py | 14 +-
superset/cli.py | 6 +-
superset/connectors/druid/models.py | 8 +-
superset/connectors/druid/views.py | 12 +-
superset/connectors/sqla/models.py | 6 +-
superset/connectors/sqla/views.py | 10 +-
superset/data/__init__.py | 27 +--
superset/models/core.py | 13 +-
superset/models/helpers.py | 4 +-
superset/models/sql_lab.py | 6 +-
superset/security.py | 458 ++++++++++++++++++++++--------------
superset/sql_lab.py | 5 +-
superset/utils.py | 32 ++-
superset/views/base.py | 145 +-----------
superset/views/core.py | 70 +++---
tests/access_tests.py | 161 ++++++-------
tests/base_tests.py | 66 +++---
tests/celery_tests.py | 11 +-
tests/core_tests.py | 22 +-
tests/druid_tests.py | 19 +-
tests/security_tests.py | 57 ++---
tests/sqllab_tests.py | 24 +-
23 files changed, 599 insertions(+), 585 deletions(-)
diff --git a/UPDATING.MD b/UPDATING.MD
new file mode 100644
index 0000000..7fb3e85
--- /dev/null
+++ b/UPDATING.MD
@@ -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)
\ No newline at end of file
diff --git a/superset/__init__.py b/superset/__init__.py
index d420b76..83154ca 100644
--- a/superset/__init__.py
+++ b/superset/__init__.py
@@ -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')
diff --git a/superset/cli.py b/superset/cli.py
index 95f6df7..b146877 100755
--- a/superset/cli.py
+++ b/superset/cli.py
@@ -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()
diff --git a/superset/connectors/druid/models.py b/superset/connectors/druid/models.py
index f4f137e..107e3c8 100644
--- a/superset/connectors/druid/models.py
+++ b/superset/connectors/druid/models.py
@@ -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(
diff --git a/superset/connectors/druid/views.py b/superset/connectors/druid/views.py
index f4a2089..02b8cb4 100644
--- a/superset/connectors/druid/views.py
+++ b/superset/connectors/druid/views.py
@@ -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)
diff --git a/superset/connectors/sqla/models.py b/superset/connectors/sqla/models.py
index ef8c68e..e2dca32 100644
--- a/superset/connectors/sqla/models.py
+++ b/superset/connectors/sqla/models.py
@@ -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 (
diff --git a/superset/connectors/sqla/views.py b/superset/connectors/sqla/views.py
index b667475..16a218f 100644
--- a/superset/connectors/sqla/views.py
+++ b/superset/connectors/sqla/views.py
@@ -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(_(
diff --git a/superset/data/__init__.py b/superset/data/__init__.py
index ec87994..9f505c1 100644
--- a/superset/data/__init__.py
+++ b/superset/data/__init__.py
@@ -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()
diff --git a/superset/models/core.py b/superset/models/core.py
index cd7cc44..c32ac5c 100644
--- a/superset/models/core.py
+++ b/superset/models/core.py
@@ -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
diff --git a/superset/models/helpers.py b/superset/models/helpers.py
index db395c1..718550b 100644
--- a/superset/models/helpers.py
+++ b/superset/models/helpers.py
@@ -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)
diff --git a/superset/models/sql_lab.py b/superset/models/sql_lab.py
index 81ee41a..5dfd8a6 100644
--- a/superset/models/sql_lab.py
+++ b/superset/models/sql_lab.py
@@ -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(
diff --git a/superset/security.py b/superset/security.py
index 4d5b9f4..8ea91b9 100644
--- a/superset/security.py
+++ b/superset/security.py
@@ -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)
-
-
-def is_user_defined_permission(perm):
- return perm.permission.name in OBJECT_SPEC_PERMISSIONS
-
-
-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 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 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
- )
-
-
-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, 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 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_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 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:
- 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 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())
-
- for metric in metrics:
- if metric.is_restricted:
- merge_pv('metric_access', metric.perm)
-
-
-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))
-
-
-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()
-
- # 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)
-
- if conf.get('PUBLIC_ROLE_LIKE_GAMMA', False):
- set_role('Public', is_gamma_pvm)
-
- create_missing_perms()
-
- # commit role and view menu updates
- sm.get_session.commit()
- clean_perms()
+class SupersetSecurityManager(SecurityManager):
+
+ def get_schema_perm(self, database, schema):
+ if schema:
+ return '[{}].[{}]'.format(database, schema)
+
+ 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 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):
+ from superset import db
+
+ 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
+
+ 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):
+ 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)
+
+ 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
+
+ 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 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(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
+
+ 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))
+
+ 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)
+
+ 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 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)
+
+ 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')
+
+ 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)
+
+ if conf.get('PUBLIC_ROLE_LIKE_GAMMA', False):
+ self.set_role('Public', self.is_gamma_pvm)
+
+ self.create_missing_perms()
+
+ # commit role and view menu updates
+ self.get_session.commit()
+ self.clean_perms()
+
+ 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()
+
+ 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
+ )
+
+ 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',
+ }
diff --git a/superset/sql_lab.py b/superset/sql_lab.py
index d28de7c..c13addf 100644
--- a/superset/sql_lab.py
+++ b/superset/sql_lab.py
@@ -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
diff --git a/superset/utils.py b/superset/utils.py
index 78fb12b..8e91e8d 100644
--- a/superset/utils.py
+++ b/superset/utils.py
@@ -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
diff --git a/superset/views/base.py b/superset/views/base.py
index 54a98c2..328789f 100644
--- a/superset/views/base.py
+++ b/superset/views/base.py
@@ -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()
diff --git a/superset/views/core.py b/superset/views/core.py
index a080a4b..f0956e3 100755
--- a/superset/views/core.py
+++ b/superset/views/core.py
@@ -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)
diff --git a/tests/access_tests.py b/tests/access_tests.py
index 39938c9..a669f5d 100644
--- a/tests/access_tests.py
+++ b/tests/access_tests.py
@@ -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()
diff --git a/tests/base_tests.py b/tests/base_tests.py
index dcc6798..c491637 100644
--- a/tests/base_tests.py
+++ b/tests/base_tests.py
@@ -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
diff --git a/tests/celery_tests.py b/tests/celery_tests.py
index 172176e..79b71e9 100644
--- a/tests/celery_tests.py
+++ b/tests/celery_tests.py
@@ -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)
diff --git a/tests/core_tests.py b/tests/core_tests.py
index e4df8bf..6f82af8 100644
--- a/tests/core_tests.py
+++ b/tests/core_tests.py
@@ -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))
diff --git a/tests/druid_tests.py b/tests/druid_tests.py
index e72eb25..7406dac 100644
--- a/tests/druid_tests.py
+++ b/tests/druid_tests.py
@@ -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
diff --git a/tests/security_tests.py b/tests/security_tests.py
index e117394..58ec0c7 100644
--- a/tests/security_tests.py
+++ b/tests/security_tests.py
@@ -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'))
diff --git a/tests/sqllab_tests.py b/tests/sqllab_tests.py
index 977bbe0..afab140 100644
--- a/tests/sqllab_tests.py
+++ b/tests/sqllab_tests.py
@@ -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)
--
To stop receiving notification emails like this one, please contact
johnbodley@apache.org.