File Coverage

blib/lib/OAuth/Lite2/Client/ExternalService.pm
Criterion Covered Total %
statement 40 42 95.2
branch n/a
condition n/a
subroutine 14 14 100.0
pod n/a
total 54 56 96.4


line stmt bran cond sub pod time code
1             package OAuth::Lite2::Client::ExternalService;
2 1     1   1498 use strict;
  1         2  
  1         25  
3 1     1   5 use warnings;
  1         1  
  1         20  
4 1     1   5 use base 'Class::ErrorHandler';
  1         1  
  1         60  
5 1     1   15 use bytes ();
  1         1  
  1         13  
6              
7 1     1   4 use Carp ();
  1         2  
  1         14  
8 1     1   3 use Try::Tiny qw/try catch/;
  1         2  
  1         50  
9 1     1   4 use LWP::UserAgent;
  1         2  
  1         22  
10 1     1   4 use MIME::Base64 qw(encode_base64);
  1         1  
  1         54  
11 1     1   6 use HTTP::Request;
  1         1  
  1         27  
12 1     1   4 use HTTP::Headers;
  1         2  
  1         21  
13 1     1   5 use Params::Validate qw(HASHREF);
  1         2  
  1         57  
14 1     1   5 use OAuth::Lite2;
  1         1  
  1         15  
15 1     1   4 use OAuth::Lite2::Util qw(build_content);
  1         2  
  1         36  
16 1     1   43 use OAuth::Lite2::Client::TokenResponseParser;
  0            
  0            
