Skip to content

Commit

Permalink
[metric] Adding security for restricted metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
John Bodley committed Sep 12, 2019
1 parent c566141 commit ca30ca4
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 11 deletions.
24 changes: 23 additions & 1 deletion superset/security.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@
from superset.exceptions import SupersetSecurityException

if TYPE_CHECKING:
from superset.common.query_context import QueryContext
from superset.models.core import Database, BaseDatasource
from superset.viz import BaseViz

from superset.utils.core import DatasourceName # noqa: E402

Expand Down Expand Up @@ -783,11 +785,31 @@ def assert_datasource_permission(self, datasource: "BaseDatasource") -> None:
Assert the the user has permission to access the Superset datasource.
:param datasource: The Superset datasource
:rasies SupersetSecurityException: If the user does not have permission
:raises SupersetSecurityException: If the user does not have permission
"""

if not self.datasource_access(datasource):
raise SupersetSecurityException(
self.get_datasource_access_error_msg(datasource),
self.get_datasource_access_link(datasource),
)

def assert_query_context_permission(self, query_context: "QueryContext") -> None:
"""
Assert the the user has permission to access the query context.
:param query_context: The query context
:raises SupersetSecurityException: If the user does not have permission
"""

self.assert_datasource_permission(query_context.datasource)

def assert_viz_permission(self, viz: "BaseViz") -> None:
"""
Assert the the user has permission to access the visualization.
:param viz: The visualization
:raises SupersetSecurityException: If the user does not have permission
"""

self.assert_datasource_permission(viz.datasource)
2 changes: 1 addition & 1 deletion superset/views/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def query(self):
params: query_context: json_blob
"""
query_context = QueryContext(**json.loads(request.form.get("query_context")))
security_manager.assert_datasource_permission(query_context.datasource)
security_manager.assert_query_context_permission(query_context)
payload_json = query_context.get_payload()
return json.dumps(
payload_json, default=utils.json_int_dttm_ser, ignore_nan=True
Expand Down
16 changes: 8 additions & 8 deletions superset/views/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ def check_datasource_perms(
force=False,
)

security_manager.assert_datasource_permission(viz_obj.datasource)
security_manager.assert_viz_permission(viz_obj)


def check_slice_perms(self, slice_id):
Expand All @@ -177,18 +177,18 @@ def check_slice_perms(self, slice_id):
This function takes `self` since it must have the same signature as the
the decorated method.
"""

form_data, slc = get_form_data(slice_id, use_slice_data=True)
datasource_type = slc.datasource.type
datasource_id = slc.datasource.id

viz_obj = get_viz(
datasource_type=datasource_type,
datasource_id=datasource_id,
datasource_type=slc.datasource.type,
datasource_id=slc.datasource.id,
form_data=form_data,
force=False,
)
security_manager.assert_datasource_permission(viz_obj.datasource)

security_manager.assert_viz_permission(viz_obj)


def _deserialize_results_payload(
Expand Down Expand Up @@ -2933,7 +2933,7 @@ def slice_query(self, slice_id):
get the database query string for this slice
"""
viz_obj = get_viz(slice_id)
security_manager.assert_datasource_permission(viz_obj.datasource)
security_manager.assert_viz_permission(viz_obj)
return self.get_query_string_response(viz_obj)

@api
Expand Down
53 changes: 52 additions & 1 deletion tests/security_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
# under the License.
import inspect
import unittest
from unittest.mock import Mock, patch

from superset import app, appbuilder, security_manager
from superset import app, appbuilder, security_manager, viz
from superset.exceptions import SupersetSecurityException
from .base_tests import SupersetTestCase


Expand Down Expand Up @@ -324,3 +326,52 @@ def test_views_are_secured(self):
if unsecured_views:
view_str = "\n".join([str(v) for v in unsecured_views])
raise Exception(f"Some views are not secured:\n{view_str}")


class SecurityManagerTests(SupersetTestCase):
"""
Testing the Security Manager.
"""

@patch("superset.security.SupersetSecurityManager.datasource_access")
def test_assert_datasource_permission(self, mock_datasource_access):
datasource = self.get_datasource_mock()

# Datasource with the "datasource_access" permission.
mock_datasource_access.return_value = True
security_manager.assert_datasource_permission(datasource)

# Datasource without the "datasource_access" permission.
mock_datasource_access.return_value = False

with self.assertRaises(SupersetSecurityException):
security_manager.assert_datasource_permission(datasource)

@patch("superset.security.SupersetSecurityManager.datasource_access")
def test_assert_query_context_permission(self, mock_datasource_access):
query_context = Mock()
query_context.datasource = self.get_datasource_mock()

# Query context with the "datasource_access" permission.
mock_datasource_access.return_value = True
security_manager.assert_query_context_permission(query_context)

# Query context without the "datasource_access" permission.
mock_datasource_access.return_value = False

with self.assertRaises(SupersetSecurityException):
security_manager.assert_query_context_permission(query_context)

@patch("superset.security.SupersetSecurityManager.datasource_access")
def test_assert_viz_permission(self, mock_datasource_access):
test_viz = viz.TableViz(self.get_datasource_mock(), form_data={})

# Visualization with the "datasource_access" permission.
mock_datasource_access.return_value = True
security_manager.assert_viz_permission(test_viz)

# Visualization without the "datasource_access" permission.
mock_datasource_access.return_value = False

with self.assertRaises(SupersetSecurityException):
security_manager.assert_viz_permission(test_viz)

0 comments on commit ca30ca4

Please sign in to comment.