summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2012-10-29 01:55:58 -0400
committerChris McDonough <chrism@plope.com>2012-10-29 01:55:58 -0400
commit4fa68826e6d0980c6fd40b992c111f4496d202cf (patch)
tree9cfd4192d7a9b265da16856d9002471ed4f92e7f
parent220435320613530bde80dd1c4a38a3e719f4af5d (diff)
parentc7337ba1b02915824cb33803993c8ba236ed23b9 (diff)
downloadpyramid-4fa68826e6d0980c6fd40b992c111f4496d202cf.tar.gz
pyramid-4fa68826e6d0980c6fd40b992c111f4496d202cf.tar.bz2
pyramid-4fa68826e6d0980c6fd40b992c111f4496d202cf.zip
Merge branch 'master' into 1.4-branch
-rw-r--r--CHANGES.txt8
-rw-r--r--docs/narr/viewconfig.rst12
-rw-r--r--pyramid/config/predicates.py20
-rw-r--r--pyramid/config/routes.py14
-rw-r--r--pyramid/config/views.py14
-rw-r--r--pyramid/tests/test_config/test_predicates.py56
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'