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

Conversation

merwok
Copy link
Contributor

@merwok merwok commented Jun 22, 2020

Fixes #1602

@stevepiercy
Copy link
Member

@merwok fyi, thanks for the offer to update What's New, but it is easier to do a single copy-pasta job at release time. See https://github.com/Pylons/pyramid/blob/master/RELEASING.txt#L49-L58 for process.

@merwok

This comment has been minimized.

@mmerickel
Copy link
Member

mmerickel commented Jul 1, 2020

This configuration will not work because the two view configs have the same specificity:

They have the same view weighting but because they are properly mutually exclusive, the correct one will be selected for each request. This configuration will work.

There could definitely be issues with effective_principals because you could setup configurations that were not mutually exclusive. For example Everyone vs Authenticated is ambiguous, because authenticated users also contain the Everyone principal.

@merwok

This comment has been minimized.

@merwok merwok marked this pull request as ready for review July 1, 2020 23:43
src/pyramid/predicates.py Outdated Show resolved Hide resolved
docs/narr/viewconfig.rst Outdated Show resolved Hide resolved
specified and is ``True``, the request must be for an authenticated user,
as determined by the :term:`security policy` in use. If it is specified and
``False``, the associated view callable will match only if the request does
not have an authenticated user.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is specified and its value is ``True``, only a request from an
authenticated user, as determined by the :term:`security policy`
in use, will satisfy this predicate.

If it is specified and its value is ``False``, only a request from
a user who is not authenticated will satisfy this predicate.

The is_authenticated predicate is applicable to both routes and views, and this version makes it copy-pasteable into route config. I like less maintenance!

Also I don't think it is correct to say that a "view callable will match", but maybe "predicate will match" or "predicate is satisfied". I took a shot at it, but maybe @mmerickel can wordsmith it better. Whatever is correct in Pyramid terminology.

The sentences should be merged into one paragraph. I put them separately for easier comprehension.

Copy link
Contributor Author

@merwok merwok Jul 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, that should have been the view config will match! (not correct to say the view callable will be invoked, there are other predicates) (edit: but the other predicate docs do say that 🙁)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have kept the doc as it was (not copy-pastable between route and view doc), to follow the existing style.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the predicate docs are suboptimal. There's an open issue that describes the current state, identifies the problems, and offers suggestions to improve the situation. I'd appreciate input on the best direction forward, then I'll create a PR for it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m not sure about my wording the view config will match, it seems a little imprecise.
(the route will match feels correct, if a little dry — maybe route definition?)

I agree now that the predicate will match is simple, correct and reusable so I will edit the new docs.

src/pyramid/config/routes.py Show resolved Hide resolved
src/pyramid/config/views.py Show resolved Hide resolved
src/pyramid/interfaces.py Outdated Show resolved Hide resolved
src/pyramid/interfaces.py Outdated Show resolved Hide resolved
src/pyramid/interfaces.py Outdated Show resolved Hide resolved
src/pyramid/interfaces.py Outdated Show resolved Hide resolved
src/pyramid/security.py Outdated Show resolved Hide resolved
docs/narr/viewconfig.rst Outdated Show resolved Hide resolved
Copy link
Member

@mmerickel mmerickel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great. No major changes, just a few little things.

CHANGES.rst Outdated Show resolved Hide resolved
CHANGES.rst Outdated Show resolved Hide resolved
src/pyramid/predicates.py Outdated Show resolved Hide resolved
@merwok merwok force-pushed the feature/is_authenticated branch 3 times, most recently from cf34271 to 46c8308 Compare July 2, 2020 17:05
@merwok merwok requested a review from mmerickel July 2, 2020 18:12
Copy link
Member

@mmerickel mmerickel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work, thank you @merwok. I'm gonna wait for @stevepiercy since he also marked the PR for changes, but things look good to me.

@merwok
Copy link
Contributor Author

merwok commented Jul 2, 2020

Oh also let me validate the whole thing with a tiny app! (can only trust unit tests so far)

@merwok
Copy link
Contributor Author

merwok commented Jul 2, 2020

I have added a bunch of routes and views to a minimal app and it looks good.

Python
def hello_world(request):
    return Response("Hello World!")


def hello_member(request):
    return Response("For members only.")


