Credentials are used to verify users, using the store, given data from
the frontend.
-To implement authentication in a catalyst application you need to add this
+To implement authentication in a Catalyst application you need to add this
module, plus at least one store and one credential module.
Authentication data can also be stored in a session, if the application
is using the L<Catalyst::Plugin::Session> module.
+=head1 INTRODUCTION
+
+=head2 The Authentication/Authorization Process
+
+Web applications typically need to identify a user - to tell the user apart
+from other users. This is usually done in order to display private information
+that is only that user's business, or to limit access to the application so
+that only certain entities can access certain parts.
+
+This process is split up into several steps. First you ask the user to identify
+themselves. At this point you can't be sure that the user is really who they
+claim to be.
+
+Then the user tells you who they are, and backs this claim with some piece of
+information that only the real user could give you. For example, a password is
+a secret that is known to both the user and you. When the user tells you this
+password you can assume they're in on the secret and can be trusted (ignore
+identity theft for now). Checking the password, or any other proof is called
+B<credential verification>.
+
+By this time you know exactly who the user is - the user's identity is
+B<authenticated>. This is where this module's job stops, and other plugins step
+in. The next logical step is B<authorization>, the process of deciding what a
+user is (or isn't) allowed to do. For example, say your users are split into
+two main groups - regular users and administrators. You should verify that the
+currently logged in user is indeed an administrator before performing the
+actions of an administrative part of your application. One way to do this is
+with role based access control.
+
+=head2 The Components In This Framework
+
+=head3 Credential Verifiers
+
+When user input is transferred to the L<Catalyst> application (typically via
+form inputs) this data then enters the authentication framework through these
+plugins.
+
+These plugins check the data, and ensure that it really proves the user is who
+they claim to be.
+
+=head3 Storage Backends
+
+The credentials also identify a user, and this family of modules is supposed to
+take this identification data and return a standardized object oriented
+representation of users.
+
+When a user is retrieved from a store it is not necessarily authenticated.
+Credential verifiers can either accept a user object, or fetch the object
+themselves from the default store.
+
+=head3 The Core Plugin
+
+This plugin on its own is the glue, providing store registration, session
+integration, and other goodness for the other plugins.
+
+=head3 Other Plugins
+
+More layers of plugins can be stacked on top of the authentication code. For
+example, L<Catalyst::Plugin::Session::PerUser> provides an abstraction of
+browser sessions that is more persistent per users.
+L<Catalyst::Plugin::Authorization::Roles> provides an accepted way to separate
+and group users into categories, and then check which categories the current
+user belongs to.
+
+=head1 EXAMPLE
+
+Let's say we were storing users in an Apache style htpasswd file. Users are
+stored in that file, with a hashed password and some extra comments. Users are
+verified by supplying a password which is matched with the file.
+
+This means that our application will begin like this:
+
+ package MyApp;
+
+ use Catalyst qw/
+ Authentication
+ Authentication::Credential::Password
+ Authentication::Store::Htpasswd
+ /;
+
+ __PACKAGE__->config->{authentication}{htpasswd} = "passwdfile";
+
+This loads the appropriate methods and also sets the htpasswd store as the
+default store.
+
+So, now that we have the code loaded we need to get data from the user into the
+credential verifier.
+
+Let's create an authentication controller:
+
+ package MyApp::Controller::Auth;
+
+ sub login : Local {
+ my ( $self, $c ) = @_;
+
+ if ( my $user = $c->req->param("user")
+ and my $password = $c->req->param("password") )
+ {
+ if ( $c->login( $user, $password ) ) {
+ $c->res->body( "hello " . $c->user->name );
+ } else {
+ # login incorrect
+ }
+ }
+ else {
+ # invalid form input
+ }
+ }
+
+This code should be very readable. If all the necessary fields are supplied,
+call the L<Authentication::Credential::Password/login> method on the
+controller. If that succeeds the user is logged in.
+
+It could be simplified though:
+
+ sub login : Local {
+ my ( $self, $c ) = @_;
+
+ if ( $c->login ) {
+ ...
+ }
+ }
+
+Since the C<login> method knows how to find logically named parameters on it's
+own.
+
+The credential verifier will ask the default store to get the user whose ID is
+the user parameter. In this case the default store is the htpasswd one. Once it
+fetches the user from the store the password is checked and if it's OK
+C<< $c->user >> will contain the user object returned from the htpasswd store.
+
+We can also pass a user object to the credential verifier manually, if we have
+several stores per app. This is discussed in
+L<Catalyst::Plugin::Authentication::Store>.
+
+Now imagine each admin user has a comment set in the htpasswd file saying
+"admin".
+
+A restricted action might look like this:
+
+ sub restricted : Local {
+ my ( $self, $c ) = @_;
+
+ $c->detach("unauthorized")
+ unless $c->user_exists
+ and $c->user->extra_info() eq "admin";
+
+ # do something restricted here
+ }
+
+This is somewhat similar to role based access control.
+L<Catalyst::Plugin::Authentication::Store::Htpasswd> treats the extra info
+field as a comma separated list of roles if it's treated that way. Let's
+leverage this. Add the role authorization plugin:
+
+ use Catalyst qw/
+ ...
+ Authorization::Roles
+ /;
+
+ sub restricted : Local {
+ my ( $self, $c ) = @_;
+
+ $c->detach("unauthorized") unless $c->check_user_roles("admin");
+
+ # do something restricted here
+ }
+
+This is somewhat simpler and will work if you change your store, too, since the
+role interface is consistent.
+
+Let's say your app grew, and you now have 10000 users. It's no longer efficient
+to maintain an htpasswd file, so you move this data to a database.
+
+ use Catalyst qw/
+ Authentication
+ Authentication::Credential::Password
+ Authentication::Store::DBIC
+ Authorization::Roles
+ /;
+
+ __PACKAGE__->config->{authentication}{dbic} = ...; # see the DBIC store docs
+
+The rest of your code should be unchanged. Now let's say you are integrating
+typekey authentication to your system. For simplicity's sake we'll assume that
+the user's are still keyed in the same way.
+
+ use Catalyst qw/
+ Authentication
+ Authentication::Credential::Password
+ Authentication::Credential::TypeKey
+ Authentication::Store::DBIC
+ Authorization::Roles
+ /;
+
+And in your auth controller add a new action:
+
+ sub typekey : Local {
+ my ( $self, $c ) = @_;
+
+ if ( $c->authenticate_typekey) { # uses $c->req and Authen::TypeKey
+ # same stuff as the $c->login method
+ # ...
+ }
+ }
+
+You've now added a new credential verification mechanizm orthogonally to the
+other components. All you have to do is make sure that the credential verifiers
+pass on the same types of parameters to the store in order to retrieve user
+objects.
+
=head1 METHODS
=over 4
If you're just going to say
- if ( $c->user_user ) {
+ if ( $c->user_exists ) {
# foo
} else {
$c->forward("login");
}
-it should be more efficient than C<< $c->user >> when a user is marked in the session
-but C<< $c->user >> hasn't been called yet.
+it should be more efficient than C<< $c->user >> when a user is marked in the
+session but C<< $c->user >> hasn't been called yet.
=item logout
=head1 SEE ALSO
-L<Catalyst::Plugin::Authentication::Credential::Password>,
+This list might not be up to date.
+
+=head2 User Storage Backends
+
L<Catalyst::Plugin::Authentication::Store::Minimal>,
+L<Catalyst::Plugin::Authentication::Store::Htpasswd>,
+L<Catalyst::Plugin::Authentication::Store::DBIC> (also works with Class::DBI).
+
+=head2 Credential verification
+
+L<Catalyst::Plugin::Authentication::Credential::Password>,
+L<Catalyst::Plugin::Authentication::Credential::HTTP>,
+L<Catalyst::Plugin::Authentication::Credential::TypeKey>
+
+=head2 Authorization
+
L<Catalyst::Plugin::Authorization::ACL>,
-L<Catalyst::Plugin::Authorization::Roles>.
+L<Catalyst::Plugin::Authorization::Roles>
+
+=head2 Internals Documentation
+
+L<Catalyst::Plugin::Authentication::Store>
+
+=head2 Misc
+
+L<Catalyst::Plugin::Session>,
+L<Catalyst::Plugin::Session::PerUser>
=head1 DON'T SEE ALSO
-This module along with it's sub plugins deprecate a great number of other
-modules. These include Catalyst::Plugin::Authentication::Simple,
-Catalyst::Plugin::Authentication::CDBI.
+This module along with its sub plugins deprecate a great number of other
+modules. These include L<Catalyst::Plugin::Authentication::Simple>,
+L<Catalyst::Plugin::Authentication::CDBI>.
At the time of writing these plugins have not yet been replaced or updated, but
-should be eventually: Catalyst::Plugin::Authentication::OpenID,
-Catalyst::Plugin::Authentication::LDAP,
-Catalyst::Plugin::Authentication::CDBI::Basic,
-Catalyst::Plugin::Authentication::Basic::Remote
+should be eventually: L<Catalyst::Plugin::Authentication::OpenID>,
+L<Catalyst::Plugin::Authentication::LDAP>,
+L<Catalyst::Plugin::Authentication::CDBI::Basic>,
+L<Catalyst::Plugin::Authentication::Basic::Remote>.
=head1 AUTHORS