Commit | Line | Data |
fc19db6b |
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 |