diff options
| author | Chris McDonough <chrism@plope.com> | 2012-10-28 23:17:31 -0400 |
|---|---|---|
| committer | Chris McDonough <chrism@plope.com> | 2012-10-28 23:17:31 -0400 |
| commit | c7337ba1b02915824cb33803993c8ba236ed23b9 (patch) | |
| tree | 9cfd4192d7a9b265da16856d9002471ed4f92e7f | |
| parent | 4a6cca62ddf33580b1de210ef5ca54bfb2769243 (diff) | |
| download | pyramid-c7337ba1b02915824cb33803993c8ba236ed23b9.tar.gz pyramid-c7337ba1b02915824cb33803993c8ba236ed23b9.tar.bz2 pyramid-c7337ba1b02915824cb33803993c8ba236ed23b9.zip | |
- Added an ``effective_principals`` route and view predicate.
| -rw-r--r-- | CHANGES.txt | 8 | ||||
| -rw-r--r-- | docs/narr/viewconfig.rst | 12 | ||||
| -rw-r--r-- | pyramid/config/predicates.py | 20 | ||||
| -rw-r--r-- | pyramid/config/routes.py | 14 | ||||
| -rw-r--r-- | pyramid/config/views.py | 14 | ||||
| -rw-r--r-- | pyramid/tests/test_config/test_predicates.py | 56 |
6 files changed, 124 insertions, 0 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 1eec21fc2..740de0f17 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,11 @@ +Next release +============ + +Features +-------- + +- Added an ``effective_principals`` route and view predicate. + 1.4a3 (2012-10-26) ================== diff --git a/docs/narr/viewconfig.rst b/docs/narr/viewconfig.rst index 752e6ad72..6373a8d26 100644 --- a/docs/narr/viewconfig.rst +++ b/docs/narr/viewconfig.rst @@ -431,6 +431,18 @@ configured view. .. versionadded:: 1.4a3 +``effective_principals`` + + If specified, this value should be a :term:`principal` identifier or a + sequence of principal identifiers. If the + :func:`pyramid.security.effective_principals` method indicates that every + principal named in the argument list is present in the current request, this + predicate will return True; otherwise it will return False. For example: + ``effective_principals=pyramid.security.Authenticated`` or + ``effective_principals=('fred', 'group:admins')``. + + .. versionadded:: 1.4a4 + ``custom_predicates`` If ``custom_predicates`` is specified, it must be a sequence of references to custom predicate callables. Use custom predicates when no set of diff --git a/pyramid/config/predicates.py b/pyramid/config/predicates.py index adbdcbbc0..e31425899 100644 --- a/pyramid/config/predicates.py +++ b/pyramid/config/predicates.py @@ -13,6 +13,7 @@ from pyramid.traversal import ( from pyramid.urldispatch import _compile_route from pyramid.util import object_description from pyramid.session import check_csrf_token +from pyramid.security import effective_principals from .util import as_sorted_tuple @@ -267,3 +268,22 @@ class PhysicalPathPredicate(object): def __call__(self, context, request): return resource_path_tuple(context) == self.val +class EffectivePrincipalsPredicate(object): + def __init__(self, val, config): + if is_nonstr_iter(val): + self.val = set(val) + else: + self.val = set((val,)) + + def text(self): + return 'effective_principals = %s' % sorted(list(self.val)) + + phash = text + + def __call__(self, context, request): + req_principals = effective_principals(request) + if is_nonstr_iter(req_principals): + rpset = set(req_principals) + if self.val.issubset(rpset): + return True + return False diff --git a/pyramid/config/routes.py b/pyramid/config/routes.py index 30bebfb98..7c61d5912 100644 --- a/pyramid/config/routes.py +++ b/pyramid/config/routes.py @@ -238,6 +238,19 @@ class RoutesConfiguratorMixin(object): request, this predicate will be true. If this predicate returns ``False``, route matching continues. + effective_principals + + If specified, this value should be a :term:`principal` identifier or + a sequence of principal identifiers. If the + :func:`pyramid.security.effective_principals` method indicates that + every principal named in the argument list is present in the current + request, this predicate will return True; otherwise it will return + False. For example: + ``effective_principals=pyramid.security.Authenticated`` or + ``effective_principals=('fred', 'group:admins')``. + + .. versionadded:: 1.4a4 + custom_predicates This value should be a sequence of references to custom @@ -499,6 +512,7 @@ class RoutesConfiguratorMixin(object): ('request_param', p.RequestParamPredicate), ('header', p.HeaderPredicate), ('accept', p.AcceptPredicate), + ('effective_principals', p.EffectivePrincipalsPredicate), ('custom', p.CustomPredicate), ('traverse', p.TraversePredicate), ): diff --git a/pyramid/config/views.py b/pyramid/config/views.py index e52f9d64b..b01d17efd 100644 --- a/pyramid/config/views.py +++ b/pyramid/config/views.py @@ -1030,6 +1030,19 @@ class ViewsConfiguratorMixin(object): .. versionadded:: 1.4a3 + effective_principals + + If specified, this value should be a :term:`principal` identifier or + a sequence of principal identifiers. If the + :func:`pyramid.security.effective_principals` method indicates that + every principal named in the argument list is present in the current + request, this predicate will return True; otherwise it will return + False. For example: + ``effective_principals=pyramid.security.Authenticated`` or + ``effective_principals=('fred', 'group:admins')``. + + .. versionadded:: 1.4a4 + custom_predicates This value should be a sequence of references to custom @@ -1387,6 +1400,7 @@ class ViewsConfiguratorMixin(object): ('match_param', p.MatchParamPredicate), ('check_csrf', p.CheckCSRFTokenPredicate), ('physical_path', p.PhysicalPathPredicate), + ('effective_principals', p.EffectivePrincipalsPredicate), ('custom', p.CustomPredicate), ): self.add_view_predicate(name, factory) diff --git a/pyramid/tests/test_config/test_predicates.py b/pyramid/tests/test_config/test_predicates.py index 84d9b184d..91dfb0fb6 100644 --- a/pyramid/tests/test_config/test_predicates.py +++ b/pyramid/tests/test_config/test_predicates.py @@ -1,5 +1,7 @@ import unittest +from pyramid import testing + from pyramid.compat import text_ class TestXHRPredicate(unittest.TestCase): @@ -434,6 +436,60 @@ class Test_PhysicalPathPredicate(unittest.TestCase): context.__parent__ = root self.assertFalse(inst(context, None)) +class Test_EffectivePrincipalsPredicate(unittest.TestCase): + def setUp(self): + self.config = testing.setUp() + + def tearDown(self): + testing.tearDown() + + def _makeOne(self, val, config): + from pyramid.config.predicates import EffectivePrincipalsPredicate + return EffectivePrincipalsPredicate(val, config) + + def test_text(self): + inst = self._makeOne(('verna', 'fred'), None) + self.assertEqual(inst.text(), + "effective_principals = ['fred', 'verna']") + + def test_text_noniter(self): + inst = self._makeOne('verna', None) + self.assertEqual(inst.text(), + "effective_principals = ['verna']") + + def test_phash(self): + inst = self._makeOne(('verna', 'fred'), None) + self.assertEqual(inst.phash(), + "effective_principals = ['fred', 'verna']") + + def test_it_call_no_authentication_policy(self): + request = testing.DummyRequest() + inst = self._makeOne(('verna', 'fred'), None) + context = Dummy() + self.assertFalse(inst(context, request)) + + def test_it_call_authentication_policy_provides_superset(self): + request = testing.DummyRequest() + self.config.testing_securitypolicy('fred', groupids=('verna', 'bambi')) + inst = self._makeOne(('verna', 'fred'), None) + context = Dummy() + self.assertTrue(inst(context, request)) + + def test_it_call_authentication_policy_provides_superset_implicit(self): + from pyramid.security import Authenticated + request = testing.DummyRequest() + self.config.testing_securitypolicy('fred', groupids=('verna', 'bambi')) + inst = self._makeOne(Authenticated, None) + context = Dummy() + self.assertTrue(inst(context, request)) + + def test_it_call_authentication_policy_doesnt_provide_superset(self): + request = testing.DummyRequest() + self.config.testing_securitypolicy('fred') + inst = self._makeOne(('verna', 'fred'), None) + context = Dummy() + self.assertFalse(inst(context, request)) + class predicate(object): def __repr__(self): return 'predicate' |
