POD doc pokingses
[catagits/Catalyst-Plugin-Authentication.git] / lib / Catalyst / Plugin / Authentication.pm
CommitLineData
06675d2e 1package Catalyst::Plugin::Authentication;
2
b003080b 3use base qw/Class::Accessor::Fast Class::Data::Inheritable/;
06675d2e 4
b003080b 5BEGIN {
7bb06c91 6 __PACKAGE__->mk_accessors(qw/_user/);
b003080b 7}
06675d2e 8
9use strict;
10use warnings;
11
96777f3a 12use Tie::RefHash;
12dae309 13use Class::Inspector;
5c5af345 14use Catalyst::Authentication::Realm;
96777f3a 15
bbf1cb39 16# this optimization breaks under Template::Toolkit
17# use user_exists instead
e145babc 18#BEGIN {
19# require constant;
20# constant->import(have_want => eval { require Want });
21#}
a1e5bd36 22
7c4d44af 23our $VERSION = "0.10005";
c7c003d3 24
06675d2e 25sub set_authenticated {
54c8dc06 26 my ( $c, $user, $realmname ) = @_;
06675d2e 27
28 $c->user($user);
e300c5b6 29 $c->request->{user} = $user; # compatibility kludge
06675d2e 30
54c8dc06 31 if (!$realmname) {
32 $realmname = 'default';
06675d2e 33 }
646ea5b1 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 }
54c8dc06 40
41 if ( $c->isa("Catalyst::Plugin::Session")
7c4d44af 42 and $c->config->{'Plugin::Authentication'}{'use_session'}
54c8dc06 43 and $user->supports("session") )
44 {
646ea5b1 45 $realm->save_user_in_session($c, $user);
54c8dc06 46 }
646ea5b1 47 $user->auth_realm($realm->name);
54c8dc06 48
49 $c->NEXT::set_authenticated($user, $realmname);
06675d2e 50}
51
7bb06c91 52sub user {
e300c5b6 53 my $c = shift;
7bb06c91 54
e300c5b6 55 if (@_) {
56 return $c->_user(@_);
57 }
7bb06c91 58
45c7644b 59 if ( defined($c->_user) ) {
60 return $c->_user;
56e23e7a 61 } else {
47c6643f 62 return $c->auth_restore_user;
e300c5b6 63 }
7bb06c91 64}
65
54c8dc06 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.
ce0b058d 68sub user_exists {
69 my $c = shift;
9deccb83 70 return defined($c->_user) || defined($c->_user_in_session);
56e23e7a 71}
72
45c7644b 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}
54c8dc06 86
646ea5b1 87sub __old_save_user_in_session {
e8919861 88 my ( $c, $user, $realmname ) = @_;
12dae309 89
54c8dc06 90 $c->session->{__user_realm} = $realmname;
91
45c7644b 92 # we want to ask the store for a user prepared for the session.
54c8dc06 93 # but older modules split this functionality between the user and the
45c7644b 94 # store. We try the store first. If not, we use the old method.
54c8dc06 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 }
12dae309 101}
102
06675d2e 103sub logout {
104 my $c = shift;
105
106 $c->user(undef);
b003080b 107
54c8dc06 108 if (
109 $c->isa("Catalyst::Plugin::Session")
7c4d44af 110 and $c->config->{'Plugin::Authentication'}{'use_session'}
54c8dc06 111 and $c->session_is_valid
112 ) {
113 delete @{ $c->session }{qw/__user __user_realm/};
b003080b 114 }
351e2a82 115
116 $c->NEXT::logout(@_);
06675d2e 117}
118
54c8dc06 119sub find_user {
120 my ( $c, $userinfo, $realmname ) = @_;
121
122 $realmname ||= 'default';
123 my $realm = $c->get_auth_realm($realmname);
646ea5b1 124
125 if (!$realm) {
126 Catalyst::Exception->throw(
127 "find_user called with nonexistant realm: '$realmname'.");
7d0922d8 128 }
646ea5b1 129 return $realm->find_user($userinfo, $c);
7d0922d8 130}
131
54c8dc06 132
47c6643f 133sub _user_in_session {
134 my $c = shift;
135
57751a69 136 return unless
137 $c->isa("Catalyst::Plugin::Session")
7c4d44af 138 and $c->config->{'Plugin::Authentication'}{'use_session'}
57751a69 139 and $c->session_is_valid;
47c6643f 140
141 return $c->session->{__user};
488433fd 142}
47c6643f 143
7bb06c91 144sub auth_restore_user {
54c8dc06 145 my ( $c, $frozen_user, $realmname ) = @_;
7bb06c91 146
47c6643f 147 $frozen_user ||= $c->_user_in_session;
148 return unless defined($frozen_user);
4402d92d 149
54c8dc06 150 $realmname ||= $c->session->{__user_realm};
151 return unless $realmname; # FIXME die unless? This is an internal inconsistency
7bb06c91 152
54c8dc06 153 my $realm = $c->get_auth_realm($realmname);
646ea5b1 154 $c->_user( my $user = $realm->from_session( $c, $frozen_user ) );
54c8dc06 155
156 # this sets the realm the user originated in.
45c7644b 157 $user->auth_realm($realmname);
daed2d14 158
e300c5b6 159 return $user;
7bb06c91 160
161}
162
54c8dc06 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. :-(
06675d2e 165sub setup {
c5fbff80 166 my $app = shift;
06675d2e 167
c5fbff80 168 $app->_authentication_initialize();
169 $app->NEXT::setup(@_);
54c8dc06 170}
171
172## the actual initialization routine. whee.
173sub _authentication_initialize {
c5fbff80 174 my $app = shift;
54c8dc06 175
d6209239 176 ## let's avoid recreating / configuring everything if we have already done it, eh?
177 if ($app->can('_auth_realms')) { return };
c5fbff80 178
d6209239 179 ## make classdata where it is used.
180 $app->mk_classdata( '_auth_realms' => {});
937d5ab9 181
7c4d44af 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 }
06675d2e 191
7c4d44af 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 }
c5fbff80 197
54c8dc06 198 if (exists($cfg->{'realms'})) {
54c8dc06 199 foreach my $realm (keys %{$cfg->{'realms'}}) {
c5fbff80 200 $app->setup_auth_realm($realm, $cfg->{'realms'}{$realm});
54c8dc06 201 }
646ea5b1 202 # if we have a 'default_realm' in the config hash and we don't already
54c8dc06 203 # have a realm called 'default', we point default at the realm specified
c5fbff80 204 if (exists($cfg->{'default_realm'}) && !$app->get_auth_realm('default')) {
205 $app->_set_default_auth_realm($cfg->{'default_realm'});
54c8dc06 206 }
207 } else {
c5fbff80 208
58db3441 209 ## BACKWARDS COMPATIBILITY - if realms is not defined - then we are probably dealing
c5fbff80 210 ## with an old-school config. The only caveat here is that we must add a classname
211
58db3441 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
54c8dc06 219 foreach my $storename (keys %{$cfg->{'stores'}}) {
220 my $realmcfg = {
58db3441 221 store => { class => $cfg->{'stores'}{$storename} },
54c8dc06 222 };
c5fbff80 223 $app->setup_auth_realm($storename, $realmcfg);
54c8dc06 224 }
225 }
226
06675d2e 227}
228
54c8dc06 229# set up realmname.
230sub setup_auth_realm {
231 my ($app, $realmname, $config) = @_;
232
e05c457e 233 my $realmclass = $config->{class};
234
235 if( !$realmclass ) {
5c5af345 236 $realmclass = 'Catalyst::Authentication::Realm';
e05c457e 237 } elsif ($realmclass !~ /^\+(.*)$/ ) {
5c5af345 238 $realmclass = "Catalyst::Authentication::Realm::${realmclass}";
e05c457e 239 } else {
240 $realmclass = $1;
54c8dc06 241 }
e05c457e 242
243 Catalyst::Utils::ensure_class_loaded( $realmclass );
244
646ea5b1 245 my $realm = $realmclass->new($realmname, $config, $app);
246 if ($realm) {
247 $app->auth_realms->{$realmname} = $realm;
58db3441 248 } else {
646ea5b1 249 $app->log->debug("realm initialization for '$realmname' failed.");
58db3441 250 }
646ea5b1 251 return $realm;
96777f3a 252}
253
54c8dc06 254sub auth_realms {
255 my $self = shift;
256 return($self->_auth_realms);
96777f3a 257}
258
54c8dc06 259sub get_auth_realm {
260 my ($app, $realmname) = @_;
261 return $app->auth_realms->{$realmname};
262}
96777f3a 263
e8919861 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 {
54c8dc06 271 my ($app, $realmname) = @_;
272
273 if (exists($app->auth_realms->{$realmname})) {
274 $app->auth_realms->{'default'} = $app->auth_realms->{$realmname};
12dae309 275 }
54c8dc06 276 return $app->get_auth_realm('default');
96777f3a 277}
278
54c8dc06 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
45c7644b 288 ## note to self - make authenticate throw an exception if realm is invalid.
289
646ea5b1 290 if ($realm) {
291 return $realm->authenticate($app, $userinfo);
54c8dc06 292 } else {
646ea5b1 293 Catalyst::Exception->throw(
294 "authenticate called with nonexistant realm: '$realmname'.");
295
54c8dc06 296 }
0cc778ab 297 return undef;
96777f3a 298}
299
54c8dc06 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 ) = @_;
96777f3a 314
54c8dc06 315 return $c->find_user( {'id' => $uid, 'rest'=>\@rest }, 'default' );
96777f3a 316}
317
e8919861 318
54c8dc06 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.
96777f3a 324sub default_auth_store {
12dae309 325 my $self = shift;
96777f3a 326
646ea5b1 327 my $realm = $self->get_auth_realm('default');
328 if (!$realm) {
e05c457e 329 $realm = $self->setup_auth_realm('default', { class => 'Compatibility' });
646ea5b1 330 }
12dae309 331 if ( my $new = shift ) {
646ea5b1 332 $realm->store($new);
58db3441 333
334 my $storeclass;
335 if (ref($new)) {
336 $storeclass = ref($new);
337 } else {
338 $storeclass = $new;
339 }
54c8dc06 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 }
12dae309 352 }
96777f3a 353
646ea5b1 354 return $self->get_auth_realm('default')->store;
96777f3a 355}
356
54c8dc06 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
646ea5b1 363 my %hash = ( $self->get_auth_realm('default')->store => 'default' );
54c8dc06 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
646ea5b1 385 my %hash = ( 'default' => $self->get_auth_realm('default')->store);
54c8dc06 386}
387
06675d2e 388__PACKAGE__;
389
390__END__
391
392=pod
393
394=head1 NAME
395
55395841 396Catalyst::Plugin::Authentication - Infrastructure plugin for the Catalyst
397authentication framework.
06675d2e 398
399=head1 SYNOPSIS
400
189b5b0c 401 use Catalyst qw/
402 Authentication
189b5b0c 403 /;
404
405 # later on ...
c5fbff80 406 $c->authenticate({ username => 'myusername',
407 password => 'mypassword' });
54c8dc06 408 my $age = $c->user->get('age');
189b5b0c 409 $c->logout;
06675d2e 410
411=head1 DESCRIPTION
412
16ef3eb8 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
e8919861 422'Realm'. A Catalyst application using the authentication framework must have
423at least one realm, and may have several.
189b5b0c 424
6a36933d 425To implement authentication in a Catalyst application you need to add this
16ef3eb8 426module, and specify at least one realm in the configuration.
189b5b0c 427
e7522758 428Authentication data can also be stored in a session, if the application
429is using the L<Catalyst::Plugin::Session> module.
06675d2e 430
30e90c6f 431B<NOTE> in version 0.10 of this module, the interface to this module changed.
432Please see L</COMPATIBILITY ROUTINES> for more information.
e8919861 433
4bb9b01c 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
6a36933d 447Then the user tells you who they are, and backs this claim with some piece of
4bb9b01c 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
16ef3eb8 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
4bb9b01c 461currently logged in user is indeed an administrator before performing the
c5fbff80 462actions in an administrative part of your application. These decisions may be
16ef3eb8 463made within your application code using just the information available after
464authentication, or it may be facilitated by a number of plugins.
4bb9b01c 465
466=head2 The Components In This Framework
467
62f27384 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
5afc0dde 472verifier and a User storage (Store) backend. As of version 0.10003, realms are
473now objects that you can create and customize.
62f27384 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
16ef3eb8 479used when no realm name is specified. More information about configuring
480realms is available in the configuration section.
62f27384 481
4bb9b01c 482=head3 Credential Verifiers
483
4e86cf54 484When user input is transferred to the L<Catalyst> application
485(typically via form inputs) the application may pass this information
486into the authentication system through the C<<$c->authenticate()>>
487method. From there, it is passed to the appropriate Credential
488verifier.
4bb9b01c 489
490These plugins check the data, and ensure that it really proves the user is who
491they claim to be.
492
4e86cf54 493Credential verifiers compatible with versions of this module 0.10x and
494upwards should be in the namespace
495C<Catalyst::Authentication::Credential>.
496
4bb9b01c 497=head3 Storage Backends
498
45c7644b 499The authentication data also identifies a user, and the Storage backend modules
62f27384 500use this data to locate and return a standardized object-oriented
501representation of a user.
4bb9b01c 502
503When a user is retrieved from a store it is not necessarily authenticated.
62f27384 504Credential verifiers accept a set of authentication data and use this
505information to retrieve the user from the store they are paired with.
4bb9b01c 506
4e86cf54 507storage backends compatible with versions of this module 0.10x and
508upwards should be in the namespace
509C<Catalyst::Authentication::Store>.
510
4bb9b01c 511=head3 The Core Plugin
512
62f27384 513This plugin on its own is the glue, providing realm configuration, session
4bb9b01c 514integration, and other goodness for the other plugins.
515
516=head3 Other Plugins
517
518More layers of plugins can be stacked on top of the authentication code. For
519example, L<Catalyst::Plugin::Session::PerUser> provides an abstraction of
4e86cf54 520browser sessions that is more persistent per user.
4bb9b01c 521L<Catalyst::Plugin::Authorization::Roles> provides an accepted way to separate
522and group users into categories, and then check which categories the current
523user belongs to.
524
5e91c057 525=head1 EXAMPLE
526
16ef3eb8 527Let's say we were storing users in a simple perl hash. Users are
528verified by supplying a password which is matched within the hash.
5e91c057 529
530This means that our application will begin like this:
531
532 package MyApp;
533
534 use Catalyst qw/
535 Authentication
5e91c057 536 /;
537
7c4d44af 538 __PACKAGE__->config->{'Plugin::Authentication'} =
c5fbff80 539 {
540 default_realm => 'members',
541 realms => {
542 members => {
543 credential => {
544 class => 'Password',
545 password_field => 'password',
546 password_type => 'clear'
547 },
548 store => {
549 class => 'Minimal',
550 users = {
551 bob => {
552 password => "s00p3r",
553 editor => 'yes',
554 roles => [qw/edit delete/],
555 },
556 william => {
557 password => "s3cr3t",
558 roles => [qw/comment/],
559 }
560 }
561 }
562 }
563 }
564 };
62f27384 565
5e91c057 566
16ef3eb8 567This tells the authentication plugin what realms are available, which
568credential and store modules are used, and the configuration of each. With
569this code loaded, we can now attempt to authenticate users.
5e91c057 570
62f27384 571To show an example of this, let's create an authentication controller:
5e91c057 572
573 package MyApp::Controller::Auth;
574
575 sub login : Local {
576 my ( $self, $c ) = @_;
577
4e86cf54 578 if ( my $user = $c->req->param("user")
5e91c057 579 and my $password = $c->req->param("password") )
580 {
62f27384 581 if ( $c->authenticate( { username => $user,
582 password => $password } ) ) {
583 $c->res->body( "hello " . $c->user->get("name") );
5e91c057 584 } else {
585 # login incorrect
586 }
587 }
588 else {
589 # invalid form input
590 }
591 }
592
4e86cf54 593This code should be self-explanatory. If all the necessary fields are supplied,
594call the C<authenticate> method on the context object. If it succeeds the
c5fbff80 595user is logged in.
5e91c057 596
4e86cf54 597The credential verifier will attempt to retrieve the user whose
598details match the authentication information provided to
599C<<$c->authenticate()>>. Once it fetches the user the password is
600checked and if it matches the user will be B<authenticated> and
601C<<$c->user>> will contain the user object retrieved from the store.
5e91c057 602
62f27384 603In the above case, the default realm is checked, but we could just as easily
604check an alternate realm. If this were an admin login, for example, we could
4e86cf54 605authenticate on the admin realm by simply changing the C<<$c->authenticate()>>
62f27384 606call:
5e91c057 607
62f27384 608 if ( $c->authenticate( { username => $user,
4e86cf54 609 password => $password }, 'admin' ) ) {
62f27384 610 $c->res->body( "hello " . $c->user->get("name") );
611 } ...
5e91c057 612
5e91c057 613
c5fbff80 614Now suppose we want to restrict the ability to edit to a user with an
615'editor' value of yes.
5e91c057 616
62f27384 617The restricted action might look like this:
5e91c057 618
62f27384 619 sub edit : Local {
5e91c057 620 my ( $self, $c ) = @_;
621
622 $c->detach("unauthorized")
623 unless $c->user_exists
c5fbff80 624 and $c->user->get('editor') eq 'yes';
5e91c057 625
626 # do something restricted here
627 }
628
4e86cf54 629(Note that if you have multiple realms, you can use
630C<<$c->user_in_realm('realmname')>>) in place of
631C<<$c->user_exists();>> This will essentially perform the same
632verification as user_exists, with the added requirement that if there
633is a user, it must have come from the realm specified.)
c5fbff80 634
635The above example is somewhat similar to role based access control.
5c5af345 636L<Catalyst::Authentication::Store::Minimal> treats the roles field as
62f27384 637an array of role names. Let's leverage this. Add the role authorization
638plugin:
5e91c057 639
640 use Catalyst qw/
641 ...
642 Authorization::Roles
643 /;
644
62f27384 645 sub edit : Local {
5e91c057 646 my ( $self, $c ) = @_;
647
62f27384 648 $c->detach("unauthorized") unless $c->check_roles("edit");
5e91c057 649
650 # do something restricted here
651 }
652
653This is somewhat simpler and will work if you change your store, too, since the
654role interface is consistent.
655
0cc778ab 656Let's say your app grew, and you now have 10000 users. It's no longer
657efficient to maintain a hash of users, so you move this data to a database.
4e86cf54 658You can accomplish this simply by installing the L<DBIx::Class|Catalyst::Authentication::Store::DBIx::Class> Store and
0cc778ab 659changing your config:
5e91c057 660
7c4d44af 661 __PACKAGE__->config->{'Plugin::Authentication'} =
0cc778ab 662 {
663 default_realm => 'members',
664 realms => {
665 members => {
666 credential => {
c5fbff80 667 class => 'Password',
668 password_field => 'password',
669 password_type => 'clear'
0cc778ab 670 },
671 store => {
672 class => 'DBIx::Class',
673 user_class => 'MyApp::Users',
674 role_column => 'roles'
675 }
676 }
677 }
678 };
5e91c057 679
0cc778ab 680The authentication system works behind the scenes to load your data from the
681new source. The rest of your application is completely unchanged.
5e91c057 682
189b5b0c 683
684=head1 CONFIGURATION
685
0cc778ab 686 # example
7c4d44af 687 __PACKAGE__->config->{'Plugin::Authentication'} =
0cc778ab 688 {
689 default_realm => 'members',
690 realms => {
691 members => {
692 credential => {
c5fbff80 693 class => 'Password',
694 password_field => 'password',
695 password_type => 'clear'
0cc778ab 696 },
697 store => {
698 class => 'DBIx::Class',
699 user_class => 'MyApp::Users',
700 role_column => 'roles'
701 }
702 },
703 admins => {
704 credential => {
c5fbff80 705 class => 'Password',
706 password_field => 'password',
707 password_type => 'clear'
0cc778ab 708 },
709 store => {
710 class => '+MyApp::Authentication::Store::NetAuth',
711 authserver => '192.168.10.17'
712 }
713 }
714
715 }
716 };
717
078c2289 718=over 4
719
189b5b0c 720=item use_session
721
722Whether or not to store the user's logged in state in the session, if the
e8919861 723application is also using L<Catalyst::Plugin::Session>. This
e7522758 724value is set to true per default.
725
0cc778ab 726=item default_realm
fe4cf44a 727
0cc778ab 728This defines which realm should be used as when no realm is provided to methods
729that require a realm such as authenticate or find_user.
7d0922d8 730
0cc778ab 731=item realms
7d0922d8 732
0cc778ab 733This contains the series of realm configurations you want to use for your app.
734The only rule here is that there must be at least one. A realm consists of a
735name, which is used to reference the realm, a credential and a store.
4fbe2e14 736
7c3d201d 737You can also specify a realm class to instantiate instead of the default
738L<Catalyst::Authentication::Realm> class using the 'class' element within the
739realm config.
5afc0dde 740
0cc778ab 741Each realm config contains two hashes, one called 'credential' and one called
742'store', each of which provide configuration details to the respective modules.
743The contents of these hashes is specific to the module being used, with the
744exception of the 'class' element, which tells the core Authentication module the
e8919861 745classname to instantiate.
4fbe2e14 746
0cc778ab 747The 'class' element follows the standard Catalyst mechanism of class
748specification. If a class is prefixed with a +, it is assumed to be a complete
749class name. Otherwise it is considered to be a portion of the class name. For
e8919861 750credentials, the classname 'B<Password>', for example, is expanded to
5c5af345 751Catalyst::Authentication::Credential::B<Password>. For stores, the
e8919861 752classname 'B<storename>' is expanded to:
5c5af345 753Catalyst::Authentication::Store::B<storename>.
4fbe2e14 754
fe4cf44a 755=back
756
e8919861 757=head1 METHODS
758
4e86cf54 759=head2 $c->authenticate( $userinfo, [ $realm ])
e8919861 760
761Attempts to authenticate the user using the information in the $userinfo hash
762reference using the realm $realm. $realm may be omitted, in which case the
763default realm is checked.
764
4e86cf54 765=head2 $c->user( )
e8919861 766
767Returns the currently logged in user or undef if there is none.
768
4e86cf54 769=head2 $c->user_exists( )
e8919861 770
771Returns true if a user is logged in right now. The difference between
772user_exists and user is that user_exists will return true if a user is logged
45c7644b 773in, even if it has not been yet retrieved from the storage backend. If you only
e8919861 774need to know if the user is logged in, depending on the storage mechanism this
775can be much more efficient.
776
4e86cf54 777=head2 $c->user_in_realm( $realm )
45c7644b 778
779Works like user_exists, except that it only returns true if a user is both
c5fbff80 780logged in right now and was retrieved from the realm provided.
45c7644b 781
4e86cf54 782=head2 $c->logout( )
e8919861 783
4e86cf54 784Logs the user out, Deletes the currently logged in user from C<<$c->user>> and the session.
e8919861 785
4e86cf54 786=head2 $c->find_user( $userinfo, $realm )
e8919861 787
788Fetch a particular users details, matching the provided user info, from the realm
789specified in $realm.
790
06675d2e 791=head1 INTERNAL METHODS
792
e8919861 793These methods are for Catalyst::Plugin::Authentication B<INTERNAL USE> only.
794Please do not use them in your own code, whether application or credential /
795store modules. If you do, you will very likely get the nasty shock of having
796to fix / rewrite your code when things change. They are documented here only
797for reference.
06675d2e 798
4e86cf54 799=head2 $c->set_authenticated( $user, $realmname )
06675d2e 800
e8919861 801Marks a user as authenticated. This is called from within the authenticate
802routine when a credential returns a user. $realmname defaults to 'default'
06675d2e 803
4e86cf54 804=head2 $c->auth_restore_user( $user, $realmname )
e300c5b6 805
e8919861 806Used to restore a user from the session. In most cases this is called without
807arguments to restore the user via the session. Can be called with arguments
808when restoring a user from some other method. Currently not used in this way.
e300c5b6 809
4e86cf54 810=head2 $c->save_user_in_session( $user, $realmname )
e300c5b6 811
e8919861 812Used to save the user in a session. Saves $user in session, marked as
813originating in $realmname. Both arguments are required.
e300c5b6 814
4e86cf54 815=head2 $c->auth_realms( )
06675d2e 816
e8919861 817Returns a hashref containing realmname -> realm instance pairs. Realm
818instances contain an instantiated store and credential object as the 'store'
819and 'credential' elements, respectively
06675d2e 820
4e86cf54 821=head2 $c->get_auth_realm( $realmname )
06675d2e 822
e8919861 823Retrieves the realm instance for the realmname provided.
06675d2e 824
fbe577ac 825=head1 SEE ALSO
826
649de93b 827This list might not be up to date. Below are modules known to work with the updated
828API of 0.10 and are therefore compatible with realms.
4bb9b01c 829
5afc0dde 830=head2 Realms
831
5c5af345 832L<Catalyst::Authentication::Realm>
5afc0dde 833
4bb9b01c 834=head2 User Storage Backends
835
5c5af345 836L<Catalyst::Authentication::Store::Minimal>,
837L<Catalyst::Authentication::Store::DBIx::Class>,
4bb9b01c 838
839=head2 Credential verification
840
5c5af345 841L<Catalyst::Authentication::Credential::Password>,
4bb9b01c 842
843=head2 Authorization
844
fbe577ac 845L<Catalyst::Plugin::Authorization::ACL>,
4bb9b01c 846L<Catalyst::Plugin::Authorization::Roles>
847
5e91c057 848=head2 Internals Documentation
849
649de93b 850L<Catalyst::Plugin::Authentication::Internals>
5e91c057 851
4bb9b01c 852=head2 Misc
853
854L<Catalyst::Plugin::Session>,
855L<Catalyst::Plugin::Session::PerUser>
fbe577ac 856
93f08fb0 857=head1 DON'T SEE ALSO
858
1a05e6ed 859This module along with its sub plugins deprecate a great number of other
860modules. These include L<Catalyst::Plugin::Authentication::Simple>,
861L<Catalyst::Plugin::Authentication::CDBI>.
93f08fb0 862
863At the time of writing these plugins have not yet been replaced or updated, but
1a05e6ed 864should be eventually: L<Catalyst::Plugin::Authentication::OpenID>,
865L<Catalyst::Plugin::Authentication::LDAP>,
866L<Catalyst::Plugin::Authentication::CDBI::Basic>,
867L<Catalyst::Plugin::Authentication::Basic::Remote>.
93f08fb0 868
649de93b 869=head1 INCOMPATABILITIES
870
871The realms based configuration and functionality of the 0.10 update
872of L<Catalyst::Plugin::Authentication> required a change in the API used by
873credentials and stores. It has a compatibility mode which allows use of
874modules that have not yet been updated. This, however, completely mimics the
875older api and disables the new realm-based features. In other words you can
876not mix the older credential and store modules with realms, or realm-based
877configs. The changes required to update modules are relatively minor and are
878covered in L<Catalyst::Plugin::Authentication::Internals>. We hope that most
879modules will move to the compatible list above very quickly.
0cc778ab 880
881=head1 COMPATIBILITY ROUTINES
882
e8919861 883In version 0.10 of L<Catalyst::Plugin::Authentication>, the API
884changed. For app developers, this change is fairly minor, but for
885Credential and Store authors, the changes are significant.
886
887Please see the documentation in version 0.09 of
30e90c6f 888Catalyst::Plugin::Authentication for a better understanding of how the old API
e8919861 889functioned.
890
891The items below are still present in the plugin, though using them is
892deprecated. They remain only as a transition tool, for those sites which can
30e90c6f 893not yet be upgraded to use the new system due to local customizations or use
894of Credential / Store modules that have not yet been updated to work with the
45c7644b 895new API.
e8919861 896
897These routines should not be used in any application using realms
898functionality or any of the methods described above. These are for reference
899purposes only.
0cc778ab 900
4e86cf54 901=head2 $c->login( )
e8919861 902
903This method is used to initiate authentication and user retrieval. Technically
649de93b 904this is part of the old Password credential module and it still resides in the
905L<Password|Catalyst::Plugin::Authentication::Credential::Password> class. It is
906included here for reference only.
e8919861 907
4e86cf54 908=head2 $c->default_auth_store( )
0cc778ab 909
910Return the store whose name is 'default'.
911
7c4d44af 912This is set to C<< $c->config->{'Plugin::Authentication'}{store} >> if that value exists,
0cc778ab 913or by using a Store plugin:
914
30e90c6f 915 # load the Minimal authentication store.
0cc778ab 916 use Catalyst qw/Authentication Authentication::Store::Minimal/;
917
918Sets the default store to
45c7644b 919L<Catalyst::Plugin::Authentication::Store::Minimal>.
0cc778ab 920
4e86cf54 921=head2 $c->get_auth_store( $name )
0cc778ab 922
923Return the store whose name is $name.
924
4e86cf54 925=head2 $c->get_auth_store_name( $store )
0cc778ab 926
927Return the name of the store $store.
928
4e86cf54 929=head2 $c->auth_stores( )
0cc778ab 930
931A hash keyed by name, with the stores registered in the app.
932
4e86cf54 933=head2 $c->register_auth_stores( %stores_by_name )
0cc778ab 934
935Register stores into the application.
936
4e86cf54 937=head2 $c->auth_store_names( )
078c2289 938
4e86cf54 939=head2 $c->get_user( )
078c2289 940
4e86cf54 941=head2 $c->setup( )
078c2289 942
4e86cf54 943=head2 $c->setup_auth_realm( )
078c2289 944
2bcde605 945=head1 AUTHORS
fbe577ac 946
947Yuval Kogman, C<nothingmuch@woobling.org>
2bcde605 948
649de93b 949Jay Kuri, C<jayk@cpan.org>
950
7d2f34eb 951Jess Robinson
2bcde605 952
7d2f34eb 953David Kamholz
06675d2e 954
ff46c00b 955=head1 COPYRIGHT & LICENSE
fbe577ac 956
957 Copyright (c) 2005 the aforementioned authors. All rights
958 reserved. This program is free software; you can redistribute
959 it and/or modify it under the same terms as Perl itself.
960
961=cut
06675d2e 962