[Catalyst-commits] r6555 - in trunk/Catalyst-Plugin-Authentication: . lib/Catalyst/Plugin lib/Catalyst/Plugin/Authentication lib/Catalyst/Plugin/Authentication/Credential lib/Catalyst/Plugin/Authentication/Store

matthewt at dev.catalyst.perl.org matthewt at dev.catalyst.perl.org
Tue Jul 17 17:58:53 GMT 2007


Author: matthewt
Date: 2007-07-17 17:58:53 +0100 (Tue, 17 Jul 2007)
New Revision: 6555

Modified:
   trunk/Catalyst-Plugin-Authentication/
   trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication.pm
   trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/Credential/Password.pm
   trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/Internals.pod
   trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/Store.pod
   trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/Store/Minimal.pm
Log:
 r36178 at cain (orig r6059):  jayk | 2007-02-06 05:45:22 +0000
 many documentation updates
 



Property changes on: trunk/Catalyst-Plugin-Authentication
___________________________________________________________________
Name: svk:merge
   - 4ad37cd2-5fec-0310-835f-b3785c72a374:/branches/Catalyst-Plugin-Authentication:5998
   + 4ad37cd2-5fec-0310-835f-b3785c72a374:/branches/Catalyst-Plugin-Authentication:6059

Modified: trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/Credential/Password.pm
===================================================================
--- trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/Credential/Password.pm	2007-07-17 16:58:45 UTC (rev 6554)
+++ trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/Credential/Password.pm	2007-07-17 16:58:53 UTC (rev 6555)
@@ -88,7 +88,7 @@
 
 ## BACKWARDS COMPATIBILITY - all subs below here are deprecated 
 ## They are here for compatibility with older modules that use / inherit from C::P::A::Password 
-## login()'s existance relies rather heavily on the fact that Credential::Password
+## login()'s existance relies rather heavily on the fact that only Credential::Password
 ## is being used as a credential.  This may not be the case.  This is only here 
 ## for backward compatibility.  It will go away in a future version
 ## login should not be used in new applications.
@@ -252,6 +252,10 @@
 encryption/hashing algorithms. The one the module uses is determined by the
 credential configuration.
 
+Those who have used L<Catalyst::Plugin::Authentication> prior to the 0.10 release
+should note that the password field and type information is no longer part
+of the store configuration and is now part of the Password credential configuration.
+
 =over 4 
 
 =item class 
@@ -325,12 +329,13 @@
 
 =head1 USAGE
 
