File Coverage

lib/Auth/YubiKey/Client/Web/Response.pm
Criterion Covered Total %
statement 9 47 19.1
branch 0 14 0.0
condition n/a
subroutine 3 9 33.3
pod 0 5 0.0
total 12 75 16.0


line stmt bran cond sub pod time code
1             package Auth::YubiKey::Client::Web::Response;
2             {
3             $Auth::YubiKey::Client::Web::Response::VERSION = '0.0.1';
4             }
5             {
6             $Auth::YubiKey::Client::Web::Response::DIST = 'Auth-YubiKey-Client-Web';
7             }
8 1     1   7 use Moo;
  1         2  
  1         10  
9              
10 1     1   378 use Digest::HMAC_SHA1 'hmac_sha1';
  1         2  
  1         56  
11 1     1   14 use MIME::Base64;
  1         3  
  1         2525  
12              
13             has request_apikey => (
14             is => 'ro',
15             required => 1,
16             );
17             has request_otp => (
18             is => 'ro',
19             required => 1,
20             );
21             has request_nonce => (
22             is => 'ro',
23             required => 1,
24             );
25             has request_response => (
26             is => 'ro',
27             required => 1,
28             );
29             has h => (
30             is => 'rw'
31             );
32             has t => (
33             is => 'rw'
34             );
35             has otp => (
36             is => 'rw'
37             );
38             has nonce => (
39             is => 'rw'
40             );
41             has sl => (
42             is => 'rw'
43             );
44             has status => (
45             is => 'rw'
46             );
47             has public_id => (
48             is => 'rw',
49             );
50             has datastring => (
51             is => 'rw',
52             );
53              
54             sub BUILDARGS {
55 0     0 0   my ( $class, @args ) = @_;
56 0 0         unshift @args, "attr1" if @args % 2 == 1;
57              
58             # store response keys (for later verifying the response signature 'h'
59 0           my %response_for;
60              
61             # run through the response blob; extract key=val data
62             # - add key, val to @args for object initialisation
63             # - store the key, val for later building and verifying the signature
64 0           foreach my $line (split(/\n/,{@args}->{request_response})) {
65 0 0         if ($line =~ /=/) {
66 0           $line =~ s/\s//g;
67 0           my ($key,$val) = split(/=/,$line,2);
68 0           $response_for{$key}=$val;
69 0           push @args, $key, $val;
70             }
71             }
72              
73             # store the generated response line
74 0           push @args, 'datastring', _build_datastring(\%response_for);
75              
76 0           return {@args};
77             }
78              
79             sub _build_datastring {
80 0     0     my $response_for = shift;
81 0           my @response_blobs;
82              
83 0           foreach my $key (sort keys %{$response_for}) {
  0            
84 0 0         next if $key eq 'h'; # don't include the signature itself
85 0           push @response_blobs,
86             sprintf('%s=%s',
87             $key,
88             $response_for->{$key}
89             )
90             ;
91             }
92            
93 0           return join('&', @response_blobs);
94             }
95              
96             sub BUILD {
97 0     0 0   my $self = shift;
98              
99 0 0         return if $self->status eq 'NO_SUCH_CLIENT';
100              
101 0 0         if ($self->otp ne $self->request_otp) {
102 0           $self->status('ERR_MSG_OTP');
103 0           return;
104             }
105              
106 0 0         if ($self->nonce ne $self->request_nonce) {
107 0           $self->status('ERR_MSG_NONCE');
108 0           return;
109             }
110              
111 0           my $hmac = encode_base64(
112             hmac_sha1(
113             $self->datastring,
114             decode_base64($self->request_apikey)
115             )
116             );
117 0           chomp $hmac;
118              
119 0 0         if ($self->h ne $hmac) {
120 0           $self->status('ERR_SIGNATURE_MISMATCH');
121 0           return;
122             }
123              
124             # Since the rest of the OTP is always 32 characters, the method to extract
125             # the identity is to remove 32 characters from the end and then use the
126             # remaining string, which should be 2-16 characters, as the YubiKey
127             # identity.
128             $self->public_id(
129 0           substr $self->otp, 0, -32
130             );
131             }
132              
133             sub is_success {
134 0     0 0   my $self = shift;
135 0           return !!($self->status eq 'OK');
136             }
137              
138             sub is_error {
139 0     0 0   my $self = shift;
140 0           return !!($self->status ne 'OK');
141             }
142              
143             sub parse_response {
144 0     0 0   my $self = shift;
145 0           my $response = shift;
146             }
147              
148             1;
149             # ABSTRACT: Response object when using the Yubico Web API
150              
151             =pod
152              
153             =head1 NAME
154              
155             Auth::YubiKey::Client::Web::Response - Response object when using the Yubico Web API
156              
157             =head1 VERSION
158              
159             version 0.0.1
160              
161             =head1 AUTHOR
162              
163             Chisel
164              
165             =head1 COPYRIGHT AND LICENSE
166              
167             This software is copyright (c) 2013 by Chisel Wright.
168              
169             This is free software; you can redistribute it and/or modify it under
170             the same terms as the Perl 5 programming language system itself.
171              
172             =cut
173              
174             __END__