r33942@cain (orig r5492): jayk | 2006-11-11 06:44:28 +0000
[catagits/Catalyst-Plugin-Authentication.git] / lib / Catalyst / Plugin / Authentication.pm
CommitLineData
07e49bc7 1#!/usr/bin/perl
2
3package Catalyst::Plugin::Authentication;
4
dde93f12 5use base qw/Class::Accessor::Fast Class::Data::Inheritable/;
07e49bc7 6
dde93f12 7BEGIN {
2e3b369c 8 __PACKAGE__->mk_accessors(qw/_user/);
f869137d 9 __PACKAGE__->mk_classdata($_) for qw/_auth_realms/;
dde93f12 10}
07e49bc7 11
12use strict;
13use warnings;
14
8b52f75e 15use Tie::RefHash;
f2fee7ad 16use Class::Inspector;
8b52f75e 17
7605d422 18# this optimization breaks under Template::Toolkit
19# use user_exists instead
c8c961f5 20#BEGIN {
21# require constant;
22# constant->import(have_want => eval { require Want });
23#}
816e5745 24
f869137d 25our $VERSION = "0.10";
49bd39d0 26
07e49bc7 27sub set_authenticated {
f869137d 28 my ( $c, $user, $realmname ) = @_;
07e49bc7 29
30 $c->user($user);
f0348b1d 31 $c->request->{user} = $user; # compatibility kludge
07e49bc7 32
f869137d 33 if (!$realmname) {
34 $realmname = 'default';
07e49bc7 35 }
f869137d 36
37 if ( $c->isa("Catalyst::Plugin::Session")
38 and $c->config->{authentication}{use_session}
39 and $user->supports("session") )
40 {
41 $c->save_user_in_session($realmname, $user);
42 }
43 $user->_set_auth_realm($realmname);
44
45 $c->NEXT::set_authenticated($user, $realmname);
07e49bc7 46}
47
04c8c049 48sub _should_save_user_in_session {
49 my ( $c, $user ) = @_;
50
51 $c->_auth_sessions_supported
52 and $c->config->{authentication}{use_session}
53 and $user->supports("session");
54}
55
56sub _should_load_user_from_session {
57 my ( $c, $user ) = @_;
58
59 $c->_auth_sessions_supported
60 and $c->config->{authentication}{use_session}
61 and $c->session_is_valid;
62}
63
64sub _auth_sessions_supported {
65 my $c = shift;
66 $c->isa("Catalyst::Plugin::Session");
67}
68
2e3b369c 69sub user {
f0348b1d 70 my $c = shift;
2e3b369c 71
f0348b1d 72 if (@_) {
73 return $c->_user(@_);
74 }
2e3b369c 75
58009177 76 if ( defined(my $user = $c->_user) ) {
77 return $user;
78 } else {
d0d5fbef 79 return $c->auth_restore_user;
f0348b1d 80 }
2e3b369c 81}
82
f869137d 83# change this to allow specification of a realm - to verify the user is part of that realm
84# in addition to verifying that they exist.
1a2be169 85sub user_exists {
86 my $c = shift;
30d5659d 87 return defined($c->_user) || defined($c->_user_in_session);
58009177 88}
89
f869137d 90
f2fee7ad 91sub save_user_in_session {
f869137d 92 my ( $c, $realmname, $user ) = @_;
f2fee7ad 93
f869137d 94 $c->session->{__user_realm} = $realmname;
95
96 # we want to ask the backend for a user prepared for the session.
97 # but older modules split this functionality between the user and the
98 # backend. We try the store first. If not, we use the old method.
99 my $realm = $c->get_auth_realm($realmname);
100 if ($realm->{'store'}->can('for_session')) {
101 $c->session->{__user} = $realm->{'store'}->for_session($c, $user);
102 } else {
103 $c->session->{__user} = $user->for_session;
104 }
f2fee7ad 105}
106
07e49bc7 107sub logout {
108 my $c = shift;
109
110 $c->user(undef);
dde93f12 111
f869137d 112 if (
113 $c->isa("Catalyst::Plugin::Session")
114 and $c->config->{authentication}{use_session}
115 and $c->session_is_valid
116 ) {
117 delete @{ $c->session }{qw/__user __user_realm/};
dde93f12 118 }
49df63da 119
120 $c->NEXT::logout(@_);
07e49bc7 121}
122
f869137d 123sub find_user {
124 my ( $c, $userinfo, $realmname ) = @_;
125
126 $realmname ||= 'default';
127 my $realm = $c->get_auth_realm($realmname);
128 if ( $realm->{'store'} ) {
129 return $realm->{'store'}->find_user($userinfo, $c);
130 } else {
131 $c->log->debug('find_user: unable to locate a store matching the requested realm');
5435c348 132 }
133}
134
f869137d 135
d0d5fbef 136sub _user_in_session {
137 my $c = shift;
138
04c8c049 139 return unless $c->_should_load_user_from_session;
d0d5fbef 140
141 return $c->session->{__user};
04c8c049 142}
d0d5fbef 143
04c8c049 144sub _store_in_session {
145 my $c = shift;
146
147 # we don't need verification, it's only called if _user_in_session returned something useful
148
149 return $c->session->{__user_store};
d0d5fbef 150}
151
2e3b369c 152sub auth_restore_user {
f869137d 153 my ( $c, $frozen_user, $realmname ) = @_;
2e3b369c 154
d0d5fbef 155 $frozen_user ||= $c->_user_in_session;
156 return unless defined($frozen_user);
b7a0db6d 157
f869137d 158 $realmname ||= $c->session->{__user_realm};
159 return unless $realmname; # FIXME die unless? This is an internal inconsistency
2e3b369c 160
f869137d 161 my $realm = $c->get_auth_realm($realmname);
162 $c->_user( my $user = $realm->{'store'}->from_session( $c, $frozen_user ) );
163
164 # this sets the realm the user originated in.
165 $user->_set_auth_realm($realmname);
f0348b1d 166 return $user;
2e3b369c 167
168}
169
f869137d 170# we can't actually do our setup in setup because the model has not yet been loaded.
171# So we have to trigger off of setup_finished. :-(
07e49bc7 172sub setup {
173 my $c = shift;
174
f869137d 175 $c->_authentication_initialize();
176 $c->NEXT::setup(@_);
177}
178
179## the actual initialization routine. whee.
180sub _authentication_initialize {
181 my $c = shift;
182
183 if ($c->_auth_realms) { return };
184
185 my $cfg = $c->config->{'authentication'} || {};
07e49bc7 186
187 %$cfg = (
188 use_session => 1,
189 %$cfg,
190 );
dde93f12 191
f869137d 192 my $realmhash = {};
193 $c->_auth_realms($realmhash);
194
195 ## BACKWARDS COMPATIBILITY - if realm is not defined - then we are probably dealing
196 ## with an old-school config. The only caveat here is that we must add a classname
197 if (exists($cfg->{'realms'})) {
198
199 foreach my $realm (keys %{$cfg->{'realms'}}) {
200 $c->setup_auth_realm($realm, $cfg->{'realms'}{$realm});
201 }
202
203 # if we have a 'default-realm' in the config hash and we don't already
204 # have a realm called 'default', we point default at the realm specified
205 if (exists($cfg->{'default_realm'}) && !$c->get_auth_realm('default')) {
206 $c->set_default_auth_realm($cfg->{'default_realm'});
207 }
208 } else {
209 foreach my $storename (keys %{$cfg->{'stores'}}) {
210 my $realmcfg = {
211 store => $cfg->{'stores'}{$storename},
212 };
213 $c->setup_auth_realm($storename, $realmcfg);
214 }
215 }
216
07e49bc7 217}
218
f869137d 219
220# set up realmname.
221sub setup_auth_realm {
222 my ($app, $realmname, $config) = @_;
223
224 $app->log->debug("Setting up $realmname");
225 if (!exists($config->{'store'}{'class'})) {
226 Carp::croak "Couldn't setup the authentication realm named '$realmname', no class defined";
227 }
228
229 # use the
230 my $storeclass = $config->{'store'}{'class'};
231
232 ## follow catalyst class naming - a + prefix means a fully qualified class, otherwise it's
233 ## taken to mean C::P::A::Store::(specifiedclass)::Backend
234 if ($storeclass !~ /^\+(.*)$/ ) {
235 $storeclass = "Catalyst::Plugin::Authentication::Store::${storeclass}::Backend";
236 } else {
237 $storeclass = $1;
238 }
239
240
241 # a little niceness - since most systems seem to use the password credential class,
242 # if no credential class is specified we use password.
243 $config->{credential}{class} ||= "Catalyst::Plugin::Authentication::Credential::Password";
244
245 my $credentialclass = $config->{'credential'}{'class'};
246
247 ## follow catalyst class naming - a + prefix means a fully qualified class, otherwise it's
248 ## taken to mean C::P::A::Credential::(specifiedclass)
249 if ($credentialclass !~ /^\+(.*)$/ ) {
250 $credentialclass = "Catalyst::Plugin::Authentication::Credential::${credentialclass}";
251 } else {
252 $credentialclass = $1;
253 }
254
255 # if we made it here - we have what we need to load the classes;
256 Catalyst::Utils::ensure_class_loaded( $credentialclass );
257 Catalyst::Utils::ensure_class_loaded( $storeclass );
258
259 # BACKWARDS COMPATIBILITY - if the store class does not define find_user, we define it in terms
260 # of get_user and add it to the class. this is because the auth routines use find_user,
261 # and rely on it being present. (this avoids per-call checks)
262 if (!$storeclass->can('find_user')) {
263 no strict 'refs';
264 *{"${storeclass}::find_user"} = sub {
265 my ($self, $info) = @_;
266 my @rest = @{$info->{rest}} if exists($info->{rest});
267 $self->get_user($info->{id}, @rest);
268 };
269 }
270
271 $app->auth_realms->{$realmname}{'store'} = $storeclass->new($config->{'store'}, $app);
272 if ($credentialclass->can('new')) {
273 $app->auth_realms->{$realmname}{'credential'} = $credentialclass->new($config->{'credential'}, $app);
274 } else {
275 # if the credential class is not actually a class - has no 'new' operator, we wrap it,
276 # once again - to allow our code to be simple at runtime and allow non-OO packages to function.
277 my $wrapperclass = 'Catalyst::Plugin::Authentication::Credential::Wrapper';
278 Catalyst::Utils::ensure_class_loaded( $wrapperclass );
279 $app->auth_realms->{$realmname}{'credential'} = $wrapperclass->new($config->{'credential'}, $app);
280 }
8b52f75e 281}
282
f869137d 283sub auth_realms {
284 my $self = shift;
285 return($self->_auth_realms);
8b52f75e 286}
287
f869137d 288sub get_auth_realm {
289 my ($app, $realmname) = @_;
290 return $app->auth_realms->{$realmname};
291}
8b52f75e 292
f869137d 293sub set_default_auth_realm {
294 my ($app, $realmname) = @_;
295
296 if (exists($app->auth_realms->{$realmname})) {
297 $app->auth_realms->{'default'} = $app->auth_realms->{$realmname};
f2fee7ad 298 }
f869137d 299 return $app->get_auth_realm('default');
8b52f75e 300}
301
f869137d 302sub authenticate {
303 my ($app, $userinfo, $realmname) = @_;
304
305 if (!$realmname) {
306 $realmname = 'default';
307 }
308
309 my $realm = $app->get_auth_realm($realmname);
310
311 if ($realm && exists($realm->{'credential'})) {
312 my $user = $realm->{'credential'}->authenticate($app, $realm->{store}, $userinfo);
313 if ($user) {
314 $app->set_authenticated($user, $realmname);
315 return $user;
316 }
317 } else {
318 $app->log->debug("The realm requested, '$realmname' does not exist," .
319 " or there is no credential associated with it.")
320 }
46c08636 321 return undef;
8b52f75e 322}
323
f869137d 324## BACKWARDS COMPATIBILITY -- Warning: Here be monsters!
325#
326# What follows are backwards compatibility routines - for use with Stores and Credentials
327# that have not been updated to work with C::P::Authentication v0.10.
328# These are here so as to not break people's existing installations, but will go away
329# in a future version.
330#
331# The old style of configuration only supports a single store, as each store module
332# sets itself as the default store upon being loaded. This is the only supported
333# 'compatibility' mode.
334#
335
336sub get_user {
337 my ( $c, $uid, @rest ) = @_;
8b52f75e 338
f869137d 339 return $c->find_user( {'id' => $uid, 'rest'=>\@rest }, 'default' );
8b52f75e 340}
341
f869137d 342##
343## this should only be called when using old-style authentication plugins. IF this gets
344## called in a new-style config - it will OVERWRITE the store of your default realm. Don't do it.
345## also - this is a partial setup - because no credential is instantiated... in other words it ONLY
346## works with old-style auth plugins and C::P::Authentication in compatibility mode. Trying to combine
347## this with a realm-type config will probably crash your app.
8b52f75e 348sub default_auth_store {
f2fee7ad 349 my $self = shift;
8b52f75e 350
f2fee7ad 351 if ( my $new = shift ) {
f869137d 352 $self->auth_realms->{'default'}{'store'} = $new;
353 my $storeclass = ref($new);
354
355 # BACKWARDS COMPATIBILITY - if the store class does not define find_user, we define it in terms
356 # of get_user and add it to the class. this is because the auth routines use find_user,
357 # and rely on it being present. (this avoids per-call checks)
358 if (!$storeclass->can('find_user')) {
359 no strict 'refs';
360 *{"${storeclass}::find_user"} = sub {
361 my ($self, $info) = @_;
362 my @rest = @{$info->{rest}} if exists($info->{rest});
363 $self->get_user($info->{id}, @rest);
364 };
365 }
f2fee7ad 366 }
8b52f75e 367
f869137d 368 return $self->get_auth_realm('default')->{'store'};
8b52f75e 369}
370
f869137d 371## BACKWARDS COMPATIBILITY
372## this only ever returns a hash containing 'default' - as that is the only
373## supported mode of calling this.
374sub auth_store_names {
375 my $self = shift;
376
377 my %hash = ( $self->get_auth_realm('default')->{'store'} => 'default' );
378}
379
380sub get_auth_store {
381 my ( $self, $name ) = @_;
382
383 if ($name ne 'default') {
384 Carp::croak "get_auth_store called on non-default realm '$name'. Only default supported in compatibility mode";
385 } else {
386 $self->default_auth_store();
387 }
388}
389
390sub get_auth_store_name {
391 my ( $self, $store ) = @_;
392 return 'default';
393}
394
395# sub auth_stores is only used internally - here for completeness
396sub auth_stores {
397 my $self = shift;
398
399 my %hash = ( 'default' => $self->get_auth_realm('default')->{'store'});
400}
401
402
403
404
405
406
07e49bc7 407__PACKAGE__;
408
409__END__
410
411=pod
412
413=head1 NAME
414
033d2c24 415Catalyst::Plugin::Authentication - Infrastructure plugin for the Catalyst
416authentication framework.
07e49bc7 417
418=head1 SYNOPSIS
419
18a3c897 420 use Catalyst qw/
421 Authentication
18a3c897 422 /;
423
424 # later on ...
f869137d 425 $c->authenticate({ username => 'myusername', password => 'mypassword' });
426 my $age = $c->user->get('age');
18a3c897 427 $c->logout;
07e49bc7 428
429=head1 DESCRIPTION
430
14929a35 431The authentication plugin provides generic user support. It is the basis
432for both authentication (checking the user is who they claim to be), and
433authorization (allowing the user to do what the system authorises them to do).
07e49bc7 434
14929a35 435Using authentication is split into two parts. A Store is used to actually
436store the user information, and can store any amount of data related to
437the user. Multiple stores can be accessed from within one application.
c955e5dc 438Credentials are used to verify users, using information from the store,
439given data from the frontend.
18a3c897 440
f0f9cd72 441To implement authentication in a Catalyst application you need to add this
14929a35 442module, plus at least one store and one credential module.
18a3c897 443
14929a35 444Authentication data can also be stored in a session, if the application
445is using the L<Catalyst::Plugin::Session> module.
07e49bc7 446
e5108df9 447=head1 INTRODUCTION
448
449=head2 The Authentication/Authorization Process
450
451Web applications typically need to identify a user - to tell the user apart
452from other users. This is usually done in order to display private information
453that is only that user's business, or to limit access to the application so
454that only certain entities can access certain parts.
455
456This process is split up into several steps. First you ask the user to identify
457themselves. At this point you can't be sure that the user is really who they
458claim to be.
459
f0f9cd72 460Then the user tells you who they are, and backs this claim with some piece of
e5108df9 461information that only the real user could give you. For example, a password is
462a secret that is known to both the user and you. When the user tells you this
463password you can assume they're in on the secret and can be trusted (ignore
464identity theft for now). Checking the password, or any other proof is called
465B<credential verification>.
466
467By this time you know exactly who the user is - the user's identity is
468B<authenticated>. This is where this module's job stops, and other plugins step
469in. The next logical step is B<authorization>, the process of deciding what a
470user is (or isn't) allowed to do. For example, say your users are split into
471two main groups - regular users and administrators. You should verify that the
472currently logged in user is indeed an administrator before performing the
f0f9cd72 473actions of an administrative part of your application. One way to do this is
e5108df9 474with role based access control.
475
476=head2 The Components In This Framework
477
c955e5dc 478=head3 Realms
479
480Configuration of the Catalyst::Plugin::Authentication framework is done in
481terms of realms. In simplest terms, a realm is a pairing of a Credential
482verifier and a User storage (Store) backend.
483
484An application can have any number of Realms, each of which operates
485independant of the others. Each realm has a name, which is used to identify it
486as the target of an authentication request. This name can be anything, such as
487'users' or 'members'. One realm must be defined as the default_realm, which is
488used when no realm name is specified. More about this in the configuration
489section.
490
e5108df9 491=head3 Credential Verifiers
492
493When user input is transferred to the L<Catalyst> application (typically via
c955e5dc 494form inputs) this authentication data then enters the authentication framework
495through the $c->authenticate() routine. From there, it is passed to the
496appropriate Credential verifier.
e5108df9 497
498These plugins check the data, and ensure that it really proves the user is who
499they claim to be.
500
501=head3 Storage Backends
502
c955e5dc 503The authentication data also identify a user, and the Storage Backend modules
504use this data to locate and return a standardized object-oriented
505representation of a user.
e5108df9 506
507When a user is retrieved from a store it is not necessarily authenticated.
c955e5dc 508Credential verifiers accept a set of authentication data and use this
509information to retrieve the user from the store they are paired with.
e5108df9 510
511=head3 The Core Plugin
512
c955e5dc 513This plugin on its own is the glue, providing realm configuration, session
e5108df9 514integration, and other goodness for the other plugins.
515
516=head3 Other Plugins
517
518More layers of plugins can be stacked on top of the authentication code. For
519example, L<Catalyst::Plugin::Session::PerUser> provides an abstraction of
520browser sessions that is more persistent per users.
521L<Catalyst::Plugin::Authorization::Roles> provides an accepted way to separate
522and group users into categories, and then check which categories the current
523user belongs to.
524
caae740f 525=head1 EXAMPLE
526
c955e5dc 527Let's say we were storing users in an simple perl hash. Users are
f0f9cd72 528stored in that file, with a hashed password and some extra comments. Users are
529verified by supplying a password which is matched with the file.
caae740f 530
531This means that our application will begin like this:
532
533 package MyApp;
534
535 use Catalyst qw/
536 Authentication
caae740f 537 /;
538
c955e5dc 539 __PACKAGE__->config->{authentication} =
540 {
541 default_realm => 'members',
542 realms => {
543 members => {
544 credential => {
545 class => 'Password'
546 },
547 store => {
46c08636 548 class => 'Minimal',
c955e5dc 549 users = {
550 bob => {
551 password => "s3cr3t",
552 editor => 'yes',
553 roles => [qw/edit delete/],
554 },
555 william => {
556 password => "s00p3r",
557 roles => [qw/comment/],
558 }
559 }
560 }
561 }
562 }
563 };
564
caae740f 565
c955e5dc 566This tells the authentication plugin what realms are available, which credential
567and store modules are used, and the configuration of each.
caae740f 568
c955e5dc 569With this code loaded, we can now attempt to authenticate users.
caae740f 570
c955e5dc 571To show an example of this, let's create an authentication controller:
caae740f 572
573 package MyApp::Controller::Auth;
574
575 sub login : Local {
576 my ( $self, $c ) = @_;
577
578 if ( my $user = $c->req->param("user")
579 and my $password = $c->req->param("password") )
580 {
c955e5dc 581 if ( $c->authenticate( { username => $user,
582 password => $password } ) ) {
583 $c->res->body( "hello " . $c->user->get("name") );
caae740f 584 } else {
585 # login incorrect
586 }
587 }
588 else {
589 # invalid form input
590 }
591 }
592
593This code should be very readable. If all the necessary fields are supplied,
c955e5dc 594call the L<Catalyst::Plugin::Authentication/authenticate> method in the
595controller. If it succeeds the user is logged in.
caae740f 596
c955e5dc 597The credential verifier will attempt to retrieve the user whose details match
598the authentication information provided to $c->authenticate(). Once it fetches
599the user the password is checked and if it matches the user will be
600'authenticated' and C<< $c->user >> will contain the user object retrieved
601from the store.
caae740f 602
c955e5dc 603In the above case, the default realm is checked, but we could just as easily
604check an alternate realm. If this were an admin login, for example, we could
605authenticate on the admin realm by simply changing the $c->authenticate()
606call:
caae740f 607
c955e5dc 608 if ( $c->authenticate( { username => $user,
609 password => $password }, 'admin' )l ) {
610 $c->res->body( "hello " . $c->user->get("name") );
611 } ...
caae740f 612
caae740f 613
c955e5dc 614Now suppose we want to restrict the ability to edit to a user with 'edit'
615in it's roles list.
caae740f 616
c955e5dc 617The restricted action might look like this:
caae740f 618
c955e5dc 619 sub edit : Local {
caae740f 620 my ( $self, $c ) = @_;
621
622 $c->detach("unauthorized")
623 unless $c->user_exists
c955e5dc 624 and $c->user->get('editor') == 'yes';
caae740f 625
626 # do something restricted here
627 }
628
629This is somewhat similar to role based access control.
c955e5dc 630L<Catalyst::Plugin::Authentication::Store::Minimal> treats the roles field as
631an array of role names. Let's leverage this. Add the role authorization
632plugin:
caae740f 633
634 use Catalyst qw/
635 ...
636 Authorization::Roles
637 /;
638
c955e5dc 639 sub edit : Local {
caae740f 640 my ( $self, $c ) = @_;
641
c955e5dc 642 $c->detach("unauthorized") unless $c->check_roles("edit");
caae740f 643
644 # do something restricted here
645 }
646
647This is somewhat simpler and will work if you change your store, too, since the
648role interface is consistent.
649
46c08636 650Let's say your app grew, and you now have 10000 users. It's no longer
651efficient to maintain a hash of users, so you move this data to a database.
652You can accomplish this simply by installing the DBIx::Class Store and
653changing your config:
caae740f 654
46c08636 655 __PACKAGE__->config->{authentication} =
656 {
657 default_realm => 'members',
658 realms => {
659 members => {
660 credential => {
661 class => 'Password'
662 },
663 store => {
664 class => 'DBIx::Class',
665 user_class => 'MyApp::Users',
666 role_column => 'roles'
667 }
668 }
669 }
670 };
caae740f 671
46c08636 672The authentication system works behind the scenes to load your data from the
673new source. The rest of your application is completely unchanged.
caae740f 674
46c08636 675=head1 METHODS
caae740f 676
46c08636 677=over 4
caae740f 678
caae740f 679
46c08636 680=item authenticate $userinfo, $realm
07e49bc7 681
46c08636 682Attempts to authenticate the user using the information in $userinfo hash
683reference using the realm $realm. $realm may be omitted, in which case the
684default realm is checked.
07e49bc7 685
07e49bc7 686=item user
687
18a3c897 688Returns the currently logged in user or undef if there is none.
07e49bc7 689
1a2be169 690=item user_exists
691
46c08636 692Returns true if a user is logged in right now. The difference between
693user_exists and user is that user_exists will return true if a user is logged
694in, even if it has not been retrieved from the storage backend. If you only
695need to know if the user is logged in, depending on the storage mechanism this
696can be much more efficient.
1a2be169 697
b7a0db6d 698=item logout
699
46c08636 700Logs the user out, Deletes the currently logged in user from C<user> and the session.
b7a0db6d 701
46c08636 702=item find_user( $userinfo, $realm )
5435c348 703
46c08636 704Fetch a particular users details, matching the provided user info, from the realm
705specified in $realm.
18a3c897 706
707=back
708
709=head1 CONFIGURATION
710
711=over 4
712
46c08636 713 # example
714 __PACKAGE__->config->{authentication} =
715 {
716 default_realm => 'members',
717 realms => {
718 members => {
719 credential => {
720 class => 'Password'
721 },
722 store => {
723 class => 'DBIx::Class',
724 user_class => 'MyApp::Users',
725 role_column => 'roles'
726 }
727 },
728 admins => {
729 credential => {
730 class => 'Password'
731 },
732 store => {
733 class => '+MyApp::Authentication::Store::NetAuth',
734 authserver => '192.168.10.17'
735 }
736 }
737
738 }
739 };
740
18a3c897 741=item use_session
742
743Whether or not to store the user's logged in state in the session, if the
14929a35 744application is also using the L<Catalyst::Plugin::Session> plugin. This
745value is set to true per default.
746
46c08636 747=item default_realm
b12e226d 748
46c08636 749This defines which realm should be used as when no realm is provided to methods
750that require a realm such as authenticate or find_user.
5435c348 751
46c08636 752=item realms
5435c348 753
46c08636 754This contains the series of realm configurations you want to use for your app.
755The only rule here is that there must be at least one. A realm consists of a
756name, which is used to reference the realm, a credential and a store.
b260654c 757
46c08636 758Each realm config contains two hashes, one called 'credential' and one called
759'store', each of which provide configuration details to the respective modules.
760The contents of these hashes is specific to the module being used, with the
761exception of the 'class' element, which tells the core Authentication module the
762classname to use for that entry.
b260654c 763
46c08636 764The 'class' element follows the standard Catalyst mechanism of class
765specification. If a class is prefixed with a +, it is assumed to be a complete
766class name. Otherwise it is considered to be a portion of the class name. For
767credentials, the classname 'Password', for example, is expanded to
768Catalyst::Plugin::Authentication::Credential::Password. For stores, the
769classname 'storename' is expanded to:
770Catalyst::Plugin::Authentication::Store::storename::Backend.
b260654c 771
816e5745 772
b12e226d 773=back
774
46c08636 775
07e49bc7 776=head1 INTERNAL METHODS
777
778=over 4
779
780=item set_authenticated $user
781
782Marks a user as authenticated. Should be called from a
783C<Catalyst::Plugin::Authentication::Credential> plugin after successful
784authentication.
785
786This involves setting C<user> and the internal data in C<session> if
787L<Catalyst::Plugin::Session> is loaded.
788
f0348b1d 789=item auth_restore_user $user
790
791Used to restore a user from the session, by C<user> only when it's actually
792needed.
793
794=item save_user_in_session $user
795
796Used to save the user in a session.
797
07e49bc7 798=item prepare
799
800Revives a user from the session object if there is one.
801
802=item setup
803
804Sets the default configuration parameters.
805
806=item
807
808=back
809
36fba990 810=head1 SEE ALSO
811
e5108df9 812This list might not be up to date.
813
814=head2 User Storage Backends
815
36fba990 816L<Catalyst::Plugin::Authentication::Store::Minimal>,
e5108df9 817L<Catalyst::Plugin::Authentication::Store::Htpasswd>,
818L<Catalyst::Plugin::Authentication::Store::DBIC> (also works with Class::DBI).
819
820=head2 Credential verification
821
822L<Catalyst::Plugin::Authentication::Credential::Password>,
823L<Catalyst::Plugin::Authentication::Credential::HTTP>,
824L<Catalyst::Plugin::Authentication::Credential::TypeKey>
825
826=head2 Authorization
827
36fba990 828L<Catalyst::Plugin::Authorization::ACL>,
e5108df9 829L<Catalyst::Plugin::Authorization::Roles>
830
caae740f 831=head2 Internals Documentation
832
833L<Catalyst::Plugin::Authentication::Store>
834
e5108df9 835=head2 Misc
836
837L<Catalyst::Plugin::Session>,
838L<Catalyst::Plugin::Session::PerUser>
36fba990 839
d304b38a 840=head1 DON'T SEE ALSO
841
1db33018 842This module along with its sub plugins deprecate a great number of other
843modules. These include L<Catalyst::Plugin::Authentication::Simple>,
844L<Catalyst::Plugin::Authentication::CDBI>.
d304b38a 845
846At the time of writing these plugins have not yet been replaced or updated, but
1db33018 847should be eventually: L<Catalyst::Plugin::Authentication::OpenID>,
848L<Catalyst::Plugin::Authentication::LDAP>,
849L<Catalyst::Plugin::Authentication::CDBI::Basic>,
850L<Catalyst::Plugin::Authentication::Basic::Remote>.
d304b38a 851
46c08636 852
853=head1 COMPATIBILITY ROUTINES
854
855=over 4
856
857In version 0.10 of the L<Catalyst::Plugin::Authentication> plugin, the API
858used changed. For app developers, this change is fairly minor, but for
859Credential and Store authors, the changes are significant. The items below are
860still present in the plugin, though using them is deprecated. They remain only
861as a transition tool, for those sites which can not be upgraded to use the new
862system due to local customizations, or use of Credential / store modules that
863have not yet been updated.
864
865=head1 METHODS FOR STORE MANAGEMENT
866
867=over 4
868
869=item default_auth_store
870
871Return the store whose name is 'default'.
872
873This is set to C<< $c->config->{authentication}{store} >> if that value exists,
874or by using a Store plugin:
875
876 use Catalyst qw/Authentication Authentication::Store::Minimal/;
877
878Sets the default store to
879L<Catalyst::Plugin::Authentication::Store::Minimal::Backend>.
880
881
882=item get_auth_store $name
883
884Return the store whose name is $name.
885
886=item get_auth_store_name $store
887
888Return the name of the store $store.
889
890=item auth_stores
891
892A hash keyed by name, with the stores registered in the app.
893
894=item auth_store_names
895
896A ref-hash keyed by store, which contains the names of the stores.
897
898=item register_auth_stores %stores_by_name
899
900Register stores into the application.
901
902=back
903
904
905
51111c81 906=head1 AUTHORS
36fba990 907
908Yuval Kogman, C<nothingmuch@woobling.org>
51111c81 909
7d4c2ed8 910Jess Robinson
51111c81 911
7d4c2ed8 912David Kamholz
07e49bc7 913
8f86f029 914=head1 COPYRIGHT & LICENSE
36fba990 915
916 Copyright (c) 2005 the aforementioned authors. All rights
917 reserved. This program is free software; you can redistribute
918 it and/or modify it under the same terms as Perl itself.
919
920=cut
07e49bc7 921