Changelog + version bump + prereq fixing for C::P::Auth
[catagits/Catalyst-Plugin-Authentication.git] / lib / Catalyst / Plugin / Authentication.pm
index 877d85c..ab25422 100644 (file)
@@ -22,7 +22,7 @@ use Class::Inspector;
 #      constant->import(have_want => eval { require Want });
 #}
 
-our $VERSION = "0.04";
+our $VERSION = "0.05";
 
 sub set_authenticated {
     my ( $c, $user ) = @_;
@@ -228,7 +228,7 @@ the user. Multiple stores can be accessed from within one application.
 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 
@@ -247,7 +247,7 @@ 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 peice of
+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
@@ -260,7 +260,7 @@ 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 apploication. One way to do this is
+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
@@ -286,7 +286,7 @@ themselves from the default store.
 
 =head3 The Core Plugin
 
-This plugin on it's own is the glue, providing store registration, session
+This plugin on its own is the glue, providing store registration, session
 integration, and other goodness for the other plugins.
 
 =head3 Other Plugins
@@ -298,6 +298,153 @@ 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_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 
@@ -315,14 +462,14 @@ user from the auth store.
 
 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
 
@@ -458,6 +605,10 @@ L<Catalyst::Plugin::Authentication::Credential::TypeKey>
 L<Catalyst::Plugin::Authorization::ACL>,
 L<Catalyst::Plugin::Authorization::Roles>
 
+=head2 Internals Documentation
+
+L<Catalyst::Plugin::Authentication::Store>
+
 =head2 Misc
 
 L<Catalyst::Plugin::Session>,
@@ -465,15 +616,15 @@ 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