17              
18             =head1 NAME
19              
20             OAuth::Lite2::Client::ExternalService - OAuth 2.0 Federated Assertion Profile Client
21              
22             =head1 SYNOPSIS
23              
24             my $client = OAuth::Lite2::Client::ExternalService->new(
25             id => q{my_client_id},
26             secret => q{my_client_secret},
27             access_token_uri => q{http://example.org/token},
28             );
29              
30             sub get_access_token {
31             my $your_app = shift;
32              
33             my $access_token = $client->get_access_token(
34             assertion => $your_app->request->param("assertion"),
35             scope => q{photo},
36             ) or return $your_app->error( $client->errstr );
37              
38             $your_app->store->save( access_token => $access_token->access_token );
39             $your_app->store->save( expires_at => time() + $access_token->expires_in );
40             $your_app->store->save( refresh_token => $access_token->refresh_token );
41             }
42              
43             sub refresh_access_token {
44             my $your_app = shift;
45              
46             my $access_token = $client->refresh_access_token(
47             refresh_token => $refresh_token,
48             ) or return $your_app->error( $client->errstr );
49              
50             $your_app->store->save( access_token => $access_token->access_token );
51             $your_app->store->save( expires_at => time() + $access_token->expires_in );
52             $your_app->store->save( refresh_token => $access_token->refresh_token );
53             }
54              
55             sub access_to_protected_resource {
56             my $your_app = shift;
57              
58             my $access_token = $your_app->store->get("access_token");
59             my $expires_at = $your_app->store->get("expires_at");
60             my $refresh_token = $your_app->store->get("refresh_token");
61              
62             unless ($access_token) {
63             $your_app->show_reauthorize_page();
64             return;
65             }
66              
67             if ($expires_at < time()) {
68             $your_app->refresh_access_token();
69             return;
70             }
71              
72             my $req = HTTP::Request->new( GET => q{http://example.org/photo} );
73             $req->header( Authorization => sprintf(q{OAuth %s}, $access_token) );
74             my $agent = LWP::UserAgent->new;
75             my $res = $agent->request($req);
76             ...
77             }
78              
79              
80             =head1 DESCRIPTION
81              
82             OAuth 2.0 Federated Assertion Profile Client.
83              
84              
85             =head2 new( %params )
86              
87             =over 4
88              
89             =item id
90              
91             Client ID
92              
93             =item secret
94              
95             Client secret
96              
97             =item access_token_uri
98              
99             token endpoint uri on auth-server.
100              
101             =item refresh_token_uri
102              
103             refresh-token endpoint uri on auth-server.
104             if you omit this, access_token_uri is used instead.
105              
106             =item agent
107              
108             user agent. if you omit this, LWP::UserAgent's object is set by default.
109             You can use your custom agent or preset-agents.
110              
111             See also
112              
113             L
114             L
115             L
116              
117             =back
118              
119             =cut
120              
121             sub new {
122             my $class = shift;
123              
124             my %args = Params::Validate::validate(@_, {
125             id => 1,
126             secret => 1,
127             access_token_uri => { optional => 1 },
128             refresh_token_uri => { optional => 1 },
129             agent => { optional => 1 },
130             });
131              
132             my $self = bless {
133             id => undef,
134             secret => undef,
135             access_token_uri => undef,
136             refresh_token_uri => undef,
137             last_request => undef,
138             last_response => undef,
139             %args,
140             }, $class;
141              
142             unless ($self->{agent}) {
143             $self->{agent} = LWP::UserAgent->new;
144             $self->{agent}->agent(
145             join "/", __PACKAGE__, $OAuth::Lite2::VERSION);
146             }
147              
148             # $self->{format} ||= 'json';
149             $self->{response_parser} = OAuth::Lite2::Client::TokenResponseParser->new;
150              
151             return $self;
152             }
153              
154             =head2 get_access_token( %params )
155              
156             =over 4
157              
158             =item assertion
159              
160             =item type
161              
162             =item iss
163              
164             =item aud
165              
166             =item scope
167              
168             =back
169              
170             =cut
171              
172             sub get_access_token {
173             my $self = shift;
174              
175             my %args = Params::Validate::validate(@_, {
176             assertion => 1,
177             type => { optional => 1 },
178             iss => { optional => 1 },
179             aud => { optional => 1 },
180             scope => { optional => 1 },
181             uri => { optional => 1 },
182             use_basic_schema => { optional => 1 },
183             });
184              
185             unless (exists $args{uri}) {
186             $args{uri} = $self->{access_token_uri}
187             || Carp::croak "uri not found";
188             }
189              
190             my %params = (
191             grant_type => 'external_service',
192             assertion => $args{assertion},
193             );
194              
195             unless ($args{use_basic_schema}){
196             $params{client_id} = $self->{id};
197             $params{client_secret} = $self->{secret};
198             }
199              
200             # optional params
201             $params{type} = $args{type}
202             if $args{type};
203             $params{iss} = $args{iss}
204             if $args{iss};
205             $params{aud} = $args{aud}
206             if $args{aud};
207             $params{scope} = $args{scope}
208             if $args{scope};
209              
210             my $content = build_content(\%params);
211             my $headers = HTTP::Headers->new;
212             $headers->header("Content-Type" => q{application/x-www-form-urlencoded});
213             $headers->header("Content-Length" => bytes::length($content));
214             $headers->authorization_basic($self->{id}, $self->{secret})
215             if($args{use_basic_schema});
216             my $req = HTTP::Request->new( POST => $args{uri}, $headers, $content );
217              
218             my $res = $self->{agent}->request($req);
219             $self->{last_request} = $req;
220             $self->{last_response} = $res;
221              
222             my ($token, $errmsg);
223             try {
224             $token = $self->{response_parser}->parse($res);
225             } catch {
226             $errmsg = "$_";
227             };
228             return $token || $self->error($errmsg);
229              
230             }
231              
232             =head2 refresh_access_token( %params )
233              
234             =over 4
235              
236             =item refresh_token
237              
238             =back
239              
240             =cut
241              
242             sub refresh_access_token {
243             my $self = shift;
244              
245             my %args = Params::Validate::validate(@_, {
246             refresh_token => 1,
247             uri => { optional => 1 },
248             use_basic_schema => { optional => 1 },
249             });
250              
251             unless (exists $args{uri}) {
252             $args{uri} = $self->{access_token_uri}
253             || Carp::croak "uri not found";
254             }
255              
256             my %params = (
257             grant_type => 'refresh_token',
258             refresh_token => $args{refresh_token},
259             );
260              
261             unless ($args{use_basic_schema}){
262             $params{client_id} = $self->{id};
263             $params{client_secret} = $self->{secret};
264             }
265              
266             my $content = build_content(\%params);
267             my $headers = HTTP::Headers->new;
268             $headers->header("Content-Type" => q{application/x-www-form-urlencoded});
269             $headers->header("Content-Length" => bytes::length($content));
270             $headers->authorization_basic($self->{id}, $self->{secret})
271             if($args{use_basic_schema});
272             my $req = HTTP::Request->new( POST => $args{uri}, $headers, $content );
273              
274             my $res = $self->{agent}->request($req);
275             $self->{last_request} = $req;
276             $self->{last_response} = $res;
277              
278             my ($token, $errmsg);
279             try {
280             $token = $self->{response_parser}->parse($res);
281             } catch {
282             $errmsg = "$_";
283             };
284             return $token || $self->error($errmsg);
285             }
286              
287             =head2 last_request
288              
289             Returns a HTTP::Request object that is used
290             when you obtain or refresh access token last time internally.
291              
292             =head2 last_response
293              
294             Returns a HTTP::Response object that is used
295             when you obtain or refresh access token last time internally.
296              
297             =cut
298              
299             sub last_request { $_[0]->{last_request} }
300             sub last_response { $_[0]->{last_response} }
301              
302             =head1 AUTHOR
303              
304             Ryo Ito, Eritou.06@gmail.comE
305              
306             =head1 COPYRIGHT AND LICENSE
307              
308             Copyright (C) 2014 by Ryo Ito
309              
310             This library is free software; you can redistribute it and/or modify
311             it under the same terms as Perl itself, either Perl version 5.8.8 or,
312             at your option, any later version of Perl 5 you may have available.
313              
314             =cut
315              
316             1;