many documentation updates
[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/);
b003080b 9}
06675d2e 10
11use strict;
12use warnings;
13
96777f3a 14use Tie::RefHash;
12dae309 15use Class::Inspector;
96777f3a 16
bbf1cb39 17# this optimization breaks under Template::Toolkit
18# use user_exists instead
e145babc 19#BEGIN {
20# require constant;
21# constant->import(have_want => eval { require Want });
22#}
a1e5bd36 23
c5fbff80 24our $VERSION = "0.09999_01";
c7c003d3 25
06675d2e 26sub set_authenticated {
54c8dc06 27 my ( $c, $user, $realmname ) = @_;
06675d2e 28
29 $c->user($user);
e300c5b6 30 $c->request->{user} = $user; # compatibility kludge
06675d2e 31
54c8dc06 32 if (!$realmname) {
33 $realmname = 'default';
06675d2e 34 }
54c8dc06 35
36 if ( $c->isa("Catalyst::Plugin::Session")
37 and $c->config->{authentication}{use_session}
38 and $user->supports("session") )
39 {
e8919861 40 $c->save_user_in_session($user, $realmname);
54c8dc06 41 }
45c7644b 42 $user->auth_realm($realmname);
54c8dc06 43
44 $c->NEXT::set_authenticated($user, $realmname);
06675d2e 45}
46
488433fd 47sub _should_save_user_in_session {
48 my ( $c, $user ) = @_;
49
50 $c->_auth_sessions_supported
51 and $c->config->{authentication}{use_session}
52 and $user->supports("session");
53}
54
55sub _should_load_user_from_session {
56 my ( $c, $user ) = @_;
57
58 $c->_auth_sessions_supported
59 and $c->config->{authentication}{use_session}
60 and $c->session_is_valid;
61}
62
63sub _auth_sessions_supported {
64 my $c = shift;
65 $c->isa("Catalyst::Plugin::Session");
66}
67
7bb06c91 68sub user {
e300c5b6 69 my $c = shift;
7bb06c91 70
e300c5b6 71 if (@_) {
72 return $c->_user(@_);
73 }
7bb06c91 74
45c7644b 75 if ( defined($c->_user) ) {
76 return $c->_user;
56e23e7a 77 } else {
47c6643f 78 return $c->auth_restore_user;
e300c5b6 79 }
7bb06c91 80}
81
54c8dc06 82# change this to allow specification of a realm - to verify the user is part of that realm
83# in addition to verifying that they exist.
ce0b058d 84sub user_exists {
85 my $c = shift;
9deccb83 86 return defined($c->_user) || defined($c->_user_in_session);
56e23e7a 87}
88
45c7644b 89# works like user_exists - except only returns true if user
90# exists AND is in the realm requested.
91sub user_in_realm {
92 my ($c, $realmname) = @_;
93
94 if (defined($c->_user)) {
95 return ($c->_user->auth_realm eq $realmname);
96 } elsif (defined($c->_user_in_session)) {
97 return ($c->session->{__user_realm} eq $realmname);
98 } else {
99 return undef;
100 }
101}
54c8dc06 102
12dae309 103sub save_user_in_session {
e8919861 104 my ( $c, $user, $realmname ) = @_;
12dae309 105
54c8dc06 106 $c->session->{__user_realm} = $realmname;
107
45c7644b 108 # we want to ask the store for a user prepared for the session.
54c8dc06 109 # but older modules split this functionality between the user and the
45c7644b 110 # store. We try the store first. If not, we use the old method.
54c8dc06 111 my $realm = $c->get_auth_realm($realmname);
112 if ($realm->{'store'}->can('for_session')) {
113 $c->session->{__user} = $realm->{'store'}->for_session($c, $user);
114 } else {
115 $c->session->{__user} = $user->for_session;
116 }
12dae309 117}
118
06675d2e 119sub logout {
120 my $c = shift;
121
122 $c->user(undef);
b003080b 123
54c8dc06 124 if (
125 $c->isa("Catalyst::Plugin::Session")
126 and $c->config->{authentication}{use_session}
127 and $c->session_is_valid
128 ) {
129 delete @{ $c->session }{qw/__user __user_realm/};
b003080b 130 }
351e2a82 131
132 $c->NEXT::logout(@_);
06675d2e 133}
134
54c8dc06 135sub find_user {
136 my ( $c, $userinfo, $realmname ) = @_;
137
138 $realmname ||= 'default';
139 my $realm = $c->get_auth_realm($realmname);
140 if ( $realm->{'store'} ) {
141 return $realm->{'store'}->find_user($userinfo, $c);
142 } else {
143 $c->log->debug('find_user: unable to locate a store matching the requested realm');
7d0922d8 144 }
145}
146
54c8dc06 147
47c6643f 148sub _user_in_session {
149 my $c = shift;
150
488433fd 151 return unless $c->_should_load_user_from_session;
47c6643f 152
153 return $c->session->{__user};
488433fd 154}
47c6643f 155
7bb06c91 156sub auth_restore_user {
54c8dc06 157 my ( $c, $frozen_user, $realmname ) = @_;
7bb06c91 158
47c6643f 159 $frozen_user ||= $c->_user_in_session;
160 return unless defined($frozen_user);
4402d92d 161
54c8dc06 162 $realmname ||= $c->session->{__user_realm};
163 return unless $realmname; # FIXME die unless? This is an internal inconsistency
7bb06c91 164
54c8dc06 165 my $realm = $c->get_auth_realm($realmname);
166 $c->_user( my $user = $realm->{'store'}->from_session( $c, $frozen_user ) );
167
168 # this sets the realm the user originated in.
45c7644b 169 $user->auth_realm($realmname);
e300c5b6 170 return $user;
7bb06c91 171
172}
173
54c8dc06 174# we can't actually do our setup in setup because the model has not yet been loaded.
175# So we have to trigger off of setup_finished. :-(
06675d2e 176sub setup {
c5fbff80 177 my $app = shift;
06675d2e 178
c5fbff80 179 $app->_authentication_initialize();
180 $app->NEXT::setup(@_);
54c8dc06 181}
182
183## the actual initialization routine. whee.
184sub _authentication_initialize {
c5fbff80 185 my $app = shift;
54c8dc06 186
c5fbff80 187 if ($app->_auth_realms) { return };
54c8dc06 188
c5fbff80 189
937d5ab9 190
c5fbff80 191 my $cfg = $app->config->{'authentication'} ||= {};
06675d2e 192
c5fbff80 193 $cfg->{use_session} = 1;
b003080b 194
c5fbff80 195 ## make classdata where it is used.
196 $app->mk_classdata( _auth_realms => {});
54c8dc06 197
c5fbff80 198
199
54c8dc06 200 if (exists($cfg->{'realms'})) {
54c8dc06 201 foreach my $realm (keys %{$cfg->{'realms'}}) {
c5fbff80 202 $app->setup_auth_realm($realm, $cfg->{'realms'}{$realm});
54c8dc06 203 }
54c8dc06 204 # if we have a 'default-realm' in the config hash and we don't already
205 # have a realm called 'default', we point default at the realm specified
c5fbff80 206 if (exists($cfg->{'default_realm'}) && !$app->get_auth_realm('default')) {
207 $app->_set_default_auth_realm($cfg->{'default_realm'});
54c8dc06 208 }
209 } else {
c5fbff80 210
211 ## BACKWARDS COMPATIBILITY - if realm is not defined - then we are probably dealing
212 ## with an old-school config. The only caveat here is that we must add a classname
213
54c8dc06 214 foreach my $storename (keys %{$cfg->{'stores'}}) {
215 my $realmcfg = {
216 store => $cfg->{'stores'}{$storename},
217 };
c5fbff80 218 $app->setup_auth_realm($storename, $realmcfg);
54c8dc06 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);
96777f3a 277}
278
54c8dc06 279sub auth_realms {
280 my $self = shift;
281 return($self->_auth_realms);
96777f3a 282}
283
54c8dc06 284sub get_auth_realm {
285 my ($app, $realmname) = @_;
286 return $app->auth_realms->{$realmname};
287}
96777f3a 288
e8919861 289
290# Very internal method. Vital Valuable Urgent, Do not touch on pain of death.
291# Using this method just assigns the default realm to be the value associated
292# with the realmname provided. It WILL overwrite any real realm called 'default'
293# so can be very confusing if used improperly. It's used properly already.
294# Translation: don't use it.
295sub _set_default_auth_realm {
54c8dc06 296 my ($app, $realmname) = @_;
297
298 if (exists($app->auth_realms->{$realmname})) {
299 $app->auth_realms->{'default'} = $app->auth_realms->{$realmname};
12dae309 300 }
54c8dc06 301 return $app->get_auth_realm('default');
96777f3a 302}
303
54c8dc06 304sub authenticate {
305 my ($app, $userinfo, $realmname) = @_;
306
307 if (!$realmname) {
308 $realmname = 'default';
309 }
310
311 my $realm = $app->get_auth_realm($realmname);
312
45c7644b 313 ## note to self - make authenticate throw an exception if realm is invalid.
314
54c8dc06 315 if ($realm && exists($realm->{'credential'})) {
316 my $user = $realm->{'credential'}->authenticate($app, $realm->{store}, $userinfo);
649de93b 317 if (ref($user)) {
54c8dc06 318 $app->set_authenticated($user, $realmname);
319 return $user;
320 }
321 } else {
322 $app->log->debug("The realm requested, '$realmname' does not exist," .
323 " or there is no credential associated with it.")
324 }
0cc778ab 325 return undef;
96777f3a 326}
327
54c8dc06 328## BACKWARDS COMPATIBILITY -- Warning: Here be monsters!
329#
330# What follows are backwards compatibility routines - for use with Stores and Credentials
331# that have not been updated to work with C::P::Authentication v0.10.
332# These are here so as to not break people's existing installations, but will go away
333# in a future version.
334#
335# The old style of configuration only supports a single store, as each store module
336# sets itself as the default store upon being loaded. This is the only supported
337# 'compatibility' mode.
338#
339
340sub get_user {
341 my ( $c, $uid, @rest ) = @_;
96777f3a 342
54c8dc06 343 return $c->find_user( {'id' => $uid, 'rest'=>\@rest }, 'default' );
96777f3a 344}
345
e8919861 346
54c8dc06 347## this should only be called when using old-style authentication plugins. IF this gets
348## called in a new-style config - it will OVERWRITE the store of your default realm. Don't do it.
349## also - this is a partial setup - because no credential is instantiated... in other words it ONLY
350## works with old-style auth plugins and C::P::Authentication in compatibility mode. Trying to combine
351## this with a realm-type config will probably crash your app.
96777f3a 352sub default_auth_store {
12dae309 353 my $self = shift;
96777f3a 354
12dae309 355 if ( my $new = shift ) {
54c8dc06 356 $self->auth_realms->{'default'}{'store'} = $new;
357 my $storeclass = ref($new);
358
359 # BACKWARDS COMPATIBILITY - if the store class does not define find_user, we define it in terms
360 # of get_user and add it to the class. this is because the auth routines use find_user,
361 # and rely on it being present. (this avoids per-call checks)
362 if (!$storeclass->can('find_user')) {
363 no strict 'refs';
364 *{"${storeclass}::find_user"} = sub {
365 my ($self, $info) = @_;
366 my @rest = @{$info->{rest}} if exists($info->{rest});
367 $self->get_user($info->{id}, @rest);
368 };
369 }
12dae309 370 }
96777f3a 371
54c8dc06 372 return $self->get_auth_realm('default')->{'store'};
96777f3a 373}
374
54c8dc06 375## BACKWARDS COMPATIBILITY
376## this only ever returns a hash containing 'default' - as that is the only
377## supported mode of calling this.
378sub auth_store_names {
379 my $self = shift;
380
381 my %hash = ( $self->get_auth_realm('default')->{'store'} => 'default' );
382}
383
384sub get_auth_store {
385 my ( $self, $name ) = @_;
386
387 if ($name ne 'default') {
388 Carp::croak "get_auth_store called on non-default realm '$name'. Only default supported in compatibility mode";
389 } else {
390 $self->default_auth_store();
391 }
392}
393
394sub get_auth_store_name {
395 my ( $self, $store ) = @_;
396 return 'default';
397}
398
399# sub auth_stores is only used internally - here for completeness
400sub auth_stores {
401 my $self = shift;
402
403 my %hash = ( 'default' => $self->get_auth_realm('default')->{'store'});
404}
405
06675d2e 406__PACKAGE__;
407
408__END__
409
410=pod
411
412=head1 NAME
413
55395841 414Catalyst::Plugin::Authentication - Infrastructure plugin for the Catalyst
415authentication framework.
06675d2e 416
417=head1 SYNOPSIS
418
189b5b0c 419 use Catalyst qw/
420 Authentication
189b5b0c 421 /;
422
423 # later on ...
c5fbff80 424 $c->authenticate({ username => 'myusername',
425 password => 'mypassword' });
54c8dc06 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
c5fbff80 480actions in an administrative part of your application. These decisions may be
16ef3eb8 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} =
c5fbff80 547 {
548 default_realm => 'members',
549 realms => {
550 members => {
551 credential => {
552 class => 'Password',
553 password_field => 'password',
554 password_type => 'clear'
555 },
556 store => {
557 class => 'Minimal',
558 users = {
559 bob => {
560 password => "s00p3r",
561 editor => 'yes',
562 roles => [qw/edit delete/],
563 },
564 william => {
565 password => "s3cr3t",
566 roles => [qw/comment/],
567 }
568 }
569 }
570 }
571 }
572 };
62f27384 573
5e91c057 574
16ef3eb8 575This tells the authentication plugin what realms are available, which
576credential and store modules are used, and the configuration of each. With
577this code loaded, we can now attempt to authenticate users.
5e91c057 578
62f27384 579To show an example of this, let's create an authentication controller:
5e91c057 580
581 package MyApp::Controller::Auth;
582
583 sub login : Local {
584 my ( $self, $c ) = @_;
585
586 if ( my $user = $c->req->param("user")
587 and my $password = $c->req->param("password") )
588 {
62f27384 589 if ( $c->authenticate( { username => $user,
590 password => $password } ) ) {
591 $c->res->body( "hello " . $c->user->get("name") );
5e91c057 592 } else {
593 # login incorrect
594 }
595 }
596 else {
597 # invalid form input
598 }
599 }
600
601This code should be very readable. If all the necessary fields are supplied,
c5fbff80 602call the "authenticate" method from the controller. If it succeeds the
603user is logged in.
5e91c057 604
62f27384 605The credential verifier will attempt to retrieve the user whose details match
606the authentication information provided to $c->authenticate(). Once it fetches
607the user the password is checked and if it matches the user will be
16ef3eb8 608B<authenticated> and C<< $c->user >> will contain the user object retrieved
62f27384 609from the store.
5e91c057 610
62f27384 611In the above case, the default realm is checked, but we could just as easily
612check an alternate realm. If this were an admin login, for example, we could
613authenticate on the admin realm by simply changing the $c->authenticate()
614call:
5e91c057 615
62f27384 616 if ( $c->authenticate( { username => $user,
617 password => $password }, 'admin' )l ) {
618 $c->res->body( "hello " . $c->user->get("name") );
619 } ...
5e91c057 620
5e91c057 621
c5fbff80 622Now suppose we want to restrict the ability to edit to a user with an
623'editor' value of yes.
5e91c057 624
62f27384 625The restricted action might look like this:
5e91c057 626
62f27384 627 sub edit : Local {
5e91c057 628 my ( $self, $c ) = @_;
629
630 $c->detach("unauthorized")
631 unless $c->user_exists
c5fbff80 632 and $c->user->get('editor') eq 'yes';
5e91c057 633
634 # do something restricted here
635 }
636
c5fbff80 637(Note that if you have multiple realms, you can use $c->user_in_realm('realmname')
638in place of $c->user_exists(); This will essentially perform the same
639verification as user_exists, with the added requirement that if there is a
640user, it must have come from the realm specified.)
641
642The above example is somewhat similar to role based access control.
62f27384 643L<Catalyst::Plugin::Authentication::Store::Minimal> treats the roles field as
644an array of role names. Let's leverage this. Add the role authorization
645plugin:
5e91c057 646
647 use Catalyst qw/
648 ...
649 Authorization::Roles
650 /;
651
62f27384 652 sub edit : Local {
5e91c057 653 my ( $self, $c ) = @_;
654
62f27384 655 $c->detach("unauthorized") unless $c->check_roles("edit");
5e91c057 656
657 # do something restricted here
658 }
659
660This is somewhat simpler and will work if you change your store, too, since the
661role interface is consistent.
662
0cc778ab 663Let's say your app grew, and you now have 10000 users. It's no longer
664efficient to maintain a hash of users, so you move this data to a database.
665You can accomplish this simply by installing the DBIx::Class Store and
666changing your config:
5e91c057 667
0cc778ab 668 __PACKAGE__->config->{authentication} =
669 {
670 default_realm => 'members',
671 realms => {
672 members => {
673 credential => {
c5fbff80 674 class => 'Password',
675 password_field => 'password',
676 password_type => 'clear'
0cc778ab 677 },
678 store => {
679 class => 'DBIx::Class',
680 user_class => 'MyApp::Users',
681 role_column => 'roles'
682 }
683 }
684 }
685 };
5e91c057 686
0cc778ab 687The authentication system works behind the scenes to load your data from the
688new source. The rest of your application is completely unchanged.
5e91c057 689
189b5b0c 690
691=head1 CONFIGURATION
692
693=over 4
694
0cc778ab 695 # example
696 __PACKAGE__->config->{authentication} =
697 {
698 default_realm => 'members',
699 realms => {
700 members => {
701 credential => {
c5fbff80 702 class => 'Password',
703 password_field => 'password',
704 password_type => 'clear'
0cc778ab 705 },
706 store => {
707 class => 'DBIx::Class',
708 user_class => 'MyApp::Users',
709 role_column => 'roles'
710 }
711 },
712 admins => {
713 credential => {
c5fbff80 714 class => 'Password',
715 password_field => 'password',
716 password_type => 'clear'
0cc778ab 717 },
718 store => {
719 class => '+MyApp::Authentication::Store::NetAuth',
720 authserver => '192.168.10.17'
721 }
722 }
723
724 }
725 };
726
189b5b0c 727=item use_session
728
729Whether or not to store the user's logged in state in the session, if the
e8919861 730application is also using L<Catalyst::Plugin::Session>. This
e7522758 731value is set to true per default.
732
0cc778ab 733=item default_realm
fe4cf44a 734
0cc778ab 735This defines which realm should be used as when no realm is provided to methods
736that require a realm such as authenticate or find_user.
7d0922d8 737
0cc778ab 738=item realms
7d0922d8 739
0cc778ab 740This contains the series of realm configurations you want to use for your app.
741The only rule here is that there must be at least one. A realm consists of a
742name, which is used to reference the realm, a credential and a store.
4fbe2e14 743
0cc778ab 744Each realm config contains two hashes, one called 'credential' and one called
745'store', each of which provide configuration details to the respective modules.
746The contents of these hashes is specific to the module being used, with the
747exception of the 'class' element, which tells the core Authentication module the
e8919861 748classname to instantiate.
4fbe2e14 749
0cc778ab 750The 'class' element follows the standard Catalyst mechanism of class
751specification. If a class is prefixed with a +, it is assumed to be a complete
752class name. Otherwise it is considered to be a portion of the class name. For
e8919861 753credentials, the classname 'B<Password>', for example, is expanded to
754Catalyst::Plugin::Authentication::Credential::B<Password>. For stores, the
755classname 'B<storename>' is expanded to:
45c7644b 756Catalyst::Plugin::Authentication::Store::B<storename>.
4fbe2e14 757
a1e5bd36 758
fe4cf44a 759=back
760
e8919861 761
762=head1 METHODS
763
764=over 4
765
766=item authenticate( $userinfo, $realm )
767
768Attempts to authenticate the user using the information in the $userinfo hash
769reference using the realm $realm. $realm may be omitted, in which case the
770default realm is checked.
771
772=item user
773
774Returns the currently logged in user or undef if there is none.
775
776=item user_exists
777
778Returns true if a user is logged in right now. The difference between
779user_exists and user is that user_exists will return true if a user is logged
45c7644b 780in, even if it has not been yet retrieved from the storage backend. If you only
e8919861 781need to know if the user is logged in, depending on the storage mechanism this
782can be much more efficient.
783
45c7644b 784=item user_in_realm ( $realm )
785
786Works like user_exists, except that it only returns true if a user is both
c5fbff80 787logged in right now and was retrieved from the realm provided.
45c7644b 788
e8919861 789=item logout
790
791Logs the user out, Deletes the currently logged in user from $c->user and the session.
792
793=item find_user( $userinfo, $realm )
794
795Fetch a particular users details, matching the provided user info, from the realm
796specified in $realm.
797
798=back
0cc778ab 799
06675d2e 800=head1 INTERNAL METHODS
801
e8919861 802These methods are for Catalyst::Plugin::Authentication B<INTERNAL USE> only.
803Please do not use them in your own code, whether application or credential /
804store modules. If you do, you will very likely get the nasty shock of having
805to fix / rewrite your code when things change. They are documented here only
806for reference.
06675d2e 807
e8919861 808=over 4
06675d2e 809
e8919861 810=item set_authenticated ( $user, $realmname )
06675d2e 811
e8919861 812Marks a user as authenticated. This is called from within the authenticate
813routine when a credential returns a user. $realmname defaults to 'default'
06675d2e 814
e8919861 815=item auth_restore_user ( $user, $realmname )
e300c5b6 816
e8919861 817Used to restore a user from the session. In most cases this is called without
818arguments to restore the user via the session. Can be called with arguments
819when restoring a user from some other method. Currently not used in this way.
e300c5b6 820
e8919861 821=item save_user_in_session ( $user, $realmname )
e300c5b6 822
e8919861 823Used to save the user in a session. Saves $user in session, marked as
824originating in $realmname. Both arguments are required.
e300c5b6 825
e8919861 826=item auth_realms
06675d2e 827
e8919861 828Returns a hashref containing realmname -> realm instance pairs. Realm
829instances contain an instantiated store and credential object as the 'store'
830and 'credential' elements, respectively
06675d2e 831
e8919861 832=item get_auth_realm ( $realmname )
06675d2e 833
e8919861 834Retrieves the realm instance for the realmname provided.
06675d2e 835
836=item
837
838=back
839
fbe577ac 840=head1 SEE ALSO
841
649de93b 842This list might not be up to date. Below are modules known to work with the updated
843API of 0.10 and are therefore compatible with realms.
4bb9b01c 844
845=head2 User Storage Backends
846
fbe577ac 847L<Catalyst::Plugin::Authentication::Store::Minimal>,
30e90c6f 848L<Catalyst::Plugin::Authentication::Store::DBIx::Class>,
4bb9b01c 849
850=head2 Credential verification
851
852L<Catalyst::Plugin::Authentication::Credential::Password>,
4bb9b01c 853
854=head2 Authorization
855
fbe577ac 856L<Catalyst::Plugin::Authorization::ACL>,
4bb9b01c 857L<Catalyst::Plugin::Authorization::Roles>
858
5e91c057 859=head2 Internals Documentation
860
649de93b 861L<Catalyst::Plugin::Authentication::Internals>
5e91c057 862
4bb9b01c 863=head2 Misc
864
865L<Catalyst::Plugin::Session>,
866L<Catalyst::Plugin::Session::PerUser>
fbe577ac 867
93f08fb0 868=head1 DON'T SEE ALSO
869
1a05e6ed 870This module along with its sub plugins deprecate a great number of other
871modules. These include L<Catalyst::Plugin::Authentication::Simple>,
872L<Catalyst::Plugin::Authentication::CDBI>.
93f08fb0 873
874At the time of writing these plugins have not yet been replaced or updated, but
1a05e6ed 875should be eventually: L<Catalyst::Plugin::Authentication::OpenID>,
876L<Catalyst::Plugin::Authentication::LDAP>,
877L<Catalyst::Plugin::Authentication::CDBI::Basic>,
878L<Catalyst::Plugin::Authentication::Basic::Remote>.
93f08fb0 879
649de93b 880=head1 INCOMPATABILITIES
881
882The realms based configuration and functionality of the 0.10 update
883of L<Catalyst::Plugin::Authentication> required a change in the API used by
884credentials and stores. It has a compatibility mode which allows use of
885modules that have not yet been updated. This, however, completely mimics the
886older api and disables the new realm-based features. In other words you can
887not mix the older credential and store modules with realms, or realm-based
888configs. The changes required to update modules are relatively minor and are
889covered in L<Catalyst::Plugin::Authentication::Internals>. We hope that most
890modules will move to the compatible list above very quickly.
0cc778ab 891
892=head1 COMPATIBILITY ROUTINES
893
e8919861 894In version 0.10 of L<Catalyst::Plugin::Authentication>, the API
895changed. For app developers, this change is fairly minor, but for
896Credential and Store authors, the changes are significant.
897
898Please see the documentation in version 0.09 of
30e90c6f 899Catalyst::Plugin::Authentication for a better understanding of how the old API
e8919861 900functioned.
901
902The items below are still present in the plugin, though using them is
903deprecated. They remain only as a transition tool, for those sites which can
30e90c6f 904not yet be upgraded to use the new system due to local customizations or use
905of Credential / Store modules that have not yet been updated to work with the
45c7644b 906new API.
e8919861 907
908These routines should not be used in any application using realms
909functionality or any of the methods described above. These are for reference
910purposes only.
0cc778ab 911
912=over 4
913
e8919861 914=item login
915
916This method is used to initiate authentication and user retrieval. Technically
649de93b 917this is part of the old Password credential module and it still resides in the
918L<Password|Catalyst::Plugin::Authentication::Credential::Password> class. It is
919included here for reference only.
e8919861 920
0cc778ab 921=item default_auth_store
922
923Return the store whose name is 'default'.
924
925This is set to C<< $c->config->{authentication}{store} >> if that value exists,
926or by using a Store plugin:
927
30e90c6f 928 # load the Minimal authentication store.
0cc778ab 929 use Catalyst qw/Authentication Authentication::Store::Minimal/;
930
931Sets the default store to
45c7644b 932L<Catalyst::Plugin::Authentication::Store::Minimal>.
0cc778ab 933
0cc778ab 934=item get_auth_store $name
935
936Return the store whose name is $name.
937
938=item get_auth_store_name $store
939
940Return the name of the store $store.
941
942=item auth_stores
943
944A hash keyed by name, with the stores registered in the app.
945
0cc778ab 946=item register_auth_stores %stores_by_name
947
948Register stores into the application.
949
950=back
951
952
953
2bcde605 954=head1 AUTHORS
fbe577ac 955
956Yuval Kogman, C<nothingmuch@woobling.org>
2bcde605 957
649de93b 958Jay Kuri, C<jayk@cpan.org>
959
7d2f34eb 960Jess Robinson
2bcde605 961
7d2f34eb 962David Kamholz
06675d2e 963
e8919861 964
ff46c00b 965=head1 COPYRIGHT & LICENSE
fbe577ac 966
967 Copyright (c) 2005 the aforementioned authors. All rights
968 reserved. This program is free software; you can redistribute
969 it and/or modify it under the same terms as Perl itself.
970
971=cut
06675d2e 972