From 3f585d3b1efca1b2379d6c0a80246fd6e5a87640 Mon Sep 17 00:00:00 2001 From: David Gutman Date: Wed, 3 Jan 2018 14:25:46 +0100 Subject: [PATCH] Views accessible via url even if user doesn't match policy rules When a user doesn't match the policy rules of a panel then the panel tab is removed from the menu of the left, but panel views are still accessible using directly the url (ex /admin/flavors/). In most of the case, views won't work correctly because of the lack of right in the backend, but it may cause trouble when you play with policies. I think it could be more elegant to return directly a "You are not authorized to access this page" from the frontend when user try to access a view of a panel (via url) without matching the policy rules. Change-Id: I7bc93fed29568adfc14d5bcadfc8728d3b5cf633 Closes-Bug: #1741051 --- horizon/base.py | 3 +++ horizon/decorators.py | 23 +++++++++++++++++++++++ openstack_dashboard/test/settings.py | 5 +++++ 3 files changed, 31 insertions(+) diff --git a/horizon/base.py b/horizon/base.py index dfbe59a75a..cb3becd235 100644 --- a/horizon/base.py +++ b/horizon/base.py @@ -43,6 +43,7 @@ import six from horizon import conf from horizon.decorators import _current_component from horizon.decorators import require_auth +from horizon.decorators import require_component_access from horizon.decorators import require_perms from horizon import loaders from horizon.utils import settings as utils_settings @@ -320,6 +321,8 @@ class Panel(HorizonComponent): # Apply access controls to all views in the patterns permissions = getattr(self, 'permissions', []) _decorate_urlconf(urlpatterns, require_perms, permissions) + _decorate_urlconf( + urlpatterns, require_component_access, component=self) _decorate_urlconf(urlpatterns, _current_component, panel=self) # Return the three arguments to django.conf.urls.include diff --git a/horizon/decorators.py b/horizon/decorators.py index 7be22ef441..dd4fe776b0 100644 --- a/horizon/decorators.py +++ b/horizon/decorators.py @@ -90,3 +90,26 @@ def require_perms(view_func, required): return dec else: return view_func + + +def require_component_access(view_func, component): + """Perform component can_access check to access the view. + + :param component containing the view (panel or dashboard). + + Raises a :exc:`~horizon.exceptions.NotAuthorized` exception if the + user cannot access the component containing the view. + By example the check of component policy rules will be applied to its + views. + """ + from horizon.exceptions import NotAuthorized + + @functools.wraps(view_func, assigned=available_attrs(view_func)) + def dec(request, *args, **kwargs): + if not component.can_access({'request': request}): + raise NotAuthorized(_("You are not authorized to access %s") + % request.path) + + return view_func(request, *args, **kwargs) + + return dec diff --git a/openstack_dashboard/test/settings.py b/openstack_dashboard/test/settings.py index 7e6a82bd97..ad5df5240d 100644 --- a/openstack_dashboard/test/settings.py +++ b/openstack_dashboard/test/settings.py @@ -297,6 +297,11 @@ TEST_GLOBAL_MOCKS_ON_PANELS = { '.aggregates.panel.Aggregates.can_access'), 'return_value': True, }, + 'domains': { + 'method': ('openstack_dashboard.dashboards.identity' + '.domains.panel.Domains.can_access'), + 'return_value': True, + }, 'trunk-project': { 'method': ('openstack_dashboard.dashboards.project' '.trunks.panel.Trunks.can_access'),