r34289@cain (orig r5694): jayk | 2006-12-05 18:22:25 +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 {
c9b72c5b 41 $c->save_user_in_session($user, $realmname);
f869137d 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 {
c9b72c5b 92 my ( $c, $user, $realmname ) = @_;
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')) {
c9b72c5b 206 $c->_set_default_auth_realm($cfg->{'default_realm'});
f869137d 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
c9b72c5b 293
294# Very internal method. Vital Valuable Urgent, Do not touch on pain of death.
295# Using this method just assigns the default realm to be the value associated
296# with the realmname provided. It WILL overwrite any real realm called 'default'
297# so can be very confusing if used improperly. It's used properly already.
298# Translation: don't use it.
299sub _set_default_auth_realm {
f869137d 300 my ($app, $realmname) = @_;
301
302 if (exists($app->auth_realms->{$realmname})) {
303 $app->auth_realms->{'default'} = $app->auth_realms->{$realmname};
f2fee7ad 304 }
f869137d 305 return $app->get_auth_realm('default');
8b52f75e 306}
307
f869137d 308sub authenticate {
309 my ($app, $userinfo, $realmname) = @_;
310
311 if (!$realmname) {
312 $realmname = 'default';
313 }
314
315 my $realm = $app->get_auth_realm($realmname);
316
317 if ($realm && exists($realm->{'credential'})) {
318 my $user = $realm->{'credential'}->authenticate($app, $realm->{store}, $userinfo);
6229329e 319 if (ref($user)) {
f869137d 320 $app->set_authenticated($user, $realmname);
321 return $user;
322 }
323 } else {
324 $app->log->debug("The realm requested, '$realmname' does not exist," .
325 " or there is no credential associated with it.")
326 }
46c08636 327 return undef;
8b52f75e 328}
329
f869137d 330## BACKWARDS COMPATIBILITY -- Warning: Here be monsters!
331#
332# What follows are backwards compatibility routines - for use with Stores and Credentials
333# that have not been updated to work with C::P::Authentication v0.10.
334# These are here so as to not break people's existing installations, but will go away
335# in a future version.
336#
337# The old style of configuration only supports a single store, as each store module
338# sets itself as the default store upon being loaded. This is the only supported
339# 'compatibility' mode.
340#
341
342sub get_user {
343 my ( $c, $uid, @rest ) = @_;
8b52f75e 344
f869137d 345 return $c->find_user( {'id' => $uid, 'rest'=>\@rest }, 'default' );
8b52f75e 346}
347
c9b72c5b 348
f869137d 349## this should only be called when using old-style authentication plugins. IF this gets
350## called in a new-style config - it will OVERWRITE the store of your default realm. Don't do it.
351## also - this is a partial setup - because no credential is instantiated... in other words it ONLY
352## works with old-style auth plugins and C::P::Authentication in compatibility mode. Trying to combine
353## this with a realm-type config will probably crash your app.
8b52f75e 354sub default_auth_store {
f2fee7ad 355 my $self = shift;
8b52f75e 356
f2fee7ad 357 if ( my $new = shift ) {
f869137d 358 $self->auth_realms->{'default'}{'store'} = $new;
359 my $storeclass = ref($new);
360
361 # BACKWARDS COMPATIBILITY - if the store class does not define find_user, we define it in terms
362 # of get_user and add it to the class. this is because the auth routines use find_user,
363 # and rely on it being present. (this avoids per-call checks)
364 if (!$storeclass->can('find_user')) {
365 no strict 'refs';
366 *{"${storeclass}::find_user"} = sub {
367 my ($self, $info) = @_;
368 my @rest = @{$info->{rest}} if exists($info->{rest});
369 $self->get_user($info->{id}, @rest);
370 };
371 }
f2fee7ad 372 }
8b52f75e 373
f869137d 374 return $self->get_auth_realm('default')->{'store'};
8b52f75e 375}
376
f869137d 377## BACKWARDS COMPATIBILITY
378## this only ever returns a hash containing 'default' - as that is the only
379## supported mode of calling this.
380sub auth_store_names {
381 my $self = shift;
382
383 my %hash = ( $self->get_auth_realm('default')->{'store'} => 'default' );
384}
385
386sub get_auth_store {
387 my ( $self, $name ) = @_;
388
389 if ($name ne 'default') {
390 Carp::croak "get_auth_store called on non-default realm '$name'. Only default supported in compatibility mode";
391 } else {
392 $self->default_auth_store();
393 }
394}
395
396sub get_auth_store_name {
397 my ( $self, $store ) = @_;
398 return 'default';
399}
400
401# sub auth_stores is only used internally - here for completeness
402sub auth_stores {
403 my $self = shift;
404
405 my %hash = ( 'default' => $self->get_auth_realm('default')->{'store'});
406}
407
07e49bc7 408__PACKAGE__;
409
410__END__
411
412=pod
413
414=head1 NAME
415
033d2c24 416Catalyst::Plugin::Authentication - Infrastructure plugin for the Catalyst
417authentication framework.
07e49bc7 418
419=head1 SYNOPSIS
420
18a3c897 421 use Catalyst qw/
422 Authentication
18a3c897 423 /;
424
425 # later on ...
f869137d 426 $c->authenticate({ username => 'myusername', password => 'mypassword' });
427 my $age = $c->user->get('age');
18a3c897 428 $c->logout;
07e49bc7 429
430=head1 DESCRIPTION
431
5d0fd266 432The authentication plugin provides generic user support for Catalyst apps. It
433is the basis for both authentication (checking the user is who they claim to
434be), and authorization (allowing the user to do what the system authorises
435them to do).
436
437Using authentication is split into two parts. A Store is used to actually
438store the user information, and can store any amount of data related to the
439user. Credentials are used to verify users, using information from the store,
440given data from the frontend. A Credential and a Store are paired to form a
c9b72c5b 441'Realm'. A Catalyst application using the authentication framework must have
442at least one realm, and may have several.
18a3c897 443
f0f9cd72 444To implement authentication in a Catalyst application you need to add this
5d0fd266 445module, and specify at least one realm in the configuration.
18a3c897 446
14929a35 447Authentication data can also be stored in a session, if the application
448is using the L<Catalyst::Plugin::Session> module.
07e49bc7 449
d19dc3ce 450B<NOTE> in version 0.10 of this module, the interface to this module changed.
451Please see L</COMPATIBILITY ROUTINES> for more information.
c9b72c5b 452
e5108df9 453=head1 INTRODUCTION
454
455=head2 The Authentication/Authorization Process
456
457Web applications typically need to identify a user - to tell the user apart
458from other users. This is usually done in order to display private information
459that is only that user's business, or to limit access to the application so
460that only certain entities can access certain parts.
461
462This process is split up into several steps. First you ask the user to identify
463themselves. At this point you can't be sure that the user is really who they
464claim to be.
465
f0f9cd72 466Then the user tells you who they are, and backs this claim with some piece of
e5108df9 467information that only the real user could give you. For example, a password is
468a secret that is known to both the user and you. When the user tells you this
469password you can assume they're in on the secret and can be trusted (ignore
470identity theft for now). Checking the password, or any other proof is called
471B<credential verification>.
472
473By this time you know exactly who the user is - the user's identity is
5d0fd266 474B<authenticated>. This is where this module's job stops, and your application
475or other plugins step in.
476
477The next logical step is B<authorization>, the process of deciding what a user
478is (or isn't) allowed to do. For example, say your users are split into two
479main groups - regular users and administrators. You want to verify that the
e5108df9 480currently logged in user is indeed an administrator before performing the
5d0fd266 481actions in an administrative part of your application. These decisionsmay be
482made within your application code using just the information available after
483authentication, or it may be facilitated by a number of plugins.
e5108df9 484
485=head2 The Components In This Framework
486
c955e5dc 487=head3 Realms
488
489Configuration of the Catalyst::Plugin::Authentication framework is done in
490terms of realms. In simplest terms, a realm is a pairing of a Credential
491verifier and a User storage (Store) backend.
492
493An application can have any number of Realms, each of which operates
494independant of the others. Each realm has a name, which is used to identify it
495as the target of an authentication request. This name can be anything, such as
496'users' or 'members'. One realm must be defined as the default_realm, which is
5d0fd266 497used when no realm name is specified. More information about configuring
498realms is available in the configuration section.
c955e5dc 499
e5108df9 500=head3 Credential Verifiers
501
502When user input is transferred to the L<Catalyst> application (typically via
5d0fd266 503form inputs) the application may pass this information into the authentication
504system through the $c->authenticate() method. From there, it is passed to the
c955e5dc 505appropriate Credential verifier.
e5108df9 506
507These plugins check the data, and ensure that it really proves the user is who
508they claim to be.
509
510=head3 Storage Backends
511
5d0fd266 512The authentication data also identifies a user, and the Storage Backend modules
c955e5dc 513use this data to locate and return a standardized object-oriented
514representation of a user.
e5108df9 515
516When a user is retrieved from a store it is not necessarily authenticated.
c955e5dc 517Credential verifiers accept a set of authentication data and use this
518information to retrieve the user from the store they are paired with.
e5108df9 519
520=head3 The Core Plugin
521
c955e5dc 522This plugin on its own is the glue, providing realm configuration, session
e5108df9 523integration, and other goodness for the other plugins.
524
525=head3 Other Plugins
526
527More layers of plugins can be stacked on top of the authentication code. For
528example, L<Catalyst::Plugin::Session::PerUser> provides an abstraction of
529browser sessions that is more persistent per users.
530L<Catalyst::Plugin::Authorization::Roles> provides an accepted way to separate
531and group users into categories, and then check which categories the current
532user belongs to.
533
caae740f 534=head1 EXAMPLE
535
5d0fd266 536Let's say we were storing users in a simple perl hash. Users are
537verified by supplying a password which is matched within the hash.
caae740f 538
539This means that our application will begin like this:
540
541 package MyApp;
542
543 use Catalyst qw/
544 Authentication
caae740f 545 /;
546
c955e5dc 547 __PACKAGE__->config->{authentication} =
548 {
549 default_realm => 'members',
550 realms => {
551 members => {
552 credential => {
553 class => 'Password'
554 },
555 store => {
46c08636 556 class => 'Minimal',
c955e5dc 557 users = {
558 bob => {
5d0fd266 559 password => "s00p3r",
c955e5dc 560 editor => 'yes',
561 roles => [qw/edit delete/],
562 },
563 william => {
5d0fd266 564 password => "s3cr3t",
c955e5dc 565 roles => [qw/comment/],
566 }
567 }
568 }
569 }
570 }
571 };
572
caae740f 573
5d0fd266 574This tells the authentication plugin what realms are available, which
575credential and store modules are used, and the configuration of each. With
576this code loaded, we can now attempt to authenticate users.
caae740f 577
c955e5dc 578To show an example of this, let's create an authentication controller:
caae740f 579
580 package MyApp::Controller::Auth;
581
582 sub login : Local {
583 my ( $self, $c ) = @_;
584
585 if ( my $user = $c->req->param("user")
586 and my $password = $c->req->param("password") )
587 {
c955e5dc 588 if ( $c->authenticate( { username => $user,
589 password => $password } ) ) {
590 $c->res->body( "hello " . $c->user->get("name") );
caae740f 591 } else {
592 # login incorrect
593 }
594 }
595 else {
596 # invalid form input
597 }
598 }
599
600This code should be very readable. If all the necessary fields are supplied,
c955e5dc 601call the L<Catalyst::Plugin::Authentication/authenticate> method in the
602controller. If it succeeds the user is logged in.
caae740f 603
c955e5dc 604The credential verifier will attempt to retrieve the user whose details match
605the authentication information provided to $c->authenticate(). Once it fetches
606the user the password is checked and if it matches the user will be
5d0fd266 607B<authenticated> and C<< $c->user >> will contain the user object retrieved
c955e5dc 608from the store.
caae740f 609
c955e5dc 610In the above case, the default realm is checked, but we could just as easily
611check an alternate realm. If this were an admin login, for example, we could
612authenticate on the admin realm by simply changing the $c->authenticate()
613call:
caae740f 614
c955e5dc 615 if ( $c->authenticate( { username => $user,
616 password => $password }, 'admin' )l ) {
617 $c->res->body( "hello " . $c->user->get("name") );
618 } ...
caae740f 619
caae740f 620
c955e5dc 621Now suppose we want to restrict the ability to edit to a user with 'edit'
622in it's roles list.
caae740f 623
c955e5dc 624The restricted action might look like this:
caae740f 625
c955e5dc 626 sub edit : Local {
caae740f 627 my ( $self, $c ) = @_;
628
629 $c->detach("unauthorized")
630 unless $c->user_exists
c955e5dc 631 and $c->user->get('editor') == 'yes';
caae740f 632
633 # do something restricted here
634 }
635
636This is somewhat similar to role based access control.
c955e5dc 637L<Catalyst::Plugin::Authentication::Store::Minimal> treats the roles field as
638an array of role names. Let's leverage this. Add the role authorization
639plugin:
caae740f 640
641 use Catalyst qw/
642 ...
643 Authorization::Roles
644 /;
645
c955e5dc 646 sub edit : Local {
caae740f 647 my ( $self, $c ) = @_;
648
c955e5dc 649 $c->detach("unauthorized") unless $c->check_roles("edit");
caae740f 650
651 # do something restricted here
652 }
653
654This is somewhat simpler and will work if you change your store, too, since the
655role interface is consistent.
656
46c08636 657Let's say your app grew, and you now have 10000 users. It's no longer
658efficient to maintain a hash of users, so you move this data to a database.
659You can accomplish this simply by installing the DBIx::Class Store and
660changing your config:
caae740f 661
46c08636 662 __PACKAGE__->config->{authentication} =
663 {
664 default_realm => 'members',
665 realms => {
666 members => {
667 credential => {
668 class => 'Password'
669 },
670 store => {
671 class => 'DBIx::Class',
672 user_class => 'MyApp::Users',
673 role_column => 'roles'
674 }
675 }
676 }
677 };
caae740f 678
46c08636 679The authentication system works behind the scenes to load your data from the
680new source. The rest of your application is completely unchanged.
caae740f 681
18a3c897 682
683=head1 CONFIGURATION
684
685=over 4
686
46c08636 687 # example
688 __PACKAGE__->config->{authentication} =
689 {
690 default_realm => 'members',
691 realms => {
692 members => {
693 credential => {
694 class => 'Password'
695 },
696 store => {
697 class => 'DBIx::Class',
698 user_class => 'MyApp::Users',
699 role_column => 'roles'
700 }
701 },
702 admins => {
703 credential => {
704 class => 'Password'
705 },
706 store => {
707 class => '+MyApp::Authentication::Store::NetAuth',
708 authserver => '192.168.10.17'
709 }
710 }
711
712 }
713 };
714
18a3c897 715=item use_session
716
717Whether or not to store the user's logged in state in the session, if the
c9b72c5b 718application is also using L<Catalyst::Plugin::Session>. This
14929a35 719value is set to true per default.
720
46c08636 721=item default_realm
b12e226d 722
46c08636 723This defines which realm should be used as when no realm is provided to methods
724that require a realm such as authenticate or find_user.
5435c348 725
46c08636 726=item realms
5435c348 727
46c08636 728This contains the series of realm configurations you want to use for your app.
729The only rule here is that there must be at least one. A realm consists of a
730name, which is used to reference the realm, a credential and a store.
b260654c 731
46c08636 732Each realm config contains two hashes, one called 'credential' and one called
733'store', each of which provide configuration details to the respective modules.
734The contents of these hashes is specific to the module being used, with the
735exception of the 'class' element, which tells the core Authentication module the
c9b72c5b 736classname to instantiate.
b260654c 737
46c08636 738The 'class' element follows the standard Catalyst mechanism of class
739specification. If a class is prefixed with a +, it is assumed to be a complete
740class name. Otherwise it is considered to be a portion of the class name. For
c9b72c5b 741credentials, the classname 'B<Password>', for example, is expanded to
742Catalyst::Plugin::Authentication::Credential::B<Password>. For stores, the
743classname 'B<storename>' is expanded to:
744Catalyst::Plugin::Authentication::Store::B<storename>::Backend.
b260654c 745
816e5745 746
b12e226d 747=back
748
c9b72c5b 749
750=head1 METHODS
751
752=over 4
753
754=item authenticate( $userinfo, $realm )
755
756Attempts to authenticate the user using the information in the $userinfo hash
757reference using the realm $realm. $realm may be omitted, in which case the
758default realm is checked.
759
760=item user
761
762Returns the currently logged in user or undef if there is none.
763
764=item user_exists
765
766Returns true if a user is logged in right now. The difference between
767user_exists and user is that user_exists will return true if a user is logged
768in, even if it has not been retrieved from the storage backend. If you only
769need to know if the user is logged in, depending on the storage mechanism this
770can be much more efficient.
771
772=item logout
773
774Logs the user out, Deletes the currently logged in user from $c->user and the session.
775
776=item find_user( $userinfo, $realm )
777
778Fetch a particular users details, matching the provided user info, from the realm
779specified in $realm.
780
781=back
46c08636 782
07e49bc7 783=head1 INTERNAL METHODS
784
c9b72c5b 785These methods are for Catalyst::Plugin::Authentication B<INTERNAL USE> only.
786Please do not use them in your own code, whether application or credential /
787store modules. If you do, you will very likely get the nasty shock of having
788to fix / rewrite your code when things change. They are documented here only
789for reference.
07e49bc7 790
c9b72c5b 791=over 4
07e49bc7 792
c9b72c5b 793=item set_authenticated ( $user, $realmname )
07e49bc7 794
c9b72c5b 795Marks a user as authenticated. This is called from within the authenticate
796routine when a credential returns a user. $realmname defaults to 'default'
07e49bc7 797
c9b72c5b 798=item auth_restore_user ( $user, $realmname )
f0348b1d 799
c9b72c5b 800Used to restore a user from the session. In most cases this is called without
801arguments to restore the user via the session. Can be called with arguments
802when restoring a user from some other method. Currently not used in this way.
f0348b1d 803
c9b72c5b 804=item save_user_in_session ( $user, $realmname )
f0348b1d 805
c9b72c5b 806Used to save the user in a session. Saves $user in session, marked as
807originating in $realmname. Both arguments are required.
f0348b1d 808
c9b72c5b 809=item auth_realms
07e49bc7 810
c9b72c5b 811Returns a hashref containing realmname -> realm instance pairs. Realm
812instances contain an instantiated store and credential object as the 'store'
813and 'credential' elements, respectively
07e49bc7 814
c9b72c5b 815=item get_auth_realm ( $realmname )
07e49bc7 816
c9b72c5b 817Retrieves the realm instance for the realmname provided.
07e49bc7 818
819=item
820
821=back
822
36fba990 823=head1 SEE ALSO
824
6229329e 825This list might not be up to date. Below are modules known to work with the updated
826API of 0.10 and are therefore compatible with realms.
e5108df9 827
828=head2 User Storage Backends
829
36fba990 830L<Catalyst::Plugin::Authentication::Store::Minimal>,
d19dc3ce 831L<Catalyst::Plugin::Authentication::Store::DBIx::Class>,
e5108df9 832
833=head2 Credential verification
834
835L<Catalyst::Plugin::Authentication::Credential::Password>,
e5108df9 836
837=head2 Authorization
838
36fba990 839L<Catalyst::Plugin::Authorization::ACL>,
e5108df9 840L<Catalyst::Plugin::Authorization::Roles>
841
caae740f 842=head2 Internals Documentation
843
6229329e 844L<Catalyst::Plugin::Authentication::Internals>
caae740f 845
e5108df9 846=head2 Misc
847
848L<Catalyst::Plugin::Session>,
849L<Catalyst::Plugin::Session::PerUser>
36fba990 850
d304b38a 851=head1 DON'T SEE ALSO
852
1db33018 853This module along with its sub plugins deprecate a great number of other
854modules. These include L<Catalyst::Plugin::Authentication::Simple>,
855L<Catalyst::Plugin::Authentication::CDBI>.
d304b38a 856
857At the time of writing these plugins have not yet been replaced or updated, but
1db33018 858should be eventually: L<Catalyst::Plugin::Authentication::OpenID>,
859L<Catalyst::Plugin::Authentication::LDAP>,
860L<Catalyst::Plugin::Authentication::CDBI::Basic>,
861L<Catalyst::Plugin::Authentication::Basic::Remote>.
d304b38a 862
6229329e 863=head1 INCOMPATABILITIES
864
865The realms based configuration and functionality of the 0.10 update
866of L<Catalyst::Plugin::Authentication> required a change in the API used by
867credentials and stores. It has a compatibility mode which allows use of
868modules that have not yet been updated. This, however, completely mimics the
869older api and disables the new realm-based features. In other words you can
870not mix the older credential and store modules with realms, or realm-based
871configs. The changes required to update modules are relatively minor and are
872covered in L<Catalyst::Plugin::Authentication::Internals>. We hope that most
873modules will move to the compatible list above very quickly.
46c08636 874
875=head1 COMPATIBILITY ROUTINES
876
c9b72c5b 877In version 0.10 of L<Catalyst::Plugin::Authentication>, the API
878changed. For app developers, this change is fairly minor, but for
879Credential and Store authors, the changes are significant.
880
881Please see the documentation in version 0.09 of
d19dc3ce 882Catalyst::Plugin::Authentication for a better understanding of how the old API
c9b72c5b 883functioned.
884
885The items below are still present in the plugin, though using them is
886deprecated. They remain only as a transition tool, for those sites which can
d19dc3ce 887not yet be upgraded to use the new system due to local customizations or use
888of Credential / Store modules that have not yet been updated to work with the
889new backend API.
c9b72c5b 890
891These routines should not be used in any application using realms
892functionality or any of the methods described above. These are for reference
893purposes only.
46c08636 894
895=over 4
896
c9b72c5b 897=item login
898
899This method is used to initiate authentication and user retrieval. Technically
6229329e 900this is part of the old Password credential module and it still resides in the
901L<Password|Catalyst::Plugin::Authentication::Credential::Password> class. It is
902included here for reference only.
c9b72c5b 903
46c08636 904=item default_auth_store
905
906Return the store whose name is 'default'.
907
908This is set to C<< $c->config->{authentication}{store} >> if that value exists,
909or by using a Store plugin:
910
d19dc3ce 911 # load the Minimal authentication store.
46c08636 912 use Catalyst qw/Authentication Authentication::Store::Minimal/;
913
914Sets the default store to
915L<Catalyst::Plugin::Authentication::Store::Minimal::Backend>.
916
46c08636 917=item get_auth_store $name
918
919Return the store whose name is $name.
920
921=item get_auth_store_name $store
922
923Return the name of the store $store.
924
925=item auth_stores
926
927A hash keyed by name, with the stores registered in the app.
928
46c08636 929=item register_auth_stores %stores_by_name
930
931Register stores into the application.
932
933=back
934
935
936
51111c81 937=head1 AUTHORS
36fba990 938
939Yuval Kogman, C<nothingmuch@woobling.org>
51111c81 940
6229329e 941Jay Kuri, C<jayk@cpan.org>
942
7d4c2ed8 943Jess Robinson
51111c81 944
7d4c2ed8 945David Kamholz
07e49bc7 946
c9b72c5b 947
8f86f029 948=head1 COPYRIGHT & LICENSE
36fba990 949
950 Copyright (c) 2005 the aforementioned authors. All rights
951 reserved. This program is free software; you can redistribute
952 it and/or modify it under the same terms as Perl itself.
953
954=cut
07e49bc7 955