Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Request.is_authenticated and is_authenticated predicate #3598

Merged
merged 3 commits into from
Jul 6, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/narr/advanced-features.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ For our example above, you can do this instead:
.. code-block:: python
:linenos:

@view_config(route_name="items", effective_principals=pyramid.authorization.Authenticated)
@view_config(route_name="items", is_authenticated=True)
def auth_view(request):
# do one thing

Expand Down
8 changes: 8 additions & 0 deletions docs/narr/viewconfig.rst
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,12 @@ configured view.

.. versionadded:: 1.4a3

``is_authenticated``

XXX doc doc

.. versionadded:: 2.0

``effective_principals``
If specified, this value should be a :term:`principal` identifier or a
sequence of principal identifiers. If the
Expand All @@ -505,6 +511,8 @@ configured view.

.. versionadded:: 1.4a4

.. deprecated:: TODO add
merwok marked this conversation as resolved.
Show resolved Hide resolved

``custom_predicates``
If ``custom_predicates`` is specified, it must be a sequence of references to
custom predicate callables. Custom predicates can be combined with
Expand Down
7 changes: 7 additions & 0 deletions src/pyramid/config/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,12 @@ def add_route(

Removed support for media ranges.

is_authenticated

XXX doc doc

.. versionadded:: 2.0

merwok marked this conversation as resolved.
Show resolved Hide resolved
effective_principals

If specified, this value should be a :term:`principal` identifier or
Expand Down Expand Up @@ -537,6 +543,7 @@ def add_default_route_predicates(self):
('request_param', p.RequestParamPredicate),
('header', p.HeaderPredicate),
('accept', p.AcceptPredicate),
('is_authenticated', p.IsAuthenticatedPredicate),
('effective_principals', p.EffectivePrincipalsPredicate),
('custom', p.CustomPredicate),
('traverse', p.TraversePredicate),
Expand Down
7 changes: 7 additions & 0 deletions src/pyramid/config/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,12 @@ def wrapper(context, request):

.. versionadded:: 1.4a3

is_authenticated

XXX doc doc

..versionadded:: 2.0

merwok marked this conversation as resolved.
Show resolved Hide resolved
effective_principals

If specified, this value should be a :term:`principal` identifier or
Expand Down Expand Up @@ -1205,6 +1211,7 @@ def add_default_view_predicates(self):
('request_type', p.RequestTypePredicate),
('match_param', p.MatchParamPredicate),
('physical_path', p.PhysicalPathPredicate),
('is_authenticated', p.IsAuthenticatedPredicate),
('effective_principals', p.EffectivePrincipalsPredicate),
('custom', p.CustomPredicate),
):
Expand Down
12 changes: 12 additions & 0 deletions src/pyramid/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,14 @@ def app_iter_range(start, stop):
""" Return a new app_iter built from the response app_iter that
serves up only the given start:stop range. """

authenticated_identity = Attribute(
"""XXX Doc doc"""
)

authenticated_userid = Attribute(
"""XXX Doc doc"""
)

