line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package OAuth::Consumer; |
2
|
|
|
|
|
|
|
our $VERSION = '0.03'; |
3
|
4
|
|
|
4
|
|
249769
|
use strict; |
|
4
|
|
|
|
|
9
|
|
|
4
|
|
|
|
|
140
|
|
4
|
4
|
|
|
4
|
|
21
|
use warnings; |
|
4
|
|
|
|
|
9
|
|
|
4
|
|
|
|
|
122
|
|
5
|
4
|
|
|
4
|
|
22
|
use feature 'switch'; |
|
4
|
|
|
|
|
10
|
|
|
4
|
|
|
|
|
307
|
|
6
|
4
|
|
|
4
|
|
21
|
use Carp; |
|
4
|
|
|
|
|
6
|
|
|
4
|
|
|
|
|
240
|
|
7
|
4
|
|
|
4
|
|
4570
|
use IO::Socket::INET; |
|
4
|
|
|
|
|
90715
|
|
|
4
|
|
|
|
|
36
|
|
8
|
4
|
|
|
4
|
|
6489
|
use URI::Escape; |
|
4
|
|
|
|
|
7187
|
|
|
4
|
|
|
|
|
317
|
|
9
|
4
|
|
|
4
|
|
4049
|
use HTTP::Response; |
|
4
|
|
|
|
|
134760
|
|
|
4
|
|
|
|
|
166
|
|
10
|
4
|
|
|
4
|
|
4610
|
use Encode; |
|
4
|
|
|
|
|
72095
|
|
|
4
|
|
|
|
|
452
|
|
11
|
4
|
|
|
4
|
|
4246
|
use HTML::Entities; |
|
4
|
|
|
|
|
32949
|
|
|
4
|
|
|
|
|
408
|
|
12
|
4
|
|
|
4
|
|
109
|
use parent 'LWP::Authen::OAuth'; |
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
37
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
=encoding utf-8 |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=head1 NAME |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
OAuth::Consumer - LWP based user agent with OAuth for consumer application |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=head1 SYNOPSIS |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
OAuth is a protocol to allow a user to authorize an application to access on its |
23
|
|
|
|
|
|
|
behalf ressources on a server without giving its password to the application. To |
24
|
|
|
|
|
|
|
achieve this aim OAuth have a fairly complicated 3-steps authentication mechanism |
25
|
|
|
|
|
|
|
which require to user to go to a website to authenticate itself. The authentication |
26
|
|
|
|
|
|
|
response is then sent-back by the user itself through a callback mechanism. |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
OAuth::Consumer hide away to complexity of this process, including the set-up of |
29
|
|
|
|
|
|
|
a callback webserver which can be called by the user browser when its |
30
|
|
|
|
|
|
|
authentication is performed. |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
This library is oriented toward desktop application, it could possibly be used |
33
|
|
|
|
|
|
|
in a web application but I have not tried it (and the LWP setup may not be the |
34
|
|
|
|
|
|
|
most appropiate in this case). |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
Authenticating your application with OAuth to access some user's ressources is |
37
|
|
|
|
|
|
|
a matter of requesting and authorising a I. This can be done with the |
38
|
|
|
|
|
|
|
following steps: |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
use OAuth::Consumer; |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
my $ua = OAuth::Consumer->new( |
43
|
|
|
|
|
|
|
oauth_consumer_key => 'key', |
44
|
|
|
|
|
|
|
oauth_consumer_secret => 'secret' |
45
|
|
|
|
|
|
|
oauth_request_token_url => 'http://provider/oauth/request_token', |
46
|
|
|
|
|
|
|
oauth_authorize_url => 'http://provider/oauth/authorize', |
47
|
|
|
|
|
|
|
oauth_access_token_url => 'http://provider/oauth/access_token' |
48
|
|
|
|
|
|
|
); |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
my $verifer_url = $ua->get_request_token(); |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
print "You should authentify yourself at this URL: $verifier_url\n"; |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
my ($token, $secret) = $ua->get_access_token() |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
At this point, C<$ua> is an OAuth enabled LWP user-agent that you can use to |
57
|
|
|
|
|
|
|
access OAuth protected ressources. You should save the C<$token> and C<$secret> |
58
|
|
|
|
|
|
|
that you got and, in a later session, you may just do the following to gain |
59
|
|
|
|
|
|
|
access to the protected ressources: |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
my $ua = OAuth::Consumer->new( |
62
|
|
|
|
|
|
|
oauth_consumer_key => 'key', |
63
|
|
|
|
|
|
|
oauth_consumer_secret => 'secret' |
64
|
|
|
|
|
|
|
oauth_token_=> $token, |
65
|
|
|
|
|
|
|
oauth_token_secret => $secret |
66
|
|
|
|
|
|
|
); |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
=head1 DESCRIPTION |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
As OAuth::Consumer is a high-level library, this documentation does not describe |
71
|
|
|
|
|
|
|
precisely the OAuth protocol. You may find documentation on this protocol on |
72
|
|
|
|
|
|
|
these websites: |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
=over 4 |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
=item L |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
=item L |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
=item L |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
=item L |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
=back |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
=head1 CONSTRUCTOR |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
my $ua = OAuth::Consumer->new(%args); |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
The OAuth::Consumer constructor gives you an LWP::UserAgent object (well, strictly |
92
|
|
|
|
|
|
|
speaking this is an LWP::Authen::OAuth object, but you should not use directly |
93
|
|
|
|
|
|
|
the method of this module). This object is able to authenticate using the OAuth |
94
|
|
|
|
|
|
|
1.0 or 1.0a protocol (but not OAuth 2.0). |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
You can give to the constructor any LWP::UserAgent arguments. The OAuth::Consumer |
97
|
|
|
|
|
|
|
constructor expects some additionnal arguments described here: |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=over 4 |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
=item * C and C |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
These values are specific to your application. Depending on the service you are |
104
|
|
|
|
|
|
|
trying to access, you may either choose them arbitrarily, you may be given them |
105
|
|
|
|
|
|
|
by the service provider (e.g. on your application page after registration for |
106
|
|
|
|
|
|
|
Twitter or Google), or they may be fixed to some specific values. |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
If you specify nothing, the default value of C is used for both (some |
109
|
|
|
|
|
|
|
OAuth provider are known to accept this -- e.g. the Tomboy sync service -- this |
110
|
|
|
|
|
|
|
may not be the case of the service you are trying to access). |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
=item * C and C |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
The whole point of the OAuth protocol is for an application to get an access token |
115
|
|
|
|
|
|
|
and an associated secret. The consumer key and secret are associated to an |
116
|
|
|
|
|
|
|
application, but the token and its secret are associated to a specific user of |
117
|
|
|
|
|
|
|
this application. |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
If you already have those (e.g. some service provider, like Twitter, will give |
120
|
|
|
|
|
|
|
it to your user on there) |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
=item * C, C, and C |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
These are the OAuth endpoints. If you already have an C and |
125
|
|
|
|
|
|
|
C then you do not need these endpoints, otherwise they should |
126
|
|
|
|
|
|
|
be provided to you by the service provider. |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
Some service provider will provide already authorised tokens and as such will not |
129
|
|
|
|
|
|
|
provide an C. In this case, you should give C<'null'> for |
130
|
|
|
|
|
|
|
this parameter and use the C<'manual'> type for C (see |
131
|
|
|
|
|
|
|
below). |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
=item * C |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
You may specify the oauth version to use. Currently only version C<'1.0'> and |
136
|
|
|
|
|
|
|
C<'1.0a'> are supported by the library. The default is C<'1.0a'>, you may need to |
137
|
|
|
|
|
|
|
revert to C<'1.0'> with some server. |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
=item * C |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
Only the C signature mode is supported for now (which happens to be |
142
|
|
|
|
|
|
|
the default value of this option). So you should not use this argument. |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
=item * C |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
This parameter allows you to specify the where the user will be sent by the |
147
|
|
|
|
|
|
|
service provider once he has authorised your application. If you do not specify |
148
|
|
|
|
|
|
|
anything for this parameter, it default to C where C |
149
|
|
|
|
|
|
|
is a randomly chosen port where the library will listen for the end of the |
150
|
|
|
|
|
|
|
authorisation procedure. |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
You should not overide this value unless you are familiar with the OAuth protocol |
153
|
|
|
|
|
|
|
and you know what you are doing. |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
Some service providers (such as Google), allow the special value C<'oob'> (out of |
156
|
|
|
|
|
|
|
band) which will redirect the user to a web page which will show the verifier |
157
|
|
|
|
|
|
|
value. This value may then be passed as parameter to the C |
158
|
|
|
|
|
|
|
method. This C<'oob'> value is the default when the C is |
159
|
|
|
|
|
|
|
C (see just below). |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
=item * C |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
This parameter allows to specify how the verifier code is received by your |
164
|
|
|
|
|
|
|
application. Currently the library support three modes. The default is |
165
|
|
|
|
|
|
|
C<'blocking'>. In this mode, a call to C will be blocking until |
166
|
|
|
|
|
|
|
the user complete its authentication process at the url given as the result of |
167
|
|
|
|
|
|
|
the C call. During this time, the library will have set up a |
168
|
|
|
|
|
|
|
small web server which will wait to be triggered by the user browser at the end |
169
|
|
|
|
|
|
|
of this authentication. |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
If this setting is not working for you, you may use an C of |
172
|
|
|
|
|
|
|
C<'manual'>. In this case, no web server is set up by the library and you must |
173
|
|
|
|
|
|
|
supply the I code manually to the C method. This |
174
|
|
|
|
|
|
|
verifier may be entered by your user (some service provider will show it to your |
175
|
|
|
|
|
|
|
user) or you may read eat programatically (e.g. performing the authorisation |
176
|
|
|
|
|
|
|
process with WWW::Mechanize directed at the URL which is given back by the |
177
|
|
|
|
|
|
|
C method). |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
The C mode is the default if you supply an C argument to |
180
|
|
|
|
|
|
|
the constructor. |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
Finally there is the C mode. This mode is similar in functionnalities to |
183
|
|
|
|
|
|
|
the C mode except that the small web server (which get the result of |
184
|
|
|
|
|
|
|
the authentication) is run in a separate thread. This enable you more flexibilities |
185
|
|
|
|
|
|
|
as you can complete the authentication process (be it by your user or with a |
186
|
|
|
|
|
|
|
programatic method) before calling the C. Obviously, you will |
187
|
|
|
|
|
|
|
need a Perl with threads enabled to use this mode. |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
You should also note that in C mode the library itself is not thread-safe! |
190
|
|
|
|
|
|
|
It plays with the C handler and as such it should be called from the main |
191
|
|
|
|
|
|
|
thread of the program. Also, there may not be multiple concurently running |
192
|
|
|
|
|
|
|
OAuth::Consumer object (that is in-between the C and |
193
|
|
|
|
|
|
|
C call) if you are in C mode. |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
=item * C and C |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
You can use these two options to customise the message that the user get after its |
198
|
|
|
|
|
|
|
authentication in the browser. You may either pass a string of text which will |
199
|
|
|
|
|
|
|
be embedded in a small web page, or you may pass a complete web page (which must |
200
|
|
|
|
|
|
|
then start with the C<<''>> tag to be recognised) which will be used as-is. |
201
|
|
|
|
|
|
|
In the later case the argument must be UTF-8 encoded (not in Perl internal string |
202
|
|
|
|
|
|
|
representation) with all HTML entities properly escaped (but no checks at all |
203
|
|
|
|
|
|
|
will be performed on the argument beyond the test for the first tag). |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
=item * C |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
This parameter set the timeout value in the C method call. |
208
|
|
|
|
|
|
|
That is, the time the user have to performs its authentication on the service |
209
|
|
|
|
|
|
|
provider website. This parameter is ignored when C is |
210
|
|
|
|
|
|
|
C. |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
The default value is C<180> (3 minutes). You may set it to C to |
213
|
|
|
|
|
|
|
completely remove any timeout. |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
=back |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
=head1 METHODS |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
The methods described here allow you to get an authorised access token and its |
221
|
|
|
|
|
|
|
associated secret. If you already have those (maybe from previous call to these |
222
|
|
|
|
|
|
|
methods) then you do not need them. |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
An OAuth::Consumer object is also an LWP::UserAgent object and as such you can |
225
|
|
|
|
|
|
|
use any method of the LWP::UserAgent class with an OAuth::Consumer object. If |
226
|
|
|
|
|
|
|
your object is properly identified you may use it directly (e.g. with its C |
227
|
|
|
|
|
|
|
or C method) to access OAuth protected ressources (that is, directly after |
228
|
|
|
|
|
|
|
it is constructed if you provided valid C and C |
229
|
|
|
|
|
|
|
to the constructor, or after a call to C/C |
230
|
|
|
|
|
|
|
if you need a new token). |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
=head2 get_request_token |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
my $verifer_url = $ua->get_request_token(%args) |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
This call initiates a new authorisation procedure. It does not expect any |
237
|
|
|
|
|
|
|
arguments but you can provide any additionnal OAuth argument required by your |
238
|
|
|
|
|
|
|
service provider. Example of such argument are C, C, |
239
|
|
|
|
|
|
|
or C. You should look at the documentation of your service provider to |
240
|
|
|
|
|
|
|
know which arguments it expects. These arguments will be added as POST arguments |
241
|
|
|
|
|
|
|
in the OAuth query. If you need to pass them as GET arguments (in the url of the |
242
|
|
|
|
|
|
|
query), then you should modify yourself the C that you |
243
|
|
|
|
|
|
|
give to the constructor of the class. |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
On success, this method returns a string containing an URL to which the |
246
|
|
|
|
|
|
|
application user should be directed to authorise your application to access to |
247
|
|
|
|
|
|
|
the service provider on behalf of this user. At the end of its authorisation the |
248
|
|
|
|
|
|
|
user's browser will be automatically redirected to a small web server set up by |
249
|
|
|
|
|
|
|
the library. This web server will automatically read the C code that |
250
|
|
|
|
|
|
|
is given by the service provider. |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
You may also use this C to programatically authorise your request |
253
|
|
|
|
|
|
|
(e.g. with WWW::Mechanize). |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
Finally, if your service provider does not need you to authenticate your token |
256
|
|
|
|
|
|
|
then the return value may be ignored and you may directly call the |
257
|
|
|
|
|
|
|
C method. In that case you must set the C |
258
|
|
|
|
|
|
|
to C to prevent the application from blocking. |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
The method will C in case of error. |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
=head2 get_access_token |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
my ($token, $secret) = $ua->get_access_token(%args) |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
Once you have redirected your user to the verifier url, you can call this method. |
267
|
|
|
|
|
|
|
It will block until the user finishes authenticating itself on the service |
268
|
|
|
|
|
|
|
provider's website. If this process takes more time than the value of the |
269
|
|
|
|
|
|
|
C parameter (in the constructor) then the method will |
270
|
|
|
|
|
|
|
croak with the following message: C<'Timeout error while waiting for a callback connection'>. |
271
|
|
|
|
|
|
|
You can trap this error (with C) and, optionnaly, restart the call to |
272
|
|
|
|
|
|
|
C (which will wait for the same duration) if the C |
273
|
|
|
|
|
|
|
is C (you may not call this function more than once per call to |
274
|
|
|
|
|
|
|
C in C mode). |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
If the C parameter is C<'blocking'> you must call this |
277
|
|
|
|
|
|
|
function as soon as you have instructed your user to authenticate at the |
278
|
|
|
|
|
|
|
I URL. |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
If the C parameter is C<'manual'> then this function will |
281
|
|
|
|
|
|
|
not block. But then you I specify an C named argument to |
282
|
|
|
|
|
|
|
this function with its value being the value of the verifier that you got (your |
283
|
|
|
|
|
|
|
user may have entered it in your application if your using out-of-bound |
284
|
|
|
|
|
|
|
verification). |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
If your service provider does not require you to verify the request token (and |
287
|
|
|
|
|
|
|
as such did not give you an C). You must use C<'manual'> |
288
|
|
|
|
|
|
|
mode with a dummy C in the constructor and you should pass |
289
|
|
|
|
|
|
|
an empty value to the C argument of this method. |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
All other arguments in the C<%args> hash will be passed with the I |
292
|
|
|
|
|
|
|
query. To the author knowledge, no service providers require any arguments with |
293
|
|
|
|
|
|
|
this query (as opposed to the I query). |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
Finally, this function plays with the C function and associated handler. |
296
|
|
|
|
|
|
|
So you should not rely on alarm handler set accross this function call. |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
=cut |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
my @internal_opts = qw( |
302
|
|
|
|
|
|
|
oauth_request_token_url oauth_authorize_url oauth_access_token_url |
303
|
|
|
|
|
|
|
oauth_version oauth_callback oauth_verifier_type oauth_verifier_valid_msg |
304
|
|
|
|
|
|
|
oauth_verifier_invalid_msg oauth_verifier_timeout); |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
my $max_content_len_for_error = 60; |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
sub new { |
309
|
0
|
|
|
0
|
1
|
|
my ($class, %args) = @_; |
310
|
|
|
|
|
|
|
|
311
|
0
|
|
|
|
|
|
my %opts; |
312
|
0
|
|
|
|
|
|
for my $o (@internal_opts) |
313
|
|
|
|
|
|
|
{ |
314
|
0
|
|
|
|
|
|
$opts{$o} = delete $args{$o}; |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
|
317
|
0
|
|
0
|
|
|
|
$args{oauth_consumer_key} ||= 'anyone'; |
318
|
0
|
|
0
|
|
|
|
$args{oauth_consumer_secret} ||= 'anyone'; |
319
|
|
|
|
|
|
|
|
320
|
0
|
|
0
|
|
|
|
$opts{oauth_version} ||= '1.0a'; |
321
|
0
|
0
|
0
|
|
|
|
$opts{oauth_verifier_type} ||= $opts{oauth_callback} ? 'manual' : 'blocking'; |
322
|
0
|
|
0
|
|
|
|
$opts{oauth_verifier_valid_msg} ||= 'Authentication accepted you can go back to the application'; |
323
|
0
|
|
0
|
|
|
|
$opts{oauth_verifier_invalid_msg} ||= 'There have been a problem with your authentication'; |
324
|
0
|
|
0
|
|
|
|
$opts{oauth_verifier_timeout} //= 180; # / |
325
|
|
|
|
|
|
|
|
326
|
0
|
|
|
|
|
|
given($opts{oauth_verifier_type}) { |
327
|
0
|
|
|
|
|
|
when(/^(manual|blocking)$/) { } |
328
|
0
|
|
|
|
|
|
when('thread') { |
329
|
0
|
0
|
|
|
|
|
if (not eval 'use threads; 1') { |
|
|
0
|
|
|
|
|
|
330
|
0
|
|
|
|
|
|
croak "You need a thread enabled Perl to a use oauth_verifier_type of 'thread'"; |
331
|
|
|
|
|
|
|
} elsif (not eval 'use Thread::Queue; 1') { |
332
|
0
|
|
|
|
|
|
croak "You need 'Thread::Queue' to use a oauth_verifier_type of 'thread'"; |
333
|
|
|
|
|
|
|
} |
334
|
|
|
|
|
|
|
} |
335
|
0
|
|
|
|
|
|
default { |
336
|
0
|
|
|
|
|
|
croak "Unknown value for the oauth_verifier_type parameter: ".$opts{oauth_verifier_type}; |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
|
340
|
0
|
|
|
|
|
|
my $self = $class->SUPER::new(%args); |
341
|
|
|
|
|
|
|
|
342
|
0
|
|
|
|
|
|
for(keys %opts) |
343
|
|
|
|
|
|
|
{ |
344
|
0
|
|
|
|
|
|
$self->{$_} = $opts{$_}; |
345
|
|
|
|
|
|
|
} |
346
|
|
|
|
|
|
|
|
347
|
0
|
|
|
|
|
|
return $self; |
348
|
|
|
|
|
|
|
} |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
sub m__start_server { |
352
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
353
|
|
|
|
|
|
|
|
354
|
0
|
|
|
|
|
|
my $sock = IO::Socket::INET->new( |
355
|
|
|
|
|
|
|
Listen => 1, |
356
|
|
|
|
|
|
|
LocalAddr => 'localhost', |
357
|
|
|
|
|
|
|
LocalPort => 0, |
358
|
|
|
|
|
|
|
Proto => 'tcp', |
359
|
|
|
|
|
|
|
Timeout => $self->{oauth_verifier_timeout} |
360
|
|
|
|
|
|
|
); |
361
|
|
|
|
|
|
|
|
362
|
0
|
0
|
|
|
|
|
return unless $sock; |
363
|
|
|
|
|
|
|
|
364
|
0
|
|
|
|
|
|
$self->{oauth_consumer_server_sock} = $sock; |
365
|
0
|
|
|
|
|
|
$self->{oauth_consumer_server_port} = $sock->sockport(); |
366
|
0
|
0
|
|
|
|
|
carp "ignored oauth_callback parameter" if $self->{oauth_callback}; |
367
|
0
|
|
|
|
|
|
$self->{oauth_callback} = "http://localhost:".$sock->sockport().'/oauth_callback'; |
368
|
|
|
|
|
|
|
|
369
|
0
|
|
|
|
|
|
return $self->{oauth_callback}; |
370
|
|
|
|
|
|
|
} |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
sub __forge_response { |
373
|
0
|
|
|
0
|
|
|
my ($ok, $txt) = @_; |
374
|
|
|
|
|
|
|
|
375
|
0
|
0
|
|
|
|
|
my $code = $ok ? 200 : 500; |
376
|
0
|
0
|
|
|
|
|
my $msg = $ok ? 'OK' : 'Server Error'; |
377
|
0
|
|
|
|
|
|
my $content; |
378
|
0
|
0
|
|
|
|
|
if ($txt =~ m/^\s*/) { |
379
|
0
|
|
|
|
|
|
$content = $txt; |
380
|
|
|
|
|
|
|
} else { |
381
|
0
|
|
|
|
|
|
$content = encode('UTF-8', ''.encode_entities($txt).''); |
382
|
|
|
|
|
|
|
} |
383
|
|
|
|
|
|
|
|
384
|
0
|
|
|
|
|
|
my $m = HTTP::Response->new($code, $msg, [ |
385
|
|
|
|
|
|
|
'Content-Type' => 'text/html;charset=UTF-8', |
386
|
|
|
|
|
|
|
'Content-Length' => length($content) |
387
|
|
|
|
|
|
|
], $content); |
388
|
0
|
|
|
|
|
|
$m->protocol("HTTP/1.0"); |
389
|
|
|
|
|
|
|
|
390
|
0
|
|
|
|
|
|
return $m->as_string(); |
391
|
|
|
|
|
|
|
} |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
sub m__get_verifier { |
394
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
395
|
|
|
|
|
|
|
|
396
|
0
|
|
|
|
|
|
my $sock = $self->{oauth_consumer_server_sock}->accept(); |
397
|
0
|
0
|
|
|
|
|
return 'OAUTH::CONSUMER::ERR:Timeout error while waiting for a callback connection' unless $sock; |
398
|
0
|
|
|
|
|
|
$self->{oauth_consumer_server_sock}->close(); |
399
|
|
|
|
|
|
|
|
400
|
0
|
|
|
|
|
|
my $get_line; |
401
|
0
|
|
|
|
|
|
eval { |
402
|
0
|
|
|
0
|
|
|
local $SIG{ALRM} = sub { die "Timeout error while reading the callback data\n" }; |
|
0
|
|
|
|
|
|
|
403
|
0
|
|
|
|
|
|
alarm 5; |
404
|
0
|
|
|
|
|
|
$get_line = $sock->getline(); |
405
|
0
|
|
|
|
|
|
alarm 0; |
406
|
|
|
|
|
|
|
}; |
407
|
0
|
0
|
|
|
|
|
return "OAUTH::CONSUMER::ERR:$@" if $@; |
408
|
|
|
|
|
|
|
|
409
|
0
|
0
|
|
|
|
|
if ($get_line =~ m{^GET\s+/oauth_callback.*oauth_verifier=([-0-9a-z_]+)}i) { |
410
|
0
|
|
|
|
|
|
$self->{oauth_verifier} = $1; |
411
|
0
|
|
|
|
|
|
$sock->print(__forge_response(1, $self->{oauth_verifier_valid_msg})); |
412
|
0
|
|
|
|
|
|
$sock->close(); |
413
|
0
|
|
|
|
|
|
return $self->{oauth_verifier}; |
414
|
|
|
|
|
|
|
} else { |
415
|
0
|
|
|
|
|
|
$sock->print(__forge_response(0, $self->{oauth_verifier_invalid_msg})); |
416
|
0
|
|
|
|
|
|
$sock->close(); |
417
|
0
|
|
|
|
|
|
return "OAUTH::CONSUMER::ERR:no match in GET line '$get_line'"; |
418
|
|
|
|
|
|
|
} |
419
|
|
|
|
|
|
|
} |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
sub m__get_thread_verifier { |
422
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
423
|
|
|
|
|
|
|
|
424
|
0
|
|
|
|
|
|
$self->{thread}->join(); |
425
|
0
|
|
|
|
|
|
delete $self->{thread}; |
426
|
0
|
|
|
|
|
|
$SIG{ALRM} = $self->{previous_alrm_handler}; |
427
|
|
|
|
|
|
|
# On n'utilise pas la valeur de retour du thread pour faire quelquechose de |
428
|
|
|
|
|
|
|
# plus facilement extensible. |
429
|
0
|
|
|
|
|
|
return $self->{thread_queue}->dequeue(); |
430
|
|
|
|
|
|
|
} |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
sub DESTROY { |
433
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
434
|
|
|
|
|
|
|
|
435
|
0
|
0
|
|
|
|
|
if ($self->{thread}) { |
436
|
0
|
0
|
|
|
|
|
if ($self->{thread}->is_joinable()) { |
437
|
0
|
|
|
|
|
|
$self->{thread}->join(); |
438
|
|
|
|
|
|
|
} else { |
439
|
0
|
|
|
|
|
|
$self->{thread}->detach(); |
440
|
|
|
|
|
|
|
} |
441
|
|
|
|
|
|
|
} |
442
|
|
|
|
|
|
|
} |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
sub m__start_thread_server { |
445
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
446
|
|
|
|
|
|
|
|
447
|
0
|
|
|
|
|
|
$self->{thread_queue} = Thread::Queue->new(); |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
$self->{thread} = threads->create(sub { |
450
|
0
|
|
|
0
|
|
|
$self->{thread_queue}->enqueue($self->m__start_server()); |
451
|
0
|
|
|
|
|
|
$self->{thread_queue}->enqueue($self->m__get_verifier()); |
452
|
0
|
|
|
|
|
|
}); |
453
|
|
|
|
|
|
|
|
454
|
0
|
|
|
|
|
|
$self->{previous_alrm_handler} = $SIG{ALRM}; |
455
|
|
|
|
|
|
|
$SIG{ALRM} = sub { |
456
|
0
|
|
|
0
|
|
|
$self->{thread}->is_running(); |
457
|
0
|
|
|
|
|
|
$self->{thread}->kill('ALRM'); |
458
|
0
|
|
|
|
|
|
}; |
459
|
|
|
|
|
|
|
|
460
|
0
|
|
|
|
|
|
return $self->{thread_queue}->dequeue(); |
461
|
|
|
|
|
|
|
} |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
sub get_request_token { |
464
|
0
|
|
|
0
|
1
|
|
my ($self, %args) = @_; |
465
|
|
|
|
|
|
|
|
466
|
0
|
|
|
|
|
|
my $ver_type = $self->{oauth_verifier_type}; |
467
|
0
|
0
|
|
|
|
|
croak "oauth_request_token_url must be set" unless $self->{oauth_request_token_url}; |
468
|
0
|
0
|
|
|
|
|
croak "oauth_authorize_url must be set" unless $self->{oauth_authorize_url}; |
469
|
0
|
0
|
|
|
|
|
croak "Invalid oauth_verifier_type: $ver_type" unless $ver_type =~ m/^(manual|blocking|thread)$/; |
470
|
|
|
|
|
|
|
|
471
|
0
|
|
|
|
|
|
given($ver_type) { |
472
|
0
|
|
|
|
|
|
when('blocking') { |
473
|
0
|
|
|
|
|
|
$self->{oauth_callback} = $self->m__start_server(); |
474
|
0
|
0
|
|
|
|
|
croak "Cannot open the verifier callback: $!" unless $self->{oauth_callback}; |
475
|
|
|
|
|
|
|
} |
476
|
0
|
|
|
|
|
|
when('thread') { |
477
|
0
|
|
|
|
|
|
$self->{oauth_callback} = $self->m__start_thread_server(); |
478
|
0
|
0
|
|
|
|
|
croak "Cannot open the verifier callback: $!" unless $self->{oauth_callback}; |
479
|
|
|
|
|
|
|
} |
480
|
0
|
|
|
|
|
|
when('manual') { |
481
|
0
|
0
|
|
|
|
|
if (not $self->{oauth_callback}) { |
482
|
|
|
|
|
|
|
# we must supply a callback |
483
|
|
|
|
|
|
|
# carp "You should provide a value for the 'oauth_callback' parameter"; |
484
|
0
|
|
|
|
|
|
$self->{oauth_callback} = 'oob'; |
485
|
|
|
|
|
|
|
} |
486
|
|
|
|
|
|
|
} |
487
|
0
|
|
|
|
|
|
default { |
488
|
0
|
|
|
|
|
|
croak "Unknown value for the oauth_verifier_type parameter: $ver_type"; |
489
|
|
|
|
|
|
|
} |
490
|
|
|
|
|
|
|
} |
491
|
0
|
|
|
|
|
|
my $cback = uri_escape($self->{oauth_callback}); |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
# request a 'request' token |
494
|
0
|
|
|
|
|
|
my $r = $self->post($self->{oauth_request_token_url}, Authorization => "OAuth oauth_callback=\"$cback\"", %args); |
495
|
0
|
0
|
|
|
|
|
if ($r->is_error) { |
496
|
0
|
0
|
|
|
|
|
my $str = length $r->content > $max_content_len_for_error ? |
497
|
|
|
|
|
|
|
substr($r->content, 0, $max_content_len_for_error - 3).'...' |
498
|
|
|
|
|
|
|
: $r->content; |
499
|
0
|
|
|
|
|
|
croak "error during the GetRequestToken call: ".$r->message." ($str)"; |
500
|
|
|
|
|
|
|
} |
501
|
|
|
|
|
|
|
|
502
|
0
|
|
|
|
|
|
$self->oauth_update_from_response($r); |
503
|
0
|
|
|
|
|
|
my $token = $self->oauth_token(); |
504
|
0
|
|
|
|
|
|
my $auth_url = $self->{oauth_authorize_url}."?oauth_token=$token"; |
505
|
0
|
0
|
|
|
|
|
if ($self->{oauth_version} eq '1.0') { |
506
|
0
|
|
|
|
|
|
$auth_url .= '&oauth_callback='.$cback; |
507
|
|
|
|
|
|
|
} |
508
|
|
|
|
|
|
|
|
509
|
0
|
|
|
|
|
|
return $auth_url; |
510
|
|
|
|
|
|
|
} |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
sub get_access_token { |
515
|
0
|
|
|
0
|
1
|
|
my ($self, %args) = @_; |
516
|
|
|
|
|
|
|
|
517
|
0
|
0
|
|
|
|
|
croak "oauth_access_token_url must be set" unless $self->{oauth_access_token_url}; |
518
|
|
|
|
|
|
|
|
519
|
0
|
|
|
|
|
|
given($self->{oauth_verifier_type}) { |
520
|
0
|
|
|
|
|
|
when('blocking') { |
521
|
0
|
|
|
|
|
|
$self->{oauth_verifier} = $self->m__get_verifier(); |
522
|
|
|
|
|
|
|
} |
523
|
0
|
|
|
|
|
|
when('thread') { |
524
|
0
|
|
|
|
|
|
$self->{oauth_verifier} = $self->m__get_thread_verifier(); |
525
|
|
|
|
|
|
|
} |
526
|
0
|
|
|
|
|
|
when('manual') { |
527
|
0
|
0
|
|
|
|
|
croak 'You must supply a oauth_verifier' unless exists $args{oauth_verifier}; |
528
|
0
|
|
|
|
|
|
$self->{oauth_verifier} = delete $args{oauth_verifier}; |
529
|
|
|
|
|
|
|
} |
530
|
0
|
|
|
|
|
|
default { |
531
|
0
|
|
|
|
|
|
croak "Unknown value for the oauth_verifier_type parameter: ".$self->{oauth_verifier_type}; |
532
|
|
|
|
|
|
|
} |
533
|
|
|
|
|
|
|
} |
534
|
0
|
0
|
|
|
|
|
if ($self->{oauth_verifier} =~ m/^OAUTH::CONSUMER::ERR:(.*?)$/m) { |
535
|
0
|
|
|
|
|
|
croak $1; |
536
|
|
|
|
|
|
|
} |
537
|
|
|
|
|
|
|
|
538
|
0
|
|
|
|
|
|
my $verif_header = 'OAuth oauth_verifier="'.uri_escape($self->{oauth_verifier}).'"'; |
539
|
0
|
|
|
|
|
|
my $r = $self->post($self->{oauth_access_token_url}, Authorization => $verif_header, %args); |
540
|
0
|
0
|
|
|
|
|
if ($r->is_error) { |
541
|
0
|
0
|
|
|
|
|
my $str = length $r->content > $max_content_len_for_error ? |
542
|
|
|
|
|
|
|
substr($r->content, 0, $max_content_len_for_error - 3).'...' |
543
|
|
|
|
|
|
|
: $r->content; |
544
|
0
|
|
|
|
|
|
croak "error during the GetAccessToken call: ".$r->message." ($str)"; |
545
|
|
|
|
|
|
|
} |
546
|
0
|
|
|
|
|
|
$self->oauth_update_from_response($r); |
547
|
|
|
|
|
|
|
|
548
|
0
|
|
|
|
|
|
my $token = $self->oauth_token(); |
549
|
0
|
|
|
|
|
|
my $secret = $self->oauth_token_secret(); |
550
|
|
|
|
|
|
|
|
551
|
0
|
|
|
|
|
|
return ($token, $secret); |
552
|
|
|
|
|
|
|
} |
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
1; |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
=head1 EXAMPLES |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
=head2 Getting an access token and secret |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
Here are the steps to follow to request an access token from a ressource |
567
|
|
|
|
|
|
|
provider. To achieve this, you need the 3 endpoints URL that should be described |
568
|
|
|
|
|
|
|
in the documentation of the API of the provider. You also need a consumer key and |
569
|
|
|
|
|
|
|
secret. Depending on the provider and the service, these value may be fixed to |
570
|
|
|
|
|
|
|
a specific value or you may need to register your application at the provider |
571
|
|
|
|
|
|
|
website to get them. |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
Some providers require extra arguments for the C call. These |
574
|
|
|
|
|
|
|
arguments are not mendatory in the OAuth specification but you should check the |
575
|
|
|
|
|
|
|
API documentation of your service provider to know what it expects. |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
my $ua = OAuth::Consumer->new( |
578
|
|
|
|
|
|
|
oauth_consumer_key => 'my-consumer-key', |
579
|
|
|
|
|
|
|
oauth_consumer_secret => 'my-consumer-secret', |
580
|
|
|
|
|
|
|
oauth_request_token_url => 'http://oauth-provider.example.com/request_token', |
581
|
|
|
|
|
|
|
oauth_access_token_url => 'http://oauth-provider.example.com/access_token', |
582
|
|
|
|
|
|
|
oauth_authorize_url => 'http://oauth-provider.example.com/authorize', |
583
|
|
|
|
|
|
|
); |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
my $verifier_url = $ua->get_request_token( |
586
|
|
|
|
|
|
|
scope => 'http://oauth-provider.example.com/scope1', |
587
|
|
|
|
|
|
|
xoauth_displayname => 'My Application Name' |
588
|
|
|
|
|
|
|
); |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
# Send your user to $verifier_url to authenticate or use a WWW::Mechanize |
591
|
|
|
|
|
|
|
# robot to performs the authentication programatically. In this later case, |
592
|
|
|
|
|
|
|
# you should use the "oauth_verifier_type => thread" argument in the call to |
593
|
|
|
|
|
|
|
# new to ensure that the authentication can terminate before the call to |
594
|
|
|
|
|
|
|
# get_access_token. |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
my ($token, $secret) = $ua->get_access_token(); |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
$r = $ua->get('http://oauth-provider.example.com/protected_ressource'); |
599
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
At the end of this procedure you should store the C<$token> and C<$secret> values |
601
|
|
|
|
|
|
|
as they should remains valid (usually service providers do not expire those). |
602
|
|
|
|
|
|
|
You can then use them directly in a future session. |
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
=head2 Getting an access token and secret with out-of-bound (OOB) verifier |
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
If your service provider will not redirect your user to OAuth::Consumer |
607
|
|
|
|
|
|
|
validation page, or if it is not feasible to ask the user to use his browser on |
608
|
|
|
|
|
|
|
the same machine as where the program is running, you may use out-of-bound |
609
|
|
|
|
|
|
|
verification where the user will be shown the verification code and can then |
610
|
|
|
|
|
|
|
enter it in your application. |
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
Not all service provider support the C callback scheme, so the example below |
613
|
|
|
|
|
|
|
may not work correctly. An alternative is to redirect the user to a web page that |
614
|
|
|
|
|
|
|
you control and that will show the user the verification code. Some practice about |
615
|
|
|
|
|
|
|
this are discussed on this web page: L. |
616
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
my $ua = OAuth::Consumer->new( |
618
|
|
|
|
|
|
|
oauth_consumer_key => 'my-consumer-key', |
619
|
|
|
|
|
|
|
oauth_consumer_secret => 'my-consumer-secret', |
620
|
|
|
|
|
|
|
oauth_verifier_type => 'manual', |
621
|
|
|
|
|
|
|
oauth_request_token_url => 'http://oauth-provider.example.com/request_token', |
622
|
|
|
|
|
|
|
oauth_access_token_url => 'http://oauth-provider.example.com/access_token', |
623
|
|
|
|
|
|
|
oauth_authorize_url => 'http://oauth-provider.example.com/authorize', |
624
|
|
|
|
|
|
|
); |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
my $verifier_url = $ua->get_request_token(); |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
print "Please, authenticate yourself at: $verifier_url\n"; |
629
|
|
|
|
|
|
|
print "Type in the verification code that you got: "; |
630
|
|
|
|
|
|
|
my $verifier = ; |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
my ($token, $secret) = $ua->get_access_token(oauth_verifier => $verifier); |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
$r = $ua->get('http://oauth-provider.example.com/protected_ressource'); |
635
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
Be carefull that a verifier URL may not remain valid for a long time (usual |
637
|
|
|
|
|
|
|
expiration time is around an hour). |
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
=head2 Using an access token and secret |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
If you saved your user specific access token and secret from a previous session |
642
|
|
|
|
|
|
|
or if your service provider does not allow for the authentication procedure and, |
643
|
|
|
|
|
|
|
instead, gives directly the token and its secret to your user on some web page |
644
|
|
|
|
|
|
|
(e.g. this is what Twitter does), then you can directly use these value in the |
645
|
|
|
|
|
|
|
constructor of the OAuth::Consumer object and completely skip the authentication |
646
|
|
|
|
|
|
|
procedure. |
647
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
my $ua = OAuth::Consumer->new( |
649
|
|
|
|
|
|
|
oauth_consumer_key => 'my-consumer-key', |
650
|
|
|
|
|
|
|
oauth_consumer_secret => 'my-consumer-secret', |
651
|
|
|
|
|
|
|
oauth_token => $token, |
652
|
|
|
|
|
|
|
oauth_token_secret => $secret |
653
|
|
|
|
|
|
|
); |
654
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
$r = $ua->get('http://oauth-provider.example.com/protected_ressource'); |
656
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
However, you should check your response code in case the token has been revoked |
658
|
|
|
|
|
|
|
or has expired (in which cases you will probably get a status code of C<401> or |
659
|
|
|
|
|
|
|
C<403>, but some servers return a C<500> status code). |
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
=head2 Two-legged request (tokenless or consumer mode) |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
Some service provider only require a your consumer key to authorise the access |
664
|
|
|
|
|
|
|
to some protected ressource. This is called two-legged request (as opposed to |
665
|
|
|
|
|
|
|
the normal three-legged mode) or tokenless mode. |
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
In this case, once you got your consumer key and secret (probably from your |
668
|
|
|
|
|
|
|
application page on the service provider website) you can just use those to |
669
|
|
|
|
|
|
|
access protected ressource. |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
my $ua = OAuth::Consumer->new( |
672
|
|
|
|
|
|
|
oauth_consumer_key => 'my-consumer-key', |
673
|
|
|
|
|
|
|
oauth_consumer_secret => 'my-consumer-secret', |
674
|
|
|
|
|
|
|
); |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
$r = $ua->get('http://oauth-provider.example.com/two-legged_ressource'); |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
=head1 CAVEATS |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
=over 4 |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
=item * Currently only the OAuth 1.0 and 1.0a are supported. The OAuth 2.0 protocol |
683
|
|
|
|
|
|
|
is quiet different from the 1.0 version (and varies greatly from one service |
684
|
|
|
|
|
|
|
provider to an other) so there is no plan currently to upgrade thise library to |
685
|
|
|
|
|
|
|
it. |
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
=item * Only the C signature mode is supported in the OAuth message. This |
688
|
|
|
|
|
|
|
is partly due to the fact that this is the only mode supported by the LWP::Authen::OAuth |
689
|
|
|
|
|
|
|
library from which OAuth::Consumer is inheriting and also to the fact that this |
690
|
|
|
|
|
|
|
mode is supported by all major OAuth enabled service provider. Let me know if you |
691
|
|
|
|
|
|
|
need another signature mode. |
692
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
=back |
694
|
|
|
|
|
|
|
|
695
|
|
|
|
|
|
|
=head1 BUGS |
696
|
|
|
|
|
|
|
|
697
|
|
|
|
|
|
|
Please report any bugs or feature requests to C, or |
698
|
|
|
|
|
|
|
through the web interface at L. |
699
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
However note that the tests for this distribution all depend on external service |
701
|
|
|
|
|
|
|
which may be unavailable or broken at some point. I have removed from the |
702
|
|
|
|
|
|
|
distribution the test depending on unreliable provider but some errors may still |
703
|
|
|
|
|
|
|
happen. |
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
=head1 SEE ALSO |
706
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
LWP::Authen::OAuth, LWP::UserAgent, OAuth::Simple, Net::OAuth, OAuth::Lite, |
708
|
|
|
|
|
|
|
Net::OAuth::Simple, OAuth::Lite::Consumer |
709
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
=head1 AUTHOR |
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
Mathias Kende (mathias@cpan.org) |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
=head1 VERSION |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
Version 0.03 (March 2013) |
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
Copyright 2013 © Mathias Kende. All rights reserved. |
721
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or |
723
|
|
|
|
|
|
|
modify it under the same terms as Perl itself. |
724
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
=cut |
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
|