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