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