File Coverage

blib/lib/OAuth/Lite/ServerUtil.pm
Criterion Covered Total %
statement 80 81 98.7
branch 24 34 70.5
condition 2 4 50.0
subroutine 18 18 100.0
pod 8 8 100.0
total 132 145 91.0


line stmt bran cond sub pod time code
1             package OAuth::Lite::ServerUtil;
2              
3 2     2   1913 use strict;
  2         5  
  2         67  
4 2     2   11 use warnings;
  2         4  
  2         66  
5              
6 2     2   12 use base 'Class::ErrorHandler';
  2         3  
  2         691  
7              
8 2         140 use OAuth::Lite::Util qw(
9             decode_param
10             create_signature_base_string
11 2     2   702 );
  2         4  
12 2     2   974 use OAuth::Lite::Problems qw(:all);
  2         4  
  2         434  
13 2     2   612 use List::MoreUtils qw(any none);
  2         13818  
  2         19  
14 2     2   2451 use UNIVERSAL::require;
  2         1187  
  2         21  
15 2     2   66 use Carp ();
  2         4  
  2         1907  
16              
17             =head1 NAME
18              
19             OAuth::Lite::ServerUtil - server side utility
20              
21             =head1 SYNOPSIS
22              
23             my $util = OAuth::Lite::ServerUtil->new;
24             $util->support_signature_method('HMAC-SHA1');
25             $util->allow_extra_params(qw/file size/);
26              
27             unless ($util->validate_params($oauth_params)) {
28             return $server->error(400, $util->errstr);
29             }
30              
31             $util->verify_signature(
32             method => $r->method,
33             params => $oauth_params,
34             url => $request_uri,
35             consumer_secret => $consumer->secret,
36             ) or return $server->error(401, $util->errstr);
37              
38             And see L source code.
39              
40             =head1 DESCRIPTION
41              
42             This module helps you to implement application that acts as OAuth Service Provider.
43              
44             =head1 PAY ATTENTION
45              
46             If you use OAuth 1.31 or older version, its has invalid way to normalize params.
47             (when there are two or more same key and they contain ASCII and non ASCII value)
48              
49             But the many services have already supported deprecated version,
50             and the correct way breaks backward compatibility.
51             So, from 1.32, supported both correct and deprecated method.
52              
53             use $OAuth::Lite::USE_DEPRECATED_NORMALIZER to switch behaviour.
54             Currently 1 is set by default to keep backward compatibility.
55              
56             use OAuth::Lite::ServerUtil;
57             use OAuth::Lite;
58              
59             $OAuth::Lite::USE_DEPRECATED_NORMALIZER = 0;
60             ...
61              
62              
63             =head1 METHODS
64              
65             =head2 new
66              
67             Constructor
68              
69             my $util = OAuth::Lite::ServerUtil->new;
70              
71             Set strict true by default, and it judge unsupported param as invalid when validating params.
72             You can build ServerUtil as non-strict mode, then it accepts unsupported parameters.
73              
74             my $util = OAuth::Lite::ServerUtil->new( strict => 0 );
75              
76             =cut
77              
78             sub new {
79 2     2 1 99 my $class = shift;
80 2         7 my %args = @_;
81 2 100       9 my $strict = exists $args{strict} ? $args{strict} : 1;
82 2         8 my $self = bless {
83             supported_signature_methods => {},
84             allowed_extra_params => [],
85             strict => $strict,
86             }, $class;
87 2         6 $self;
88             }
89              
90             =head2 allow_extra_param($param_name);
91              
92             When you validate oauth parameters, if an extra parameter
93             is included, the validation will fail.
94              
95             my $params = {
96             oauth_version => '1.0',
97             ...and other oauth parameters,
98             };
99             $params->{file} = "foo.jpg";
100              
101             # fail!
102             unless ($util->validate_params($params)) {
103             $your_app->error( $util->errstr );
104             }
105              
106             So, if you want allow extra parameter, use this method.
107              
108             $util->allow_extra_param('file');
109              
110             my $params = {
111             oauth_version => '1.0',
112             ...and other oauth parameters,
113             };
114             $params->{file} = "foo.jpg";
115              
116             # Now this results successfully.
117             unless ($util->validate_params($params)) {
118             $your_app->error( $util->errstr );
119             }
120              
121             =cut
122              
123             sub allow_extra_param {
124 3     3 1 7 my ($self, $param) = @_;
125 3         5 push @{ $self->{allowed_extra_params} }, $param;
  3         9  
126             }
127              
128             =head2 allow_extra_params($param1, $param2, ...)
129              
130             You can allow multiple extra parameters at once.
131              
132             $util->allow_extra_params(qw/file size/);
133              
134             =cut
135              
136             sub allow_extra_params {
137 1     1 1 3 my $self = shift;
138 1         7 $self->allow_extra_param($_) for @_;
139             }
140              
141             =head2 support_signature_method($method_class_name);
142              
143             Set the signature method class's name that your server can supports.
144              
145             $util->support_signature_method('HMAC_SHA1');
146              
147             This method requires indicated signature method class inside.
148             So, you should install OAuth::Lite::SignatureMethod::$method_class_name beforehand.
149             For example, when your choise is HMAC_SHA1, you need to have
150             OAuth::Lite::SignatureMethod::HMAC_SHA1 installed in your server.
151              
152             =cut
153              
154             sub support_signature_method {
155 5     5 1 336 my ($self, $method_class) = @_;
156 5         20 $method_class =~ s/-/_/g;
157 5         19 my $class = join('::', 'OAuth::Lite::SignatureMethod', $method_class);
158 5 100       36 $class->require or Carp::croak sprintf(q{Couldn't require class, %s}, $class);
159 3         103 $self->{supported_signature_methods}{$class->method_name} = $class;
160             }
161              
162             =head2 support_signature_methods($method1, $method2, ...);
163              
164             You can set multiple signature method class at once.
165              
166             $util->support_signature_methods(qw/HMAC_SHA1 RSA_SHA1/);
167              
168             =cut
169              
170             sub support_signature_methods {
171 2     2 1 1042 my $self = shift;
172 2         9 $self->support_signature_method($_) for @_;
173             }
174              
175             =head2 validate_params($params, [$check_token]);
176              
177             Check if the request includes all required params
178             and doesn't include unsupported params.
179             It doesn't check unsupported params when working on strict mode.
180              
181             unless ($util->validate_params($params)) {
182             $your_app->error( $util->errstr );
183             }
184              
185             When the request is to exchange tokens or to access to protected resources,
186             pass 1 for second argument. This flag indicates that oauth_token param is needed.
187              
188             unless ($util->validate_params($params, 1)) {
189             $your_app->error( $util->errstr );
190             }
191              
192             =cut
193              
194             sub validate_params {
195 6     6 1 909 my ($self, $origin_params, $check_token) = @_;
196 6         41 my $params = {%$origin_params}; #copy
197 6 50       20 delete $params->{oauth_consumer_key} or return $self->error(PARAMETER_ABSENT);
198 6 50       14 delete $params->{oauth_nonce} or return $self->error(PARAMETER_ABSENT);
199 6 50       13 delete $params->{oauth_timestamp} or return $self->error(PARAMETER_ABSENT);
200 6 50       13 delete $params->{oauth_signature_method} or return $self->error(PARAMETER_ABSENT);
201 6 50       14 delete $params->{oauth_signature} or return $self->error(PARAMETER_ABSENT);
202 6         9 delete $params->{oauth_version};
203 6 100       12 if ($check_token) {
204 4 100       17 delete $params->{oauth_token} or return $self->error(PARAMETER_ABSENT);
205             }
206 5 100       16 if ( $self->{strict} ) {
207 4         12 my @extra_params = keys %$params;
208 4         7 my @allowed = @{ $self->{allowed_extra_params} };
  4         10  
209 4         10 for my $extra ( @extra_params ) {
210 11 100   24   40 if (none { $extra eq $_ } @allowed) {
  24         53  
211 2         8 return $self->error(PARAMETER_REJECTED);
212             }
213             }
214             }
215 3         18 1;
216             }
217              
218             =head2 validate_signature_method($method_name)
219              
220             unless ($util->validate_signature_method('HMAC-SHA1')) {
221            
222             $your_app->error(qq/Unsupported signature method/);
223             ...
224             }
225              
226             =cut
227              
228             sub validate_signature_method {
229 8     8 1 613 my ($self, $method) = @_;
230 8 50       21 return unless $method;
231 8     17   40 any { $_ eq $method } keys %{$self->{supported_signature_methods}};
  17         56  
  8         40  
232             }
233              
234             =head2 verify_signature(%args)
235              
236             =over 4
237              
238             =item method - HTTP request method
239              
240             =item params - parameters hash reference
241              
242             =item url - requested uri
243              
244             =item consumer_secret - consumer secret value(optional)
245              
246             =item token_secret - token secret value(optional)
247              
248             =back
249              
250             # you can omit consumer_secret and token_secret if you don't need them.
251             $util->verify_signature(
252             method => $r->method,
253             params => $params,
254             url => $requested_uri,
255             consumer_secret => $consumer_secret,
256             token_secret => $token_secret,
257             ) or die $utl->errstr;
258              
259             =cut
260              
261             sub verify_signature {
262 2     2 1 295 my ($self, %args) = @_;
263              
264 2 50       7 my $http_method = $args{method} or Carp::croak(qq/method not found/);
265 2 50       6 my $url = $args{url} or Carp::croak(qq/url not found/);
266 2 50       7 my $params = $args{params} or Carp::croak(qq/params not found/);
267              
268 2   50     4 my $consumer_secret = $args{consumer_secret} || '';
269 2   50     10 my $token_secret = $args{token_secret} || '';
270 2         3 my $signature_method = $params->{oauth_signature_method};
271 2         17 my $signature = $params->{oauth_signature};
272              
273 2         7 my $base_string = create_signature_base_string($http_method, $url, $params);
274 2 50       8 unless ($self->validate_signature_method($signature_method)) {
275 0         0 return $self->error(SIGNATURE_METHOD_REJECTED);
276             }
277 2         9 my $method_class = $self->{supported_signature_methods}{$signature_method};
278 2         12 my $method = $method_class->new(
279             consumer_secret => $consumer_secret,
280             token_secret => $token_secret,
281             );
282 2 100       9 unless ($method->verify($base_string, $signature)) {
283 1         5 return $self->error(SIGNATURE_INVALID);
284             }
285 1         11 1;
286             }
287              
288             =head1 SEE ALSO
289              
290             L
291              
292             =head1 AUTHOR
293              
294             Lyo Kato, C
295              
296             =head1 COPYRIGHT AND LICENSE
297              
298             This library is free software; you can redistribute it and/or modify
299             it under the same terms as Perl itself, either Perl version 5.8.6 or,
300             at your option, any later version of Perl 5 you may have available.
301              
302             =cut
303              
304             1;