-The Password credential module is very simple to use.  Once configured as indicated
-above, authenticating using this module is simply a matter of calling $c->authenticate()
-with an authinfo hashref that includes the B<password> element.  The password element should
-contain the password supplied by the user to be authenticated, in clear text.  The other
-information supplied in the auth hash is ignored by the Password module, and simply passed
-to the auth store to be used to retrieve the user.  An example call follows:
+The Password credential module is very simple to use. Once configured as
+indicated above, authenticating using this module is simply a matter of
+calling $c->authenticate() with an authinfo hashref that includes the
+B<password> element. The password element should contain the password supplied
+by the user to be authenticated, in clear text. The other information supplied
+in the auth hash is ignored by the Password module, and simply passed to the
+auth store to be used to retrieve the user. An example call follows:
 
     if ($c->authenticate({ username => $username,
                            password => $password} )) {

Modified: trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/Internals.pod
===================================================================
--- trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/Internals.pod	2007-07-17 16:58:45 UTC (rev 6554)
+++ trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/Internals.pod	2007-07-17 16:58:53 UTC (rev 6555)
@@ -106,10 +106,11 @@
 information for the store module. The second argument is a reference to the
 Catalyst application.
 
-    Note that when new() is called, Catalyst has not yet loaded the various 
-    controller and model classes, nor is it definite that other plugins have 
-    been loaded, so your new() method must not rely on any of those being 
-    present.  If any of this is required for your store to function, you should
+    Note that when new() is called, Catalyst has not yet loaded 
+    the various controller and model classes, nor is it definite
+    that other plugins have been loaded, so your new() method 
+    must not rely on any of those being present.  If any of 
+    this is required for your store to function, you should
     defer that part of initialization until the first method call. 
 
 The C<new()> method should return a blessed reference to your store object.
@@ -126,8 +127,8 @@
 is what $authinfo is required to contain.  Many stores will simply use a 
 username element in $authinfo to locate the user, but more advanced functionality
 is possible and you may bend the $authinfo to your needs.  Be aware, however, that
-both Credentials and Stores work with the same $authinfo hash, so take care to
-avoid overlapping element names.
+both Credentials and Stores usually work with the same $authinfo hash, so take 
+care to avoid overlapping element names.
 
 Please note that this routine may be called numerous times in various
 circumstances, and that a successful match for a user here does B<NOT>
@@ -218,11 +219,12 @@
 information. This is used as a standard method of accessing an authenticated
 user's data, and MUST be implemented by all user objects.  
 
-    Note: There is no equivalent 'set' method. Each user class is likely
-    to vary greatly in how data must be saved and it is therefore impractical to 
-    try to provide a standard way of accomplishing it. When an application 
-    developer needs to save data, they should obtain the underlying object / data
-    by calling get_object, and work with it directly.
+    Note: There is no equivalent 'set' method. Each user class is 
+    likely to vary greatly in how data must be saved and it is 
+    therefore impractical to try to provide a standard way of 
+    accomplishing it. When an application developer needs to save 
+    data, they should obtain the underlying object / data by 
+    calling get_object, and work with it directly.
     
 
 =item get_object( )
@@ -241,4 +243,92 @@
 
 =head1 WRITING A CREDENTIAL
 
-... Documentation fairy fell asleep here.  
+Compared to writing a store, writing a credential is very simple.  There is only
+one class to implement, and it consists of only two required routines. They are:
+
+    new()           - instantiates the credential object
+    authenticate()  - performs the authentication and returns a user object
+    
+=head2 CREDENTIAL METHODS
+
+=over 4
+
+=item new( $config, $app )
+
+Like the Store method of the same name, the C<new()> method is called only 
+once, during the setup process of 
+L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication>. The
+first argument, C<$config>, is a hash reference containing the configuration
+information for the credential module. The second argument is a reference 
+to the Catalyst application.
+
+    Again, when the credential's new() method is called, Catalyst 
+    has not yet loaded the various controller and model classes. 
+
+The new method should perform any necessary setup required and instantiate 
+your credential object.  It should return your instantiated credential.
+
+=item authenticate( $c, $authstore, $authinfo )
+
+This is the workhorse of your credential.  When $c->authenticate() is called
+the L<Catalyst::Plugin::Authentication|Catalyst::Plugin::Authentication> module retrieves the
+store object from the realm and passes it, along with the $authinfo hash
+to your credential's authenticate method.  Your module should use the 
+$authinfo hash to obtain the user from the store passed, and then perform 
+any credential verification steps necessary to authenticate the user.  This
+method should return the user object returned by the authentication store if
+credential verification succeeded.  It should return undef on failure.  
+
+How your credential module performs the credential verification is entirely
+up to you.  In most cases, the credential will retrieve a user from the store
+first (using the stores find_user() method), and then validate the user's 
+information.  However, this does not have to be the case.  
+
+It is perfectly acceptable for your credential to perform other tasks prior to
+attempting to retrieve the user from the store. It may also make sense for
+your credential to perform activities which help to locate the user in
+question, for example, finding a user id based on an encrypted token.
+In these scenarios, the $authinfo hash passed to the store's find_user()
+can be different than that which is passed in to $c->authenticate(). Once
+again this is perfectly acceptable if it makes sense for your credential,
+though you are strongly advised to note this behavior clearly in your 
+credential's documentation - as application authors are almost 
+certainly expecting the user to be found using the information provided 
+to $c->authenticate().
+
+Look at the L<Catalyst::Plugin::Authentication::Credential::Password|Catalyst::Plugin::Authentication::Credential::Password>
+module source to see this in action.  In order to avoid possible 
+mismatches between the encrypted and unencrypted passwords, the password 
+credential actually removes the provided password from the authinfo 
+array.  It does this because, in many cases, the store's password 
+field will be encrypted in some way, and the password passed to 
+$c->authenticate is almost certainly in plaintext. 
+
+NOTE: You should always assume that a store is going to use all
+the information passed to it to locate the user in question. 
+If there are fields in the $authinfo hash that you are sure
+are specific to your credential, you may want to consider 
+removing them before user retrieval.  A better solution is to
+place those arguments that are specific to your credential 
+within their own subhash named after your module.
+ 
+The L<Catalyst::Plugin::Authentication::Store::DBIx::Class|Catalyst::Plugin::Authentication::Store::DBIx::Class> module does this
+in order to encapsulate arguments intended specifically for 
+that module. See the L<Catalyst::Plugin::Authentication::Store::DBIx::Class::User|Catalyst::Plugin::Authentication::Store::DBIx::Class::User>
+source for details.
+
+=back
+
+=head1 AUTHORS
+
+Jay Kuri, C<jayk at cpan.org>
+
+=head1 COPYRIGHT & LICENSE
+
+        Copyright (c) 2005 the aforementioned authors. All rights
+        reserved. This program is free software; you can redistribute
+        it and/or modify it under the same terms as Perl itself.
+
+=cut
+
+ 
\ No newline at end of file

Modified: trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/Store/Minimal.pm
===================================================================
--- trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/Store/Minimal.pm	2007-07-17 16:58:45 UTC (rev 6554)
+++ trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/Store/Minimal.pm	2007-07-17 16:58:53 UTC (rev 6555)
@@ -121,7 +121,9 @@
                         realms => {
                             members => {
                                 credential => {
-                                    class => 'Password'
+                                    class => 'Password',
+                                    password_field => 'password',
+                                    password_type => 'clear'
                                 },
                                 store => {
                                     class => 'Minimal',

Modified: trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/Store.pod
===================================================================
--- trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/Store.pod	2007-07-17 16:58:45 UTC (rev 6554)
+++ trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/Store.pod	2007-07-17 16:58:53 UTC (rev 6555)
@@ -5,10 +5,14 @@
 
 =head1 MULTIPLE BACKENDS
 
-B<NOTE> This is documentation for the old store system. This is not how the new realm-based stores
-work. Nobody has managed to rewrite this part of the documentation yet.  
+B<NOTE> This is documentation for the old store system used in versions of
+L<Catalyst::Plugin::Authentication> prior to 0.10.  This is NOT how the 
+new realm-based stores work. This is here for reference only.
+
 See L<Catalyst::Plugin::Authentication::Internals> instead.
 
+=head1 OLD STORE DOCUMENTATION BELOW
+
 A key issue to understand about authentication stores is that there are
 potentially many of them. Each one is registered into the application, and has
 a name.

Modified: trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication.pm
===================================================================
--- trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication.pm	2007-07-17 16:58:45 UTC (rev 6554)
+++ trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication.pm	2007-07-17 16:58:53 UTC (rev 6555)
@@ -6,7 +6,6 @@
 
 BEGIN {
     __PACKAGE__->mk_accessors(qw/_user/);
-    __PACKAGE__->mk_classdata($_) for qw/_auth_realms/;
 }
 
 use strict;
@@ -22,7 +21,7 @@
 #	constant->import(have_want => eval { require Want });
 #}
 
-our $VERSION = "0.10";
+our $VERSION = "0.09999_01";
 
 sub set_authenticated {
     my ( $c, $user, $realmname ) = @_;
@@ -175,51 +174,48 @@
 # we can't actually do our setup in setup because the model has not yet been loaded.  
 # So we have to trigger off of setup_finished.  :-(
 sub setup {
-    my $c = shift;
+    my $app = shift;
 
-    $c->_authentication_initialize();
-    $c->NEXT::setup(@_);
+    $app->_authentication_initialize();
+    $app->NEXT::setup(@_);
 }
 
 ## the actual initialization routine. whee.
 sub _authentication_initialize {
-    my $c = shift;
+    my $app = shift;
 
-    if ($c->_auth_realms) { return };
+    if ($app->_auth_realms) { return };
     
-    if (!exists($c->config->{'authentication'}) {
-        $c->config->{'authentication'} = {};
-    }
+
     
-    my $cfg = $c->config->{'authentication'};
+    my $cfg = $app->config->{'authentication'} ||= {};
 
-    %$cfg = (
-        use_session => 1,
-        %$cfg,
-    );
+    $cfg->{use_session} = 1;
 
-    my $realmhash = {};
-    $c->_auth_realms($realmhash);
+    ## make classdata where it is used.  
+    $app->mk_classdata( _auth_realms => {});
     
-    ## BACKWARDS COMPATIBILITY - if realm is not defined - then we are probably dealing
-    ## with an old-school config.  The only caveat here is that we must add a classname 
+    
+
     if (exists($cfg->{'realms'})) {
-        
         foreach my $realm (keys %{$cfg->{'realms'}}) {
-            $c->setup_auth_realm($realm, $cfg->{'realms'}{$realm});
+            $app->setup_auth_realm($realm, $cfg->{'realms'}{$realm});
         }
-
         #  if we have a 'default-realm' in the config hash and we don't already 
         # have a realm called 'default', we point default at the realm specified
-        if (exists($cfg->{'default_realm'}) && !$c->get_auth_realm('default')) {
-            $c->_set_default_auth_realm($cfg->{'default_realm'});
+        if (exists($cfg->{'default_realm'}) && !$app->get_auth_realm('default')) {
+            $app->_set_default_auth_realm($cfg->{'default_realm'});
         }
     } else {
+        
+        ## BACKWARDS COMPATIBILITY - if realm is not defined - then we are probably dealing
+        ## with an old-school config.  The only caveat here is that we must add a classname
+        
         foreach my $storename (keys %{$cfg->{'stores'}}) {
             my $realmcfg = {
                 store => $cfg->{'stores'}{$storename},
             };
-            $c->setup_auth_realm($storename, $realmcfg);
+            $app->setup_auth_realm($storename, $realmcfg);
         }
     }
     
@@ -278,7 +274,6 @@
     
     $app->auth_realms->{$realmname}{'store'} = $storeclass->new($config->{'store'}, $app);
     $app->auth_realms->{$realmname}{'credential'} = $credentialclass->new($config->{'credential'}, $app);
-   
 }
 
 sub auth_realms {
@@ -426,7 +421,8 @@
     /;
 
     # later on ...
-    $c->authenticate({ username => 'myusername', password => 'mypassword' });
+    $c->authenticate({ username => 'myusername', 
+                       password => 'mypassword' });
     my $age = $c->user->get('age');
     $c->logout;
 
@@ -481,7 +477,7 @@
 is (or isn't) allowed to do. For example, say your users are split into two
 main groups - regular users and administrators. You want to verify that the
 currently logged in user is indeed an administrator before performing the
-actions in an administrative part of your application. These decisionsmay be
+actions in an administrative part of your application. These decisions may be
 made within your application code using just the information available after
 authentication, or it may be facilitated by a number of plugins.  
 
@@ -548,30 +544,32 @@
     /;
 
     __PACKAGE__->config->{authentication} = 
-                    {  
-                        default_realm => 'members',
-                        realms => {
-                            members => {
-                                credential => {
-                                    class => 'Password'
-                                },
-                                store => {
-                                    class => 'Minimal',
-                	                users = {
-                	                    bob => {
-                	                        password => "s00p3r",                	                    
-                	                        editor => 'yes',
-                	                        roles => [qw/edit delete/],
-                	                    },
-                	                    william => {
-                	                        password => "s3cr3t",
-                	                        roles => [qw/comment/],
-                	                    }
-                	                }	                
-                	            }
-                	        }
-                    	}
-                    };
+                {  
+                    default_realm => 'members',
+                    realms => {
+                        members => {
+                            credential => {
+                                class => 'Password',
+                                password_field => 'password',
+                                password_type => 'clear'
+                            },
+                            store => {
+                                class => 'Minimal',
+            	                users = {
+            	                    bob => {
+            	                        password => "s00p3r",                	                    
+            	                        editor => 'yes',
+            	                        roles => [qw/edit delete/],
+            	                    },
+            	                    william => {
+            	                        password => "s3cr3t",
+            	                        roles => [qw/comment/],
+            	                    }
+            	                }	                
+            	            }
+            	        }
+                	}
+                };
     
 
 This tells the authentication plugin what realms are available, which
@@ -601,8 +599,8 @@
     }
 
 This code should be very readable. If all the necessary fields are supplied,
-call the L<Catalyst::Plugin::Authentication/authenticate> method in the
-controller. If it succeeds the user is logged in.
+call the "authenticate" method from the controller. If it succeeds the 
+user is logged in.
 
 The credential verifier will attempt to retrieve the user whose details match
 the authentication information provided to $c->authenticate(). Once it fetches
@@ -621,8 +619,8 @@
     } ...
 
 
-Now suppose we want to restrict the ability to edit to a user with 'edit'
-in it's roles list.  
+Now suppose we want to restrict the ability to edit to a user with an 
+'editor' value of yes.
 
 The restricted action might look like this:
 
@@ -631,12 +629,17 @@
 
         $c->detach("unauthorized")
           unless $c->user_exists
-          and $c->user->get('editor') == 'yes';
+          and $c->user->get('editor') eq 'yes';
 
         # do something restricted here
     }
 
-This is somewhat similar to role based access control.
+(Note that if you have multiple realms, you can use $c->user_in_realm('realmname')
+in place of $c->user_exists(); This will essentially perform the same 
+verification as user_exists, with the added requirement that if there is a 
+user, it must have come from the realm specified.)
+
+The above example is somewhat similar to role based access control.  
 L<Catalyst::Plugin::Authentication::Store::Minimal> treats the roles field as
 an array of role names. Let's leverage this. Add the role authorization
 plugin:
@@ -668,7 +671,9 @@
                         realms => {
                             members => {
                                 credential => {
-                                    class => 'Password'
+                                    class => 'Password',
+                                    password_field => 'password',
+                                    password_type => 'clear'
                                 },
                                 store => {
                                     class => 'DBIx::Class',
@@ -694,7 +699,9 @@
                     realms => {
                         members => {
                             credential => {
-                                class => 'Password'
+                                class => 'Password',
+                                password_field => 'password',
+                                password_type => 'clear'
                             },
                             store => {
                                 class => 'DBIx::Class',
@@ -704,7 +711,9 @@
             	        },
             	        admins => {
             	            credential => {
-            	                class => 'Password'
+            	                class => 'Password',
+            	                password_field => 'password',
+                                password_type => 'clear'
             	            },
             	            store => {
             	                class => '+MyApp::Authentication::Store::NetAuth',
@@ -775,7 +784,7 @@
 =item user_in_realm ( $realm )
 
 Works like user_exists, except that it only returns true if a user is both 
-logged in right now and is from the realm provided.  
+logged in right now and was retrieved from the realm provided.  
 
 =item logout
 




More information about the Catalyst-commits mailing list