File Coverage

blib/lib/OIDC/Lite/Model/IDToken.pm
Criterion Covered Total %
statement 85 86 98.8
branch 27 28 96.4
condition 9 9 100.0
subroutine 17 17 100.0
pod 6 6 100.0
total 144 146 98.6


line stmt bran cond sub pod time code
1             package OIDC::Lite::Model::IDToken;
2 2     2   17464 use strict;
  2         4  
  2         80  
3 2     2   9 use warnings;
  2         2  
  2         54  
4 2     2   7 use base 'Class::Accessor::Fast';
  2         4  
  2         527  
5              
6 2     2   3180 use MIME::Base64 qw/encode_base64url decode_base64url/;
  2         1558  
  2         158  
7 2     2   1364 use JSON::WebToken qw/encode_jwt decode_jwt/;
  2         38234  
  2         180  
8 2     2   1187 use Params::Validate;
  2         10480  
  2         146  
9 2     2   12326 use Digest::SHA qw/sha256 sha384 sha512/;
  2         17503  
  2         226  
10 2     2   925 use OIDC::Lite::Util::JWT;
  2         3  
  2         60  
11              
12 2     2   9 use constant HALF_BITS_DENOMINATOR => 2 * 8;
  2         2  
  2         81  
13 2     2   7 use constant ALG_LEN => 2;
  2         3  
  2         61  
14 2     2   7 use constant BITS_LEN => 3;
  2         7  
  2         1217  
