File Coverage

blib/lib/Crypt/OpenToken/Token.pm
Criterion Covered Total %
statement 50 52 96.1
branch 16 18 88.8
condition 3 4 75.0
subroutine 11 12 91.6
pod 6 6 100.0
total 86 92 93.4


line stmt bran cond sub pod time code
1             package Crypt::OpenToken::Token;
2              
3 7     7   138376 use Moose;
  7         480846  
  7         67  
4 7     7   58810 use DateTime;
  7         3425411  
  7         390  
5 7     7   4487 use Date::Parse qw(str2time);
  7         51751  
  7         659  
6 7     7   145 use namespace::autoclean;
  7         19  
  7         80  
7              
8             # XXX: this could be a *lot* smarter; right now its just a glorified hashref
9             has 'version' => (
10             is => 'rw',
11             default => 1,
12             );
13             has 'cipher' => (is => 'rw');
14             has 'hmac' => (is => 'rw');
15             has 'iv_length' => (is => 'rw');
16             has 'iv' => (is => 'rw');
17             has 'key_length' => (is => 'rw');
18             has 'key' => (is => 'rw');
19             has 'payload_length' => (is => 'rw');
20             has 'payload' => (is => 'rw');
21             has 'data' => (is => 'rw', default => sub { {} });
22              
23             sub subject {
24 0     0 1 0 my $self = shift;
25 0         0 return $self->data->{subject};
26             }
27              
28             sub is_valid {
29 5     5 1 20127 my $self = shift;
30 5         12 my %args = @_;
31 5   100     27 my $skew = $args{clock_skew} || 5;
32 5         22 my $now = DateTime->now(time_zone => 'UTC');
33              
34 5         1609 my $not_before = $self->not_before;
35 5 100       18 if ($not_before) {
36 4         31 $not_before->subtract(seconds => $skew);
37 4 100       4273 return 0 if ($now < $not_before);
38             }
39              
40 3         154 my $not_on_or_after = $self->not_on_or_after;
41 3 50       12 if ($not_on_or_after) {
42 3         22 $not_on_or_after->add(seconds => $skew);
43 3 100       2958 return 0 if ($now >= $not_on_or_after);
44             }
45              
46 2         207 return 1;
47             }
48              
49             sub requires_renewal {
50 3     3 1 12619 my $self = shift;
51 3         8 my %args = @_;
52 3   50     19 my $skew = $args{clock_skew} || 5;
53 3         13 my $now = DateTime->now(time_zone => 'UTC');
54              
55 3         1013 my $renew_until = $self->renew_until;
56 3 100       10 if ($renew_until) {
57 2         17 $renew_until->add(seconds => $skew);
58 2 100       1803 return 1 if ($now > $renew_until);
59             }
60              
61 2         88 return 0;
62             }
63              
64             sub renew_until {
65 3     3 1 7 my $self = shift;
66 3         97 my $when = $self->data->{'renew-until'};
67 3 100       13 return $when ? $self->_parse_iso8601_to_datetime($when) : undef;
68             }
69              
70             sub not_before {
71 5     5 1 10 my $self = shift;
72 5         166 my $when = $self->data->{'not-before'};
73 5 100       21 return $when ? $self->_parse_iso8601_to_datetime($when) : undef;
74             }
75              
76             sub not_on_or_after {
77 3     3 1 5 my $self = shift;
78 3         95 my $when = $self->data->{'not-on-or-after'};
79 3 50       12 return $when ? $self->_parse_iso8601_to_datetime($when) : undef;
80             }
81              
82             sub _parse_iso8601_to_datetime {
83 9     9   20 my ($self, $gmt_str) = @_;
84 9         27 my $time_t = str2time($gmt_str);
85 9         2435 my $when = DateTime->from_epoch(epoch => $time_t, time_zone => 'UTC');
86 9         2992 return $when;
87             }
88              
89 7     7   4733 no Moose;
  7         16  
  7         72  
90              
91             1;
92              
93             =head1 NAME
94              
95             Crypt::OpenToken::Token - OpenToken data object
96              
97             =head1 SYNOPSIS
98              
99             use Crypt::OpenToken;
100              
101             # the OpenToken that you're looking to validate
102             my $token_string = '.....';
103              
104             # create factory based on shared password, and parse the token
105             my $factory = Crypt::OpenToken->new(password => 'abc123');
106             my $token = $factory->parse($token_string);
107              
108             # check if the token is still valid or requires renewal, based on
109             # an allowable time skew (in seconds)
110             my $skew = 5;
111              
112             if ($token->is_valid(clock_skew => $skew)) {
113             # token is valid, do something with the data
114             }
115              
116             if ($token->requires_renewal(clock_skew => $skew)) {
117             # token should be renewed by authenticating the User again
118             }
119              
120             =head1 DESCRIPTION
121              
122             This module implements the data representation of an OpenToken.
123              
124             =head1 METHODS
125              
126             =over
127              
128             =item subject()
129              
130             Returns the "subject" field as specified in the token data.
131              
132             =item is_valid(clock_skew => $allowable_skew)
133              
134             Checks to see if the OpenToken is valid, based on the standard fields
135             specified in the IETF draft specification.
136              
137             Can accept an optional C<clock_skew> parameter, which specifies the amount of
138             allowable clock skew (in seconds). Defaults to "5 seconds".
139              
140             =item requires_renewal(clock_skew => $allowable_skew)
141              
142             Checks to see if the OpenToken is past its "renew-until" timestamp, and
143             requires that it be renewed by re-authenticating the User. B<Not>
144             automatically renewed/reissued, but by B<re-authenticating> the User.
145              
146             Can accept an optional C<clock_skew> parameter, which specifies the amount of
147             allowable clock skew (in seconds). Defaults to "5 seconds".
148              
149             =item renew_until()
150              
151             Returns a C<DateTime> object representing the "renew-until" field specified in
152             the token data; the date/time at which the token B<must not> automatically be
153             re-issued without further authentication.
154              
155             If no "renew-until" field was specified, this method returns C<undef>.
156              
157             =item not_before()
158              
159             Returns a C<DateTime> object representing the "not-before" field specified in
160             the token data; the date/time when the token was created. A token received
161             before this date/time B<must> be rejected as invalid.
162              
163             If no "not-before" field was specified, this method returns C<undef>.
164              
165             =item not_on_or_after()
166              
167             Returns a C<DateTime> object representing the "not-on-or-after" field
168             specified in the token data; the time/time at which the token will expire. A
169             token received on or after this date/time B<must> be rejected as invalid.
170              
171             If no "not-on-or-after" field was specified, this method returns C<undef>.
172              
173             =back
174              
175             =head1 AUTHOR
176              
177             Graham TerMarsch (cpan@howlingfrog.com)
178              
179             =head1 COPYRIGHT & LICENSE
180              
181             C<Crypt::OpenToken> is Copyright (C) 2010, Socialtext, and is released under
182             the Artistic-2.0 license.
183              
184             =cut