More docs
[catagits/Catalyst-Plugin-Authentication.git] / lib / Catalyst / Plugin / Authentication.pm
CommitLineData
06675d2e 1#!/usr/bin/perl
2
3package Catalyst::Plugin::Authentication;
4
b003080b 5use base qw/Class::Accessor::Fast Class::Data::Inheritable/;
06675d2e 6
b003080b 7BEGIN {
7bb06c91 8 __PACKAGE__->mk_accessors(qw/_user/);
96777f3a 9 __PACKAGE__->mk_classdata($_) for qw/_auth_stores _auth_store_names/;
b003080b 10}
06675d2e 11
12use strict;
13use warnings;
14
96777f3a 15use Tie::RefHash;
12dae309 16use Class::Inspector;
96777f3a 17
e145babc 18#BEGIN {
19# require constant;
20# constant->import(have_want => eval { require Want });
21#}
a1e5bd36 22
e09a839c 23our $VERSION = "0.02";
c7c003d3 24
06675d2e 25sub 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 41sub 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 58sub user_exists {
59 my $c = shift;
60 return defined($c->_user);
61}
62
12dae309 63sub 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 71sub 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 83sub 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 96sub 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 110sub 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 128sub 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 146sub get_auth_store {
12dae309 147 my ( $self, $name ) = @_;
148 $self->auth_stores->{$name} || ( Class::Inspector->loaded($name) && $name );
96777f3a 149}
150
151sub get_auth_store_name {
12dae309 152 my ( $self, $store ) = @_;
153 $self->auth_store_names->{$store};
96777f3a 154}
155
156sub 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
166sub auth_stores {
12dae309 167 my $self = shift;
168 $self->_auth_stores(@_) || $self->_auth_stores( {} );
96777f3a 169}
170
171sub 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
180sub 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 198Catalyst::Plugin::Authentication - Infrastructure plugin for the Catalyst
199authentication 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
e7522758 217The authentication plugin provides generic user support. It is the basis
218for both authentication (checking the user is who they claim to be), and
219authorization (allowing the user to do what the system authorises them to do).
06675d2e 220
e7522758 221Using authentication is split into two parts. A Store is used to actually
222store the user information, and can store any amount of data related to
223the user. Multiple stores can be accessed from within one application.
224Credentials are used to verify users, using the store, given data from
225the frontend.
189b5b0c 226
e7522758 227To implement authentication in a catalyst application you need to add this
228module, plus at least one store and one credential module.
189b5b0c 229
e7522758 230Authentication data can also be stored in a session, if the application
231is using the L<Catalyst::Plugin::Session> module.
06675d2e 232
233=head1 METHODS
234
235=over 4
236
06675d2e 237=item user
238
189b5b0c 239Returns the currently logged in user or undef if there is none.
06675d2e 240
ce0b058d 241=item user_exists
242
243Whether or not a user is logged in right now.
244
245The reason this method exists is that C<<$c->user>> may needlessly load the
246user from the auth store.
247
248If you're just going to say
249
250 if ( $c->user_user ) {
251 # foo
252 } else {
253 $c->forward("login");
254 }
255
256it should be more efficient than C<<$c->user>> when a user is marked in the session
1e055395 257but C<< $c->user >> hasn't been called yet.
ce0b058d 258
4402d92d 259=item logout
260
261Delete the currently logged in user from C<user> and the session.
262
7d0922d8 263=item get_user $uid
264
189b5b0c 265Fetch a particular users details, defined by the given ID, via the default store.
266
267=back
268
269=head1 CONFIGURATION
270
271=over 4
272
273=item use_session
274
275Whether or not to store the user's logged in state in the session, if the
e7522758 276application is also using the L<Catalyst::Plugin::Session> plugin. This
277value is set to true per default.
278
279=item store
280
1e055395 281If multiple stores are being used, set the module you want as default here.
7d0922d8 282
4fbe2e14 283=back
284
1e055395 285=item stores
286
287If multiple stores are being used, you need to provide a name for each store
288here, as a hash, the keys are the names you wish to use, and the values are
289the the names of the plugins.
290
291 # example
292 __PACKAGE__->config( authentication => {
293 store => 'Catalyst::Plugin::Authentication::Store::HtPasswd',
294 stores => {
295 'dbic' => 'Catalyst::Plugin::Authentication::Store::DBIC'
296 }
297 });
298
299
4fbe2e14 300=head1 METHODS FOR STORE MANAGEMENT
301
fe4cf44a 302=over 4
303
7d0922d8 304=item default_auth_store
305
4fbe2e14 306Return the store whose name is 'default'.
7d0922d8 307
189b5b0c 308This is set to C<< $c->config->{authentication}{store} >> if that value exists,
4fbe2e14 309or by using a Store plugin:
310
311 use Catalyst qw/Authentication Authentication::Store::Minimal/;
312
313Sets the default store to
314L<Catalyst::Plugin::Authentication::Store::Minimal::Backend>.
315
a1e5bd36 316
4fbe2e14 317=item get_auth_store $name
318
319Return the store whose name is $name.
320
321=item get_auth_store_name $store
322
323Return the name of the store $store.
324
325=item auth_stores
326
327A hash keyed by name, with the stores registered in the app.
328
329=item auth_store_names
330
331A ref-hash keyed by store, which contains the names of the stores.
332
333=item register_auth_stores %stores_by_name
334
335Register stores into the application.
06675d2e 336
fe4cf44a 337=back
338
06675d2e 339=head1 INTERNAL METHODS
340
341=over 4
342
343=item set_authenticated $user
344
345Marks a user as authenticated. Should be called from a
346C<Catalyst::Plugin::Authentication::Credential> plugin after successful
347authentication.
348
349This involves setting C<user> and the internal data in C<session> if
350L<Catalyst::Plugin::Session> is loaded.
351
e300c5b6 352=item auth_restore_user $user
353
354Used to restore a user from the session, by C<user> only when it's actually
355needed.
356
357=item save_user_in_session $user
358
359Used to save the user in a session.
360
06675d2e 361=item prepare
362
363Revives a user from the session object if there is one.
364
365=item setup
366
367Sets the default configuration parameters.
368
369=item
370
371=back
372
fbe577ac 373=head1 SEE ALSO
374
375L<Catalyst::Plugin::Authentication::Credential::Password>,
376L<Catalyst::Plugin::Authentication::Store::Minimal>,
377L<Catalyst::Plugin::Authorization::ACL>,
378L<Catalyst::Plugin::Authorization::Roles>.
379
380=head1 AUTHOR
381
382Yuval Kogman, C<nothingmuch@woobling.org>
7d2f34eb 383Jess Robinson
384David Kamholz
06675d2e 385
fbe577ac 386=head1 COPYRIGHT & LICNESE
387
388 Copyright (c) 2005 the aforementioned authors. All rights
389 reserved. This program is free software; you can redistribute
390 it and/or modify it under the same terms as Perl itself.
391
392=cut
06675d2e 393