Skip to content

Commit ef0f686

Browse files
authored
Merge pull request #3760 from Pylons/tseaver-qt_cleanup
docs: quick tutorial cleanups
2 parents 72f6185 + 1ebd988 commit ef0f686

File tree

17 files changed

+62
-276
lines changed

17 files changed

+62
-276
lines changed

docs/quick_tutorial/authentication.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ Subsequent requests return that cookie and identify the user.
137137
In our template, we fetched the ``logged_in`` value from the view class. We use
138138
this to calculate the logged-in user, if any. In the template we can then
139139
choose to show a login link to anonymous visitors or a logout link to logged-in
140-
users.
140+
users, including their login name.
141141

142142

143143
Extra credit

docs/quick_tutorial/authentication/tutorial/home.pt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
<div>
99
<a tal:condition="view.logged_in is None"
1010
href="${request.application_url}/login">Log In</a>
11-
<a tal:condition="view.logged_in is not None"
12-
href="${request.application_url}/logout">Logout</a>
11+
<span tal:condition="view.logged_in is not None">
12+
<a href="${request.application_url}/logout">Logout</a>
13+
as ${view.logged_in}
14+
</span>
1315
</div>
1416

1517
<h1>Hi ${name}</h1>

docs/quick_tutorial/authentication/tutorial/login.pt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
<span tal:replace="message"/>
99

1010
<form action="${url}" method="post">
11-
<input type="hidden" name="came_from"
12-
value="${came_from}"/>
1311
<label for="login">Username</label>
1412
<input type="text" id="login"
1513
name="login"

docs/quick_tutorial/authentication/tutorial/views.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,6 @@ def hello(self):
3333
def login(self):
3434
request = self.request
3535
login_url = request.route_url('login')
36-
referrer = request.url
37-
if referrer == login_url:
38-
referrer = '/' # never use login form itself as came_from
39-
came_from = request.params.get('came_from', referrer)
4036
message = ''
4137
login = ''
4238
password = ''
@@ -46,15 +42,14 @@ def login(self):
4642
hashed_pw = USERS.get(login)
4743
if hashed_pw and check_password(password, hashed_pw):
4844
headers = remember(request, login)
49-
return HTTPFound(location=came_from,
45+
return HTTPFound(location=request.route_url("home"),
5046
headers=headers)
5147
message = 'Failed login'
5248

5349
return dict(
5450
name='Login',
5551
message=message,
5652
url=request.application_url + '/login',
57-
came_from=came_from,
5853
login=login,
5954
password=password,
6055
)

docs/quick_tutorial/authorization.rst

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,17 @@ Of course, this only applies on ``Root``. Some other part of the site (a.k.a.
104104
*context*) might have a different ACL.
105105

106106
If you are not logged in and visit ``/howdy``, you need to get shown the login
107-
screen. How does Pyramid know what is the login page to use? We explicitly told
108-
Pyramid that the ``login`` view should be used by decorating the view with
109-
``@forbidden_view_config``.
107+
screen. How does Pyramid know what is the login page to use? We defined an
108+
explicit "forbidden view", decorating that view with
109+
``@forbidden_view_config``, and then had it store the information about the
110+
route being protected in the request's session, before redirecting to the
111+
login view.
112+
113+
.. note::
114+
115+
We use the session to store the ``came_from`` information, rather than a
116+
hidden form input, in order to avoid trusting user-supplied data (from the
117+
form or query string) when constructing redirect URLs.
110118

111119

112120
Extra credit

docs/quick_tutorial/authorization/tutorial/__init__.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
from pyramid.config import Configurator
2+
from pyramid.session import SignedCookieSessionFactory
23

34
from .security import SecurityPolicy
45

56

67
def main(global_config, **settings):
7-
config = Configurator(settings=settings,
8-
root_factory='.resources.Root')
8+
my_session_factory = SignedCookieSessionFactory('itsaseekreet')
9+
config = Configurator(
10+
settings=settings,
11+
root_factory='.resources.Root',
12+
session_factory=my_session_factory,
13+
)
914
config.include('pyramid_chameleon')
1015

1116
config.set_security_policy(

docs/quick_tutorial/authorization/tutorial/home.pt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
<div>
99
<a tal:condition="view.logged_in is None"
1010
href="${request.application_url}/login">Log In</a>
11-
<a tal:condition="view.logged_in is not None"
12-
href="${request.application_url}/logout">Logout</a>
11+
<span tal:condition="view.logged_in is not None">
12+
<a href="${request.application_url}/logout">Logout</a>
13+
as ${view.logged_in}
14+
</span>
1315
</div>
1416

1517
<h1>Hi ${name}</h1>

docs/quick_tutorial/authorization/tutorial/login.pt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
<span tal:replace="message"/>
99

1010
<form action="${url}" method="post">
11-
<input type="hidden" name="came_from"
12-
value="${came_from}"/>
1311
<label for="login">Username</label>
1412
<input type="text" id="login"
1513
name="login"

docs/quick_tutorial/authorization/tutorial/views.py

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,33 +30,58 @@ def home(self):
3030
def hello(self):
3131
return {'name': 'Hello View'}
3232

33+
@forbidden_view_config()
34+
def forbidden(self):
35+
request = self.request
36+
session = request.session
37+
if request.matched_route is not None:
38+
session['came_from'] = {
39+
'route_name': request.matched_route.name,
40+
'route_kwargs': request.matchdict,
41+
}
42+
if request.authenticated_userid is not None:
43+
session['message'] = (
44+
f'User {request.authenticated_userid} is not allowed '
45+
f'to see this resource. Please log in as another user.'
46+
)
47+
else:
48+
if 'came_from' in session:
49+
del session['came_from']
50+
51+
return HTTPFound(request.route_url('login'))
52+
3353
@view_config(route_name='login', renderer='login.pt')
34-
@forbidden_view_config(renderer='login.pt')
3554
def login(self):
3655
request = self.request
56+
session = request.session
3757
login_url = request.route_url('login')
38-
referrer = request.url
39-
if referrer == login_url:
40-
referrer = '/' # never use login form itself as came_from
41-
came_from = request.params.get('came_from', referrer)
42-
message = ''
58+
came_from = session.get('came_from')
59+
message = session.get('message', '')
4360
login = ''
4461
password = ''
62+
4563
if 'form.submitted' in request.params:
4664
login = request.params['login']
4765
password = request.params['password']
4866
hashed_pw = USERS.get(login)
4967
if hashed_pw and check_password(password, hashed_pw):
5068
headers = remember(request, login)
51-
return HTTPFound(location=came_from,
52-
headers=headers)
69+
70+
if came_from is not None:
71+
return_to = request.route_url(
72+
came_from['route_name'], **came_from['route_kwargs'],
73+
)
74+
else:
75+
return_to = request.route_url('home')
76+
77+
return HTTPFound(location=return_to, headers=headers)
78+
5379
message = 'Failed login'
5480

5581
return dict(
5682
name='Login',
5783
message=message,
5884
url=request.application_url + '/login',
59-
came_from=came_from,
6085
login=login,
6186
password=password,
6287
)

docs/quick_tutorial/retail_forms/development.ini

Lines changed: 0 additions & 9 deletions
This file was deleted.

0 commit comments

Comments
 (0)