File Coverage

blib/lib/Crypt/OpenToken/Token.pm
Criterion Covered Total %
statement 47 49 95.9
branch 16 18 88.8
condition 3 4 75.0
subroutine 10 11 90.9
pod 6 6 100.0
total 82 88 93.1


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