Commit | Line | Data |
06675d2e |
1 | #!/usr/bin/perl |
2 | |
3 | package Catalyst::Plugin::Authentication; |
4 | |
b003080b |
5 | use base qw/Class::Accessor::Fast Class::Data::Inheritable/; |
06675d2e |
6 | |
b003080b |
7 | BEGIN { |
7bb06c91 |
8 | __PACKAGE__->mk_accessors(qw/_user/); |
96777f3a |
9 | __PACKAGE__->mk_classdata($_) for qw/_auth_stores _auth_store_names/; |
b003080b |
10 | } |
06675d2e |
11 | |
12 | use strict; |
13 | use warnings; |
14 | |
96777f3a |
15 | use Tie::RefHash; |
12dae309 |
16 | use Class::Inspector; |
96777f3a |
17 | |
e145babc |
18 | #BEGIN { |
19 | # require constant; |
20 | # constant->import(have_want => eval { require Want }); |
21 | #} |
a1e5bd36 |
22 | |
e09a839c |
23 | our $VERSION = "0.02"; |
c7c003d3 |
24 | |
06675d2e |
25 | sub set_authenticated { |
26 | my ( $c, $user ) = @_; |
27 | |
28 | $c->user($user); |
e300c5b6 |
29 | $c->request->{user} = $user; # compatibility kludge |
06675d2e |
30 | |
31 | if ( $c->isa("Catalyst::Plugin::Session") |
96777f3a |
32 | and $c->config->{authentication}{use_session} |
12dae309 |
33 | and $user->supports("session") ) |
06675d2e |
34 | { |
12dae309 |
35 | $c->save_user_in_session($user); |
06675d2e |
36 | } |
55395841 |
37 | |
4fbe2e14 |
38 | $c->NEXT::set_authenticated($user); |
06675d2e |
39 | } |
40 | |
7bb06c91 |
41 | sub user { |
e300c5b6 |
42 | my $c = shift; |
7bb06c91 |
43 | |
e300c5b6 |
44 | if (@_) { |
45 | return $c->_user(@_); |
46 | } |
7bb06c91 |
47 | |
e300c5b6 |
48 | my $user = $c->_user; |
7bb06c91 |
49 | |
e300c5b6 |
50 | if ( $user and !Scalar::Util::blessed($user) ) { |
cde43a59 |
51 | # return 1 if have_want() && Want::want("BOOL"); |
e300c5b6 |
52 | return $c->auth_restore_user($user); |
53 | } |
7bb06c91 |
54 | |
e300c5b6 |
55 | return $user; |
7bb06c91 |
56 | } |
57 | |
ce0b058d |
58 | sub user_exists { |
59 | my $c = shift; |
60 | return defined($c->_user); |
61 | } |
62 | |
12dae309 |
63 | sub save_user_in_session { |
e300c5b6 |
64 | my ( $c, $user ) = @_; |
12dae309 |
65 | |
66 | my $store = $user->store || ref $user; |
67 | $c->session->{__user_store} = $c->get_auth_store_name($store) || $store; |
68 | $c->session->{__user} = $user->for_session; |
69 | } |
70 | |
06675d2e |
71 | sub logout { |
72 | my $c = shift; |
73 | |
74 | $c->user(undef); |
b003080b |
75 | |
76 | if ( $c->isa("Catalyst::Plugin::Session") |
77 | and $c->config->{authentication}{use_session} ) |
78 | { |
96777f3a |
79 | delete @{ $c->session }{qw/__user __user_store/}; |
b003080b |
80 | } |
06675d2e |
81 | } |
82 | |
7d0922d8 |
83 | sub get_user { |
84 | my ( $c, $uid ) = @_; |
85 | |
86 | if ( my $store = $c->default_auth_store ) { |
87 | return $store->get_user($uid); |
88 | } |
89 | else { |
90 | Catalyst::Exception->throw( |
91 | "The user id $uid was passed to an authentication " |
92 | . "plugin, but no default store was specified" ); |
93 | } |
94 | } |
95 | |
06675d2e |
96 | sub prepare { |
97 | my $c = shift->NEXT::prepare(@_); |
98 | |
4fbe2e14 |
99 | if ( $c->isa("Catalyst::Plugin::Session") |
06675d2e |
100 | and !$c->user ) |
101 | { |
7bb06c91 |
102 | if ( $c->sessionid and my $frozen_user = $c->session->{__user} ) { |
e300c5b6 |
103 | $c->_user($frozen_user); |
06675d2e |
104 | } |
105 | } |
106 | |
107 | return $c; |
108 | } |
109 | |
7bb06c91 |
110 | sub auth_restore_user { |
e300c5b6 |
111 | my ( $c, $frozen_user, $store_name ) = @_; |
7bb06c91 |
112 | |
4fbe2e14 |
113 | return |
cde43a59 |
114 | unless $c->isa("Catalyst::Plugin::Session") |
4fbe2e14 |
115 | and $c->config->{authentication}{use_session} |
116 | and $c->sessionid; |
4402d92d |
117 | |
e300c5b6 |
118 | $store_name ||= $c->session->{__user_store}; |
119 | $frozen_user ||= $c->session->{__user}; |
7bb06c91 |
120 | |
e300c5b6 |
121 | my $store = $c->get_auth_store($store_name); |
122 | $c->_user( my $user = $store->from_session( $c, $frozen_user ) ); |
7bb06c91 |
123 | |
e300c5b6 |
124 | return $user; |
7bb06c91 |
125 | |
126 | } |
127 | |
06675d2e |
128 | sub setup { |
129 | my $c = shift; |
130 | |
712a35bf |
131 | my $cfg = $c->config->{authentication} || {}; |
06675d2e |
132 | |
133 | %$cfg = ( |
134 | use_session => 1, |
135 | %$cfg, |
136 | ); |
b003080b |
137 | |
12dae309 |
138 | $c->register_auth_stores( |
139 | default => $cfg->{store}, |
140 | %{ $cfg->{stores} || {} }, |
141 | ); |
96777f3a |
142 | |
b003080b |
143 | $c->NEXT::setup(@_); |
06675d2e |
144 | } |
145 | |
96777f3a |
146 | sub get_auth_store { |
12dae309 |
147 | my ( $self, $name ) = @_; |
148 | $self->auth_stores->{$name} || ( Class::Inspector->loaded($name) && $name ); |
96777f3a |
149 | } |
150 | |
151 | sub get_auth_store_name { |
12dae309 |
152 | my ( $self, $store ) = @_; |
153 | $self->auth_store_names->{$store}; |
96777f3a |
154 | } |
155 | |
156 | sub register_auth_stores { |
12dae309 |
157 | my ( $self, %new ) = @_; |
96777f3a |
158 | |
12dae309 |
159 | foreach my $name ( keys %new ) { |
160 | my $store = $new{$name} or next; |
161 | $self->auth_stores->{$name} = $store; |
162 | $self->auth_store_names->{$store} = $name; |
163 | } |
96777f3a |
164 | } |
165 | |
166 | sub auth_stores { |
12dae309 |
167 | my $self = shift; |
168 | $self->_auth_stores(@_) || $self->_auth_stores( {} ); |
96777f3a |
169 | } |
170 | |
171 | sub auth_store_names { |
12dae309 |
172 | my $self = shift; |
96777f3a |
173 | |
4402d92d |
174 | $self->_auth_store_names || do { |
12dae309 |
175 | tie my %hash, 'Tie::RefHash'; |
176 | $self->_auth_store_names( \%hash ); |
4fbe2e14 |
177 | } |
96777f3a |
178 | } |
179 | |
180 | sub default_auth_store { |
12dae309 |
181 | my $self = shift; |
96777f3a |
182 | |
12dae309 |
183 | if ( my $new = shift ) { |
184 | $self->register_auth_stores( default => $new ); |
185 | } |
96777f3a |
186 | |
12dae309 |
187 | $self->get_auth_store("default"); |
96777f3a |
188 | } |
189 | |
06675d2e |
190 | __PACKAGE__; |
191 | |
192 | __END__ |
193 | |
194 | =pod |
195 | |
196 | =head1 NAME |
197 | |
55395841 |
198 | Catalyst::Plugin::Authentication - Infrastructure plugin for the Catalyst |
199 | authentication framework. |
06675d2e |
200 | |
201 | =head1 SYNOPSIS |
202 | |
189b5b0c |
203 | use Catalyst qw/ |
204 | Authentication |
205 | Authentication::Store::Foo |
206 | Authentication::Credential::Password |
207 | /; |
208 | |
209 | # later on ... |
210 | # ->login is provided by the Credential::Password module |
211 | $c->login('myusername', 'mypassword'); |
212 | my $age = $c->user->age; |
213 | $c->logout; |
06675d2e |
214 | |
215 | =head1 DESCRIPTION |
216 | |
189b5b0c |
217 | The authentication plugin provides generic user support. It is the basis for both authentication (checking the user is who they claim to be), and authorization (allowing the user to do what the system authorises them to do). |
06675d2e |
218 | |
189b5b0c |
219 | Using authentication is split into two parts. A Store is used to actually store the user information, and can store any amount of data related to the user. Multiple stores can be accessed from within one application. Credentials are used to verify users, using the store, given data from the frontend. |
220 | |
221 | To implement authentication in a catalyst application you need to add this module, plus at least one store and one credential module. |
222 | |
223 | Authentication data can also be stored in a session, if the application is using the L<Catalyst::Plugin::Session> module. |
06675d2e |
224 | |
225 | =head1 METHODS |
226 | |
227 | =over 4 |
228 | |
06675d2e |
229 | =item user |
230 | |
189b5b0c |
231 | Returns the currently logged in user or undef if there is none. |
06675d2e |
232 | |
ce0b058d |
233 | =item user_exists |
234 | |
235 | Whether or not a user is logged in right now. |
236 | |
237 | The reason this method exists is that C<<$c->user>> may needlessly load the |
238 | user from the auth store. |
239 | |
240 | If you're just going to say |
241 | |
242 | if ( $c->user_user ) { |
243 | # foo |
244 | } else { |
245 | $c->forward("login"); |
246 | } |
247 | |
248 | it should be more efficient than C<<$c->user>> when a user is marked in the session |
249 | but C<<$c->user>> hasn't been called yet. |
250 | |
4402d92d |
251 | =item logout |
252 | |
253 | Delete the currently logged in user from C<user> and the session. |
254 | |
7d0922d8 |
255 | =item get_user $uid |
256 | |
189b5b0c |
257 | Fetch a particular users details, defined by the given ID, via the default store. |
258 | |
259 | =back |
260 | |
261 | =head1 CONFIGURATION |
262 | |
263 | =over 4 |
264 | |
265 | =item use_session |
266 | |
267 | Whether or not to store the user's logged in state in the session, if the |
268 | application is also using the L<Catalyst::Plugin::Session> plugin. |
7d0922d8 |
269 | |
4fbe2e14 |
270 | =back |
271 | |
272 | =head1 METHODS FOR STORE MANAGEMENT |
273 | |
fe4cf44a |
274 | =over 4 |
275 | |
7d0922d8 |
276 | =item default_auth_store |
277 | |
4fbe2e14 |
278 | Return the store whose name is 'default'. |
7d0922d8 |
279 | |
189b5b0c |
280 | This is set to C<< $c->config->{authentication}{store} >> if that value exists, |
4fbe2e14 |
281 | or by using a Store plugin: |
282 | |
283 | use Catalyst qw/Authentication Authentication::Store::Minimal/; |
284 | |
285 | Sets the default store to |
286 | L<Catalyst::Plugin::Authentication::Store::Minimal::Backend>. |
287 | |
a1e5bd36 |
288 | |
4fbe2e14 |
289 | =item get_auth_store $name |
290 | |
291 | Return the store whose name is $name. |
292 | |
293 | =item get_auth_store_name $store |
294 | |
295 | Return the name of the store $store. |
296 | |
297 | =item auth_stores |
298 | |
299 | A hash keyed by name, with the stores registered in the app. |
300 | |
301 | =item auth_store_names |
302 | |
303 | A ref-hash keyed by store, which contains the names of the stores. |
304 | |
305 | =item register_auth_stores %stores_by_name |
306 | |
307 | Register stores into the application. |
06675d2e |
308 | |
fe4cf44a |
309 | =back |
310 | |
06675d2e |
311 | =head1 INTERNAL METHODS |
312 | |
313 | =over 4 |
314 | |
315 | =item set_authenticated $user |
316 | |
317 | Marks a user as authenticated. Should be called from a |
318 | C<Catalyst::Plugin::Authentication::Credential> plugin after successful |
319 | authentication. |
320 | |
321 | This involves setting C<user> and the internal data in C<session> if |
322 | L<Catalyst::Plugin::Session> is loaded. |
323 | |
e300c5b6 |
324 | =item auth_restore_user $user |
325 | |
326 | Used to restore a user from the session, by C<user> only when it's actually |
327 | needed. |
328 | |
329 | =item save_user_in_session $user |
330 | |
331 | Used to save the user in a session. |
332 | |
06675d2e |
333 | =item prepare |
334 | |
335 | Revives a user from the session object if there is one. |
336 | |
337 | =item setup |
338 | |
339 | Sets the default configuration parameters. |
340 | |
341 | =item |
342 | |
343 | =back |
344 | |
fbe577ac |
345 | =head1 SEE ALSO |
346 | |
347 | L<Catalyst::Plugin::Authentication::Credential::Password>, |
348 | L<Catalyst::Plugin::Authentication::Store::Minimal>, |
349 | L<Catalyst::Plugin::Authorization::ACL>, |
350 | L<Catalyst::Plugin::Authorization::Roles>. |
351 | |
352 | =head1 AUTHOR |
353 | |
354 | Yuval Kogman, C<nothingmuch@woobling.org> |
06675d2e |
355 | |
fbe577ac |
356 | =head1 COPYRIGHT & LICNESE |
357 | |
358 | Copyright (c) 2005 the aforementioned authors. All rights |
359 | reserved. This program is free software; you can redistribute |
360 | it and/or modify it under the same terms as Perl itself. |
361 | |
362 | =cut |
06675d2e |
363 | |