Merge lp:~leonardr/launchpad/bug-271010 into lp:launchpad

Proposed by Leonard Richardson
Status: Merged
Approved by: Leonard Richardson
Approved revision: no longer in the source branch.
Merged at revision: 12503
Proposed branch: lp:~leonardr/launchpad/bug-271010
Merge into: lp:launchpad
Diff against target: 341 lines (+95/-119)
5 files modified
lib/canonical/launchpad/browser/oauth.py (+0/-20)
lib/canonical/launchpad/pagetests/oauth/authorize-token.txt (+16/-10)
lib/canonical/launchpad/templates/oauth-authorize.pt (+79/-6)
lib/canonical/launchpad/templates/token-authorized.pt (+0/-76)
lib/canonical/launchpad/zcml/launchpad.zcml (+0/-7)
To merge this branch: bzr merge lp:~leonardr/launchpad/bug-271010
Reviewer Review Type Date Requested Status
Graham Binns (community) code Approve
Review via email: mp+51760@code.launchpad.net

Commit message

[r=gmb][bug=271010] [ui=none] When a request token is authorized, display the success message immediately instead of redirecting to a page that displays the success message. By the time the browser requests that page, the request token may have been exchanged for an access token, making it impossible to display the success message.

Description of the change

When you authorize a request token on +authorize-token, your browser is redirected to another page. If there's an OAuth callback URL set, you get redirected to that URL. If there's no callback URL, you get redirected to +token-authorized, which just prints a message "yay, you authorized the request token".

Here's the problem: newer versions of launchpadlib are polling Launchpad once a second, trying to exchange that request token for an access token. Once the exchange happens, the request token is destroyed and +token-authorized stops working. If the exchange happens before your browser makes that redirect request, by the time you arrive on +token-authorized your request token will no longer exist. You'll get an OOPS (see bug 271010). Worse, it looks like your integration failed, even though it actually succeeded.

This branch gets rid of +token-authorized altogether. The "yay, you authorized the request token" message is now part of the +authorize-token view, and is sent in response to the request that authorizes the request token. There's no redirect (except to an OAuth callback URL, which is a completely different case) and thus no possibility that the request token is destroyed before the message can be printed.

