Add a session cache of can_access call results
This patch adds a decorator and function to all horizon components so that the results of calls to can_access are cached in the session. This should prevent large numbers of calls to APIs when can_access functions need to get information from services. The cache is stored in session['allowed'] using self.__class__ as the key, this ensures each key is human readable and can be easily mocked out in future tests. Change-Id: Ic65e4cb6499ecae4b09dd525416656a6f41853f5 Closes-Bug: 1367716
This commit is contained in:
parent
c4e3c0c776
commit
16db58faba
@ -56,6 +56,23 @@ def _decorate_urlconf(urlpatterns, decorator, *args, **kwargs):
|
||||
_decorate_urlconf(pattern.url_patterns, decorator, *args, **kwargs)
|
||||
|
||||
|
||||
def access_cached(func):
|
||||
def inner(self, context):
|
||||
session = context['request'].session
|
||||
try:
|
||||
if session['allowed']['valid_for'] != session.get('token'):
|
||||
raise KeyError()
|
||||
except KeyError:
|
||||
session['allowed'] = {"valid_for": session.get('token')}
|
||||
|
||||
key = "%s.%s" % (self.__class__.__module__, self.__class__.__name__)
|
||||
if key not in session['allowed']:
|
||||
session['allowed'][key] = func(self, context)
|
||||
session.modified = True
|
||||
return session['allowed'][key]
|
||||
return inner
|
||||
|
||||
|
||||
class NotRegistered(Exception):
|
||||
pass
|
||||
|
||||
@ -90,8 +107,17 @@ class HorizonComponent(object):
|
||||
urlpatterns = patterns('')
|
||||
return urlpatterns
|
||||
|
||||
@access_cached
|
||||
def can_access(self, context):
|
||||
"""Checks to see that the user has role based access to this component.
|
||||
"""Return whether the user has role based access to this component.
|
||||
|
||||
This method is not intended to be overridden.
|
||||
The result of the method is stored in per-session cache.
|
||||
"""
|
||||
return self.allowed(context)
|
||||
|
||||
def allowed(self, context):
|
||||
"""Checks if the user is allowed to access this component.
|
||||
|
||||
This method should be overridden to return the result of
|
||||
any policy checks required for the user to access this component
|
||||
@ -568,7 +594,7 @@ class Dashboard(Registry, HorizonComponent):
|
||||
del loaders.panel_template_dirs[key]
|
||||
return success
|
||||
|
||||
def can_access(self, context):
|
||||
def allowed(self, context):
|
||||
"""Checks for role based access for this dashboard.
|
||||
|
||||
Checks for access to any panels in the dashboard and of the the
|
||||
|
@ -57,7 +57,7 @@ class RbacNoAccessPanel(horizon.Panel):
|
||||
name = "RBAC Panel No"
|
||||
slug = "rbac_panel_no"
|
||||
|
||||
def _can_access(self, request):
|
||||
def allowed(self, context):
|
||||
return False
|
||||
|
||||
|
||||
@ -508,7 +508,7 @@ class RbacHorizonTests(test.TestCase):
|
||||
dash.register(panel)
|
||||
|
||||
def test_rbac_panels(self):
|
||||
context = {'request': None}
|
||||
context = {'request': self.request}
|
||||
cats = horizon.get_dashboard("cats")
|
||||
self.assertEqual(cats._registered_with, base.Horizon)
|
||||
self.assertQuerysetEqual(cats.get_panels(),
|
||||
|
@ -23,7 +23,7 @@ class Firewall(horizon.Panel):
|
||||
slug = "firewalls"
|
||||
permissions = ('openstack.services.network',)
|
||||
|
||||
def can_access(self, context):
|
||||
def allowed(self, context):
|
||||
request = context['request']
|
||||
if not request.user.has_perms(self.permissions):
|
||||
return False
|
||||
@ -31,7 +31,7 @@ class Firewall(horizon.Panel):
|
||||
config_name='enable_firewall',
|
||||
ext_name='fwaas'):
|
||||
return False
|
||||
if not super(Firewall, self).can_access(context):
|
||||
if not super(Firewall, self).allowed(context):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
@ -23,7 +23,7 @@ class LoadBalancer(horizon.Panel):
|
||||
slug = "loadbalancers"
|
||||
permissions = ('openstack.services.network',)
|
||||
|
||||
def can_access(self, context):
|
||||
def allowed(self, context):
|
||||
request = context['request']
|
||||
if not request.user.has_perms(self.permissions):
|
||||
return False
|
||||
@ -31,7 +31,7 @@ class LoadBalancer(horizon.Panel):
|
||||
config_name='enable_lb',
|
||||
ext_name='lbaas'):
|
||||
return False
|
||||
if not super(LoadBalancer, self).can_access(context):
|
||||
if not super(LoadBalancer, self).allowed(context):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
@ -27,7 +27,7 @@ class VPN(horizon.Panel):
|
||||
slug = 'vpn'
|
||||
permissions = ('openstack.services.network',)
|
||||
|
||||
def can_access(self, context):
|
||||
def allowed(self, context):
|
||||
request = context['request']
|
||||
if not request.user.has_perms(self.permissions):
|
||||
return False
|
||||
@ -35,7 +35,7 @@ class VPN(horizon.Panel):
|
||||
config_name='enable_vpn',
|
||||
ext_name='vpnaas'):
|
||||
return False
|
||||
if not super(VPN, self).can_access(context):
|
||||
if not super(VPN, self).allowed(context):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user