Changelog C::P::Authentication
[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
2bcde605 23our $VERSION = "0.03";
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 }
351e2a82 81
82 $c->NEXT::logout(@_);
06675d2e 83}
84
7d0922d8 85sub get_user {
86 my ( $c, $uid ) = @_;
87
88 if ( my $store = $c->default_auth_store ) {
89 return $store->get_user($uid);
90 }
91 else {
92 Catalyst::Exception->throw(
93 "The user id $uid was passed to an authentication "
94 . "plugin, but no default store was specified" );
95 }
96}
97
06675d2e 98sub prepare {
99 my $c = shift->NEXT::prepare(@_);
100
4fbe2e14 101 if ( $c->isa("Catalyst::Plugin::Session")
06675d2e 102 and !$c->user )
103 {
7bb06c91 104 if ( $c->sessionid and my $frozen_user = $c->session->{__user} ) {
e300c5b6 105 $c->_user($frozen_user);
06675d2e 106 }
107 }
108
109 return $c;
110}
111
7bb06c91 112sub auth_restore_user {
e300c5b6 113 my ( $c, $frozen_user, $store_name ) = @_;
7bb06c91 114
4fbe2e14 115 return
cde43a59 116 unless $c->isa("Catalyst::Plugin::Session")
4fbe2e14 117 and $c->config->{authentication}{use_session}
118 and $c->sessionid;
4402d92d 119
e300c5b6 120 $store_name ||= $c->session->{__user_store};
121 $frozen_user ||= $c->session->{__user};
7bb06c91 122
e300c5b6 123 my $store = $c->get_auth_store($store_name);
124 $c->_user( my $user = $store->from_session( $c, $frozen_user ) );
7bb06c91 125
e300c5b6 126 return $user;
7bb06c91 127
128}
129
06675d2e 130sub setup {
131 my $c = shift;
132
712a35bf 133 my $cfg = $c->config->{authentication} || {};
06675d2e 134
135 %$cfg = (
136 use_session => 1,
137 %$cfg,
138 );
b003080b 139
12dae309 140 $c->register_auth_stores(
141 default => $cfg->{store},
142 %{ $cfg->{stores} || {} },
143 );
96777f3a 144
b003080b 145 $c->NEXT::setup(@_);
06675d2e 146}
147
96777f3a 148sub get_auth_store {
12dae309 149 my ( $self, $name ) = @_;
150 $self->auth_stores->{$name} || ( Class::Inspector->loaded($name) && $name );
96777f3a 151}
152
153sub get_auth_store_name {
12dae309 154 my ( $self, $store ) = @_;
155 $self->auth_store_names->{$store};
96777f3a 156}
157
158sub register_auth_stores {
12dae309 159 my ( $self, %new ) = @_;
96777f3a 160
12dae309 161 foreach my $name ( keys %new ) {
162 my $store = $new{$name} or next;
163 $self->auth_stores->{$name} = $store;
164 $self->auth_store_names->{$store} = $name;
165 }
96777f3a 166}
167
168sub auth_stores {
12dae309 169 my $self = shift;
170 $self->_auth_stores(@_) || $self->_auth_stores( {} );
96777f3a 171}
172
173sub auth_store_names {
12dae309 174 my $self = shift;
96777f3a 175
4402d92d 176 $self->_auth_store_names || do {
12dae309 177 tie my %hash, 'Tie::RefHash';
178 $self->_auth_store_names( \%hash );
4fbe2e14 179 }
96777f3a 180}
181
182sub default_auth_store {
12dae309 183 my $self = shift;
96777f3a 184
12dae309 185 if ( my $new = shift ) {
186 $self->register_auth_stores( default => $new );
187 }
96777f3a 188
12dae309 189 $self->get_auth_store("default");
96777f3a 190}
191
06675d2e 192__PACKAGE__;
193
194__END__
195
196=pod
197
198=head1 NAME
199
55395841 200Catalyst::Plugin::Authentication - Infrastructure plugin for the Catalyst
201authentication framework.
06675d2e 202
203=head1 SYNOPSIS
204
189b5b0c 205 use Catalyst qw/
206 Authentication
207 Authentication::Store::Foo
208 Authentication::Credential::Password
209 /;
210
211 # later on ...
212 # ->login is provided by the Credential::Password module
213 $c->login('myusername', 'mypassword');
214 my $age = $c->user->age;
215 $c->logout;
06675d2e 216
217=head1 DESCRIPTION
218
e7522758 219The authentication plugin provides generic user support. It is the basis
220for both authentication (checking the user is who they claim to be), and
221authorization (allowing the user to do what the system authorises them to do).
06675d2e 222
e7522758 223Using authentication is split into two parts. A Store is used to actually
224store the user information, and can store any amount of data related to
225the user. Multiple stores can be accessed from within one application.
226Credentials are used to verify users, using the store, given data from
227the frontend.
189b5b0c 228
e7522758 229To implement authentication in a catalyst application you need to add this
230module, plus at least one store and one credential module.
189b5b0c 231
e7522758 232Authentication data can also be stored in a session, if the application
233is using the L<Catalyst::Plugin::Session> module.
06675d2e 234
235=head1 METHODS
236
237=over 4
238
06675d2e 239=item user
240
189b5b0c 241Returns the currently logged in user or undef if there is none.
06675d2e 242
ce0b058d 243=item user_exists
244
245Whether or not a user is logged in right now.
246
247The reason this method exists is that C<<$c->user>> may needlessly load the
248user from the auth store.
249
250If you're just going to say
251
252 if ( $c->user_user ) {
253 # foo
254 } else {
255 $c->forward("login");
256 }
257
258it should be more efficient than C<<$c->user>> when a user is marked in the session
1e055395 259but C<< $c->user >> hasn't been called yet.
ce0b058d 260
4402d92d 261=item logout
262
263Delete the currently logged in user from C<user> and the session.
264
7d0922d8 265=item get_user $uid
266
189b5b0c 267Fetch a particular users details, defined by the given ID, via the default store.
268
269=back
270
271=head1 CONFIGURATION
272
273=over 4
274
275=item use_session
276
277Whether or not to store the user's logged in state in the session, if the
e7522758 278application is also using the L<Catalyst::Plugin::Session> plugin. This
279value is set to true per default.
280
281=item store
282
1e055395 283If multiple stores are being used, set the module you want as default here.
7d0922d8 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
2bcde605 299=back
1e055395 300
4fbe2e14 301=head1 METHODS FOR STORE MANAGEMENT
302
fe4cf44a 303=over 4
304
7d0922d8 305=item default_auth_store
306
4fbe2e14 307Return the store whose name is 'default'.
7d0922d8 308
189b5b0c 309This is set to C<< $c->config->{authentication}{store} >> if that value exists,
4fbe2e14 310or by using a Store plugin:
311
312 use Catalyst qw/Authentication Authentication::Store::Minimal/;
313
314Sets the default store to
315L<Catalyst::Plugin::Authentication::Store::Minimal::Backend>.
316
a1e5bd36 317
4fbe2e14 318=item get_auth_store $name
319
320Return the store whose name is $name.
321
322=item get_auth_store_name $store
323
324Return the name of the store $store.
325
326=item auth_stores
327
328A hash keyed by name, with the stores registered in the app.
329
330=item auth_store_names
331
332A ref-hash keyed by store, which contains the names of the stores.
333
334=item register_auth_stores %stores_by_name
335
336Register stores into the application.
06675d2e 337
fe4cf44a 338=back
339
06675d2e 340=head1 INTERNAL METHODS
341
342=over 4
343
344=item set_authenticated $user
345
346Marks a user as authenticated. Should be called from a
347C<Catalyst::Plugin::Authentication::Credential> plugin after successful
348authentication.
349
350This involves setting C<user> and the internal data in C<session> if
351L<Catalyst::Plugin::Session> is loaded.
352
e300c5b6 353=item auth_restore_user $user
354
355Used to restore a user from the session, by C<user> only when it's actually
356needed.
357
358=item save_user_in_session $user
359
360Used to save the user in a session.
361
06675d2e 362=item prepare
363
364Revives a user from the session object if there is one.
365
366=item setup
367
368Sets the default configuration parameters.
369
370=item
371
372=back
373
fbe577ac 374=head1 SEE ALSO
375
376L<Catalyst::Plugin::Authentication::Credential::Password>,
377L<Catalyst::Plugin::Authentication::Store::Minimal>,
378L<Catalyst::Plugin::Authorization::ACL>,
379L<Catalyst::Plugin::Authorization::Roles>.
380
2bcde605 381=head1 AUTHORS
fbe577ac 382
383Yuval Kogman, C<nothingmuch@woobling.org>
2bcde605 384
7d2f34eb 385Jess Robinson
2bcde605 386
7d2f34eb 387David Kamholz
06675d2e 388
fbe577ac 389=head1 COPYRIGHT & LICNESE
390
391 Copyright (c) 2005 the aforementioned authors. All rights
392 reserved. This program is free software; you can redistribute
393 it and/or modify it under the same terms as Perl itself.
394
395=cut
06675d2e 396