Decoupling of Session and Auth-
[catagits/Catalyst-Plugin-Authentication.git] / lib / Catalyst / Plugin / Authentication.pm
1 package Catalyst::Plugin::Authentication;
2
3 use base qw/Class::Accessor::Fast Class::Data::Inheritable/;
4
5 BEGIN {
6     __PACKAGE__->mk_accessors(qw/_user/);
7 }
8
9 use strict;
10 use warnings;
11
12 use Tie::RefHash;
13 use Class::Inspector;
14 use Catalyst::Authentication::Realm;
15
16 # this optimization breaks under Template::Toolkit
17 # use user_exists instead
18 #BEGIN {
19 #       require constant;
20 #       constant->import(have_want => eval { require Want });
21 #}
22
23 ## NOTE TO SELF:
24 ## move user persistence into realm.  
25 ## basically I'll provide 'persist_user' which will save the currently auth'd user.  
26 ## 'restore_user' which will restore the user, and 'user_is_restorable' which is a 
27 ## true/false on whether there is a user to restore.  
28
29 our $VERSION = "0.11000";
30
31 sub set_authenticated {
32     my ( $c, $user, $realmname ) = @_;
33
34     $c->user($user);
35     $c->request->{user} = $user;    # compatibility kludge
36
37     if (!$realmname) {
38         $realmname = 'default';
39     }
40     my $realm = $c->get_auth_realm($realmname);
41     
42     if (!$realm) {
43         Catalyst::Exception->throw(
44                 "set_authenticated called with nonexistant realm: '$realmname'.");
45     }
46     $user->auth_realm($realm->name);
47
48     $c->persist_user();    
49     
50     $c->NEXT::set_authenticated($user, $realmname);
51 }
52
53 sub user {
54     my $c = shift;
55
56     if (@_) {
57         return $c->_user(@_);
58     }
59
60     if ( defined($c->_user) ) {
61         return $c->_user;
62     } else {
63         return $c->auth_restore_user;
64     }
65 }
66
67 # change this to allow specification of a realm - to verify the user is part of that realm
68 # in addition to verifying that they exist.
69 sub user_exists {
70         my $c = shift;
71         return defined($c->_user) || defined($c->_find_realm_for_persisted_user);
72 }
73
74 # works like user_exists - except only returns true if user 
75 # exists AND is in the realm requested.
76 sub user_in_realm {
77     my ($c, $realmname) = @_;
78
79     if (defined($c->_user)) {
80         return ($c->_user->auth_realm eq $realmname);
81     } else {
82         my $realm = $c->_find_realm_for_persisted_user;
83         if ($realm) {
84             return ($realm->name eq $realmname);
85         } else {
86             return undef;
87         }
88     }
89 }
90
91 sub __old_save_user_in_session {
92     my ( $c, $user, $realmname ) = @_;
93
94     $c->session->{__user_realm} = $realmname;
95     
96     # we want to ask the store for a user prepared for the session.
97     # but older modules split this functionality between the user and the
98     # store.  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     }
105 }
106
107 sub persist_user {
108     my $c = shift;
109
110     if ($c->user_exists) {
111         
112         ## if we have a valid session handler - we store the 
113         ## realm in the session.  If not - we have to hope that 
114         ## the realm can recognize it's frozen user somehow.
115         if ($c->isa("Catalyst::Plugin::Session") && 
116             $c->config->{'Plugin::Authentication'}{'use_session'} && 
117             $c->session_is_valid) {
118         
119             $c->session->{'__user_realm'} = $c->_user->auth_realm; 
120         }
121         
122         my $realm = $c->get_auth_realm($c->_user->auth_realm);
123         
124         # used to call $realm->save_user_in_session
125         $realm->persist_user($c, $c->user);
126     }
127 }
128
129
130 ## this was a short lived method to update user information - 
131 ## you should use persist_user instead.
132 sub update_user_in_session {
133     my $c = shift;
134
135     return $c->persist_user;
136 }
137
138 sub logout {
139     my $c = shift;
140
141     $c->user(undef);
142
143     my $realm = $c->_find_realm_for_persisted_user;
144     if ($realm) {
145         $realm->remove_persisted_user($c);
146     }
147     
148     $c->NEXT::logout(@_);
149 }
150
151 sub find_user {
152     my ( $c, $userinfo, $realmname ) = @_;
153     
154     $realmname ||= 'default';
155     my $realm = $c->get_auth_realm($realmname);
156     
157     if (!$realm) {
158         Catalyst::Exception->throw(
159                 "find_user called with nonexistant realm: '$realmname'.");
160     }
161     return $realm->find_user($userinfo, $c);
162 }
163
164
165 sub _find_realm_for_persisted_user {
166     my $c = shift;
167     
168     my $realm;
169     if ($c->isa("Catalyst::Plugin::Session")
170         and $c->config->{'Plugin::Authentication'}{'use_session'}
171         and $c->session_is_valid 
172         and exists($c->session->{'__user_realm'})) {
173     
174         $realm = $c->auth_realms->{$c->session->{'__user_realm'}};
175         if ($realm->user_is_restorable($c)) {
176             return $realm; 
177         }
178     } else {
179         ## we have no choice but to ask each realm whether it has a persisted user.
180         foreach my $realmname (@{$c->_auth_realm_restore_order}) {
181             my $ret = $c->auth_realms->{$realmname}->user_is_restorable($c);
182             if ($ret) {
183                 return $c->auth_realms->{$realmname};
184             }
185         }
186     }
187     return undef;
188 }
189
190 sub auth_restore_user {
191     my ( $c, $frozen_user, $realmname ) = @_;
192
193     my $realm;
194     if (defined($realmname)) {
195         $realm = $c->get_auth_realm($realmname); 
196     } else {
197         $realm = $c->_find_realm_for_persisted_user;
198     }
199     return unless $realm; # FIXME die unless? This is an internal inconsistency
200
201     $c->_user( my $user = $realm->restore_user( $c, $frozen_user ) );
202     
203     # this sets the realm the user originated in.
204     $user->auth_realm($realm->name);
205         
206     return $user;
207
208 }
209
210 # we can't actually do our setup in setup because the model has not yet been loaded.  
211 # So we have to trigger off of setup_finished.  :-(
212 sub setup {
213     my $app = shift;
214
215     $app->_authentication_initialize();
216     $app->NEXT::setup(@_);
217 }
218
219 ## the actual initialization routine. whee.
220 sub _authentication_initialize {
221     my $app = shift;
222
223     ## let's avoid recreating / configuring everything if we have already done it, eh?
224     if ($app->can('_auth_realms')) { return };
225
226     ## make classdata where it is used.  
227     $app->mk_classdata( '_auth_realms' => {});
228     
229     ## the order to attempt restore in - If we don't have session - we have 
230     ## no way to be sure where a frozen user came from - so we have to 
231     ## ask each realm if it can restore the user.  Unfortunately it is possible 
232     ## that multiple realms could restore the user from the data we have - 
233     ## So we have to determine at setup time what order to ask the realms in.  
234     ## The default is to use the user_restore_priority values defined in the realm
235     ## config. if they are not defined - we go by alphabetical order.   Note that 
236     ## the 'default' realm always gets first chance at it unless it is explicitly
237     ## placed elsewhere by user_restore_priority.  Remember this only comes
238     ## into play if session is disabled. 
239     
240     $app->mk_classdata( '_auth_realm_restore_order' => []);
241     
242     my $cfg = $app->config->{'Plugin::Authentication'};
243     if (!defined($cfg)) {
244         if (exists($app->config->{'authentication'})) {
245             $cfg = $app->config->{'authentication'};
246             $app->config->{'Plugin::Authentication'} = $app->config->{'authentication'};
247         } else {
248             $cfg = {};
249         }
250     }
251
252     # old default was to force use_session on.  This must remain for that
253     # reason - but if use_session is already in the config, we respect it's setting.
254     if (!exists($cfg->{'use_session'})) {
255         $cfg->{'use_session'} = 1;
256     }
257     
258     if (exists($cfg->{'realms'})) {
259         
260         my %auth_restore_order;
261         my $authcount = 2;
262         my $defaultrealm = 'default';
263         
264         foreach my $realm (sort keys %{$cfg->{'realms'}}) {
265             
266             $app->setup_auth_realm($realm, $cfg->{'realms'}{$realm});
267             
268             if (exists($cfg->{'realms'}{$realm}{'user_restore_priority'})) {
269                 $auth_restore_order{$realm} = $cfg->{'realms'}{$realm}{'user_restore_priority'};
270             } else {
271                 $auth_restore_order{$realm} = $authcount++;
272             }
273         }
274         
275         # if we have a 'default_realm' in the config hash and we don't already 
276         # have a realm called 'default', we point default at the realm specified
277         if (exists($cfg->{'default_realm'}) && !$app->get_auth_realm('default')) {
278             if ($app->_set_default_auth_realm($cfg->{'default_realm'})) {
279                 $defaultrealm = $cfg->{'default_realm'};
280                 $auth_restore_order{'default'} = $auth_restore_order{$cfg->{'default_realm'}};
281                 delete($auth_restore_order{$cfg->{'default_realm'}});
282             }
283         }
284         
285         ## if the default realm did not have a defined priority in it's config - we put it at the front.
286         if (!exists($cfg->{'realms'}{$defaultrealm}{'user_restore_priority'})) {
287             $auth_restore_order{'default'} = 1;
288         }
289         
290         @{$app->_auth_realm_restore_order} = sort { $auth_restore_order{$a} <=> $auth_restore_order{$b} } keys %auth_restore_order;
291         
292     } else {
293         
294         ## BACKWARDS COMPATIBILITY - if realms is not defined - then we are probably dealing
295         ## with an old-school config.  The only caveat here is that we must add a classname
296         
297         ## also - we have to treat {store} as {stores}{default} - because 
298         ## while it is not a clear as a valid config in the docs, it 
299         ## is functional with the old api. Whee!
300         if (exists($cfg->{'store'}) && !exists($cfg->{'stores'}{'default'})) {
301             $cfg->{'stores'}{'default'} = $cfg->{'store'};
302         }
303
304         push @{$app->_auth_realm_restore_order}, 'default';
305         foreach my $storename (keys %{$cfg->{'stores'}}) {
306             my $realmcfg = {
307                 store => { class => $cfg->{'stores'}{$storename} },
308             };
309             $app->setup_auth_realm($storename, $realmcfg);
310         }
311     } 
312     
313 }
314
315 # set up realmname.
316 sub setup_auth_realm {
317     my ($app, $realmname, $config) = @_;
318     
319     my $realmclass = $config->{class};
320
321     if( !$realmclass ) {
322         $realmclass = 'Catalyst::Authentication::Realm';
323     } elsif ($realmclass !~ /^\+(.*)$/ ) {
324         $realmclass = "Catalyst::Authentication::Realm::${realmclass}";
325     } else {
326         $realmclass = $1;
327     }
328
329     Catalyst::Utils::ensure_class_loaded( $realmclass );
330
331     my $realm = $realmclass->new($realmname, $config, $app);
332     if ($realm) {
333         $app->auth_realms->{$realmname} = $realm;
334     } else {
335         $app->log->debug("realm initialization for '$realmname' failed.");
336     }
337     return $realm;
338 }
339
340 sub auth_realms {
341     my $self = shift;
342     return($self->_auth_realms);
343 }
344
345 sub get_auth_realm {
346     my ($app, $realmname) = @_;
347     
348     return $app->auth_realms->{$realmname};
349     
350 }
351
352
353 # Very internal method.  Vital Valuable Urgent, Do not touch on pain of death.
354 # Using this method just assigns the default realm to be the value associated
355 # with the realmname provided.  It WILL overwrite any real realm called 'default'
356 # so can be very confusing if used improperly.  It's used properly already. 
357 # Translation: don't use it.
358 sub _set_default_auth_realm {
359     my ($app, $realmname) = @_;
360     
361     if (exists($app->auth_realms->{$realmname})) {
362         $app->auth_realms->{'default'} = $app->auth_realms->{$realmname};
363     }
364     return $app->get_auth_realm('default');
365 }
366
367 sub authenticate {
368     my ($app, $userinfo, $realmname) = @_;
369     
370     if (!$realmname) {
371         $realmname = 'default';
372     }
373         
374     my $realm = $app->get_auth_realm($realmname);
375     
376     ## note to self - make authenticate throw an exception if realm is invalid.
377     
378     if ($realm) {
379         return $realm->authenticate($app, $userinfo);
380     } else {
381         Catalyst::Exception->throw(
382                 "authenticate called with nonexistant realm: '$realmname'.");
383
384     }
385     return undef;
386 }
387
388 ## BACKWARDS COMPATIBILITY  -- Warning:  Here be monsters!
389 #
390 # What follows are backwards compatibility routines - for use with Stores and Credentials
391 # that have not been updated to work with C::P::Authentication v0.10.  
392 # These are here so as to not break people's existing installations, but will go away
393 # in a future version.
394 #
395 # The old style of configuration only supports a single store, as each store module
396 # sets itself as the default store upon being loaded.  This is the only supported 
397 # 'compatibility' mode.  
398 #
399
400 sub get_user {
401     my ( $c, $uid, @rest ) = @_;
402
403     return $c->find_user( {'id' => $uid, 'rest'=>\@rest }, 'default' );
404 }
405
406
407 ## this should only be called when using old-style authentication plugins.  IF this gets
408 ## called in a new-style config - it will OVERWRITE the store of your default realm.  Don't do it.
409 ## also - this is a partial setup - because no credential is instantiated... in other words it ONLY
410 ## works with old-style auth plugins and C::P::Authentication in compatibility mode.  Trying to combine
411 ## this with a realm-type config will probably crash your app.
412 sub default_auth_store {
413     my $self = shift;
414
415     my $realm = $self->get_auth_realm('default');
416     if (!$realm) {
417         $realm = $self->setup_auth_realm('default', { class => 'Compatibility' });
418     }
419     if ( my $new = shift ) {
420         $realm->store($new);
421         
422         my $storeclass;
423         if (ref($new)) {
424             $storeclass = ref($new);
425         } else {
426             $storeclass = $new;
427         }
428         
429         # BACKWARDS COMPATIBILITY - if the store class does not define find_user, we define it in terms 
430         # of get_user and add it to the class.  this is because the auth routines use find_user, 
431         # and rely on it being present. (this avoids per-call checks)
432         if (!$storeclass->can('find_user')) {
433             no strict 'refs';
434             *{"${storeclass}::find_user"} = sub {
435                                                     my ($self, $info) = @_;
436                                                     my @rest = @{$info->{rest}} if exists($info->{rest});
437                                                     $self->get_user($info->{id}, @rest);
438                                                 };
439         }
440     }
441
442     return $self->get_auth_realm('default')->store;
443 }
444
445 ## BACKWARDS COMPATIBILITY
446 ## this only ever returns a hash containing 'default' - as that is the only
447 ## supported mode of calling this.
448 sub auth_store_names {
449     my $self = shift;
450
451     my %hash = (  $self->get_auth_realm('default')->store => 'default' );
452 }
453
454 sub get_auth_store {
455     my ( $self, $name ) = @_;
456     
457     if ($name ne 'default') {
458         Carp::croak "get_auth_store called on non-default realm '$name'. Only default supported in compatibility mode";        
459     } else {
460         $self->default_auth_store();
461     }
462 }
463
464 sub get_auth_store_name {
465     my ( $self, $store ) = @_;
466     return 'default';
467 }
468
469 # sub auth_stores is only used internally - here for completeness
470 sub auth_stores {
471     my $self = shift;
472
473     my %hash = ( 'default' => $self->get_auth_realm('default')->store);
474 }
475
476 __PACKAGE__;
477
478 __END__
479
480 =pod
481
482 =head1 NAME
483
484 Catalyst::Plugin::Authentication - Infrastructure plugin for the Catalyst
485 authentication framework.
486
487 =head1 SYNOPSIS
488
489     use Catalyst qw/
490         Authentication
491     /;
492
493     # later on ...
494     $c->authenticate({ username => 'myusername', 
495                        password => 'mypassword' });
496     my $age = $c->user->get('age');
497     $c->logout;
498
499 =head1 DESCRIPTION
500
501 The authentication plugin provides generic user support for Catalyst apps. It
502 is the basis for both authentication (checking the user is who they claim to
503 be), and authorization (allowing the user to do what the system authorises
504 them to do).
505
506 Using authentication is split into two parts. A Store is used to actually
507 store the user information, and can store any amount of data related to the
508 user. Credentials are used to verify users, using information from the store,
509 given data from the frontend. A Credential and a Store are paired to form a
510 'Realm'. A Catalyst application using the authentication framework must have
511 at least one realm, and may have several.
512
513 To implement authentication in a Catalyst application you need to add this 
514 module, and specify at least one realm in the configuration. 
515
516 Authentication data can also be stored in a session, if the application 
517 is using the L<Catalyst::Plugin::Session> module.
518
519 B<NOTE> in version 0.10 of this module, the interface to this module changed.
520 Please see L</COMPATIBILITY ROUTINES> for more information.
521
522 =head1 INTRODUCTION
523
524 =head2 The Authentication/Authorization Process
525
526 Web applications typically need to identify a user - to tell the user apart
527 from other users. This is usually done in order to display private information
528 that is only that user's business, or to limit access to the application so
529 that only certain entities can access certain parts.
530
531 This process is split up into several steps. First you ask the user to identify
532 themselves. At this point you can't be sure that the user is really who they
533 claim to be.
534
535 Then the user tells you who they are, and backs this claim with some piece of
536 information that only the real user could give you. For example, a password is
537 a secret that is known to both the user and you. When the user tells you this
538 password you can assume they're in on the secret and can be trusted (ignore
539 identity theft for now). Checking the password, or any other proof is called
540 B<credential verification>.
541
542 By this time you know exactly who the user is - the user's identity is
543 B<authenticated>. This is where this module's job stops, and your application
544 or other plugins step in.  
545
546 The next logical step is B<authorization>, the process of deciding what a user
547 is (or isn't) allowed to do. For example, say your users are split into two
548 main groups - regular users and administrators. You want to verify that the
549 currently logged in user is indeed an administrator before performing the
550 actions in an administrative part of your application. These decisions may be
551 made within your application code using just the information available after
552 authentication, or it may be facilitated by a number of plugins.  
553
554 =head2 The Components In This Framework
555
556 =head3 Realms
557
558 Configuration of the Catalyst::Plugin::Authentication framework is done in
559 terms of realms. In simplest terms, a realm is a pairing of a Credential
560 verifier and a User storage (Store) backend. As of version 0.10003, realms are
561 now objects that you can create and customize.
562
563 An application can have any number of Realms, each of which operates
564 independant of the others. Each realm has a name, which is used to identify it
565 as the target of an authentication request. This name can be anything, such as
566 'users' or 'members'. One realm must be defined as the default_realm, which is
567 used when no realm name is specified. More information about configuring
568 realms is available in the configuration section.
569
570 =head3 Credential Verifiers
571
572 When user input is transferred to the L<Catalyst> application
573 (typically via form inputs) the application may pass this information
574 into the authentication system through the C<<$c->authenticate()>>
575 method.  From there, it is passed to the appropriate Credential
576 verifier.
577
578 These plugins check the data, and ensure that it really proves the user is who
579 they claim to be.
580
581 Credential verifiers compatible with versions of this module 0.10x and
582 upwards should be in the namespace
583 C<Catalyst::Authentication::Credential>.
584
585 =head3 Storage Backends
586
587 The authentication data also identifies a user, and the Storage backend modules
588 use this data to locate and return a standardized object-oriented
589 representation of a user.
590
591 When a user is retrieved from a store it is not necessarily authenticated.
592 Credential verifiers accept a set of authentication data and use this
593 information to retrieve the user from the store they are paired with.
594
595 storage backends compatible with versions of this module 0.10x and
596 upwards should be in the namespace
597 C<Catalyst::Authentication::Store>.
598
599 =head3 The Core Plugin
600
601 This plugin on its own is the glue, providing realm configuration, session
602 integration, and other goodness for the other plugins.
603
604 =head3 Other Plugins
605
606 More layers of plugins can be stacked on top of the authentication code. For
607 example, L<Catalyst::Plugin::Session::PerUser> provides an abstraction of
608 browser sessions that is more persistent per user.
609 L<Catalyst::Plugin::Authorization::Roles> provides an accepted way to separate
610 and group users into categories, and then check which categories the current
611 user belongs to.
612
613 =head1 EXAMPLE
614
615 Let's say we were storing users in a simple perl hash. Users are
616 verified by supplying a password which is matched within the hash.
617
618 This means that our application will begin like this:
619
620     package MyApp;
621
622     use Catalyst qw/
623         Authentication
624     /;
625
626     __PACKAGE__->config->{'Plugin::Authentication'} = 
627                 {  
628                     default_realm => 'members',
629                     realms => {
630                         members => {
631                             credential => {
632                                 class => 'Password',
633                                 password_field => 'password',
634                                 password_type => 'clear'
635                             },
636                             store => {
637                                 class => 'Minimal',
638                                 users = {
639                                     bob => {
640                                         password => "s00p3r",                                       
641                                         editor => 'yes',
642                                         roles => [qw/edit delete/],
643                                     },
644                                     william => {
645                                         password => "s3cr3t",
646                                         roles => [qw/comment/],
647                                     }
648                                 }                       
649                             }
650                         }
651                         }
652                 };
653     
654
655 This tells the authentication plugin what realms are available, which
656 credential and store modules are used, and the configuration of each. With
657 this code loaded, we can now attempt to authenticate users.
658
659 To show an example of this, let's create an authentication controller:
660
661     package MyApp::Controller::Auth;
662
663     sub login : Local {
664         my ( $self, $c ) = @_;
665
666         if (    my $user     = $c->req->param("user")
667             and my $password = $c->req->param("password") )
668         {
669             if ( $c->authenticate( { username => $user, 
670                                      password => $password } ) ) {
671                 $c->res->body( "hello " . $c->user->get("name") );
672             } else {
673                 # login incorrect
674             }
675         }
676         else {
677             # invalid form input
678         }
679     }
680
681 This code should be self-explanatory. If all the necessary fields are supplied,
682 call the C<authenticate> method on the context object. If it succeeds the 
683 user is logged in.
684
685 The credential verifier will attempt to retrieve the user whose
686 details match the authentication information provided to
687 C<<$c->authenticate()>>. Once it fetches the user the password is
688 checked and if it matches the user will be B<authenticated> and
689 C<<$c->user>> will contain the user object retrieved from the store.
690
691 In the above case, the default realm is checked, but we could just as easily
692 check an alternate realm. If this were an admin login, for example, we could
693 authenticate on the admin realm by simply changing the C<<$c->authenticate()>>
694 call:
695
696     if ( $c->authenticate( { username => $user, 
697                              password => $password }, 'admin' ) ) {
698         $c->res->body( "hello " . $c->user->get("name") );
699     } ...
700
701
702 Now suppose we want to restrict the ability to edit to a user with an 
703 'editor' value of yes.
704
705 The restricted action might look like this:
706
707     sub edit : Local {
708         my ( $self, $c ) = @_;
709
710         $c->detach("unauthorized")
711           unless $c->user_exists
712           and $c->user->get('editor') eq 'yes';
713
714         # do something restricted here
715     }
716
717 (Note that if you have multiple realms, you can use
718 C<<$c->user_in_realm('realmname')>>) in place of
719 C<<$c->user_exists();>> This will essentially perform the same
720 verification as user_exists, with the added requirement that if there
721 is a user, it must have come from the realm specified.)
722
723 The above example is somewhat similar to role based access control.  
724 L<Catalyst::Authentication::Store::Minimal> treats the roles field as
725 an array of role names. Let's leverage this. Add the role authorization
726 plugin:
727
728     use Catalyst qw/
729         ...
730         Authorization::Roles
731     /;
732
733     sub edit : Local {
734         my ( $self, $c ) = @_;
735
736         $c->detach("unauthorized") unless $c->check_roles("edit");
737
738         # do something restricted here
739     }
740
741 This is somewhat simpler and will work if you change your store, too, since the
742 role interface is consistent.
743
744 Let's say your app grew, and you now have 10000 users. It's no longer
745 efficient to maintain a hash of users, so you move this data to a database.
746 You can accomplish this simply by installing the L<DBIx::Class|Catalyst::Authentication::Store::DBIx::Class> Store and
747 changing your config:
748
749     __PACKAGE__->config->{'Plugin::Authentication'} = 
750                     {  
751                         default_realm => 'members',
752                         realms => {
753                             members => {
754                                 credential => {
755                                     class => 'Password',
756                                     password_field => 'password',
757                                     password_type => 'clear'
758                                 },
759                                 store => {
760                                     class => 'DBIx::Class',
761                                     user_class => 'MyApp::Users',
762                                     role_column => 'roles'                      
763                                 }
764                                 }
765                         }
766                     };
767
768 The authentication system works behind the scenes to load your data from the
769 new source. The rest of your application is completely unchanged.
770
771
772 =head1 CONFIGURATION
773
774     # example
775     __PACKAGE__->config->{'Plugin::Authentication'} = 
776                 {  
777                     default_realm => 'members',
778                     realms => {
779                         members => {
780                             credential => {
781                                 class => 'Password',
782                                 password_field => 'password',
783                                 password_type => 'clear'
784                             },
785                             store => {
786                                 class => 'DBIx::Class',
787                                     user_class => 'MyApp::Users',
788                                     role_column => 'roles'                      
789                                 }
790                         },
791                         admins => {
792                             credential => {
793                                 class => 'Password',
794                                 password_field => 'password',
795                                 password_type => 'clear'
796                             },
797                             store => {
798                                 class => '+MyApp::Authentication::Store::NetAuth',
799                                 authserver => '192.168.10.17'
800                             }
801                         }
802                         
803                         }
804                 };
805
806 =over 4
807
808 =item use_session
809
810 Whether or not to store the user's logged in state in the session, if the
811 application is also using L<Catalyst::Plugin::Session>. This 
812 value is set to true per default.
813
814 =item default_realm
815
816 This defines which realm should be used as when no realm is provided to methods
817 that require a realm such as authenticate or find_user.
818
819 =item realms
820
821 This contains the series of realm configurations you want to use for your app.
822 The only rule here is that there must be at least one.  A realm consists of a
823 name, which is used to reference the realm, a credential and a store.  
824
825 You can also specify a realm class to instantiate instead of the default
826 L<Catalyst::Authentication::Realm> class using the 'class' element within the
827 realm config.
828
829 Each realm config contains two hashes, one called 'credential' and one called 
830 'store', each of which provide configuration details to the respective modules.
831 The contents of these hashes is specific to the module being used, with the 
832 exception of the 'class' element, which tells the core Authentication module the
833 classname to instantiate.  
834
835 The 'class' element follows the standard Catalyst mechanism of class
836 specification. If a class is prefixed with a +, it is assumed to be a complete
837 class name. Otherwise it is considered to be a portion of the class name. For
838 credentials, the classname 'B<Password>', for example, is expanded to
839 Catalyst::Authentication::Credential::B<Password>. For stores, the
840 classname 'B<storename>' is expanded to:
841 Catalyst::Authentication::Store::B<storename>.
842
843 =back
844
845 =head1 METHODS
846
847 =head2 $c->authenticate( $userinfo, [ $realm ])
848
849 Attempts to authenticate the user using the information in the $userinfo hash
850 reference using the realm $realm. $realm may be omitted, in which case the
851 default realm is checked.
852
853 =head2 $c->user( )
854
855 Returns the currently logged in user or undef if there is none.
856
857 =head2 $c->user_exists( )
858
859 Returns true if a user is logged in right now. The difference between
860 user_exists and user is that user_exists will return true if a user is logged
861 in, even if it has not been yet retrieved from the storage backend. If you only
862 need to know if the user is logged in, depending on the storage mechanism this
863 can be much more efficient.
864
865 =head2 $c->user_in_realm( $realm )
866
867 Works like user_exists, except that it only returns true if a user is both 
868 logged in right now and was retrieved from the realm provided.  
869
870 =head2 $c->logout( )
871
872 Logs the user out, Deletes the currently logged in user from C<<$c->user>> and the session.
873
874 =head2 $c->find_user( $userinfo, $realm )
875
876 Fetch a particular users details, matching the provided user info, from the realm 
877 specified in $realm.
878
879 =head2 persist_user()
880
881 Under normal circumstances the user data is only saved to the session during
882 initial authentication.  This call causes the auth system to save the 
883 currently authenticated users data across requests.  Useful if you have
884 changed the user data and want to ensure that future requests reflect the
885 most current data.  Assumes that at the time of this call, $c->user 
886 contains the most current data.
887
888 =head1 INTERNAL METHODS
889
890 These methods are for Catalyst::Plugin::Authentication B<INTERNAL USE> only.
891 Please do not use them in your own code, whether application or credential /
892 store modules. If you do, you will very likely get the nasty shock of having
893 to fix / rewrite your code when things change. They are documented here only
894 for reference.
895
896 =head2 $c->set_authenticated( $user, $realmname )
897
898 Marks a user as authenticated. This is called from within the authenticate
899 routine when a credential returns a user. $realmname defaults to 'default'
900
901 =head2 $c->auth_restore_user( $user, $realmname )
902
903 Used to restore a user from the session. In most cases this is called without
904 arguments to restore the user via the session. Can be called with arguments
905 when restoring a user from some other method.  Currently not used in this way.
906
907 =head2 $c->auth_realms( )
908
909 Returns a hashref containing realmname -> realm instance pairs. Realm
910 instances contain an instantiated store and credential object as the 'store'
911 and 'credential' elements, respectively
912
913 =head2 $c->get_auth_realm( $realmname )
914
915 Retrieves the realm instance for the realmname provided.
916
917 =head1 SEE ALSO
918
919 This list might not be up to date.  Below are modules known to work with the updated
920 API of 0.10 and are therefore compatible with realms.  
921
922 =head2 Realms
923
924 L<Catalyst::Authentication::Realm>
925
926 =head2 User Storage Backends
927
928 L<Catalyst::Authentication::Store::Minimal>,
929 L<Catalyst::Authentication::Store::DBIx::Class>,
930
931 =head2 Credential verification
932
933 L<Catalyst::Authentication::Credential::Password>,
934
935 =head2 Authorization
936
937 L<Catalyst::Plugin::Authorization::ACL>,
938 L<Catalyst::Plugin::Authorization::Roles>
939
940 =head2 Internals Documentation
941
942 L<Catalyst::Plugin::Authentication::Internals>
943
944 =head2 Misc
945
946 L<Catalyst::Plugin::Session>,
947 L<Catalyst::Plugin::Session::PerUser>
948
949 =head1 DON'T SEE ALSO
950
951 This module along with its sub plugins deprecate a great number of other
952 modules. These include L<Catalyst::Plugin::Authentication::Simple>,
953 L<Catalyst::Plugin::Authentication::CDBI>.
954
955 At the time of writing these plugins have not yet been replaced or updated, but
956 should be eventually: L<Catalyst::Plugin::Authentication::OpenID>,
957 L<Catalyst::Plugin::Authentication::LDAP>,
958 L<Catalyst::Plugin::Authentication::CDBI::Basic>,
959 L<Catalyst::Plugin::Authentication::Basic::Remote>.
960
961 =head1 INCOMPATABILITIES
962
963 The realms based configuration and functionality of the 0.10 update 
964 of L<Catalyst::Plugin::Authentication> required a change in the API used by
965 credentials and stores.  It has a compatibility mode which allows use of
966 modules that have not yet been updated. This, however, completely mimics the
967 older api and disables the new realm-based features. In other words you can
968 not mix the older credential and store modules with realms, or realm-based
969 configs. The changes required to update modules are relatively minor and are
970 covered in L<Catalyst::Plugin::Authentication::Internals>.  We hope that most
971 modules will move to the compatible list above very quickly.
972
973 =head1 COMPATIBILITY ROUTINES
974
975 In version 0.10 of L<Catalyst::Plugin::Authentication>, the API
976 changed. For app developers, this change is fairly minor, but for
977 Credential and Store authors, the changes are significant. 
978
979 Please see the documentation in version 0.09 of
980 Catalyst::Plugin::Authentication for a better understanding of how the old API
981 functioned.
982
983 The items below are still present in the plugin, though using them is
984 deprecated. They remain only as a transition tool, for those sites which can
985 not yet be upgraded to use the new system due to local customizations or use
986 of Credential / Store modules that have not yet been updated to work with the 
987 new API.
988
989 These routines should not be used in any application using realms
990 functionality or any of the methods described above. These are for reference
991 purposes only.
992
993 =head2 $c->login( )
994
995 This method is used to initiate authentication and user retrieval. Technically
996 this is part of the old Password credential module and it still resides in the
997 L<Password|Catalyst::Plugin::Authentication::Credential::Password> class. It is
998 included here for reference only.
999
1000 =head2 $c->default_auth_store( )
1001
1002 Return the store whose name is 'default'.
1003
1004 This is set to C<< $c->config->{'Plugin::Authentication'}{store} >> if that value exists,
1005 or by using a Store plugin:
1006
1007     # load the Minimal authentication store.
1008         use Catalyst qw/Authentication Authentication::Store::Minimal/;
1009
1010 Sets the default store to
1011 L<Catalyst::Plugin::Authentication::Store::Minimal>.
1012
1013 =head2 $c->get_auth_store( $name )
1014
1015 Return the store whose name is $name.
1016
1017 =head2 $c->get_auth_store_name( $store )
1018
1019 Return the name of the store $store.
1020
1021 =head2 $c->auth_stores( )
1022
1023 A hash keyed by name, with the stores registered in the app.
1024
1025 =head2 $c->register_auth_stores( %stores_by_name )
1026
1027 Register stores into the application.
1028
1029 =head2 $c->auth_store_names( )
1030
1031 =head2 $c->get_user( )
1032
1033 =head2 $c->setup( )
1034
1035 =head2 $c->setup_auth_realm( )
1036
1037 =head1 AUTHORS
1038
1039 Yuval Kogman, C<nothingmuch@woobling.org>
1040
1041 Jay Kuri, C<jayk@cpan.org>
1042
1043 Jess Robinson
1044
1045 David Kamholz
1046
1047 =head1 COPYRIGHT & LICENSE
1048
1049         Copyright (c) 2005 the aforementioned authors. All rights
1050         reserved. This program is free software; you can redistribute
1051         it and/or modify it under the same terms as Perl itself.
1052
1053 =cut
1054