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