def hello_stranger(request):
    return Response("You are not authenticated :)")


def includeme(config):
    config.add_route("members-only", "/cool-zone", is_authenticated=True)
    config.add_view(hello_member, route_name="members-only")

    config.add_route("home", "/home")
    config.add_route("welcome", "/home", is_authenticated=False)
    config.add_view(hello_member, route_name="home")
    config.add_view(hello_stranger, route_name="welcome")

    config.add_route("history", "/history")
    config.add_view(hello_stranger, route_name="history")
    config.add_view(hello_member, route_name="history", is_authenticated=True)

    config.add_route("profile", "/profile")
    config.add_view(hello_stranger, route_name="profile", is_authenticated=False)
    config.add_view(hello_member, route_name="profile", is_authenticated=True)
proutes
Name                         Pattern                              View                                                                     Method    
----                         -------                              ----                                                                     ------    
hello                        /                                    helloapp.hello_world                                                     *         
members-only                 /cool-zone                           helloapp.hello_member                                                    *         
home                         /home                                helloapp.hello_member                                                    *         
welcome                      /home                                helloapp.hello_stranger                                                  *         
history                      /history                             pyramid.config.views.<pyramid.config.views.MultiView object at 0x...>    *         
profile                      /profile                             pyramid.config.views.<pyramid.config.views.MultiView object at 0x...>    *         
debugtoolbar                 /_debug_toolbar/*subpath             <unknown>                                                                *         
__/_debug_toolbar/static/    /_debug_toolbar/static/*subpath      pyramid_debugtoolbar:static/                                             *         
pviews
URL = /home

    context: <pyramid.traversal.DefaultRootFactory object at 0x...>
    view name: home

    Route:
    ------
    route name: home
    route pattern: /home
    route path: /home
    subpath: 

        View:
        -----
        helloapp.hello_member.

    Route:
    ------
    route name: welcome
    route pattern: /home
    route path: /home
    subpath: 
    route predicates (is_authenticated = False)

        View:
        -----
        helloapp.hello_stranger.


URL = /cool-zone

    context: <pyramid.traversal.DefaultRootFactory object at 0x...>
    view name: cool-zone

    Route:
    ------
    route name: members-only
    route pattern: /cool-zone
    route path: /cool-zone
    subpath: 
    route predicates (is_authenticated = True)

        View:
        -----
        helloapp.hello_member.


URL = /profile

    context: <pyramid.traversal.DefaultRootFactory object at 0x...>
    view name: profile

    Route:
    ------
    route name: profile
    route pattern: /profile
    route path: /profile
    subpath: 

        View:
        -----
        helloapp.hello_stranger
        view predicates (is_authenticated = False)

        View:
        -----
        helloapp.hello_member
        view predicates (is_authenticated = True)


URL = /history

    context: <pyramid.traversal.DefaultRootFactory object at 0x...>
    view name: history

    Route:
    ------
    route name: history
    route pattern: /history
    route path: /history
    subpath: 

        View:
        -----
        helloapp.hello_member
        view predicates (is_authenticated = True)

        View:
        -----
        helloapp.hello_stranger

I saw the expected text when opening the URLs with and without security policy (a simple class with 7 lines that permits everything)!

I also deleted the original IsAuthenticated predicate in my project, installed this Pyramid branch and my tests all pass.

Copy link
Member

@stevepiercy stevepiercy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm OK with the changes as is, but would like both @merwok and @mmerickel thoughts on my comments about multiple predicates.

docs/narr/viewconfig.rst Outdated Show resolved Hide resolved
src/pyramid/config/routes.py Show resolved Hide resolved
src/pyramid/config/views.py Show resolved Hide resolved
Co-Authored-By: Steve Piercy
@merwok merwok requested a review from stevepiercy July 2, 2020 21:10
@merwok
Copy link
Contributor Author

merwok commented Jul 3, 2020

@mmerickel this is ready!

@digitalresistor digitalresistor merged commit 5269b28 into Pylons:master Jul 6, 2020
@digitalresistor
Copy link
Member

\o/ this is great, thank you @merwok!

@merwok merwok deleted the feature/is_authenticated branch July 6, 2020 14:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add authenticated view predicate
4 participants