body = Attribute(
"""The body of the response, as a str. This will read in the entire
app_iter if necessary."""
Expand Down Expand Up @@ -233,6 +241,10 @@ def encode_content(encoding='gzip', lazy=False):

headers = Attribute(""" The headers in a dictionary-like object """)

is_authenticated = Attribute(
mmerickel marked this conversation as resolved.
Show resolved Hide resolved
"""XXX doc doc"""
)

last_modified = Attribute(
""" Gets and sets and deletes the Last-Modified header. For more
information on Last-Modified see RFC 2616 section 14.29. Converts
Expand Down
13 changes: 13 additions & 0 deletions src/pyramid/predicates.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,19 @@ def __call__(self, context, request):
return False


class IsAuthenticatedPredicate:
def __init__(self, val, config):
self.val = val

def text(self):
return "is_authenticated = %r" % (self.val,)

phash = text

def __call__(self, context, request):
return request.is_authenticated == self.val


class EffectivePrincipalsPredicate:
def __init__(self, val, config):
if is_nonstr_iter(val):
Expand Down
5 changes: 5 additions & 0 deletions src/pyramid/security.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,11 @@ def authenticated_userid(self):
return None
return policy.authenticated_userid(self)

@property
def is_authenticated(self):
"""Return True if a user is authenticated for this request."""
merwok marked this conversation as resolved.
Show resolved Hide resolved
return self.authenticated_identity is not None
mmerickel marked this conversation as resolved.
Show resolved Hide resolved

def has_permission(self, permission, context=None):
""" Given a permission and an optional context, returns an instance of
:data:`pyramid.security.Allowed` if the permission is granted to this
Expand Down
38 changes: 33 additions & 5 deletions tests/test_config/test_predicates.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def _makeOne(self):
('containment', predicates.ContainmentPredicate),
('request_type', predicates.RequestTypePredicate),
('match_param', predicates.MatchParamPredicate),
('is_authenticated', predicates.IsAuthenticatedPredicate),
('custom', predicates.CustomPredicate),
('traverse', predicates.TraversePredicate),
):
Expand All @@ -38,6 +39,19 @@ def test_ordering_xhr_and_request_method_trump_only_containment(self):
def test_ordering_number_of_predicates(self):
from pyramid.config.predicates import predvalseq

order0, _, _ = self._callFUT(
mmerickel marked this conversation as resolved.
Show resolved Hide resolved
xhr='xhr',
request_method='request_method',
path_info='path_info',
request_param='param',
match_param='foo=bar',
header='header',
accept='accept',
is_authenticated=True,
containment='containment',
request_type='request_type',
custom=predvalseq([DummyCustomPredicate()]),
)
order1, _, _ = self._callFUT(
xhr='xhr',
request_method='request_method',
Expand Down Expand Up @@ -121,6 +135,7 @@ def test_ordering_number_of_predicates(self):
)
order11, _, _ = self._callFUT(xhr='xhr')
order12, _, _ = self._callFUT()
self.assertTrue(order1 > order0)
self.assertEqual(order1, order2)
self.assertTrue(order3 > order2)
self.assertTrue(order4 > order3)
Expand All @@ -131,7 +146,7 @@ def test_ordering_number_of_predicates(self):
self.assertTrue(order9 > order8)
self.assertTrue(order10 > order9)
self.assertTrue(order11 > order10)
self.assertTrue(order12 > order10)
self.assertTrue(order12 > order11)

def test_ordering_importance_of_predicates(self):
from pyramid.config.predicates import predvalseq
Expand All @@ -145,7 +160,8 @@ def test_ordering_importance_of_predicates(self):
order7, _, _ = self._callFUT(containment='containment')
order8, _, _ = self._callFUT(request_type='request_type')
order9, _, _ = self._callFUT(match_param='foo=bar')
order10, _, _ = self._callFUT(
order10, _, _ = self._callFUT(is_authenticated=True)
order11, _, _ = self._callFUT(
custom=predvalseq([DummyCustomPredicate()])
)
self.assertTrue(order1 > order2)
Expand All @@ -157,6 +173,7 @@ def test_ordering_importance_of_predicates(self):
self.assertTrue(order7 > order8)
self.assertTrue(order8 > order9)
self.assertTrue(order9 > order10)
self.assertTrue(order10 > order11)

def test_ordering_importance_and_number(self):
from pyramid.config.predicates import predvalseq
Expand Down Expand Up @@ -296,6 +313,7 @@ def test_predicate_text_is_correct(self):
]
),
match_param='foo=bar',
is_authenticated=False,
)
self.assertEqual(predicates[0].text(), 'xhr = True')
self.assertEqual(
Expand All @@ -308,9 +326,10 @@ def test_predicate_text_is_correct(self):
self.assertEqual(predicates[6].text(), 'containment = containment')
self.assertEqual(predicates[7].text(), 'request_type = request_type')
self.assertEqual(predicates[8].text(), "match_param foo=bar")
self.assertEqual(predicates[9].text(), 'custom predicate')
self.assertEqual(predicates[10].text(), 'classmethod predicate')
self.assertTrue(predicates[11].text().startswith('custom predicate'))
self.assertEqual(predicates[9].text(), "is_authenticated = False")
self.assertEqual(predicates[10].text(), 'custom predicate')
self.assertEqual(predicates[11].text(), 'classmethod predicate')
self.assertTrue(predicates[12].text().startswith('custom predicate'))

def test_predicate_text_is_correct_when_multiple(self):
_, predicates, _ = self._callFUT(
Expand Down Expand Up @@ -434,6 +453,15 @@ def test_header_multiple_mixed_fails(self):
request.headers = {'foo': 'nobar', 'spamme': 'ham'}
self.assertFalse(predicates[0](Dummy(), request))

def test_is_authenticated_true_matches(self):
...
def test_is_authenticated_true_fails(self):
...
def test_is_authenticated_false_matches(self):
...
def test_is_authenticated_false_fails(self):
...

def test_unknown_predicate(self):
from pyramid.exceptions import ConfigurationError

Expand Down