| 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
|
|
|
|
|
|
|
|