diff options
author | Jenkins <jenkins@review.openstack.org> | 2013-10-28 18:41:56 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2013-10-28 18:41:56 +0000 |
commit | 76e5ab63922dc1f7fca1d908a6e1f1451855798a (patch) | |
tree | 803ed4e5986d96689b17789f73386215cd50e89e /pecan | |
parent | 7a871eb8a4985e4795ada15d89867b81e2685908 (diff) | |
parent | 676606981efe3b5e8ce4f5bc1ce04629bd616255 (diff) | |
download | pecan-76e5ab63922dc1f7fca1d908a6e1f1451855798a.tar.gz |
Merge "Respect security for generic controllers."
Diffstat (limited to 'pecan')
-rw-r--r-- | pecan/core.py | 2 | ||||
-rw-r--r-- | pecan/secure.py | 5 | ||||
-rw-r--r-- | pecan/tests/test_secure.py | 128 |
3 files changed, 132 insertions, 3 deletions
diff --git a/pecan/core.py b/pecan/core.py index 668a42a..9c133ce 100644 --- a/pecan/core.py +++ b/pecan/core.py @@ -14,6 +14,7 @@ import six from webob import Request, Response, exc, acceptparse from .compat import urlparse, unquote_plus, izip +from .secure import handle_security from .templating import RendererFactory from .routing import lookup_controller, NonCanonicalPath from .util import _cfg, encode_if_needed @@ -429,6 +430,7 @@ class Pecan(object): im_self = six.get_method_self(controller) handlers = cfg['generic_handlers'] controller = handlers.get(req.method, handlers['DEFAULT']) + handle_security(controller, im_self) cfg = _cfg(controller) # add the controller to the state so that hooks can use it diff --git a/pecan/secure.py b/pecan/secure.py index e44aacb..62b82cb 100644 --- a/pecan/secure.py +++ b/pecan/secure.py @@ -119,7 +119,6 @@ def secure(func_or_obj, check_permissions_for_obj=None): To secure a class, invoke with two arguments: secure(<obj instance>, <check_permissions_method>) """ - if _allowed_check_permissions_types(func_or_obj): return _secure_method(func_or_obj) else: @@ -199,14 +198,14 @@ def _make_wrapper(f): # methods to evaluate security during routing -def handle_security(controller): +def handle_security(controller, im_self=None): """ Checks the security of a controller. """ if controller._pecan.get('secured', False): check_permissions = controller._pecan['check_permissions'] if isinstance(check_permissions, six.string_types): check_permissions = getattr( - six.get_method_self(controller), + im_self or six.get_method_self(controller), check_permissions ) diff --git a/pecan/tests/test_secure.py b/pecan/tests/test_secure.py index 53a63ca..0f16a98 100644 --- a/pecan/tests/test_secure.py +++ b/pecan/tests/test_secure.py @@ -174,6 +174,134 @@ class TestSecure(PecanTestCase): assert response.status_int == 200 assert response.body == b_('Hello from sub!') + def test_secured_generic_controller(self): + authorized = False + + class RootController(object): + + @classmethod + def check_permissions(cls): + return authorized + + @expose(generic=True) + def index(self): + return 'Index' + + @secure('check_permissions') + @index.when(method='POST') + def index_post(self): + return 'I should not be allowed' + + @secure('check_permissions') + @expose(generic=True) + def secret(self): + return 'I should not be allowed' + + app = TestApp(make_app( + RootController(), + debug=True, + static_root='tests/static' + )) + response = app.get('/') + assert response.status_int == 200 + response = app.post('/', expect_errors=True) + assert response.status_int == 401 + response = app.get('/secret/', expect_errors=True) + assert response.status_int == 401 + + def test_secured_generic_controller_lambda(self): + authorized = False + + class RootController(object): + + @expose(generic=True) + def index(self): + return 'Index' + + @secure(lambda: authorized) + @index.when(method='POST') + def index_post(self): + return 'I should not be allowed' + + @secure(lambda: authorized) + @expose(generic=True) + def secret(self): + return 'I should not be allowed' + + app = TestApp(make_app( + RootController(), + debug=True, + static_root='tests/static' + )) + response = app.get('/') + assert response.status_int == 200 + response = app.post('/', expect_errors=True) + assert response.status_int == 401 + response = app.get('/secret/', expect_errors=True) + assert response.status_int == 401 + + def test_secured_generic_controller_secure_attribute(self): + authorized = False + + class SecureController(object): + + @expose(generic=True) + def index(self): + return 'I should not be allowed' + + @index.when(method='POST') + def index_post(self): + return 'I should not be allowed' + + @expose(generic=True) + def secret(self): + return 'I should not be allowed' + + class RootController(object): + sub = secure(SecureController(), lambda: authorized) + + app = TestApp(make_app( + RootController(), + debug=True, + static_root='tests/static' + )) + response = app.get('/sub/', expect_errors=True) + assert response.status_int == 401 + response = app.post('/sub/', expect_errors=True) + assert response.status_int == 401 + response = app.get('/sub/secret/', expect_errors=True) + assert response.status_int == 401 + + def test_secured_generic_controller_secure_attribute_with_unlocked(self): + + class RootController(SecureController): + + @unlocked + @expose(generic=True) + def index(self): + return 'Unlocked!' + + @unlocked + @index.when(method='POST') + def index_post(self): + return 'Unlocked!' + + @expose(generic=True) + def secret(self): + return 'I should not be allowed' + + app = TestApp(make_app( + RootController(), + debug=True, + static_root='tests/static' + )) + response = app.get('/') + assert response.status_int == 200 + response = app.post('/') + assert response.status_int == 200 + response = app.get('/secret/', expect_errors=True) + assert response.status_int == 401 + def test_state_attribute(self): from pecan.secure import Any, Protected assert repr(Any) == '<SecureState Any>' |