15              
16              
17             =head1 NAME
18              
19             OIDC::Lite::Model::IDToken - model class that represents ID token
20              
21             =head1 ACCESSORS
22              
23             =head2 header
24              
25             JWT Header
26              
27             =head2 payload
28              
29             JWT Payload
30              
31             =head2 key
32              
33             Key for JWT Signature
34              
35             =cut
36              
37             __PACKAGE__->mk_accessors(qw(
38             header
39             payload
40             key
41             token_string
42             alg
43             ));
44              
45             =head1 METHODS
46              
47             =head2 new( \%header, \%payload, $key )
48              
49             Constructor
50              
51             my $id_token = OIDC::Lite::Model::IDToken->new();
52             ...
53             my $id_token = OIDC::Lite::Model::IDToken->new(
54             header => \%header,
55             payload => \%payload,
56             key => $key,
57             alg => $alg,
58             );
59              
60             =cut
61              
62             sub new {
63 35     35 1 5045 my $class = shift;
64 35 100       105 my @args = @_ == 1 ? %{$_[0]} : @_;
  1         9  
65 35         885 my %params = Params::Validate::validate_with(
66             params => \@args,
67             spec => {
68             header => { optional => 1 },
69             payload => { optional => 1 },
70             key => { optional => 1 },
71             alg => { optional => 1 },
72             },
73             allow_extra => 0,
74             );
75              
76 35         228 my $self = bless \%params, $class;
77 35 100       78 unless($self->header){
78 2         19 my %header=();
79 2         5 $self->header(\%header);
80             }
81 35 100       180 unless($self->payload){
82 2         19 my %payload=();
83 2         6 $self->payload(\%payload);
84             }
85            
86 35         142 return $self;
87             }
88              
89             =head2 get_token_string()
90              
91             generate signature and return ID Token string.
92              
93             my $id_token_string = $id_token->get_token_string();
94              
95             =cut
96              
97             sub get_token_string {
98 6     6 1 1257 my ($self) = @_;
99              
100 6 100       13 $self->header->{typ} = q{JWT}
101             unless($self->header->{typ});
102 6 100       34 $self->header->{alg} = q{none}
103             unless($self->header->{alg});
104              
105             # generate token string
106 6         29 my $jwt = encode_jwt($self->payload, $self->key, $self->header->{alg}, $self->header);
107 6         12072 $self->token_string($jwt);
108 6         35 return $jwt;
109             }
110              
111             =head2 access_token_hash()
112              
113             generate signature and return ID Token string.
114              
115             $id_token->code_hash($access_token);
116              
117             =cut
118              
119             sub access_token_hash {
120 3     3 1 13 my ($self, $access_token_string) = @_;
121              
122 3 100 100     6 if($self->header->{alg} && $self->header->{alg} ne 'none')
123             {
124 1         10 my $bit = substr($self->header->{alg}, ALG_LEN, BITS_LEN);
125 1         6 my $len = $bit/HALF_BITS_DENOMINATOR;
126 1         7 my $sha = Digest::SHA->new($bit);
127 1         24 $sha->add($access_token_string);
128 1         12 $self->payload->{at_hash} = encode_base64url(substr($sha->digest, 0, $len));
129             }
130             }
131              
132             =head2 code_hash()
133              
134             Set Authorization Code Hash to ID Token.
135              
136             $id_token->code_hash($authorization_code);
137              
138             =cut
139              
140             sub code_hash {
141 3     3 1 58 my ($self, $authorization_code) = @_;
142              
143 3 100 100     5 if($self->header->{alg} && $self->header->{alg} ne 'none')
144             {
145 1         10 my $bit = substr($self->header->{alg}, ALG_LEN, BITS_LEN);
146 1         5 my $len = $bit/HALF_BITS_DENOMINATOR;
147 1         2 my $sha = Digest::SHA->new($bit);
148 1         10 $sha->add($authorization_code);
149 1         5 $self->payload->{c_hash} = encode_base64url(substr($sha->digest, 0, $len));
150             }
151             }
152              
153             =head2 load($token_string)
154              
155             load ID Token object from token string
156              
157             my $token_string = 'eyJhbGciOiJub25lIiwidHlwIjoiSldTIn0.eyJmb28iOiJiYXIifQ.';
158             my $id_token = OIDC::Lite::Model::IDToken->load($token_string);
159              
160             =cut
161              
162             sub load {
163 28     28 1 1139 my ($self, $token_string, $key, $alg) = @_;
164 28 100       59 return unless($token_string);
165              
166 27         61 my $header = OIDC::Lite::Util::JWT::header($token_string);
167 27         48 my $payload = OIDC::Lite::Util::JWT::payload($token_string);
168 27 100 100     89 return unless ( $header and $payload );
169              
170 24         50 my $id_token = OIDC::Lite::Model::IDToken->new(
171             header => $header,
172             payload => $payload,
173             key => $key,
174             alg => $alg,
175             );
176 24         46 $id_token->token_string($token_string);
177 24         101 return $id_token;
178             }
179              
180             =head2 verify()
181              
182             verify token signature.
183              
184             my $token_string = '...';
185             my $alg = 'HS256';
186             my $key = 'shared_secret_key';
187              
188             my $id_token = OIDC::Lite::Model::IDToken->load($token_string, $key, $alg);
189             unless($id_token->verify()){
190             # validation failed
191             }
192              
193             =cut
194              
195             sub verify {
196 24     24 1 100 my ($self) = @_;
197 24 100       34 return 0
198             unless($self->token_string);
199              
200 23 100       122 $self->key('')
201             unless($self->key);
202              
203 23 100       100 unless ($self->alg) {
204 12 50       40 if ($self->header->{alg}) {
205 12         45 $self->alg($self->header->{alg});
206             } else {
207 0         0 $self->alg('none');
208             }
209             }
210              
211 23         87 my $payload = undef;
212 23         23 eval{
213 23         36 $payload = decode_jwt($self->token_string, $self->key, 1, [$self->alg]);
214             };
215 23 100       3247 if($@){
216 14         118 return 0;
217             }
218 9         33 return (defined($payload));
219             }
220              
221             =head1 AUTHOR
222              
223             Ryo Ito, Eritou.06@gmail.comE
224              
225             =head1 COPYRIGHT AND LICENSE
226              
227             Copyright (C) 2012 by Ryo Ito
228              
229             This library is free software; you can redistribute it and/or modify
230             it under the same terms as Perl itself, either Perl version 5.8.8 or,
231             at your option, any later version of Perl 5 you may have available.
232              
233             =cut
234              
235             1;