File Coverage

blib/lib/OAuth/Lite2/Server/Endpoint/Token.pm
Criterion Covered Total %
statement 19 22 86.3
branch n/a
condition n/a
subroutine 7 8 87.5
pod n/a
total 26 30 86.6


line stmt bran cond sub pod time code
1             package OAuth::Lite2::Server::Endpoint::Token;
2 7     7   17643 use strict;
  7         17  
  7         227  
3 7     7   34 use warnings;
  7         15  
  7         337  
4             use overload
5 0     0   0 q(&{}) => sub { shift->psgi_app },
6 7     7   38 fallback => 1;
  7         14  
  7         89  
7              
8 7     7   669 use Try::Tiny qw/try catch/;
  7         15  
  7         425  
9 7     7   6126 use Plack::Request;
  7         517263  
  7         218  
10 7     7   74 use Params::Validate;
  7         17  
  7         506  
11 7     7   3642 use OAuth::Lite2::Formatters;
  0            
  0            
12             use OAuth::Lite2::Server::Error;
13             use OAuth::Lite2::Server::GrantHandlers;
14             use OAuth::Lite2::ParamMethod::AuthHeader;
15              
16             sub new {
17             my $class = shift;
18             my %args = Params::Validate::validate(@_, {
19             data_handler => 1,
20             error_uri => { optional => 1 },
21             });
22             my $self = bless {
23             data_handler => $args{data_handler},
24             error_uri => $args{error_uri},
25             grant_handlers => {},
26             }, $class;
27             return $self;
28             }
29              
30             sub support_grant_type {
31             my ($self, $type) = @_;
32             my $handler = OAuth::Lite2::Server::GrantHandlers->get_handler($type)
33             or OAuth::Lite2::Server::Error::UnsupportedGrantType->throw;
34             $self->{grant_handlers}{$type} = $handler;
35             }
36              
37             sub support_grant_types {
38             my $self = shift;
39             $self->support_grant_type($_) for @_;
40             }
41              
42             sub data_handler {
43             my ($self, $handler) = @_;
44             $self->{data_handler} = $handler if $handler;
45             $self->{data_handler};
46             }
47              
48             sub psgi_app {
49             my $self = shift;
50             return $self->{psgi_app}
51             ||= $self->compile_psgi_app;
52             }
53              
54             sub compile_psgi_app {
55             my $self = shift;
56              
57             my $app = sub {
58             my $env = shift;
59             my $req = Plack::Request->new($env);
60             my $res; try {
61             $res = $self->handle_request($req);
62             } catch {
63             # Internal Server Error
64             warn $_;
65             $res = $req->new_response(500);
66             };
67             return $res->finalize;
68             };
69              
70             return $app;
71             }
72              
73             sub handle_request {
74             my ($self, $request) = @_;
75              
76             # from draft-v8, format is specified to JSON only.
77             my $format = "json";
78             # my $format = $request->param("format") || "json";
79             my $formatter = OAuth::Lite2::Formatters->get_formatter_by_name($format)
80             || OAuth::Lite2::Formatters->get_formatter_by_name("json");
81              
82             my $res = try {
83              
84             my $type = $request->param("grant_type")
85             or OAuth::Lite2::Server::Error::InvalidRequest->throw(
86             description => q{'grant_type' not found},
87             );
88              
89             my $handler = $self->{grant_handlers}{$type}
90             or OAuth::Lite2::Server::Error::UnsupportedGrantType->throw;
91              
92             my $data_handler = $self->{data_handler}->new(request => $request);
93              
94             # If Authorization Header is set, it is decoded and overwrite form encoded parameters.
95             my $parser = OAuth::Lite2::ParamMethod::AuthHeader->new;
96             my $header_credentials = $parser->basic_credentials($request);
97              
98             my $client_id = ($header_credentials->{client_id}) ? $header_credentials->{client_id} : $request->param("client_id");
99             OAuth::Lite2::Server::Error::InvalidRequest->throw(
100             description => q{'client_id' not found},
101             )unless($client_id);
102              
103             my $client_secret = ($header_credentials->{client_secret}) ? $header_credentials->{client_secret} : $request->param("client_secret");
104              
105             # The grant type which are defined in spec require client authentication,
106             # but additional grant type may not.
107             if ( $handler->is_required_client_authentication ) {
108             OAuth::Lite2::Server::Error::InvalidRequest->throw(
109             description => q{'client_secret' not found},
110             )unless($client_secret);
111             }
112              
113             $data_handler->validate_client($client_id, $client_secret, $type)
114             or OAuth::Lite2::Server::Error::InvalidClient->throw;
115              
116             $handler->{client_id} = $client_id;
117             $handler->{client_secret} = $client_secret;
118             my $result = $handler->handle_request($data_handler);
119              
120             return $request->new_response(200,
121             [ "Content-Type" => $formatter->type,
122             "Cache-Control" => "no-store" ],
123             [ $formatter->format($result) ]);
124              
125             } catch {
126              
127             if ($_->isa("OAuth::Lite2::Server::Error")) {
128              
129             my $error_params = { error => $_->type };
130             $error_params->{error_description} = $_->description
131             if $_->description;
132             $error_params->{error_uri} = $self->{error_uri}
133             if $self->{error_uri};
134              
135             return $request->new_response($_->code,
136             [ "Content-Type" => $formatter->type,
137             "Cache-Control" => "no-store" ],
138             [ $formatter->format($error_params) ]);
139              
140             } else {
141              
142             die $_;
143              
144             }
145              
146             };
147             }
148              
149             =head1 NAME
150              
151             OAuth::Lite2::Server::Endpoint::Token - token endpoint PSGI application
152              
153             =head1 SYNOPSIS
154              
155             token_endpoint.psgi
156              
157             use strict;
158             use warnings;
159             use Plack::Builder;
160             use OAuth::Lite2::Server::Endpoint::Token;
161             use MyDataHandlerClass;
162              
163             builder {
164             my $app = OAuth::Lite2::Server::Endpoint::Token->new(
165             data_handler => 'MyDataHandlerClass',
166             );
167             $app->support_grant_types(qw(authorization_code refresh_token));
168             $app;
169             };
170              
171             =head1 DESCRIPTION
172              
173             The instance of this class behaves as a PSGI application (subroutine reference).
174             This is for the OAuth 2.0 token-endpoint.
175              
176             The first thing you need to do is make your custom class, which inherits L, and then setup the PSGI file referencing it.
177              
178             =head1 METHODS
179              
180             =head2 new( %params )
181              
182             =over 4
183              
184             =item data_handler
185              
186             The name of your custom class that inherits the L package.
187              
188             =item error_uri
189              
190             Optional. This URI indicates the page that should be presented on an error. This will be included in error responses.
191              
192             =back
193              
194             =head2 support_grant_type( $type )
195              
196             Indicates support for a specific grant type. This does not remove previously supported grant types. The available values are:
197              
198             =over 4
199              
200             =item authorization_code
201              
202             =item password
203              
204             =item client_credentials
205              
206             =item refresh_token
207              
208             =back
209              
210             =head2 support_grant_types( @types )
211              
212             Allows specification of multiple grant types at once. This is equivalent to calling support_grant_type once for each type in the list. The available values are:
213              
214             =over 4
215              
216             =item authorization_code
217              
218             =item password
219              
220             =item client_credentials
221              
222             =item refresh_token
223              
224             =back
225              
226             =head2 data_handler
227              
228             This returns the class that inherits the L package. This is defined by the data_handler parameter of the constructor.
229              
230             =head2 psgi_app
231              
232             This returns a PSGI application.
233              
234             =head2 compile_psgi_app
235              
236             This will compile the PSGI application.
237              
238             =head2 handle_request( $req )
239              
240             This will parse the access token request and call the data handler's method.
241              
242             =head1 TEST
243              
244             You can test with L and some of the client classes.
245              
246             my $app = OAuth::Lite2::Server::Endpoint::Token->new(
247             data_handler => 'MyDataHandlerClass',
248             );
249             $app->support_grant_types(qw(authorization_code refresh_token));
250             my $mock_agent = OAuth::Lite2::Agent::PSGIMock->new(app => $app);
251             my $client = OAuth::Lite2::Client::UsernameAndPassword->new(
252             id => q{my_client_id},
253             secret => q{my_client_secret},
254             agent => $mock_agent,
255             );
256             my $token = $client->get_access_token(
257             username => q{foo},
258             password => q{bar},
259             );
260             ok($token);
261             is($token->access_token, q{access_token_value});
262              
263             =head1 AUTHOR
264              
265             Ryo Ito, Eritou.06@gmail.comE
266              
267             Lyo Kato, Elyo.kato@gmail.comE
268              
269             =head1 COPYRIGHT AND LICENSE
270              
271             Copyright (C) 2010 by Lyo Kato
272              
273             This library is free software; you can redistribute it and/or modify
274             it under the same terms as Perl itself, either Perl version 5.8.8 or,
275             at your option, any later version of Perl 5 you may have available.
276              
277             =cut
278              
279             1;