wraps methods before applying security in SecurceController
Resolves issue #131 Patchset updates the metaclass to wrap unbound methods before adding security. Wrapping ensures that base controllers can safely be mixed in both secure and unsecure contexts. Wrapping resolves the issue since method attributes are shared by all classes with the same bases. The original _pecan attributes of the method are shallow copied prior to adding the security attributes.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
from functools import wraps
|
||||
from inspect import getmembers, ismethod, isfunction
|
||||
from webob import exc
|
||||
|
||||
@@ -135,14 +136,20 @@ class SecureController(object):
|
||||
unlocked=[]
|
||||
)
|
||||
|
||||
for name, value in getmembers(cls):
|
||||
for name, value in getmembers(cls)[:]:
|
||||
if ismethod(value):
|
||||
if iscontroller(value) and value._pecan.get(
|
||||
'secured'
|
||||
) is None:
|
||||
value._pecan['secured'] = Protected
|
||||
value._pecan['check_permissions'] = \
|
||||
# Wrap the function so that the security context is
|
||||
# local to this class definition. This works around
|
||||
# the fact that unbound method attributes are shared
|
||||
# across classes with the same bases.
|
||||
wrapped = _make_wrapper(value)
|
||||
wrapped._pecan['secured'] = Protected
|
||||
wrapped._pecan['check_permissions'] = \
|
||||
cls.check_permissions
|
||||
setattr(cls, name, wrapped)
|
||||
elif hasattr(value, '__class__'):
|
||||
if name.startswith('__') and name.endswith('__'):
|
||||
continue
|
||||
@@ -163,6 +170,15 @@ class SecureController(object):
|
||||
return False
|
||||
|
||||
|
||||
def _make_wrapper(f):
|
||||
"""return a wrapped function with a copy of the _pecan context"""
|
||||
@wraps(f)
|
||||
def wrapper(*args, **kwargs):
|
||||
return f(*args, **kwargs)
|
||||
wrapper._pecan = f._pecan.copy()
|
||||
return wrapper
|
||||
|
||||
|
||||
# methods to evaluate security during routing
|
||||
def handle_security(controller):
|
||||
""" Checks the security of a controller. """
|
||||
|
||||
@@ -424,7 +424,6 @@ class SecureControllerSharedPermissionsRegression(unittest.TestCase):
|
||||
|
||||
self.app = TestApp(make_app(RootController()))
|
||||
|
||||
@unittest.expectedFailure
|
||||
def test_inherited_security(self):
|
||||
assert self.app.get('/secured/', status=401).status_int == 401
|
||||
assert self.app.get('/unsecured/').status_int == 200
|
||||
|
||||
Reference in New Issue
Block a user