summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2013-10-28 18:41:56 +0000
committerGerrit Code Review <review@openstack.org>2013-10-28 18:41:56 +0000
commit76e5ab63922dc1f7fca1d908a6e1f1451855798a (patch)
tree803ed4e5986d96689b17789f73386215cd50e89e
parent7a871eb8a4985e4795ada15d89867b81e2685908 (diff)
parent676606981efe3b5e8ce4f5bc1ce04629bd616255 (diff)
downloadpecan-76e5ab63922dc1f7fca1d908a6e1f1451855798a.tar.gz
Merge "Respect security for generic controllers."
-rw-r--r--pecan/core.py2
-rw-r--r--pecan/secure.py5
-rw-r--r--pecan/tests/test_secure.py128
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>'