summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Petrello <lists@ryanpetrello.com>2012-12-06 21:21:16 -0800
committerRyan Petrello <lists@ryanpetrello.com>2012-12-06 21:21:16 -0800
commit903707c3edad57630a0cfc556eafe4c851aff1ef (patch)
treeca0a2a7fe5799551d5c8d9352b0caac6ed0f0023
parentf3bc87b6b5187873e8dc11c026e68e65cdafcd74 (diff)
parente4d61c882aa664d9fb7d632f11bbf0200f096ef4 (diff)
downloadpecan-903707c3edad57630a0cfc556eafe4c851aff1ef.tar.gz
Merge pull request #151 from markmcclain/security
wraps methods before applying security in SecurceController
-rw-r--r--pecan/secure.py22
-rw-r--r--pecan/tests/test_secure.py1
2 files changed, 19 insertions, 4 deletions
diff --git a/pecan/secure.py b/pecan/secure.py
index 3e8c2af..c6f29cf 100644
--- a/pecan/secure.py
+++ b/pecan/secure.py
@@ -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. """
diff --git a/pecan/tests/test_secure.py b/pecan/tests/test_secure.py
index 749d045..f71e740 100644
--- a/pecan/tests/test_secure.py
+++ b/pecan/tests/test_secure.py
@@ -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