Lots of doc for C::P::Authentication
[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 our $VERSION = "0.01";
19
20 sub set_authenticated {
21     my ( $c, $user ) = @_;
22
23     $c->user($user);
24     $c->request->{user} = $user;    # compatibility kludge
25
26     if (    $c->isa("Catalyst::Plugin::Session")
27         and $c->config->{authentication}{use_session}
28         and $user->supports("session") )
29     {
30         $c->save_user_in_session($user);
31     }
32
33     $c->NEXT::set_authenticated($user);
34 }
35
36 sub user {
37     my $c = shift;
38
39     if (@_) {
40         return $c->_user(@_);
41     }
42
43     my $user = $c->_user;
44
45     if ( $user and !Scalar::Util::blessed($user) ) {
46         return $c->auth_restore_user($user);
47     }
48
49     return $user;
50 }
51
52 sub save_user_in_session {
53     my ( $c, $user ) = @_;
54
55     my $store = $user->store || ref $user;
56     $c->session->{__user_store} = $c->get_auth_store_name($store) || $store;
57     $c->session->{__user} = $user->for_session;
58 }
59
60 sub logout {
61     my $c = shift;
62
63     $c->user(undef);
64
65     if (    $c->isa("Catalyst::Plugin::Session")
66         and $c->config->{authentication}{use_session} )
67     {
68         delete @{ $c->session }{qw/__user __user_store/};
69     }
70 }
71
72 sub get_user {
73     my ( $c, $uid ) = @_;
74
75     if ( my $store = $c->default_auth_store ) {
76         return $store->get_user($uid);
77     }
78     else {
79         Catalyst::Exception->throw(
80                 "The user id $uid was passed to an authentication "
81               . "plugin, but no default store was specified" );
82     }
83 }
84
85 sub prepare {
86     my $c = shift->NEXT::prepare(@_);
87
88     if ( $c->isa("Catalyst::Plugin::Session")
89         and !$c->user )
90     {
91         if ( $c->sessionid and my $frozen_user = $c->session->{__user} ) {
92             $c->_user($frozen_user);
93         }
94     }
95
96     return $c;
97 }
98
99 sub auth_restore_user {
100     my ( $c, $frozen_user, $store_name ) = @_;
101
102     return
103       unless $c->isa("Catalyst::PLugin::Session")
104       and $c->config->{authentication}{use_session}
105       and $c->sessionid;
106
107     $store_name  ||= $c->session->{__user_store};
108     $frozen_user ||= $c->session->{__user};
109
110     my $store = $c->get_auth_store($store_name);
111     $c->_user( my $user = $store->from_session( $c, $frozen_user ) );
112
113     return $user;
114
115 }
116
117 sub setup {
118     my $c = shift;
119
120     my $cfg = $c->config->{authentication} || {};
121
122     %$cfg = (
123         use_session => 1,
124         %$cfg,
125     );
126
127     $c->register_auth_stores(
128         default => $cfg->{store},
129         %{ $cfg->{stores} || {} },
130     );
131
132     $c->NEXT::setup(@_);
133 }
134
135 sub get_auth_store {
136     my ( $self, $name ) = @_;
137     $self->auth_stores->{$name} || ( Class::Inspector->loaded($name) && $name );
138 }
139
140 sub get_auth_store_name {
141     my ( $self, $store ) = @_;
142     $self->auth_store_names->{$store};
143 }
144
145 sub register_auth_stores {
146     my ( $self, %new ) = @_;
147
148     foreach my $name ( keys %new ) {
149         my $store = $new{$name} or next;
150         $self->auth_stores->{$name}       = $store;
151         $self->auth_store_names->{$store} = $name;
152     }
153 }
154
155 sub auth_stores {
156     my $self = shift;
157     $self->_auth_stores(@_) || $self->_auth_stores( {} );
158 }
159
160 sub auth_store_names {
161     my $self = shift;
162
163     $self->_auth_store_names || do {
164         tie my %hash, 'Tie::RefHash';
165         $self->_auth_store_names( \%hash );
166       }
167 }
168
169 sub default_auth_store {
170     my $self = shift;
171
172     if ( my $new = shift ) {
173         $self->register_auth_stores( default => $new );
174     }
175
176     $self->get_auth_store("default");
177 }
178
179 __PACKAGE__;
180
181 __END__
182
183 =pod
184
185 =head1 NAME
186
187 Catalyst::Plugin::Authentication - Infrastructure plugin for the Catalyst
188 authentication framework.
189
190 =head1 SYNOPSIS
191
192         use Catalyst qw/
193                 Authentication
194                 Authentication::Store::Foo
195                 Authentication::Credential::Password
196         /;
197
198 =head1 DESCRIPTION
199
200 The authentication plugin is used by the various authentication and
201 authorization plugins in catalyst.
202
203 It defines the notion of a logged in user, and provides integration with the
204 L<Catalyst::Plugin::Session> plugin, 
205
206 =head1 METHODS
207
208 =over 4 
209
210 =item user
211
212 Returns the currently logged user or undef if there is none.
213
214 =item logout
215
216 Delete the currently logged in user from C<user> and the session.
217
218 =item get_user $uid
219
220 Delegate C<get_user> to the default store.
221
222 =back
223
224 =head1 METHODS FOR STORE MANAGEMENT
225
226 =item default_auth_store
227
228 Return the store whose name is 'default'.
229
230 This is set to C<<$c->config->{authentication}{store}>> if that value exists,
231 or by using a Store plugin:
232
233         use Catalyst qw/Authentication Authentication::Store::Minimal/;
234
235 Sets the default store to
236 L<Catalyst::Plugin::Authentication::Store::Minimal::Backend>.
237
238 =item get_auth_store $name
239
240 Return the store whose name is $name.
241
242 =item get_auth_store_name $store
243
244 Return the name of the store $store.
245
246 =item auth_stores
247
248 A hash keyed by name, with the stores registered in the app.
249
250 =item auth_store_names
251
252 A ref-hash keyed by store, which contains the names of the stores.
253
254 =item register_auth_stores %stores_by_name
255
256 Register stores into the application.
257
258 =head1 INTERNAL METHODS
259
260 =over 4
261
262 =item set_authenticated $user
263
264 Marks a user as authenticated. Should be called from a
265 C<Catalyst::Plugin::Authentication::Credential> plugin after successful
266 authentication.
267
268 This involves setting C<user> and the internal data in C<session> if
269 L<Catalyst::Plugin::Session> is loaded.
270
271 =item auth_restore_user $user
272
273 Used to restore a user from the session, by C<user> only when it's actually
274 needed.
275
276 =item save_user_in_session $user
277
278 Used to save the user in a session.
279
280 =item prepare
281
282 Revives a user from the session object if there is one.
283
284 =item setup
285
286 Sets the default configuration parameters.
287
288 =item 
289
290 =back
291
292 =head1 CONFIGURATION
293
294 =over 4
295
296 =item use_session
297
298 Whether or not to store the user's logged in state in the session, if the
299 application is also using the L<Catalyst::Plugin::Authentication> plugin.
300
301 =back
302
303 =cut
304
305