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