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