oauth credential - initial upload
[catagits/Catalyst-Authentication-Credential-OAuth.git] / lib / Catalyst / Authentication / Credential / OAuth.pm
1 package Catalyst::Authentication::Credential::OAuth;
2 use strict;
3 use warnings;
4
5 use Moose;
6
7 has _config => ( is => 'rw' );
8 has realm => ( is => 'ro' );
9 has debug => ( is => 'rw' );
10 has defaults => ( is => 'rw' );
11 has provider => ( is => 'rw' );
12
13 our $VERSION = "0.01";
14
15 use Net::OAuth;
16 #$Net::OAuth::PROTOCOL_VERSION = Net::OAuth::PROTOCOL_VERSION_1_0A;
17 use HTTP::Request::Common;
18 use LWP::UserAgent;
19 use String::Random qw/ random_string /;
20
21 use Catalyst::Exception ();
22
23 sub new {
24         my ($class, $config, $c, $realm) = @_;
25
26         my $self = { _config => { 
27                 %{ $config },
28                 %{ $realm->{config} }
29         } };
30
31         bless $self, $class;
32
33         $self->debug( $self->_config->{debug} );
34
35         $self->defaults( {
36                 request_method => 'GET',
37                 signature_method => 'HMAC-SHA1',
38                 nonce => random_string( 'ccccccccccccccccccc' ),
39         } );
40
41         return $self;
42 }
43
44
45 sub authenticate {
46         my ($self, $c, $realm, $auth_info) = @_;
47         
48         Catalyst::Exception->throw( "Provider is not defined." ) 
49                 unless defined $self->_config->{ $auth_info->{oauth_provider} };
50
51         $self->provider( $self->_config->{ $auth_info->{oauth_provider} } );
52
53         $self->defaults( {
54                 %{ $self->defaults },
55                 timestamp => time,
56                 consumer_key => $self->provider->{key},
57                 consumer_secret => $self->provider->{secret},
58                 callback => $c->uri_for( $c->action )->as_string,
59         } );
60
61         $c->log_debug( "authenticate() called from " . $c->request->uri ) if $self->debug;
62
63         my $ua = LWP::UserAgent->new;
64         
65         if( $c->req->params->{oauth_token} ) {
66
67                 my $response = Net::OAuth->response( 'user auth' )->from_hash( $c->req->params );
68
69                 Catalyst::Exception->throw( "access_token_endpoint not defined" )
70                         unless $self->provider->{access_token_endpoint};
71
72                 my $request = Net::OAuth->request( 'access token' )->new(
73                         %{ $self->defaults },
74                         token => $response->token,
75                         token_secret => '',
76                         request_url => $self->provider->{access_token_endpoint},
77                 );
78
79                 $request->sign;
80
81                 my $ua_response = $ua->request( GET $request->to_url );
82
83                 Catalyst::Exception->throw( $ua_response->status_line.' '.$ua_response->content )
84                         unless $ua_response->is_success;
85                 
86                 $response = Net::OAuth->response( 'access token' )->from_post_body( $ua_response->content );
87
88                 my $user = +{ 
89                         token => $response->token,
90                         token_secret => $response->token_secret,
91                         extra_params => $response->extra_params
92                 };
93
94                 my $user_obj = $realm->find_user( $user, $c );
95
96                 return $user_obj if ref $user_obj;
97
98                 $c->log->debug( 'Verified OAuth identity failed' ) if $self->debug;
99
100                 return;
101         }
102         else {
103
104                 Catalyst::Exception->throw( "request_token_endpoint not defined" )
105                         unless $self->provider->{request_token_endpoint};
106                 
107                 my $request = Net::OAuth->request( 'request token' )->new(
108                         %{ $self->defaults },
109                         request_url => $self->provider->{request_token_endpoint}
110                 );
111
112                 $request->sign;
113
114                 my $ua_response = $ua->request( GET $request->to_url );
115                                 
116                 Catalyst::Exception->throw( $ua_response->status_line.' '.$ua_response->content )
117                         unless $ua_response->is_success;
118
119                 my $response = Net::OAuth->response( 'request token' )->from_post_body( $ua_response->content );
120
121                 Catalyst::Exception->throw( "user_auth_endpoint not defined" )
122                         unless $self->provider->{user_auth_endpoint};
123
124                 $request = Net::OAuth->request( 'user auth' )->new(
125                         %{ $self->defaults },
126                         token => $response->token,
127                 );
128
129                 $c->res->redirect( $request->to_url( $self->provider->{user_auth_endpoint} ) );
130         }
131
132 }
133
134
135
136 1;
137
138
139 __END__
140
141 =head1 NAME
142
143 Catalyst::Authentication::Credential::OAuth - OAuth credential for Catalyst::Plugin::Authentication framework.
144
145 =head1 VERSION
146
147 0.01
148
149 =head1 SYNOPSIS
150
151 In MyApp.pm
152
153  use Catalyst qw/
154       Authentication
155       Session
156       Session::Store::FastMmap
157       Session::State::Cookie
158  /;
159
160
161 In myapp.conf
162
163  <Plugin::Authentication>
164       default_realm     oauth
165       <realms>
166            <oauth>
167                 <credential>
168                      class      OAuth
169                 </credential>
170                 <example_provider>
171                         key my_app_key
172                         secret my_app_secret
173                         request_token_endpoint http://example.com/oauth/request_token
174                         access_token_endpoint http://example.com/oauth/access_token
175                         user_auth_endpoint http://example.com/oauth/authorize
176                 </example_provider>
177            </oauth>
178       </realms>
179 </Plugin::Authentication>
180
181
182 In controller code,
183
184   sub oauth : Local {
185        my ($self, $c) = @_;
186
187        if( $c->authenticate( { oauth_provider => 'example_provider' } ) ) {
188              #do something with $c->user
189        }
190   }
191
192
193
194 =head1 USER METHODS
195
196 =over 4
197
198 =item $c->user->token
199
200 =item $c->user->token_secret
201
202 =item $c->user->extra_params - whatever other parameters the provider sends back
203
204 =back
205
206 =head1 AUTHOR
207
208 Cosmin Budrica E<lt>cosmin@sinapticode.comE<gt>
209
210 Bogdan Lucaciu E<lt>bogdan@sinapticode.comE<gt>
211
212 =head1 COPYRIGHT
213
214 Copyright (c) 2009 Sinapticode. All rights reserved 
215
216 This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
217
218 =cut