root/branches/release-39/extlib/Net/OAuth/Message.pm @ 2528

Revision 2528, 6.5 kB (checked in by fumiakiy, 18 months ago)

Updated Net::OAuth modules to the latest version. BugId:80041

Line 
1package Net::OAuth::Message;
2use warnings;
3use strict;
4use base qw/Class::Data::Inheritable Class::Accessor/;
5use URI::Escape;
6use UNIVERSAL::require;
7
8sub add_required_message_params {
9    my $class = shift;
10    $class->required_message_params([@{$class->required_message_params}, @_]);
11        $class->all_message_params([@{$class->all_message_params}, @_]);
12        $class->all_params([@{$class->all_params}, @_]);
13    $class->mk_accessors(@_);
14}
15
16sub add_optional_message_params {
17    my $class = shift;
18    $class->optional_message_params([@{$class->optional_message_params}, @_]);
19        $class->all_message_params([@{$class->all_message_params}, @_]);
20        $class->all_params([@{$class->all_params}, @_]);
21    $class->mk_accessors(@_);
22}
23
24sub add_required_api_params {
25    my $class = shift;
26    $class->required_api_params([@{$class->required_api_params}, @_]);
27        $class->all_api_params([@{$class->all_api_params}, @_]);
28        $class->all_params([@{$class->all_params}, @_]);
29    $class->mk_accessors(@_);
30}
31
32sub add_to_signature {
33    my $class = shift;
34    $class->signature_elements([@{$class->signature_elements}, @_]);
35}
36
37sub new {
38    my $proto = shift;
39    my $class = ref $proto || $proto;
40        my %params = @_;
41        my $self = bless \%params, $class;
42        $self->{extra_params} ||= {};
43        $self->{version} ||= '1.0';
44    $self->check;
45    return $self;
46}
47
48sub check {
49    my $self = shift;
50    foreach my $k (@{$self->required_message_params}, @{$self->required_api_params}) {
51        if (not defined $self->{$k}) {
52            die "Missing required parameter '$k'";
53        }
54    }
55    if ($self->{extra_params} and $self->allow_extra_params) {
56        foreach my $k (keys %{$self->{extra_params}}) {
57            if ($k =~ /^oauth_/) {
58                die "Parameter '$k' not allowed in arbitrary params"
59            }
60        }
61    }
62}
63
64sub encode {
65    my $str = shift;
66    $str = "" unless defined $str;
67    return URI::Escape::uri_escape_utf8($str,'^\w.~-');
68}
69
70sub decode {
71    my $str = shift;
72    return uri_unescape($str);
73}
74
75sub allow_extra_params {1}
76
77sub sign_message {0}
78
79sub gather_message_parameters {
80    my $self = shift;
81    my %opts = @_;
82    $opts{quote} = "" unless defined $opts{quote};
83    $opts{params} ||= [];
84    my %params;
85    foreach my $k (@{$self->required_message_params}, @{$self->optional_message_params}, @{$opts{add}}) {
86        next if $k eq 'signature' and (!$self->sign_message or !grep ($_ eq 'signature', @{$opts{add}}));
87        $params{"oauth_$k"} = $self->$k;
88    }
89    if ($self->{extra_params} and !$opts{no_extra} and $self->allow_extra_params) {
90        foreach my $k (keys %{$self->{extra_params}}) {
91            $params{$k} = $self->{extra_params}{$k};
92        }
93    }
94    if ($opts{hash}) {
95        return \%params;
96    }
97    my @pairs;
98    while (my ($k,$v) = each %params) {
99        push @pairs, join('=', encode($k), $opts{quote} . encode($v) . $opts{quote});
100    }
101    return sort(@pairs); # sort not required here but makes module more testable
102}
103
104sub normalized_message_parameters {
105    my $self = shift;
106    return join('&',  $self->gather_message_parameters);
107}
108
109sub signature_base_string {
110    my $self = shift;
111    return join('&', map(encode($self->$_), @{$self->signature_elements}));
112}
113
114sub sign {
115    my $self = shift;
116    my $class = $self->_signature_method_class;
117    $self->signature($class->sign($self, @_));
118}
119
120sub verify {
121    my $self = shift;
122    my $class = $self->_signature_method_class;
123    return $class->verify($self, @_);
124}
125
126sub _signature_method_class {
127    my $self = shift;
128    (my $signature_method = $self->signature_method) =~ s/\W+/_/g;
129    my $klass = 'Net::OAuth::SignatureMethod::' . $signature_method;
130    $klass->require or die "Unable to load $signature_method plugin";
131    return $klass;
132}
133
134sub to_authorization_header {
135    my $self = shift;
136    my $realm = shift;
137    my $sep = shift || ",";
138    return join($sep, "OAuth realm=\"$realm\"",
139        $self->gather_message_parameters(quote => '"', add => [qw/signature/], no_extra => 1));
140}
141
142sub from_authorization_header {
143    my $proto = shift;
144    my $class = ref $proto || $proto;
145    my @header = split /[\s]*,[\s]*/, shift;
146    shift @header;
147    return $class->_from_pairs(\@header, @_)
148}
149
150sub _from_pairs() {
151        my $class = shift;
152        my $pairs = shift;
153        if (ref $pairs ne 'ARRAY') {
154                die 'Expected an array!';
155        }
156        my %params;
157        foreach my $pair (@$pairs) {
158        my ($k,$v) = split /=/, $pair;
159        if (defined $k and defined $v) {
160            $v =~ s/(^"|"$)//g;
161            ($k,$v) = map decode($_), $k, $v;
162            $params{$k} = $v;
163        }
164    }
165    return $class->from_hash(\%params, @_);
166}
167
168sub from_hash {
169    my $proto = shift;
170    my $class = ref $proto || $proto;
171    my $hash = shift;
172        if (ref $hash ne 'HASH') {
173                die 'Expected a hash!';
174        }
175    my %api_params = @_;
176    my %msg_params;
177        foreach my $k (keys %$hash) {
178                if ($k =~ s/^oauth_//) {
179                        if (!grep ($_ eq $k, @{$class->all_message_params})) {
180                                die "Parameter oauth_$k not valid for a message of type $class\n";
181                        }
182                        else {
183                                $msg_params{$k} = $hash->{"oauth_$k"};
184                        }
185                }
186                else {
187                        $msg_params{extra_params}->{$k} = $hash->{$k};
188                }
189        }
190    return $class->new(%msg_params, %api_params);
191}
192
193sub from_url {
194        my $proto = shift;
195    my $class = ref $proto || $proto;
196    my $url = shift;
197        require URI;
198        require URI::QueryParam;
199    if (!UNIVERSAL::isa($url, 'URI')) {
200                $url = URI->new($url);
201        }
202        return $class->from_hash($url->query_form_hash, @_);
203}
204
205sub to_post_body {
206    my $self = shift;
207    return join('&', $self->gather_message_parameters(add => [qw/signature/]));
208}
209
210sub from_post_body {
211        my $proto = shift;
212    my $class = ref $proto || $proto;
213    my @pairs = split '&', shift;
214        return $class->_from_pairs(\@pairs, @_);
215}
216
217sub to_hash {
218    my $self = shift;
219    return $self->gather_message_parameters(hash => 1, add => [qw/signature/]);
220}
221
222sub to_url {
223        my $self = shift;
224        my $uri = shift;
225        if (!defined $uri and $self->can('request_url') and defined $self->request_url) {
226                $uri = $self->request_url;
227        }
228        if (defined $uri) {
229                require URI;
230                require URI::QueryParam;
231                $uri = URI->new("$uri");
232                my $params = $self->to_hash;
233                foreach my $k (sort keys %$params) {
234                        $uri->query_param($k, $params->{$k});
235                }
236                return $uri;
237        }
238        else {
239                return $self->to_post_body;
240        }
241}
242
243=head1 NAME
244
245Net::OAuth::Message - base class for OAuth messages
246
247=head1 SEE ALSO
248
249L<http://oauth.net>
250
251=head1 AUTHOR
252
253Keith Grennan, C<< <kgrennan at cpan.org> >>
254
255=head1 COPYRIGHT & LICENSE
256
257Copyright 2007 Keith Grennan, all rights reserved.
258
259This program is free software; you can redistribute it and/or modify it
260under the same terms as Perl itself.
261
262=cut
263
2641;
Note: See TracBrowser for help on using the browser.