To post a comment you must log in.
Revision history for this message
Graham Binns (gmb) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/canonical/launchpad/browser/oauth.py'
--- lib/canonical/launchpad/browser/oauth.py 2010-11-23 23:22:27 +0000
+++ lib/canonical/launchpad/browser/oauth.py 2011-03-01 15:22:04 +0000
@@ -6,7 +6,6 @@
6 'OAuthAccessTokenView',6 'OAuthAccessTokenView',
7 'OAuthAuthorizeTokenView',7 'OAuthAuthorizeTokenView',
8 'OAuthRequestTokenView',8 'OAuthRequestTokenView',
9 'OAuthTokenAuthorizedView',
10 'lookup_oauth_context']9 'lookup_oauth_context']
1110
12from datetime import (11from datetime import (
@@ -372,9 +371,6 @@
372 callback = self.request.form.get('oauth_callback')371 callback = self.request.form.get('oauth_callback')
373 if callback:372 if callback:
374 self.next_url = callback373 self.next_url = callback
375 else:
376 self.next_url = (
377 '+token-authorized?oauth_token=%s' % self.token.key)
378374
379375
380def lookup_oauth_context(context):376def lookup_oauth_context(context):
@@ -397,22 +393,6 @@
397 return context393 return context
398394
399395
400class OAuthTokenAuthorizedView(LaunchpadView):
401 """Where users who reviewed tokens may get redirected to.
402
403 If the consumer didn't include an oauth_callback when sending the user to
404 Launchpad, this is the page the user is redirected to after he logs in and
405 reviews the token.
406 """
407
408 def initialize(self):
409 key = self.request.form.get('oauth_token')
410 self.token = getUtility(IOAuthRequestTokenSet).getByKey(key)
411 assert self.token.is_reviewed, (
412 'Users should be directed to this page only if they already '
413 'authorized the token.')
414
415
416class OAuthAccessTokenView(LaunchpadView):396class OAuthAccessTokenView(LaunchpadView):
417 """Where consumers may exchange a request token for an access token."""397 """Where consumers may exchange a request token for an access token."""
418398
419399
=== modified file 'lib/canonical/launchpad/pagetests/oauth/authorize-token.txt'
--- lib/canonical/launchpad/pagetests/oauth/authorize-token.txt 2010-11-02 17:06:44 +0000
+++ lib/canonical/launchpad/pagetests/oauth/authorize-token.txt 2011-03-01 15:22:04 +0000
@@ -202,8 +202,7 @@
202 >>> token.is_reviewed202 >>> token.is_reviewed
203 True203 True
204204
205If no oauth_callback is specified, we redirect the user to205If no oauth_callback is specified, we don't redirect the user.
206+authorized-token.
207206
208 # Create a new (unreviewed) token.207 # Create a new (unreviewed) token.
209 >>> token = request_token_for(consumer)208 >>> token = request_token_for(consumer)
@@ -215,15 +214,17 @@
215 >>> browser.getControl('Read Anything').click()214 >>> browser.getControl('Read Anything').click()
216215
217 >>> browser.url216 >>> browser.url
218 'http://launchpad.dev/+token-authorized?...'217 'http://launchpad.dev/+authorize-token'
219 >>> print extract_text(find_tag_by_id(browser.contents, 'maincontent'))218 >>> print extract_text(find_tag_by_id(browser.contents, 'maincontent'))
220 Almost finished ...219 Almost finished ...
221 To finish authorizing the application identified as foobar123451432 to220 To finish authorizing the application identified as foobar123451432 to
222 access Launchpad on your behalf you should go back to the application221 access Launchpad on your behalf you should go back to the application
223 window in which you started the process and inform it that you have done222 window in which you started the process and inform it that you have done
224 your part of the process.223 your part of the process.
224 See all applications authorized to access Launchpad on your behalf.
225225
226If we can't find the token, we will explain that to the user.226If we can't find the request token (possibly because it was already
227exchanged for an access token), we will explain that to the user.
227228
228 >>> params = dict(oauth_callback='http://example.com/oauth')229 >>> params = dict(oauth_callback='http://example.com/oauth')
229 >>> browser.open(230 >>> browser.open(
@@ -233,6 +234,7 @@
233 The information provided by the remote application was incorrect or234 The information provided by the remote application was incorrect or
234 incomplete. Because of that we were unable to identify the application235 incomplete. Because of that we were unable to identify the application
235 which would access Launchpad on your behalf.236 which would access Launchpad on your behalf.
237 You may have already authorized this application.
236 See all applications authorized to access Launchpad on your behalf.238 See all applications authorized to access Launchpad on your behalf.
237239
238 >>> params = dict(240 >>> params = dict(
@@ -244,11 +246,12 @@
244 The information provided by the remote application was incorrect or246 The information provided by the remote application was incorrect or
245 incomplete. Because of that we were unable to identify the application247 incomplete. Because of that we were unable to identify the application
246 which would access Launchpad on your behalf.248 which would access Launchpad on your behalf.
249 You may have already authorized this application.
247 See all applications authorized to access Launchpad on your behalf.250 See all applications authorized to access Launchpad on your behalf.
248251
249The same happens if the token is already reviewed. Although that's252If the token is already reviewed (perhaps by the same user in another
250probably an indication that the user has already reviewed that token in253window or tab), but has not yet been exchanged for an access token,
251another window/tab so there's no need to worry.254the success message is printed.
252255
253 # Need to get the token again as it's been changed in another256 # Need to get the token again as it's been changed in another
254 # transaction.257 # transaction.
@@ -260,9 +263,9 @@
260 >>> browser.open(263 >>> browser.open(
261 ... "http://launchpad.dev/+authorize-token?%s" % urlencode(params))264 ... "http://launchpad.dev/+authorize-token?%s" % urlencode(params))
262 >>> print extract_text(find_tag_by_id(browser.contents, 'maincontent'))265 >>> print extract_text(find_tag_by_id(browser.contents, 'maincontent'))
263 Request already reviewed266 Almost finished ...
264 This request for accessing Launchpad on your behalf has been267 To finish authorizing the application identified as foobar123451432
265 reviewed ... ago.268 ...
266 See all applications authorized to access Launchpad on your behalf.269 See all applications authorized to access Launchpad on your behalf.
267270
268Desktop integration271Desktop integration
@@ -397,6 +400,7 @@
397 The Ubuntu computer called mycomputer now has access to your400 The Ubuntu computer called mycomputer now has access to your
398 Launchpad account. Within a few seconds, you should be able to401 Launchpad account. Within a few seconds, you should be able to
399 start using its Launchpad integration features.402 start using its Launchpad integration features.
403 See all applications authorized to access Launchpad on your behalf.
400404
401 >>> print token.is_reviewed405 >>> print token.is_reviewed
402 True406 True
@@ -422,6 +426,7 @@
422 The integration you just authorized will expire in 59 minutes. At426 The integration you just authorized will expire in 59 minutes. At
423 that time, you'll have to re-authorize mycomputer, if you want to427 that time, you'll have to re-authorize mycomputer, if you want to
424 keep using its Launchpad integration features.428 keep using its Launchpad integration features.
429 See all applications authorized to access Launchpad on your behalf.
425430
426 >>> print token.is_reviewed431 >>> print token.is_reviewed
427 True432 True
@@ -481,6 +486,7 @@
481 You decided against desktop integration486 You decided against desktop integration
482 You decided not to give mycomputer access to your Launchpad487 You decided not to give mycomputer access to your Launchpad
483 account. You can always change your mind later.488 account. You can always change your mind later.
489 See all applications authorized to access Launchpad on your behalf.
484490
485 >>> print token.is_reviewed491 >>> print token.is_reviewed
486 True492 True
487493
=== modified file 'lib/canonical/launchpad/templates/oauth-authorize.pt'
--- lib/canonical/launchpad/templates/oauth-authorize.pt 2010-11-02 17:06:44 +0000
+++ lib/canonical/launchpad/templates/oauth-authorize.pt 2011-03-01 15:22:04 +0000
@@ -15,6 +15,11 @@
15 incomplete. Because of that we were unable to identify the15 incomplete. Because of that we were unable to identify the
16 application which would access Launchpad on your behalf.16 application which would access Launchpad on your behalf.
17 </p>17 </p>
18
19 <p>
20 You may have already authorized this application.
21 </p>
22
18 </tal:no-token>23 </tal:no-token>
1924
20 <tal:has-token condition="token">25 <tal:has-token condition="token">
@@ -123,12 +128,80 @@
123 </tal:token-not-reviewed>128 </tal:token-not-reviewed>
124129
125 <tal:token-reviewed condition="token/is_reviewed">130 <tal:token-reviewed condition="token/is_reviewed">
126 <h1>Request already reviewed</h1>131
127 <p>132 <tal:desktop-integration
128 This request for accessing Launchpad on your behalf has been133 condition="view/token/consumer/is_integrated_desktop">
129 reviewed <tal:date-reviewed 134
130 content="token/date_reviewed/fmt:approximatedate" />.135 <tal:unauthorized
131 </p>136 condition="view/token/permission/enumvalue:UNAUTHORIZED">
137 <h1>You decided against desktop integration</h1>
138
139 <p>
140 You decided not to give
141 <strong
142 tal:content="view/token/consumer/integrated_desktop_name">hostname</strong>
143 access to your Launchpad account. You can always change your
144 mind later.
145 </p>
146 </tal:unauthorized>
147
148 <tal:authorized
149 condition="not:view/token/permission/enumvalue:UNAUTHORIZED">
150 <h1>Almost finished ...</h1>
151
152 <p>
153 The
154 <tal:desktop
155 replace="structure view/token/consumer/integrated_desktop_type" />
156 computer called
157 <strong
158 tal:content="view/token/consumer/integrated_desktop_name">hostname</strong>
159 now has access to your Launchpad account. Within a few
160 seconds, you should be able to start using its Launchpad
161 integration features.
162 </p>
163
164 <p tal:condition="view/token/date_expires">
165 The integration you just authorized will expire
166 <tal:date
167 replace="structure view/token/date_expires/fmt:approximatedate" />.
168 At that time, you'll have to re-authorize
169 <strong
170 tal:content="view/token/consumer/integrated_desktop_name">hostname</strong>,
171 if you want to keep using its Launchpad integration features.
172 </p>
173
174 </tal:authorized>
175 </tal:desktop-integration>
176
177 <tal:application-integration
178 condition="not:view/token/consumer/is_integrated_desktop">
179
180 <tal:unauthorized
181 condition="view/token/permission/enumvalue:UNAUTHORIZED">
182 <h1>Access not granted to application</h1>
183 <p>
184 The application identified as
185 <strong tal:content="view/token/consumer/key">key</strong> has not
186 been given access to your protected resources on Launchpad.
187 </p>
188 </tal:unauthorized>
189
190 <tal:authorized
191 condition="not:view/token/permission/enumvalue:UNAUTHORIZED">
192 <h1>Almost finished ...</h1>
193 <p>
194 To finish authorizing the application identified as
195 <strong tal:content="view/token/consumer/key">key</strong>
196 to access Launchpad on your behalf you should go back to
197 the application window in which you started the process
198 and inform it that you have done your part of the
199 process.
200 </p>
201 </tal:authorized>
202
203 </tal:application-integration>
204
132 </tal:token-reviewed>205 </tal:token-reviewed>
133 </tal:has-token>206 </tal:has-token>
134207
135208
=== removed file 'lib/canonical/launchpad/templates/token-authorized.pt'
--- lib/canonical/launchpad/templates/token-authorized.pt 2010-11-02 17:06:44 +0000
+++ lib/canonical/launchpad/templates/token-authorized.pt 1970-01-01 00:00:00 +0000
@@ -1,76 +0,0 @@
1<html
2 xmlns="http://www.w3.org/1999/xhtml"
3 xmlns:tal="http://xml.zope.org/namespaces/tal"
4 xmlns:metal="http://xml.zope.org/namespaces/metal"
5 xmlns:i18n="http://xml.zope.org/namespaces/i18n"
6 metal:use-macro="view/macro:page/locationless"
7 i18n:domain="launchpad"
8>
9<body>
10 <div class="top-portlet" metal:fill-slot="main">
11
12 <tal:desktop condition="view/token/consumer/is_integrated_desktop">
13
14 <tal:unauthorized condition="view/token/permission/enumvalue:UNAUTHORIZED">
15 <h1>You decided against desktop integration</h1>
16
17 <p>
18 You decided not to give
19 <strong tal:content="view/token/consumer/integrated_desktop_name">hostname</strong>
20 access to your Launchpad account. You can always change your
21 mind later.
22 </p>
23 </tal:unauthorized>
24
25 <tal:authorized condition="not:view/token/permission/enumvalue:UNAUTHORIZED">
26 <h1>Almost finished ...</h1>
27
28 <p>The
29 <tal:desktop replace="structure view/token/consumer/integrated_desktop_type" />
30 computer called
31 <strong tal:content="view/token/consumer/integrated_desktop_name">hostname</strong>
32 now has access to your Launchpad account. Within a few
33 seconds, you should be able to start using its Launchpad
34 integration features.</p>
35
36 <p tal:condition="view/token/date_expires">
37 The integration you just authorized will expire
38 <tal:date
39 replace="structure view/token/date_expires/fmt:approximatedate" />.
40 At that time, you'll have to re-authorize
41 <strong tal:content="view/token/consumer/integrated_desktop_name">hostname</strong>,
42 if you want to keep using its Launchpad integration features.
43
44 </p>
45
46 </tal:authorized>
47 </tal:desktop>
48
49 <tal:application condition="not:view/token/consumer/is_integrated_desktop">
50
51 <tal:unauthorized condition="view/token/permission/enumvalue:UNAUTHORIZED">
52 <h1>Access not granted to application</h1>
53 <p>
54 The application identified as
55 <strong tal:content="view/token/consumer/key">key</strong> has not
56 been given access to your protected resources on Launchpad.
57 </p>
58 </tal:unauthorized>
59
60 <tal:authorized condition="not:view/token/permission/enumvalue:UNAUTHORIZED">
61 <h1>Almost finished ...</h1>
62 <p>
63 To finish authorizing the application identified as
64 <strong tal:content="view/token/consumer/key">key</strong> to access
65 Launchpad on your behalf you should go back to the application window
66 in which you started the process and inform it that you have done your
67 part of the process.
68 </p>
69 </tal:authorized>
70
71 </tal:application>
72 </div>
73
74</body>
75</html>
76
770
=== modified file 'lib/canonical/launchpad/zcml/launchpad.zcml'
--- lib/canonical/launchpad/zcml/launchpad.zcml 2010-11-08 14:16:17 +0000
+++ lib/canonical/launchpad/zcml/launchpad.zcml 2011-03-01 15:22:04 +0000
@@ -261,13 +261,6 @@
261261
262 <browser:page262 <browser:page
263 for="canonical.launchpad.webapp.interfaces.ILaunchpadApplication"263 for="canonical.launchpad.webapp.interfaces.ILaunchpadApplication"
264 name="+token-authorized"
265 class="canonical.launchpad.browser.OAuthTokenAuthorizedView"
266 template="../templates/token-authorized.pt"
267 permission="launchpad.AnyPerson" />
268
269 <browser:page
270 for="canonical.launchpad.webapp.interfaces.ILaunchpadApplication"
271 name="+access-token"264 name="+access-token"
272 class="canonical.launchpad.browser.OAuthAccessTokenView"265 class="canonical.launchpad.browser.OAuthAccessTokenView"
273 permission="zope.Public" />266 permission="zope.Public" />