File Coverage

blib/lib/OIDC/Lite/Server/AuthorizationHandler.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package OIDC::Lite::Server::AuthorizationHandler;
2 1     1   929 use strict;
  1         2  
  1         32  
3 1     1   4 use warnings;
  1         2  
  1         21  
4              
5 1     1   4 use Params::Validate;
  1         1  
  1         45  
6 1     1   194 use OAuth::Lite2::Server::Error;
  0            
  0            
7              
8             my @DEFINED_DISPLAY_PARAMS = qw(
9             page
10             popup
11             touch
12             wap
13             );
14              
15             my @DEFINED_PROMPT_PARAMS = qw(
16             none
17             login
18             consent
19             select_account
20             );
21              
22             sub new {
23             my $class = shift;
24             my %args = Params::Validate::validate(@_, {
25             data_handler => 1,
26             response_types => 1,
27             });
28              
29             my $self = bless {
30             data_handler => $args{data_handler},
31             response_types => $args{response_types},
32             }, $class;
33             return $self;
34             }
35              
36             sub handle_request {
37             my ($self) = @_;
38             my $dh = $self->{data_handler};
39             my $req = $self->{data_handler}->request;
40              
41             # response_type
42             my $allowed_response_type = $self->{response_types};
43             my $response_type = $req->param("response_type")
44             or OAuth::Lite2::Server::Error::InvalidRequest->throw(
45             description => "'response_type' not found"
46             );
47              
48             my @response_type_for_sort = split(/\s/, $response_type);
49             @response_type_for_sort = sort @response_type_for_sort;
50             $response_type = join(' ', @response_type_for_sort);
51              
52             my %allowed_response_type_hash;
53             $allowed_response_type_hash{$_}++ foreach @$allowed_response_type;
54             OAuth::Lite2::Server::Error::InvalidRequest->throw(
55             description => "'response_type' not allowed"
56             ) unless (exists $allowed_response_type_hash{$response_type});
57            
58             # client_id
59             my $client_id = $req->param("client_id")
60             or OAuth::Lite2::Server::Error::InvalidClient->throw(
61             description => "'client_id' not found"
62             );
63              
64             OAuth::Lite2::Server::Error::InvalidClient->throw
65             unless ($dh->validate_client_by_id($client_id));
66              
67             OAuth::Lite2::Server::Error::InvalidRequest->throw(
68             description => "'response_type' not allowed for this 'client_id'"
69             ) unless ($dh->validate_client_for_authorization($client_id, $response_type));
70              
71             # redirect_uri
72             my $redirect_uri = $req->param("redirect_uri")
73             or OAuth::Lite2::Server::Error::InvalidRequest->throw(
74             description => "'redirect_uri' not found"
75             );
76            
77             OAuth::Lite2::Server::Error::InvalidRequest->throw(
78             description => "'redirect_uri' is invalid"
79             ) unless ($dh->validate_redirect_uri($client_id, $redirect_uri));
80              
81             # sever_state
82             # validate server_state for CSRF Protection
83             my $server_state = $req->param("server_state");
84             if ( $server_state ) {
85             OAuth::Lite2::Server::Error::InvalidServerState->throw(
86             description => "'server_state' is invalid"
87             ) unless $dh->validate_server_state($server_state, $client_id);
88             }
89              
90             # scope
91             my $scope = $req->param("scope");
92             OAuth::Lite2::Server::Error::InvalidScope->throw
93             unless ($dh->validate_scope($client_id, $scope));
94              
95             # scope and server_state
96             OAuth::Lite2::Server::Error::InvalidRequest->throw(
97             description => "This scope requires 'server_state'"
98             ) unless ($server_state || !$dh->require_server_state($scope));
99              
100             ## optional parameters
101             # nonce
102             my $nonce = $req->param("nonce");
103             if ( $response_type ne "token" && $response_type ne "code" && $response_type ne "code token") {
104             OAuth::Lite2::Server::Error::InvalidRequest->throw(
105             description => "nonce_required"
106             ) unless $nonce;
107             }
108              
109             # display
110             my $display = $req->param("display");
111             if ( $display ) {
112             my %defined_display_hash;
113             $defined_display_hash{$_}++ foreach @DEFINED_DISPLAY_PARAMS;
114             OAuth::Lite2::Server::Error::InvalidRequest->throw(
115             description => "'display' is invalid"
116             ) unless ( exists $defined_display_hash{$display} && $dh->validate_display($display));
117             }
118              
119             # prompt
120             my $prompt = $req->param("prompt");
121             if ( $prompt ) {
122             my %defined_prompt_hash;
123             $defined_prompt_hash{$_}++ foreach @DEFINED_PROMPT_PARAMS;
124             OAuth::Lite2::Server::Error::InvalidRequest->throw(
125             description => "'prompt' is invalid"
126             ) unless ( exists $defined_prompt_hash{$prompt} && $dh->validate_prompt($prompt));
127             }
128              
129             # max_age
130             OAuth::Lite2::Server::Error::InvalidRequest->throw(
131             description => "'max_age' is invalid"
132             ) unless ($dh->validate_max_age($req->parameters()));
133              
134             # ui_locales
135             my $ui_locales = $req->param("ui_locales");
136             OAuth::Lite2::Server::Error::InvalidRequest->throw(
137             description => "'ui_locales' is invalid"
138             ) unless ($dh->validate_ui_locales($ui_locales));
139              
140             # claims_locales
141             my $claims_locales = $req->param("claims_locales");
142             OAuth::Lite2::Server::Error::InvalidRequest->throw(
143             description => "'claims_locales' is invalid"
144             ) unless ($dh->validate_claims_locales($claims_locales));
145              
146             # id_token_hint
147             my $id_token_hint = $req->param("id_token_hint");
148             OAuth::Lite2::Server::Error::InvalidRequest->throw(
149             description => "'id_token_hint' is invalid"
150             ) unless ($dh->validate_id_token_hint($req->parameters));
151              
152             # login_hint
153             my $login_hint = $req->param("login_hint");
154             OAuth::Lite2::Server::Error::InvalidRequest->throw(
155             description => "'login_hint' is invalid"
156             ) unless ($dh->validate_login_hint($req->parameters));
157              
158             # acr_values
159             my $acr_values = $req->param("acr_values");
160             OAuth::Lite2::Server::Error::InvalidRequest->throw(
161             description => "'acr_values' is invalid"
162             ) unless ($dh->validate_acr_values($req->parameters()));
163              
164             # request
165             OAuth::Lite2::Server::Error::InvalidRequest->throw(
166             description => "'request' is invalid"
167             ) unless ($dh->validate_request($req->parameters()));
168              
169             # request_uri
170             OAuth::Lite2::Server::Error::InvalidRequest->throw(
171             description => "'request_uri' is invalid"
172             ) unless ($dh->validate_request_uri($req->parameters()));
173              
174             }
175              
176             sub allow {
177             my ($self) = @_;
178             my $dh = $self->{data_handler};
179             my $req = $self->{data_handler}->request;
180              
181             my @response_type_for_sort = split(/\s/, $req->param("response_type"));
182             @response_type_for_sort = sort @response_type_for_sort;
183             my $response_type = join(' ', @response_type_for_sort);
184             my $client_id = $req->param("client_id");
185             my $user_id = $dh->get_user_id_for_authorization();
186             my $scope = $req->param("scope");
187              
188             # create id_token
189             my $id_token = $dh->create_id_token();
190              
191             # create authInfo
192             my $auth_info = $dh->create_or_update_auth_info(
193             client_id => $client_id,
194             user_id => $user_id,
195             scope => $scope,
196             id_token => $id_token->get_token_string(),
197             );
198              
199             # create Access Token
200             my $access_token;
201             if (
202             $response_type eq 'token' ||
203             $response_type eq 'code token' ||
204             $response_type eq 'id_token token' ||
205             $response_type eq 'code id_token token')
206             {
207             $access_token = $dh->create_or_update_access_token(
208             auth_info => $auth_info,
209             );
210             }
211            
212             my $params = {};
213             # state
214             $params->{state} = $req->param("state") if($req->param("state"));
215            
216             # access token
217             if($access_token){
218             $id_token->access_token_hash($access_token->token);
219             $params->{access_token} = $access_token->token;
220             $params->{token_type} = q{Bearer};
221             $params->{expires_in} = $access_token->expires_in if($access_token->expires_in);
222             }
223              
224             # authorization code
225             if (
226             $response_type eq 'code' ||
227             $response_type eq 'code token' ||
228             $response_type eq 'code id_token' ||
229             $response_type eq 'code id_token token')
230             {
231             $params->{code} = $auth_info->code;
232             $id_token->code_hash($auth_info->code);
233             }
234              
235             # id_token
236             $params->{id_token} = $id_token->get_token_string()
237             if (
238             $response_type eq 'id_token' ||
239             $response_type eq 'code id_token' ||
240             $response_type eq 'id_token token' ||
241             $response_type eq 'code id_token token'
242             );
243              
244             # build response
245             my $res = {
246             redirect_uri => $req->param("redirect_uri"),
247             };
248              
249             # set data to query or fragment
250             if($response_type eq 'code'){
251             $res->{query} = $params;
252             }else{
253             $res->{fragment} = $params;
254             }
255             return $res;
256             }
257              
258             sub deny {
259             my ($self) = @_;
260             my $dh = $self->{data_handler};
261             my $req = $self->{data_handler}->request;
262              
263             my @response_type_for_sort = split(/\s/, $req->param("response_type"));
264             @response_type_for_sort = sort @response_type_for_sort;
265             my $response_type = join(' ', @response_type_for_sort);
266              
267             my $params = {
268             error => q{access_denied},
269             };
270            
271             $params->{state} = $req->param("state")
272             if($req->param("state"));
273              
274             my $res = {
275             redirect_uri => $req->param("redirect_uri"),
276             };
277              
278             # build response
279             if($response_type eq 'code'){
280             $res->{query} = $params;
281             }else{
282             $res->{fragment} = $params;
283             }
284             return $res;
285             }
286              
287             =head1 NAME
288              
289             OIDC::Lite::Server::AuthorizationHandler - handler for OpenID Connect Authorization request
290              
291             =head1 SYNOPSIS
292              
293             # At Authorization Endpoint
294             my $handler = OIDC::Lite::Server::AuthorizationHandler->new;
295             $handler->handle_request();
296              
297             # after user agreement
298             my $res;
299             if($allowed){
300             $res = $handler->allow();
301             }else{
302             $res = $handler->deny();
303             }
304             ...
305              
306             =head1 DESCRIPTION
307              
308             handler for OpenID Connect authorization request.
309              
310             =head1 METHODS
311              
312             =head2 handle_request( $req )
313              
314             Processes authorization request.
315             If there is error, L object is thrown.
316              
317             =head2 allow( $req )
318              
319             Returns authorization response params.
320              
321             =head2 deny( $req )
322              
323             Returns authorization error response params.
324              
325             =head1 AUTHOR
326              
327             Ryo Ito, Eritou.06@gmail.comE
328              
329             =head1 COPYRIGHT AND LICENSE
330              
331             Copyright (C) 2012 by Ryo Ito
332              
333             This library is free software; you can redistribute it and/or modify
334             it under the same terms as Perl itself, either Perl version 5.8.8 or,
335             at your option, any later version of Perl 5 you may have available.
336              
337             =cut
338              
339             1;