Pylons / pyramid

Pyramid - A Python web framework
https://trypyramid.com/
Other
3.97k stars 887 forks source link

Add Request.is_authenticated and is_authenticated predicate #3598

Closed merwok closed 4 years ago

merwok commented 4 years ago

Fixes #1602

stevepiercy commented 4 years ago

@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 commented 4 years ago

I keep wanting to add a note somewhere about this, but I don’t know if it’s appropriate:

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

@view_config(route_name="home", is_authenticated=True)
def home_members(request):
    ...

@view_config(route_name="home", is_authenticated=False)
def home_login(request):
    ....

The right one is add is_authenticated to one of the functions and leave the other one without the param. It may be obvious to Pyramid devs, and the example in the docs is correct (https://github.com/Pylons/pyramid/pull/3598/files#diff-c0f6b28a439e308028cc66c9f0ac7aee), but it did trip me up for a moment on a project.

mmerickel commented 4 years ago

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 commented 4 years ago

Well that’s great! I think now that my error was probably that my code was doing return request.authenticated_userid is not None without comparing to the boolean value stored as self.val :man_facepalming: :laughing:

merwok commented 4 years ago

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

merwok commented 4 years ago

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

Python ```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. * profile /profile pyramid.config.views. * debugtoolbar /_debug_toolbar/*subpath * __/_debug_toolbar/static/ /_debug_toolbar/static/*subpath pyramid_debugtoolbar:static/ * ```
pviews ``` URL = /home context: 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: 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: 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: 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.

merwok commented 4 years ago

@mmerickel this is ready!

digitalresistor commented 4 years ago

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