1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
= Asking for a request token =
Our sample consumer (whose key is 'foobar123451432') asks Launchpad for
a request token which may later be exchanged for an access token.
>>> import time
>>> from urllib import urlencode
>>> data = dict(
... oauth_consumer_key='foobar123451432',
... oauth_version='1.0',
... oauth_signature_method='PLAINTEXT',
... oauth_signature='&',
... oauth_timestamp=time.time(),
... oauth_nonce='4572616e48616d6d65724c61686176')
>>> anon_browser.open(
... 'http://launchpad.dev/+request-token', data=urlencode(data))
>>> print anon_browser.contents
oauth_token=...&oauth_token_secret=...
The consumer can ask for a JSON representation of the request token,
which will also include information about the available permission
levels.
>>> import simplejson
>>> from lp.testing.pages import setupBrowser
>>> json_browser = setupBrowser()
>>> json_browser.addHeader('Accept', 'application/json')
>>> json_browser.open(
... 'http://launchpad.dev/+request-token', data=urlencode(data))
>>> token = simplejson.loads(json_browser.contents)
>>> sorted(token.keys())
['access_levels', 'oauth_token', 'oauth_token_consumer',
'oauth_token_secret']
>>> sorted((level['value'], level['title'])
... for level in token['access_levels'])
[('READ_PRIVATE', 'Read Anything'),
('READ_PUBLIC', 'Read Non-Private Data'),
('UNAUTHORIZED', 'No Access'),
('WRITE_PRIVATE', 'Change Anything'),
('WRITE_PUBLIC', 'Change Non-Private Data')]
If the consumer key is not yet registered, we register it automatically
so that the application can proceed.
>>> from zope.component import getUtility
>>> from lp.testing import login, logout
>>> from lp.services.oauth.interfaces import IOAuthConsumerSet
>>> login('salgado@ubuntu.com')
>>> print getUtility(IOAuthConsumerSet).getByKey('joe-feed-reader')
None
>>> logout()
>>> data2 = data.copy()
>>> data2['oauth_consumer_key'] = 'joe-feed-reader'
>>> anon_browser.open(
... 'http://launchpad.dev/+request-token', data=urlencode(data2))
>>> print anon_browser.contents
oauth_token=...&oauth_token_secret=...
>>> login('salgado@ubuntu.com')
>>> getUtility(IOAuthConsumerSet).getByKey('joe-feed-reader')
<...OAuthConsumer...
>>> logout()
If the consumer key is empty, we respond with a 401 status.
>>> data2 = data.copy()
>>> data2['oauth_consumer_key'] = ''
>>> print http(r"""
... GET /+request-token?%s HTTP/1.1
... Host: launchpad.dev
... """ % urlencode(data2))
HTTP/1.1 401 Unauthorized
...
WWW-Authenticate: OAuth realm="https://api.launchpad.net"
<BLANKLINE>
The only signature method supported is PLAINTEXT, which consists of the
concatenated values of the consumer secret and token secret, separated
by a & character. That means, in our case, the signature should be only
an '&', since there's no token yet and the consumer secret is empty.
>>> data['oauth_signature']
'&'
>>> data2 = data.copy()
>>> data2['oauth_signature'] = '&somesecret'
>>> print http(r"""
... GET /+request-token?%s HTTP/1.1
... Host: launchpad.dev
... """ % urlencode(data2))
HTTP/1.1 401 Unauthorized
...
If the consumer tries to sign a request with a different method, it will
get a 400 response.
>>> data2 = data.copy()
>>> data2['oauth_signature_method'] = 'HMAC-SHA1'
>>> print http(r"""
... GET /+request-token?%s HTTP/1.1
... Host: launchpad.dev
... """ % urlencode(data2))
HTTP/1.1 400 Bad Request
...
|