Merge lp:~stevenk/launchpad/assertion-review-token into lp:launchpad

Proposed by Steve Kowalik on 2012-10-03
Status: Merged
Approved by: Steve Kowalik on 2012-10-03
Approved revision: no longer in the source branch.
Merged at revision: 16078
Proposed branch: lp:~stevenk/launchpad/assertion-review-token
Merge into: lp:launchpad
Diff against target: 134 lines (+43/-16)
3 files modified
lib/lp/services/oauth/browser/__init__.py (+12/-10)
lib/lp/services/oauth/model.py (+12/-6)
lib/lp/services/oauth/stories/authorize-token.txt (+19/-0)
To merge this branch: bzr merge lp:~stevenk/launchpad/assertion-review-token
Reviewer Review Type Date Requested Status
William Grant code 2012-10-03 Approve on 2012-10-03
Review via email: mp+127639@code.launchpad.net

Commit Message

Catch the OAuthValidationError exceptions that are raised by IOAuthRequestToken.createAccessToken() and IOAuthRequestToken.review() in the browser code and show nice error messages.

Description of the Change

Catch the AssertionErrors that are raised by IOAuthRequestToken.createAccessToken() and IOAuthRequestToken.review() in the browser code. Two out of the three cases for createAccessToken were handled, so I left one and generalized the other two. None of the cases for review() were handled, so now they both are.

I claim the LoC credit from https://code.launchpad.net/~stevenk/launchpad/destroy-simplified-branch-ff/+merge/127630 for this MP.

To post a comment you must log in.
Robert Collins (lifeless) wrote :

Wait it raises a real genuine AssertionError? Thats -very- bad form to catch....

William Grant (wgrant) wrote :

Thanks for the fixes. This looks good, except for the date_expires indentation on line 21.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/services/oauth/browser/__init__.py'
2--- lib/lp/services/oauth/browser/__init__.py 2012-01-01 02:58:52 +0000
3+++ lib/lp/services/oauth/browser/__init__.py 2012-10-03 07:18:35 +0000
4@@ -34,6 +34,7 @@
5 IOAuthRequestTokenSet,
6 OAUTH_CHALLENGE,
7 )
8+from lp.services.oauth.model import OAuthValidationError
9 from lp.services.webapp import LaunchpadView
10 from lp.services.webapp.authentication import (
11 check_oauth_signature,
12@@ -369,8 +370,13 @@
13 datetime.now(pytz.timezone('UTC')) + duration_delta)
14 else:
15 expiration_date = None
16- self.token.review(self.user, permission, self.token_context,
17- date_expires=expiration_date)
18+ try:
19+ self.token.review(
20+ self.user, permission, self.token_context,
21+ date_expires=expiration_date)
22+ except OAuthValidationError as e:
23+ self.request.response.addErrorNotification(str(e))
24+ return
25 callback = self.request.form.get('oauth_callback')
26 if callback:
27 self.next_url = callback
28@@ -427,16 +433,12 @@
29 return (
30 u"Request token has not yet been reviewed. Try again later.")
31
32- if token.permission == OAuthPermission.UNAUTHORIZED:
33- # The end-user explicitly refused to authorize this
34- # token. We send 403 ("Forbidden") instead of 401
35- # ("Unauthorized") to distinguish this case and to
36- # indicate that, as RFC2616 says, "authorization will not
37- # help."
38+ try:
39+ access_token = token.createAccessToken()
40+ except OAuthValidationError as e:
41 self.request.response.setStatus(403)
42- return u'End-user refused to authorize request token.'
43+ return unicode(e)
44
45- access_token = token.createAccessToken()
46 context_name = None
47 if access_token.context is not None:
48 context_name = access_token.context.name
49
50=== modified file 'lib/lp/services/oauth/model.py'
51--- lib/lp/services/oauth/model.py 2012-09-28 06:25:44 +0000
52+++ lib/lp/services/oauth/model.py 2012-10-03 07:18:35 +0000
53@@ -8,7 +8,9 @@
54 'OAuthConsumerSet',
55 'OAuthNonce',
56 'OAuthRequestToken',
57- 'OAuthRequestTokenSet']
58+ 'OAuthRequestTokenSet',
59+ 'OAuthValidationError',
60+ ]
61
62 from datetime import (
63 datetime,
64@@ -86,6 +88,10 @@
65 TIMESTAMP_SKEW_WINDOW = 60 * 60 # seconds, +/-
66
67
68+class OAuthValidationError(Exception):
69+ """Raised when the OAuth token cannot be validated."""
70+
71+
72 class OAuthBase:
73 """Base class for all OAuth database classes."""
74
75@@ -335,10 +341,10 @@
76 def review(self, user, permission, context=None, date_expires=None):
77 """See `IOAuthRequestToken`."""
78 if self.is_reviewed:
79- raise AssertionError(
80+ raise OAuthValidationError(
81 "Request tokens can be reviewed only once.")
82 if self.is_expired:
83- raise AssertionError(
84+ raise OAuthValidationError(
85 'This request token has expired and can no longer be '
86 'reviewed.')
87 self.date_reviewed = datetime.now(pytz.timezone('UTC'))
88@@ -360,14 +366,14 @@
89 def createAccessToken(self):
90 """See `IOAuthRequestToken`."""
91 if not self.is_reviewed:
92- raise AssertionError(
93+ raise OAuthValidationError(
94 'Cannot create an access token from an unreviewed request '
95 'token.')
96 if self.permission == OAuthPermission.UNAUTHORIZED:
97- raise AssertionError(
98+ raise OAuthValidationError(
99 'The user did not grant access to this consumer.')
100 if self.is_expired:
101- raise AssertionError(
102+ raise OAuthValidationError(
103 'This request token has expired and can no longer be '
104 'exchanged for an access token.')
105
106
107=== modified file 'lib/lp/services/oauth/stories/authorize-token.txt'
108--- lib/lp/services/oauth/stories/authorize-token.txt 2012-02-25 03:01:34 +0000
109+++ lib/lp/services/oauth/stories/authorize-token.txt 2012-10-03 07:18:35 +0000
110@@ -275,6 +275,25 @@
111 ...
112 See all applications authorized to access Launchpad on your behalf.
113
114+If the token has expired, we notify the user, and inhibit the callback.
115+
116+ >>> token = request_token_for(consumer)
117+ >>> from datetime import datetime, timedelta
118+ >>> from pytz import UTC
119+ >>> from zope.security.proxy import removeSecurityProxy
120+ >>> date_created = datetime.now(UTC) - timedelta(hours=3)
121+ >>> removeSecurityProxy(token).date_created = date_created
122+ >>> params = dict(
123+ ... oauth_token=token.key, oauth_callback='http://example.com/oauth')
124+ >>> browser.open(
125+ ... "http://launchpad.dev/+authorize-token?%s" % urlencode(params))
126+ >>> browser.getControl('Read Anything').click()
127+ >>> browser.url
128+ 'http://launchpad.dev/+authorize-token'
129+ >>> [tag] = find_tags_by_class(browser.contents, 'error message')
130+ >>> print extract_text(tag)
131+ This request token has expired and can no longer be reviewed.
132+
133 Desktop integration
134 ===================
135