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