[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