File Coverage

blib/lib/Net/Google/AuthSub.pm
Criterion Covered Total %
statement 24 109 22.0
branch 0 20 0.0
condition 0 14 0.0
subroutine 8 21 38.1
pod 11 11 100.0
total 43 175 24.5


line stmt bran cond sub pod time code
1             package Net::Google::AuthSub;
2              
3 1     1   1043 use strict;
  1         3  
  1         48  
4 1     1   6 use vars qw($VERSION $APP_NAME);
  1         2  
  1         60  
5 1     1   4520 use LWP::UserAgent;
  1         65712  
  1         36  
6 1     1   10575 use HTTP::Request::Common;
  1         2504  
  1         103  
7 1     1   9 use Net::Google::AuthSub::Response;
  1         2  
  1         26  
8 1     1   6 use URI;
  1         2  
  1         55  
9              
10             $VERSION = '0.5';
11             $APP_NAME = __PACKAGE__."-".$VERSION;
12              
13 1     1   6 use constant CLIENT_LOGIN => 0;
  1         2  
  1         67  
14 1     1   6 use constant AUTH_SUB => 1;
  1         2  
  1         1727  
15              
16             =head1 NAME
17              
18             Net::Google::AuthSub - interact with sites that implement Google style AuthSub
19              
20             =head1 SYNOPSIS
21              
22              
23             my $auth = Net::Google::AuthSub->new;
24             my $response = $auth->login($user, $pass);
25              
26             if ($response->is_success) {
27             print "Hurrah! Logged in\n";
28             } else {
29             die "Login failed: ".$response->error."\n";
30             }
31              
32             my %params = $auth->auth_params;
33             $params{Content_Type} = 'application/atom+xml; charset=UTF-8';
34             $params{Content} = $xml;
35             $params{'X-HTTP-Method-Override'} = 'DELETE';
36              
37             my $request = POST $url, %params;
38             my $r = $user_agent->request( $request );
39              
40              
41             =head1 ABOUT AUTHSUB
42              
43             AuthSub is Google's method of authentication for their web
44             services. It is also used by other web sites.
45              
46             You can read more about it here.
47              
48             http://code.google.com/apis/accounts/Authentication.html
49              
50             A Google Group for AuthSub is here.
51              
52             http://groups.google.com/group/Google-Accounts-API
53              
54             =head1 DEALING WITH CAPTCHAS
55              
56             If a login response fails then it may set the error code to
57             'CaptchRequired' and the response object will allow you to
58             retrieve the C and C fields.
59              
60             The C will be the url to a captcha image or you
61             can show the user the web page
62              
63             https://www.google.com/accounts/DisplayUnlockCaptcha
64              
65             Then retry the login attempt passing in the parameters
66             C (which is the value of C) and
67             C which is the user's answer to the CAPTCHA.
68              
69              
70             my $auth = Net::Google::AuthSub->new;
71             my $res = $auth->login($user, $pass);
72              
73             if (!$res->is_success && $res->error eq 'CaptchaRequired') {
74             my $answer = display_captcha($res->captchaurl);
75             $auth->login($user, $pass, logintoken => $res->captchatoken, logincaptcha => $answer);
76             }
77              
78              
79             You can read more here
80              
81             http://code.google.com/apis/accounts/AuthForInstalledApps.html#Using
82              
83             =head1 METHODS
84              
85             =cut
86              
87             =head2 new [param[s]]
88              
89             Return a new authorisation object. The options are
90              
91             =over 4
92              
93             =item url
94              
95             The base url of the web service to authenticate against.
96              
97             Defaults to C
98              
99             =item service
100              
101             Name of the Google service for which authorization is requested such as 'cl' for Calendar.
102              
103             Defaults to 'xapi' for calendar.
104              
105             =item source
106              
107             Short string identifying your application, for logging purposes.
108              
109             Defaults to 'Net::Google::AuthSub-'
110              
111             =item accountType
112              
113             Type of account to be authenticated.
114              
115             Defaults to 'HOSTED_OR_GOOGLE'.
116              
117             =back
118              
119             See http://code.google.com/apis/accounts/AuthForInstalledApps.html#ClientLogin for more details.
120              
121             =cut
122              
123              
124             our %BUGS = (
125             'not_dopplr_any_more' => {
126             'cuddled' => 1,
127             'json_response' => 1,
128             },
129             );
130              
131             sub new {
132 0     0 1   my $class = shift;
133 0           my %params = @_;
134              
135 0           $params{_ua} = LWP::UserAgent->new;
136 0           $params{_ua}->env_proxy;
137 0   0       $params{url} ||= 'https://www.google.com/accounts';
138 0   0       $params{service} ||= 'xapi';
139 0   0       $params{source} ||= $APP_NAME;
140 0   0       $params{accountType} ||= 'HOSTED_OR_GOOGLE';
141 0   0       $params{_compat} ||= {};
142              
143 0           my $site = delete $params{_bug_compat};
144 0 0 0       if (defined $site && exists $BUGS{$site}) {
145 0           foreach my $key (keys %{$BUGS{$site}}) {
  0            
146 0           $params{_compat}->{$key} = $BUGS{$site}->{$key};
147             }
148             }
149              
150              
151 0           return bless \%params, $class;
152             }
153              
154             =head2 login [opt[s]]
155              
156             Login to google using your username and password.
157              
158             Can optionally take a hash of options which will override the
159             default login params.
160              
161             Returns a C object.
162              
163             =cut
164              
165             sub login {
166 0     0 1   my ($self, $user, $pass, %opts) = @_;
167              
168             # setup auth request
169 0           my %params = ( Email => $user,
170             Passwd => $pass,
171             service => $self->{service},
172             source => $self->{source},
173             accountType => $self->{accountType} );
174             # allow overrides
175 0           $params{$_} = $opts{$_} for (keys %opts);
176              
177              
178 0           my $uri = URI->new($self->{url});
179 0           $uri->path($uri->path.'/ClientLogin');
180 0           my $tmp = $self->{_ua}->request(POST "$uri", [ %params ]);
181 0 0         return $self->_response_failure($tmp) unless $tmp->is_success;
182 0           my $r = Net::Google::AuthSub::Response->new($tmp, $self->{url}, _compat => $self->{_compat});
183              
184              
185             # store auth token
186 0           $self->{_auth} = $r->auth;
187 0           $self->{_auth_type} = CLIENT_LOGIN;
188 0           $self->{user} = $user;
189 0           $self->{pass} = $pass;
190 0           return $r;
191              
192             }
193              
194             sub _response_failure {
195 0     0     my $self = shift;
196 0           my $r = shift;
197 0           $@ = $r->content;
198 0           return Net::Google::AuthSub::Response->new(
199             $r,
200             $self->{url},
201             _compat => $self->{_compat}
202             ); }
203              
204              
205             =head2 authorised
206              
207             Whether or not we're authorised.
208              
209             =cut
210              
211             sub authorised {
212 0     0 1   my $self = shift;
213 0           return defined $self->{_auth};
214              
215             }
216              
217             =head2 authorized
218              
219             An alias for authorized.
220              
221             =cut
222             *authorized = \&authorised;
223              
224             =head2 auth
225              
226             Use the AuthSub method for access.
227              
228             See http://code.google.com/apis/accounts/AuthForWebApps.html
229             for details.
230              
231             =cut
232              
233             sub auth {
234 0     0 1   my ($self, $username, $token) = @_;
235 0           $self->{_auth} = $token;
236 0           $self->{_auth_type} = AUTH_SUB;
237 0           $self->{user} = $username;
238 0           return 1;
239             }
240              
241             =head2 auth_token [token]
242              
243             Get or set the current auth token
244              
245             =cut
246             sub auth_token {
247 0     0 1   my $self = shift;
248 0 0         $self->{_auth} = shift if @_;
249 0           return $self->{_auth};
250             }
251              
252             =head2 auth_type [type]
253              
254             Get or set the current auth type
255              
256             Returns either C<$Net::Google::AuthSub::CLIENT_LOGIN> or
257             C<$Net::Google::AuthSub::AUTH_SUB>.
258              
259             =cut
260             sub auth_type {
261 0     0 1   my $self = shift;
262 0 0         $self->{_auth_type} = shift if @_;
263 0           return $self->{_auth_type};
264             }
265              
266             =head2 request_token [option[s]]
267              
268             Return a URI object representing the URL which the user
269             should be directed to in order to aquire a single use token.
270              
271             The parameters are
272              
273             =over 4
274              
275             =item next (required)
276              
277             URL the user should be redirected to after a successful login.
278             This value should be a page on the web application site, and
279             can include query parameters.
280              
281             =item scope (required)
282              
283             URL identifying the service to be accessed. The resulting token
284             will enable access to the specified service only. Some services
285             may limit scope further, such as read-only access.
286              
287             For example
288              
289             http://www.google.com/calendar/feed
290              
291             =item secure
292              
293             Boolean flag indicating whether the authentication transaction
294             should issue a secure token (1) or a non-secure token (0).
295             Secure tokens are available to registered applications only.
296              
297             =item session
298              
299             Boolean flag indicating whether the one-time-use token may be
300             exchanged for a session token (1) or not (0).
301              
302             =back
303              
304             =cut
305              
306             sub request_token {
307 0     0 1   my $self = shift;
308 0           my ($next, $scope, %opts) = @_;
309 0           $opts{next} = $next;
310 0           $opts{scope} = $scope;
311              
312 0           my $uri = URI->new($self->{url});
313              
314 0           $uri->path($uri->path.'/AuthSubRequest');
315 0           $uri->query_form(%opts);
316 0           return $uri;
317             }
318              
319              
320             =head2 session_token
321              
322             Exchange the temporary token for a long-lived session token.
323              
324             The single-use token is acquired by visiting the url generated by
325             calling request_token.
326              
327             Returns the token if success and undef if failure.
328              
329             =cut
330              
331             sub session_token {
332 0     0 1   my $self = shift;
333              
334 0           my $uri = URI->new($self->{url});
335 0           $uri->path($uri->path.'/AuthSubSessionToken');
336              
337 0           my %params = $self->auth_params();
338 0           my $tmp = $self->{_ua}->request(GET "$uri", %params);
339 0 0         return $self->_response_failure($tmp) unless $tmp->is_success;
340 0           my $r = Net::Google::AuthSub::Response->new($tmp, $self->{url}, _compat => $self->{_compat});
341              
342             # store auth token
343 0           $self->{_auth} = $r->token;
344            
345 0           return $r->token;
346             }
347              
348             =head2 revoke_token
349              
350             Revoke a valid session token. Session tokens have no expiration date and
351             will remain valid unless revoked.
352              
353             Returns 1 if success and undef if failure.
354              
355             =cut
356              
357             sub revoke_token {
358 0     0 1   my $self = shift;
359              
360 0           my $uri = URI->new($self->{url});
361 0           $uri->path($uri->path.'/AuthSubRevokeToken');
362              
363 0           my %params = $self->auth_params();
364 0           my $r = $self->{_ua}->request(GET "$uri", [ %params ]);
365 0 0         return $self->_response_error($r) unless $r->is_success;
366 0           return 1;
367              
368             }
369              
370             =head2 token_info
371              
372             Call AuthSubTokenInfo to test whether a given session token is valid.
373             This method validates the token in the same way that a Google service
374             would; application developers can use this method to verify that their
375             application is getting valid tokens and handling them appropriately
376             without involving a call to the Google service. It can also be used to
377             get information about the token, including next URL, scope, and secure
378             status, as specified in the original token request.
379              
380             Returns a C object on success or undef on failure.
381              
382             =cut
383              
384             sub token_info {
385 0     0 1   my $self = shift;
386              
387 0           my $uri = URI->new($self->{url});
388 0           $uri->path($uri->path.'/AuthSubTokenInfo');
389              
390 0           my %params = $self->auth_params();
391 0           my $tmp = $self->{_ua}->request(GET "$uri", [ %params ]);
392 0           my $r = Net::Google::AuthSub::Response->new($tmp, $self->{url}, _compat => $self->{_compat});
393 0 0         return $self->_response_failure($r) unless $r->is_success;
394 0           return $r;
395             }
396              
397             =head2 auth_params
398              
399             Return any parameters needed in an HTTP request to authorise your app.
400              
401             =cut
402              
403             sub auth_params {
404 0     0 1   my $self = shift;
405              
406 0 0         return () unless $self->authorised;
407 0           return ( Authorization => $self->_auth_string );
408             }
409              
410             my %AUTH_TYPES = ( CLIENT_LOGIN() => "GoogleLogin auth", AUTH_SUB() => "AuthSub token" );
411              
412             sub _auth_string {
413 0     0     my $self = shift;
414 0 0         return "" unless $self->authorised;
415 0 0         if ($self->{_compat}->{uncuddled_auth}) {
416 0           return sprintf '%s=%s', $AUTH_TYPES{$self->{_auth_type}}, $self->{_auth};
417             } else {
418 0           return sprintf '%s="%s"', $AUTH_TYPES{$self->{_auth_type}}, $self->{_auth};
419             }
420             }
421              
422              
423             =head1 AUTHOR
424              
425             Simon Wistow
426              
427             =head1 COPYRIGHT
428              
429             Copyright, 2007 - Simon Wistow
430              
431             Released under the same terms as Perl itself
432              
433             =cut
434              
435              
436             1;