mirror of
https://github.com/apache/superset.git
synced 2024-09-17 11:09:47 -04:00
Only creating perms for restricted metrics (#655)
* Only creating perms for restricted metrics * Adding post_update hooks for is_restricted
This commit is contained in:
parent
131372740e
commit
967b2ffeb0
@ -1196,19 +1196,19 @@ class DruidDatasource(Model, AuditMixinNullable, Queryable):
|
|||||||
m.metric_name: m.json_obj
|
m.metric_name: m.json_obj
|
||||||
for m in self.metrics
|
for m in self.metrics
|
||||||
if m.metric_name in all_metrics
|
if m.metric_name in all_metrics
|
||||||
}
|
}
|
||||||
|
|
||||||
rejected_metrics = [
|
rejected_metrics = [
|
||||||
m.metric_name for m in self.metrics
|
m.metric_name for m in self.metrics
|
||||||
if m.is_restricted and
|
if m.is_restricted and
|
||||||
m.metric_name in aggregations.keys() and
|
m.metric_name in aggregations.keys() and
|
||||||
not sm.has_access('metric_access', m.perm)
|
not sm.has_access('metric_access', m.perm)
|
||||||
]
|
]
|
||||||
|
|
||||||
if rejected_metrics:
|
if rejected_metrics:
|
||||||
raise MetricPermException(
|
raise MetricPermException(
|
||||||
"Access to the metrics denied: " + ', '.join(rejected_metrics)
|
"Access to the metrics denied: " + ', '.join(rejected_metrics)
|
||||||
)
|
)
|
||||||
|
|
||||||
granularity = granularity or "all"
|
granularity = granularity or "all"
|
||||||
if granularity != "all":
|
if granularity != "all":
|
||||||
|
@ -34,6 +34,15 @@ class MetricPermException(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def can_access(security_manager, permission_name, view_name):
|
||||||
|
"""Protecting from has_access failing from missing perms/view"""
|
||||||
|
try:
|
||||||
|
return security_manager.has_access(permission_name, view_name)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def flasher(msg, severity=None):
|
def flasher(msg, severity=None):
|
||||||
"""Flask's flash if available, logging call if not"""
|
"""Flask's flash if available, logging call if not"""
|
||||||
try:
|
try:
|
||||||
@ -232,18 +241,24 @@ def init(caravel):
|
|||||||
|
|
||||||
|
|
||||||
def init_metrics_perm(caravel, metrics=None):
|
def init_metrics_perm(caravel, metrics=None):
|
||||||
|
"""Create permissions for restricted metrics
|
||||||
|
|
||||||
|
:param metrics: a list of metrics to be processed, if not specified,
|
||||||
|
all metrics are processed
|
||||||
|
:type metrics: models.SqlMetric or models.DruidMetric
|
||||||
|
"""
|
||||||
db = caravel.db
|
db = caravel.db
|
||||||
models = caravel.models
|
models = caravel.models
|
||||||
sm = caravel.appbuilder.sm
|
sm = caravel.appbuilder.sm
|
||||||
|
|
||||||
if metrics is None:
|
if not metrics:
|
||||||
metrics = []
|
metrics = []
|
||||||
for model in [models.SqlMetric, models.DruidMetric]:
|
for model in [models.SqlMetric, models.DruidMetric]:
|
||||||
metrics += list(db.session.query(model).all())
|
metrics += list(db.session.query(model).all())
|
||||||
|
|
||||||
metric_perms = filter(None, [metric.perm for metric in metrics])
|
for metric in metrics:
|
||||||
for metric_perm in metric_perms:
|
if metric.is_restricted and metric.perm:
|
||||||
merge_perm(sm, 'metric_access', metric_perm)
|
merge_perm(sm, 'metric_access', metric.perm)
|
||||||
|
|
||||||
|
|
||||||
def datetime_f(dttm):
|
def datetime_f(dttm):
|
||||||
|
@ -36,6 +36,12 @@ from caravel import appbuilder, db, models, viz, utils, app, sm, ascii_art
|
|||||||
|
|
||||||
config = app.config
|
config = app.config
|
||||||
log_this = models.Log.log_this
|
log_this = models.Log.log_this
|
||||||
|
can_access = utils.can_access
|
||||||
|
|
||||||
|
|
||||||
|
class BaseCaravelView(BaseView):
|
||||||
|
def can_access(self, permission_name, view_name):
|
||||||
|
return utils.can_access(appbuilder.sm, permission_name, view_name)
|
||||||
|
|
||||||
|
|
||||||
def get_error_msg():
|
def get_error_msg():
|
||||||
@ -244,8 +250,7 @@ appbuilder.add_view_no_menu(DruidColumnInlineView)
|
|||||||
|
|
||||||
class SqlMetricInlineView(CompactCRUDMixin, CaravelModelView): # noqa
|
class SqlMetricInlineView(CompactCRUDMixin, CaravelModelView): # noqa
|
||||||
datamodel = SQLAInterface(models.SqlMetric)
|
datamodel = SQLAInterface(models.SqlMetric)
|
||||||
list_columns = ['metric_name', 'verbose_name', 'metric_type',
|
list_columns = ['metric_name', 'verbose_name', 'metric_type']
|
||||||
'is_restricted']
|
|
||||||
edit_columns = [
|
edit_columns = [
|
||||||
'metric_name', 'description', 'verbose_name', 'metric_type',
|
'metric_name', 'description', 'verbose_name', 'metric_type',
|
||||||
'expression', 'table', 'is_restricted']
|
'expression', 'table', 'is_restricted']
|
||||||
@ -269,16 +274,18 @@ class SqlMetricInlineView(CompactCRUDMixin, CaravelModelView): # noqa
|
|||||||
'table': _("Table"),
|
'table': _("Table"),
|
||||||
}
|
}
|
||||||
|
|
||||||
def post_add(self, new_item):
|
def post_add(self, metric):
|
||||||
utils.init_metrics_perm(caravel, [new_item])
|
utils.init_metrics_perm(caravel, [metric])
|
||||||
|
|
||||||
|
def post_update(self, metric):
|
||||||
|
utils.init_metrics_perm(caravel, [metric])
|
||||||
|
|
||||||
appbuilder.add_view_no_menu(SqlMetricInlineView)
|
appbuilder.add_view_no_menu(SqlMetricInlineView)
|
||||||
|
|
||||||
|
|
||||||
class DruidMetricInlineView(CompactCRUDMixin, CaravelModelView): # noqa
|
class DruidMetricInlineView(CompactCRUDMixin, CaravelModelView): # noqa
|
||||||
datamodel = SQLAInterface(models.DruidMetric)
|
datamodel = SQLAInterface(models.DruidMetric)
|
||||||
list_columns = ['metric_name', 'verbose_name', 'metric_type',
|
list_columns = ['metric_name', 'verbose_name', 'metric_type']
|
||||||
'is_restricted']
|
|
||||||
edit_columns = [
|
edit_columns = [
|
||||||
'metric_name', 'description', 'verbose_name', 'metric_type', 'json',
|
'metric_name', 'description', 'verbose_name', 'metric_type', 'json',
|
||||||
'datasource', 'is_restricted']
|
'datasource', 'is_restricted']
|
||||||
@ -307,8 +314,11 @@ class DruidMetricInlineView(CompactCRUDMixin, CaravelModelView): # noqa
|
|||||||
'datasource': _("Druid Datasource"),
|
'datasource': _("Druid Datasource"),
|
||||||
}
|
}
|
||||||
|
|
||||||
def post_add(self, new_item):
|
def post_add(self, metric):
|
||||||
utils.init_metrics_perm(caravel, [new_item])
|
utils.init_metrics_perm(caravel, [metric])
|
||||||
|
|
||||||
|
def post_update(self, metric):
|
||||||
|
utils.init_metrics_perm(caravel, [metric])
|
||||||
|
|
||||||
|
|
||||||
appbuilder.add_view_no_menu(DruidMetricInlineView)
|
appbuilder.add_view_no_menu(DruidMetricInlineView)
|
||||||
@ -685,7 +695,7 @@ def ping():
|
|||||||
return "OK"
|
return "OK"
|
||||||
|
|
||||||
|
|
||||||
class R(BaseView):
|
class R(BaseCaravelView):
|
||||||
|
|
||||||
"""used for short urls"""
|
"""used for short urls"""
|
||||||
|
|
||||||
@ -718,16 +728,7 @@ class R(BaseView):
|
|||||||
appbuilder.add_view_no_menu(R)
|
appbuilder.add_view_no_menu(R)
|
||||||
|
|
||||||
|
|
||||||
def caravel_has_access(permission_name, view_name):
|
class Caravel(BaseCaravelView):
|
||||||
"""Protecting from has_access failing from missing perms/view"""
|
|
||||||
try:
|
|
||||||
return appbuilder.sm.has_access(permission_name, view_name)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
class Caravel(BaseView):
|
|
||||||
|
|
||||||
"""The base views for Caravel!"""
|
"""The base views for Caravel!"""
|
||||||
|
|
||||||
@ -749,9 +750,9 @@ class Caravel(BaseView):
|
|||||||
datasource = datasource[0] if datasource else None
|
datasource = datasource[0] if datasource else None
|
||||||
slice_id = request.args.get("slice_id")
|
slice_id = request.args.get("slice_id")
|
||||||
slc = None
|
slc = None
|
||||||
slice_add_perm = caravel_has_access('can_add', 'SliceModelView')
|
slice_add_perm = self.can_access('can_add', 'SliceModelView')
|
||||||
slice_edit_perm = caravel_has_access('can_edit', 'SliceModelView')
|
slice_edit_perm = self.can_access('can_edit', 'SliceModelView')
|
||||||
slice_download_perm = caravel_has_access('can_download', 'SliceModelView')
|
slice_download_perm = self.can_access('can_download', 'SliceModelView')
|
||||||
|
|
||||||
if slice_id:
|
if slice_id:
|
||||||
slc = (
|
slc = (
|
||||||
@ -763,9 +764,9 @@ class Caravel(BaseView):
|
|||||||
flash(__("The datasource seems to have been deleted"), "alert")
|
flash(__("The datasource seems to have been deleted"), "alert")
|
||||||
return redirect(error_redirect)
|
return redirect(error_redirect)
|
||||||
|
|
||||||
all_datasource_access = caravel_has_access(
|
all_datasource_access = self.can_access(
|
||||||
'all_datasource_access', 'all_datasource_access')
|
'all_datasource_access', 'all_datasource_access')
|
||||||
datasource_access = caravel_has_access(
|
datasource_access = self.can_access(
|
||||||
'datasource_access', datasource.perm)
|
'datasource_access', datasource.perm)
|
||||||
if not (all_datasource_access or datasource_access):
|
if not (all_datasource_access or datasource_access):
|
||||||
flash(__("You don't seem to have access to this datasource"), "danger")
|
flash(__("You don't seem to have access to this datasource"), "danger")
|
||||||
@ -1029,15 +1030,15 @@ class Caravel(BaseView):
|
|||||||
return self.render_template(
|
return self.render_template(
|
||||||
"caravel/dashboard.html", dashboard=dash,
|
"caravel/dashboard.html", dashboard=dash,
|
||||||
templates=templates,
|
templates=templates,
|
||||||
dash_save_perm=appbuilder.sm.has_access('can_save_dash', 'Caravel'),
|
dash_save_perm=self.can_access('can_save_dash', 'Caravel'),
|
||||||
dash_edit_perm=appbuilder.sm.has_access('can_edit', 'DashboardModelView'))
|
dash_edit_perm=self.can_access('can_edit', 'DashboardModelView'))
|
||||||
|
|
||||||
@has_access
|
@has_access
|
||||||
@expose("/sql/<database_id>/")
|
@expose("/sql/<database_id>/")
|
||||||
@log_this
|
@log_this
|
||||||
def sql(self, database_id):
|
def sql(self, database_id):
|
||||||
if (
|
if (
|
||||||
not self.appbuilder.sm.has_access(
|
not self.can_access(
|
||||||
'all_datasource_access', 'all_datasource_access')):
|
'all_datasource_access', 'all_datasource_access')):
|
||||||
flash(
|
flash(
|
||||||
"This view requires the `all_datasource_access` "
|
"This view requires the `all_datasource_access` "
|
||||||
@ -1102,7 +1103,7 @@ class Caravel(BaseView):
|
|||||||
mydb = session.query(models.Database).filter_by(id=database_id).first()
|
mydb = session.query(models.Database).filter_by(id=database_id).first()
|
||||||
|
|
||||||
if (
|
if (
|
||||||
not self.appbuilder.sm.has_access(
|
not self.can_access(
|
||||||
'all_datasource_access', 'all_datasource_access')):
|
'all_datasource_access', 'all_datasource_access')):
|
||||||
raise utils.CaravelSecurityException(_(
|
raise utils.CaravelSecurityException(_(
|
||||||
"This view requires the `all_datasource_access` permission"))
|
"This view requires the `all_datasource_access` permission"))
|
||||||
|
Loading…
Reference in New Issue
Block a user