diff options
author | Ryan Petrello <lists@ryanpetrello.com> | 2012-12-06 21:21:16 -0800 |
---|---|---|
committer | Ryan Petrello <lists@ryanpetrello.com> | 2012-12-06 21:21:16 -0800 |
commit | 903707c3edad57630a0cfc556eafe4c851aff1ef (patch) | |
tree | ca0a2a7fe5799551d5c8d9352b0caac6ed0f0023 | |
parent | f3bc87b6b5187873e8dc11c026e68e65cdafcd74 (diff) | |
parent | e4d61c882aa664d9fb7d632f11bbf0200f096ef4 (diff) | |
download | pecan-903707c3edad57630a0cfc556eafe4c851aff1ef.tar.gz |
Merge pull request #151 from markmcclain/security
wraps methods before applying security in SecurceController
-rw-r--r-- | pecan/secure.py | 22 | ||||
-rw-r--r-- | pecan/tests/test_secure.py | 1 |
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 |