r10518@t0mlaptop (orig r10517): t0m | 2009-06-12 11:27:58 +0100
Tomas Doran [Thu, 9 Sep 2010 22:56:54 +0000 (22:56 +0000)]
 Make error more useful
 r10589@t0mlaptop (orig r10588):  t0m | 2009-06-19 16:14:16 +0100
 Make Credential::Remote have a username_field config option
 r10590@t0mlaptop (orig r10589):  t0m | 2009-06-19 16:16:43 +0100
 Bump versions for release
 r10728@t0mlaptop (orig r10727):  t0m | 2009-06-29 17:55:35 +0100
 Fix issue if you have auth store plugins before authentication plugin
 r10769@t0mlaptop (orig r10768):  t0m | 2009-07-01 17:42:46 +0100
 Checking in changes prior to tagging of version 0.10014.  Changelog diff is:

 Index: Changes
 ===================================================================
 --- Changes (revision 10727)
 +++ Changes (working copy)
 @@ -1,5 +1,6 @@
  Revision history for Perl extension Catalyst::Plugin::Authentication

 +0.10014 Wed Jul  1 17:40:38 BST 2009
        - Make auth_realms method ensure authentication is initialized
          before calling methods which get created during auth initialization.
          Fixes back compat cases where auth store is in the plugin list

 r11234@t0mlaptop (orig r11233):  t0m | 2009-08-24 14:30:51 +0100
 Stop forcing $authinfo->{id} to be passed down to the store, instead using just configurable username_field.
 r11241@t0mlaptop (orig r11240):  t0m | 2009-08-25 15:27:40 +0100
 Change default username_field back to 'username', as this fits in better with the DBIC store / SimpleDB / tutorial / preexisting documentation etc
 r11243@t0mlaptop (orig r11242):  t0m | 2009-08-25 15:45:30 +0100
 Checking in changes prior to tagging of version 0.10014.  Changelog diff is:

 Index: Changes
 ===================================================================
 --- Changes (revision 11232)
 +++ Changes (working copy)
 @@ -1,6 +1,11 @@
  Revision history for Perl extension Catalyst::Plugin::Authentication

 -0.10014 Wed Jul  1 17:40:38 BST 2009
 +0.10014 Tue Aug 25 15:42:57 BST 2009
 +
 +      - Don't always supply an "id" column in the authinfo passed to the store
 +        class in ::Credential::Remote. This means that it works better with
 +        the DBIC store. (t0m)
 +
        - Make auth_realms method ensure authentication is initialized
          before calling methods which get created during auth initialization.
          Fixes back compat cases where auth store is in the plugin list

 r11276@t0mlaptop (orig r11275):  t0m | 2009-09-01 01:49:39 +0100
 Checking in changes prior to tagging of version 0.10015.  Changelog diff is:

 Index: Changes
 ===================================================================
 --- Changes (revision 11261)
 +++ Changes (working copy)
 @@ -1,5 +1,12 @@
  Revision history for Perl extension Catalyst::Plugin::Authentication

 +0.10015 Tue Sep 1 01:40:36 BST 2009
 +
 +     - Remove (undeclared) dependency on Class::Data::Inhertiable (RT#49086)
 +     - Remove dependency on Test::MockObject
 +     - Fix repository metadata in META.yml / Makefile.PL
 +     - Make POD tests author side only.
 +
  0.10014 Tue Aug 25 15:42:57 BST 2009

        - Don't always supply an "id" column in the authinfo passed to the store

 r11368@t0mlaptop (orig r11338):  t0m | 2009-09-08 08:29:46 +0100
 Small doc fixes
 r11559@t0mlaptop (orig r11524):  t0m | 2009-10-14 01:30:11 +0100
 Change example configs to fit in with recent DBIC store
 r11560@t0mlaptop (orig r11525):  t0m | 2009-10-14 01:34:35 +0100
 If this wasn't a patch in RT, I wouldn't be applying it
 r11571@t0mlaptop (orig r11536):  t0m | 2009-10-15 16:09:14 +0100
 Not needed in BEGIN
 r11572@t0mlaptop (orig r11537):  t0m | 2009-10-15 16:09:37 +0100
 Note here
 r11575@t0mlaptop (orig r11540):  t0m | 2009-10-16 01:50:28 +0100
 Add AUTOLOAD nicked from the dbic store to base class
 r11576@t0mlaptop (orig r11541):  t0m | 2009-10-16 02:28:16 +0100
 Epic cleanup and code shuffle in tests to avoid warnings
 r11628@t0mlaptop (orig r11593):  rafl | 2009-10-17 17:40:51 +0100
 Remove debugging code polluting STDERR.
 r11683@t0mlaptop (orig r11648):  jawnsy | 2009-10-21 02:41:14 +0100
 Bring copyright statement in sync with the other packages
 r12472@t0mlaptop (orig r12437):  rafl | 2009-12-19 23:51:32 +0000
 A bit of clarification - logout does not delete the session.

 semifor++
 r12526@t0mlaptop (orig r12491):  xenoterracide | 2009-12-30 12:59:24 +0000
 minor code example fix in documentation
 r12527@t0mlaptop (orig r12492):  t0m | 2009-12-30 13:04:14 +0000
 Fix hard tabs (by converting to 4 space soft tabs), fix trailing whitespace
 r12545@t0mlaptop (orig r12510):  xenoterracide | 2010-01-03 13:26:12 +0000
 Clean up documentation errors
 r12745@t0mlaptop (orig r12710):  stephan48 | 2010-01-22 21:30:20 +0000
 Fixed RT Bug 47106; Code used the wrong Object to Retrieve authinfo_munge
 r12746@t0mlaptop (orig r12711):  rafl | 2010-01-22 21:34:14 +0000
 Some formatting and whitespace tweaks.
 r12747@t0mlaptop (orig r12712):  rafl | 2010-01-22 21:44:55 +0000
 Clean up some more tabs and whitespaces.
 r12748@t0mlaptop (orig r12713):  rafl | 2010-01-22 21:45:01 +0000
 Prepare release.
 r12749@t0mlaptop (orig r12714):  rafl | 2010-01-22 21:50:39 +0000
 Add .gitignore.
 r12750@t0mlaptop (orig r12715):  rafl | 2010-01-22 21:50:43 +0000
 Ignore git files from MANIFEST.
 r12751@t0mlaptop (orig r12716):  rafl | 2010-01-22 21:50:49 +0000
 Port from NEXT to C3.

 Also clean up more silly whitespace.
 r12752@t0mlaptop (orig r12717):  rafl | 2010-01-22 21:50:55 +0000
 Version 0.10016.
 r12754@t0mlaptop (orig r12719):  rafl | 2010-01-22 21:55:20 +0000
 Add a NoTabs test and make it pass.
 r12916@t0mlaptop (orig r12880):  jawnsy | 2010-02-15 23:36:41 +0000
 fix typos Debian picked up
 r13054@t0mlaptop (orig r13018):  t0m | 2010-03-07 20:56:42 +0000
 Date in changes
 r13082@t0mlaptop (orig r13046):  xenoterracide | 2010-03-17 22:52:21 +0000
 Make debug message clear for users of progressive realms
 r13132@t0mlaptop (orig r13096):  rafl | 2010-03-29 14:58:42 +0100
 Fix syntax error.

36 files changed:
.gitignore [new file with mode: 0644]
.shipit [new file with mode: 0644]
Changes
MANIFEST.SKIP
Makefile.PL
lib/Catalyst/Authentication/Credential/Password.pm
lib/Catalyst/Authentication/Credential/Remote.pm
lib/Catalyst/Authentication/Realm/Progressive.pm
lib/Catalyst/Authentication/Store/Minimal.pm
lib/Catalyst/Authentication/User.pm
lib/Catalyst/Plugin/Authentication.pm
lib/Catalyst/Plugin/Authentication/Store/Minimal.pm
t/05_password.t
t/06_user.t
t/author/notabs.t [new file with mode: 0644]
t/author/pod.t [moved from t/pod.t with 100% similarity]
t/author/pod_coverage.t [moved from t/pod_coverage.t with 100% similarity]
t/lib/AuthRealmTestApp.pm
t/lib/AuthRealmTestApp/Controller/Root.pm [new file with mode: 0644]
t/lib/AuthRealmTestAppCompat.pm
t/lib/AuthRealmTestAppCompat/Controller/Root.pm [new file with mode: 0644]
t/lib/AuthRealmTestAppProgressive.pm
t/lib/AuthRealmTestAppProgressive/Controller/Root.pm [new file with mode: 0644]
t/lib/AuthSessionTestApp.pm
t/lib/AuthSessionTestApp/Controller/Root.pm [new file with mode: 0644]
t/lib/AuthTestApp.pm
t/lib/AuthTestApp/Controller/Root.pm [new file with mode: 0644]
t/lib/RemoteTestApp1.pm
t/lib/RemoteTestApp1/Controller/Root.pm [new file with mode: 0644]
t/lib/RemoteTestApp2.pm
t/lib/RemoteTestApp2/Controller/Root.pm [new file with mode: 0644]
t/live_app.t
t/live_app_realms_progressive.t
t/live_app_remote1.t
t/live_app_remote2.t
t/live_app_session.t

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..2bc9f34
--- /dev/null
@@ -0,0 +1,15 @@
+.*
+!.gitignore
+Makefile*
+!Makefile.PL
+META.yml
+blib
+build
+inc
+pm_to_blib
+MANIFEST*
+!MANIFEST.SKIP
+Debian*
+README
+Catalyst-Plugin-Authentication-*
+*.bs
diff --git a/.shipit b/.shipit
new file mode 100644 (file)
index 0000000..aeb2bb3
--- /dev/null
+++ b/.shipit
@@ -0,0 +1,7 @@
+# auto-generated shipit config file.
+steps = FindVersion, ChangeVersion, CheckChangeLog, DistTest, Commit, Tag, MakeDist
+
+svn.tagpattern = http://dev.catalyst.perl.org/repos/Catalyst/Catalyst-Plugin-Authentication/0.10000/tags/%v
+
+CheckChangeLog.files = Changes
+
diff --git a/Changes b/Changes
index 862aa63..c757f6f 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,5 +1,40 @@
 Revision history for Perl extension Catalyst::Plugin::Authentication
 
+0.10016 22 Jan 2010
+     - Move root actions out of applcation class in tests to remove
+       warnings in the latest Catalyst.
+     - Add AUTOLOAD method to the default user class so that methods are
+       delegated down onto the underlieing user object retrieved from
+       the store (if present)
+     - Fix typos in documentation (RT#49476)
+     - Fix compatibilty with Catalyst 5.70 (RT#50466)
+     - Various documentation improvements
+     - Fix Realm::Processive's authinfo_mungle option (RT#47106)
+
+0.10015 Tue Sep 1 01:40:36 BST 2009
+
+     - Remove (undeclared) dependency on Class::Data::Inhertiable (RT#49086)
+     - Remove dependency on Test::MockObject
+     - Fix repository metadata in META.yml / Makefile.PL
+     - Make POD tests author side only.
+
+0.10014 Tue Aug 25 15:42:57 BST 2009
+
+      - Don't always supply an "id" column in the authinfo passed to the store
+        class in ::Credential::Remote. This means that it works better with
+        the DBIC store. (t0m)
+
+      - Make auth_realms method ensure authentication is initialized
+        before calling methods which get created during auth initialization.
+        Fixes back compat cases where auth store is in the plugin list
+        before the authentication plugin. (t0m)
+
+0.10013 Fri Jun 19 16:08:00 BST 2009
+      - Add a username_field config item to ::Credential::Remote
+        (Nigel Metheringham)
+      - Die with a useful error message if we are about to try to restore
+        a user from a realm which does not exist. (t0m)
+
 0.10012 Sat Jun  6 10:58:43 BST 2009
       - Add Catalyst::Authentication::Credential::Remote which authenticates you
         directly from environment variables passed by your web server. This
index 9821cf0..15b7288 100644 (file)
@@ -3,6 +3,7 @@
 \bCVS\b
 ,v$
 \B\.svn\b
+\B\.git\b
 
 # Avoid Makemaker generated and utility files.
 \bMakefile$
@@ -34,3 +35,5 @@
 # ShipIt config
 .shipit
 
+# Ignore build dirs..
+^Catalyst-Plugin-Authentication
index 22caf38..d31751a 100644 (file)
@@ -1,7 +1,9 @@
 use inc::Module::Install 0.87;
 
-if( -e 'MANIFEST.SKIP' ) {
-    system( 'pod2text lib/Catalyst/Plugin/Authentication.pm > README' );
+if ( $Module::Install::AUTHOR ) {
+    system( 'pod2text lib/Catalyst/Plugin/Authentication.pm > README' )
+        and die;
+    require Module::Install::AuthorTests;
 }
 
 perl_version '5.008001';
@@ -16,11 +18,14 @@ requires 'Class::Inspector';
 requires 'MRO::Compat';
 requires 'Catalyst::Plugin::Session' => '0.10';
 
-test_requires 'Test::More';
+test_requires 'Test::More' => '0.88';
 test_requires 'Test::Exception';
-test_requires 'Test::MockObject';
+test_requires 'Class::MOP';
+test_requires 'Moose';
+
+author_tests 't/author';
 
 auto_install;
-resources repository => 'http://dev.catalyst.perl.org/repos/Catalyst/trunk/Catalyst-Plugin-Authentication/';
+resources repository => 'http://dev.catalyst.perl.org/repos/Catalyst/Catalyst-Plugin-Authentication/0.10000/trunk';
 
 WriteAll;
index 3545849..8010fe3 100644 (file)
@@ -10,7 +10,8 @@ has [qw/_config realm/] => ( is => 'rw' );
 
 sub BUILDARGS {
     my ($class, $config, $app, $realm) = @_;
-    
+
+    # Note _config is horrible back compat hackery!
     { realm => $realm, _config => $config };
 }
 
@@ -41,7 +42,10 @@ sub authenticate {
             return $user_obj;
         }
     } else {
-        $c->log->debug("Unable to locate user matching user info provided") if $c->debug;
+        $c->log->debug(
+            'Unable to locate user matching user info provided in realm: '
+            . $realm->name
+            ) if $c->debug;
         return;
     }
 }
@@ -121,7 +125,7 @@ provided against the user retrieved from the store.
 =head1 CONFIGURATION
 
     # example
-    __PACKAGE__->config->{'Plugin::Authentication'} = 
+    __PACKAGE__->config('Plugin::Authentication' => 
                 {  
                     default_realm => 'members',
                     realms => {
index f39602f..6c6b460 100644 (file)
@@ -6,7 +6,8 @@ use warnings;
 use base 'Class::Accessor::Fast';
 
 BEGIN {
-    __PACKAGE__->mk_accessors(qw/allow_re deny_re cutname_re source realm/);
+    __PACKAGE__->mk_accessors(
+        qw/allow_re deny_re cutname_re source realm username_field/);
 }
 
 sub new {
@@ -14,7 +15,7 @@ sub new {
 
     my $self = { };
     bless $self, $class;
-    
+
     # we are gonna compile regular expresions defined in config parameters
     # and explicitly throw an exception saying what parameter was invalid 
     if (defined($config->{allow_regexp}) && ($config->{allow_regexp} ne "")) { 
@@ -34,6 +35,7 @@ sub new {
     }
     $self->source($config->{source} || 'REMOTE_USER');
     $self->realm($realm);
+    $self->username_field($config->{username_field} || 'username');
     return $self;
 }
 
@@ -43,7 +45,7 @@ sub authenticate {
     my $remuser;
     if ($self->source eq "REMOTE_USER") {    
         # compatibility hack:
-        if (defined($c->engine->env)) {
+        if ($c->engine->can('env') && defined($c->engine->env)) {
             # BEWARE: $c->engine->env was broken prior 5.80005
             $remuser = $c->engine->env->{REMOTE_USER};
         }
@@ -102,9 +104,8 @@ sub authenticate {
             $usr = $1;
         }
     }
-    
-    $authinfo->{id} = $authinfo->{username} = $usr; 
-    $authinfo->{remote_user} = $remuser; # just to keep the original value
+
+    $authinfo->{ $self->username_field } = $usr;
     my $user_obj = $realm->find_user( $authinfo, $c );
     return ref($user_obj) ? $user_obj : undef;
 }
@@ -175,7 +176,7 @@ is able to handle.
 Besides the common methods like HTTP Basic and Digest authentication you can
 also use sophisticated ones like so called "integrated authentication" via
 NTLM or Kerberos (popular in corporate intranet applications running in Windows
-Active Directory enviroment) or even the SSL authentication when users 
+Active Directory environment) or even the SSL authentication when users 
 authenticate themself using their client SSL certificates.   
 
 The main idea of this module is based on a fact that webserver passes the name
@@ -253,7 +254,7 @@ The order deny-allow is fixed.
 This config item is B<OPTIONAL> - no default value.
 
 If param B<cutname_regexp> is specified we try to cut the final usename passed to
-Catalyst application as a substring from WEBUSER. This is usefull for 
+Catalyst application as a substring from WEBUSER. This is useful for 
 example in case of SSL authentication when WEBUSER looks like this 
 'CN=john, OU=Unit Name, O=Company, C=CZ' - from this format we can simply cut
 pure usename by cutname_regexp set to 'CN=(.*), OU=Unit Name, O=Company, C=CZ'.
@@ -262,6 +263,14 @@ Substring is always taken as '$1' regexp substring. If WEBUSER does not
 match cutname_regexp at all or if '$1' regexp substring is empty we pass the
 original WEBUSER value (without cutting) to Catalyst application.
 
+=head2 username_field
+
+This config item is B<OPTIONAL> - default is I<username>
+
+The key name in the authinfo hash that the user's username is mapped into.
+This is useful for using a store which requires a specific unusual field name
+for the username.  The username is additionally mapped onto the I<id> key.
+
 =head1 METHODS
 
 =head2 new ( $config, $app, $realm )
index f349e05..bc6f362 100644 (file)
@@ -12,8 +12,8 @@ Catalyst::Authentication::Realm::Progressive - Authenticate against multiple rea
 =head1 SYNOPSIS
 
 This Realm allows an application to use a single authenticate() call during
-which multiple realms are used and tried incrementally until one performs 
-a successful authentication is accomplished. 
+which multiple realms are used and tried incrementally until one performs
+a successful authentication is accomplished.
 
 A simple use case is a Temporary Password that looks and acts exactly as a
 regular password. Without changing the authentication code, you can
@@ -40,11 +40,11 @@ the normal realm.
                 # Modify the authinfo passed into authenticate by merging
                 # these hashes into the realm's authenticate call:
                 authinfo_munge => {
-                    'local'     => { 'type' => 'normal' },
-                    'temp'      => { 'type' => 'temporary' },
+                    normal => { 'type' => 'normal' },
+                    temp   => { 'type' => 'temporary' },
                 }
             },
-            'normal' => {
+            normal => {
                 credential => {
                     class => 'Password',
                     password_field => 'secret',
@@ -53,7 +53,7 @@ the normal realm.
                 },
                 store => {
                     class      => 'DBIx::Class',
-                    user_class => 'Schema::Person::Identity',
+                    user_model => 'Schema::Person::Identity',
                     id_field   => 'id',
                 }
             },
@@ -66,13 +66,13 @@ the normal realm.
                 },
                 store => {
                     class    => 'DBIx::Class',
-                    user_class => 'Schema::Person::Identity',
+                    user_model => 'Schema::Person::Identity',
                     id_field   => 'id',
                 }
             },
         }
     }
- ); 
+ );
 
 Then, in your controller code, to attempt authentication against both realms
 you just have to do a simple authenticate call:
@@ -89,7 +89,7 @@ you just have to do a simple authenticate call:
 
 =item realms
 
-An array reference consisting of each realm to attempt authentication against, 
+An array reference consisting of each realm to attempt authentication against,
 in the order listed.  If the realm does not exist, calling authenticate will
 die.
 
@@ -98,7 +98,7 @@ die.
 A hash reference keyed by realm names, with values being hash references to
 merge into the authinfo call that is subsequently passed into the realm's
 authenticate method.  This is useful if your store uses the same class for each
-realm, separated by some other token (in the L<EXAMPLE> authinfo_mungesection, 
+realm, separated by some other token (in the L<EXAMPLE> authinfo_mungesection,
 the 'realm' is a column on C<Schema::Person::Identity> that will be either
 'temp' or 'local', to ensure the query to fetch the user finds the right
 Identity record for that realm.
@@ -127,11 +127,11 @@ sub authenticate {
         unless ref $realms eq 'ARRAY';
     foreach my $realm_name ( @$realms ) {
         my $realm = $c->get_auth_realm( $realm_name );
-        carp "Unable to find realm: $realm_name, check configuration" 
+        carp "Unable to find realm: $realm_name, check configuration"
             unless $realm;
         my $auth = { %$authinfo };
         $auth->{realm} ||= $realm->name;
-        if ( my $info = $realm->config->{authinfo_munge}->{$realm->name} ) {
+        if ( my $info = $self->config->{authinfo_munge}->{$realm->name} ) {
             $auth = Catalyst::Utils::merge_hashes($auth, $info);
         }
         if ( my $obj = $realm->authenticate( $c, $auth ) ) {
@@ -142,8 +142,8 @@ sub authenticate {
     return;
 }
 
-## we can not rely on inheriting new() because in this case we do not 
-## load a credential or store, which is what new() sets up in the 
+## we can not rely on inheriting new() because in this case we do not
+## load a credential or store, which is what new() sets up in the
 ## standard realm.  So we have to create our realm object, set our name
 ## and return $self in order to avoid nasty warnings.
 
index 1918dd1..7b7505b 100644 (file)
@@ -12,23 +12,23 @@ sub BUILDARGS {
 }
 
 sub from_session {
-       my ( $self, $c, $id ) = @_;
+    my ( $self, $c, $id ) = @_;
 
-       return $id if ref $id;
+    return $id if ref $id;
 
-       $self->find_user( { id => $id } );
+    $self->find_user( { id => $id } );
 }
 
-## this is not necessarily a good example of what find_user can do, since all we do is   
-## look up with the id anyway.  find_user can be used to locate a user based on other 
+## this is not necessarily a good example of what find_user can do, since all we do is
+## look up with the id anyway.  find_user can be used to locate a user based on other
 ## combinations of data.  See C::P::Authentication::Store::DBIx::Class for a better example
 sub find_user {
     my ( $self, $userinfo, $c ) = @_;
 
     my $id = $userinfo->{'id'};
-    
+
     $id ||= $userinfo->{'username'};
-    
+
     return unless exists $self->userhash->{$id};
 
     my $user = $self->userhash->{$id};
@@ -58,7 +58,7 @@ sub user_supports {
 ## Backwards compatibility
 #
 # This is a backwards compatible routine.  get_user is specifically for loading a user by it's unique id
-# find_user is capable of doing the same by simply passing { id => $id }  
+# find_user is capable of doing the same by simply passing { id => $id }
 # no new code should be written using get_user as it is deprecated.
 sub get_user {
     my ( $self, $id ) = @_;
@@ -86,8 +86,8 @@ Catalyst::Authentication::Store::Minimal - Minimal authentication store
         Authentication
     /;
 
-    __PACKAGE__->config( 'Plugin::Authentication' => 
-                    {  
+    __PACKAGE__->config( 'Plugin::Authentication' =>
+                    {
                         default_realm => 'members',
                         realms => {
                             members => {
@@ -98,24 +98,24 @@ Catalyst::Authentication::Store::Minimal - Minimal authentication store
                                 },
                                 store => {
                                     class => 'Minimal',
-                                       users = {
-                                           bob => {
-                                               password => "s00p3r",                                       
-                                               editor => 'yes',
-                                               roles => [qw/edit delete/],
-                                           },
-                                           william => {
-                                               password => "s3cr3t",
-                                               roles => [qw/comment/],
-                                           }
-                                       }                       
-                                   }
-                               }
-                       }
+                                    users => {
+                                        bob => {
+                                            password => "s00p3r",
+                                            editor => 'yes',
+                                            roles => [qw/edit delete/],
+                                        },
+                                        william => {
+                                            password => "s3cr3t",
+                                            roles => [qw/comment/],
+                                        }
+                                    }
+                                }
+                            }
+                        }
                     }
     );
 
-    
+
 =head1 DESCRIPTION
 
 This authentication store lets you create a very quick and dirty user
@@ -134,7 +134,7 @@ at runtime.
 
 =over 4
 
-=item class 
+=item class
 
 The classname used for the store. This is part of
 L<Catalyst::Plugin::Authentication> and is the method by which
@@ -145,8 +145,8 @@ user store. For this module to be used, this must be set to
 =item users
 
 This is a simple hash of users, the keys are the usenames, and the values are
-hashrefs containing a password key/value pair, and optionally, a roles/list 
-of role-names pair. If using roles, you will also need to add the 
+hashrefs containing a password key/value pair, and optionally, a roles/list
+of role-names pair. If using roles, you will also need to add the
 Authorization::Roles plugin.
 
 See the SYNOPSIS for an example.
@@ -156,15 +156,15 @@ See the SYNOPSIS for an example.
 =head1 METHODS
 
 There are no publicly exported routines in the Minimal store (or indeed in
-most authentication stores)  However, below is a description of the routines 
+most authentication stores)  However, below is a description of the routines
 required by L<Catalyst::Plugin::Authentication> for all authentication stores.
 
 =head2 new( $config, $app, $realm )
 
-Constructs a new store object, which uses the user element of the supplied config 
+Constructs a new store object, which uses the user element of the supplied config
 hash ref as it's backing structure.
 
-=head2 find_user( $authinfo, $c ) 
+=head2 find_user( $authinfo, $c )
 
 Keys the hash by the 'id' or 'username' element in the authinfo hash and returns the user.
 
index e4d2106..eeff10e 100644 (file)
@@ -1,5 +1,6 @@
 package Catalyst::Authentication::User;
 use Moose;
+use Scalar::Util qw/refaddr/;
 use namespace::autoclean;
 
 ## auth_realm is the realm this user came from. 
@@ -41,7 +42,7 @@ sub supports {
 ## you most likely want to write this yourself.
 sub get {
     my ($self, $field) = @_;
-    
+
     my $object;
     if ($object = $self->get_object and $object->can($field)) {
         return $object->$field();
@@ -67,15 +68,13 @@ sub obj {
     return $self->get_object(@_);
 }
 
-## Backwards Compatibility
-## you probably want auth_realm, in fact.  but this does work for backwards compatibility.
-## store should be a read-write accessor - so it was moved to mk_accessors
-##sub store { 
-##    my ($self) = @_;
-##    return $self->auth_realm->{store};
-##}
+sub AUTOLOAD {
+    my $self = shift;
+    (my $method) = (our $AUTOLOAD =~ /([^:]+)$/);
+    return if $method eq "DESTROY";
 
 __PACKAGE__->meta->make_immutable;
+__PACKAGE__;
 
 __END__
 
@@ -92,7 +91,17 @@ Catalyst::Authentication::User - Base class for user objects.
 
 =head1 DESCRIPTION
 
-This is the base class for authenticated 
+This is the base class for authentication user objects.
+
+THIS IS NOT A COMPLETE CLASS! it is intended to provide base functionality only.
+
+It provides the base methods listed below, and any additional methods
+are proxied onto the user object fetched from the underlieing store.
+
+=head1 NOTES TO STORE IMPLEMENTORS
+
+Please read the comments in the source code of this class to work out
+which methods you should override.
 
 =head1 METHODS
 
@@ -115,12 +124,17 @@ Returns the value for the $field provided.
 
 =head2 get_object( )
 
-Returns the underlying object storing the user data.  The return value of this function will vary depending
+Returns the underlying object storing the user data.  The return value of this
+method will vary depending
 on the storage module used.
 
 =head2 obj( )
 
 Shorthand for get_object( )
 
+=head2 AUTOLOAD
+
+Delegates any unknown methods onto the user object returned by ->obj
+
 =cut
 
index 2614177..d78a63b 100644 (file)
@@ -8,7 +8,7 @@ use namespace::autoclean;
 
 has _user => ( is => 'rw' );
 
-our $VERSION = "0.10012";
+our $VERSION = "0.10016";
 
 sub set_authenticated {
     my ( $c, $user, $realmname ) = @_;
@@ -20,15 +20,15 @@ sub set_authenticated {
         $realmname = 'default';
     }
     my $realm = $c->get_auth_realm($realmname);
-    
+
     if (!$realm) {
         Catalyst::Exception->throw(
                 "set_authenticated called with nonexistant realm: '$realmname'.");
     }
     $user->auth_realm($realm->name);
 
-    $c->persist_user();    
-    
+    $c->persist_user();
+
     $c->maybe::next::method($user, $realmname);
 }
 
@@ -49,11 +49,11 @@ sub user {
 # change this to allow specification of a realm - to verify the user is part of that realm
 # in addition to verifying that they exist.
 sub user_exists {
-       my $c = shift;
-       return defined($c->_user) || defined($c->find_realm_for_persisted_user);
+    my $c = shift;
+    return defined($c->_user) || defined($c->find_realm_for_persisted_user);
 }
 
-# works like user_exists - except only returns true if user 
+# works like user_exists - except only returns true if user
 # exists AND is in the realm requested.
 sub user_in_realm {
     my ($c, $realmname) = @_;
@@ -74,7 +74,7 @@ sub __old_save_user_in_session {
     my ( $c, $user, $realmname ) = @_;
 
     $c->session->{__user_realm} = $realmname;
-    
+
     # we want to ask the store for a user prepared for the session.
     # but older modules split this functionality between the user and the
     # store.  We try the store first.  If not, we use the old method.
@@ -90,26 +90,26 @@ sub persist_user {
     my $c = shift;
 
     if ($c->user_exists) {
-        
-        ## if we have a valid session handler - we store the 
-        ## realm in the session.  If not - we have to hope that 
+
+        ## if we have a valid session handler - we store the
+        ## realm in the session.  If not - we have to hope that
         ## the realm can recognize its frozen user somehow.
-        if ($c->can('session') && 
-            $c->config->{'Plugin::Authentication'}{'use_session'} && 
+        if ($c->can('session') &&
+            $c->config->{'Plugin::Authentication'}{'use_session'} &&
             $c->session_is_valid) {
-        
-            $c->session->{'__user_realm'} = $c->_user->auth_realm; 
+
+            $c->session->{'__user_realm'} = $c->_user->auth_realm;
         }
-        
+
         my $realm = $c->get_auth_realm($c->_user->auth_realm);
-        
+
         # used to call $realm->save_user_in_session
         $realm->persist_user($c, $c->user);
     }
 }
 
 
-## this was a short lived method to update user information - 
+## this was a short lived method to update user information -
 ## you should use persist_user instead.
 sub update_user_in_session {
     my $c = shift;
@@ -126,16 +126,16 @@ sub logout {
     if ($realm) {
         $realm->remove_persisted_user($c);
     }
-    
+
     $c->maybe::next::method(@_);
 }
 
 sub find_user {
     my ( $c, $userinfo, $realmname ) = @_;
-    
+
     $realmname ||= 'default';
     my $realm = $c->get_auth_realm($realmname);
-    
+
     if (!$realm) {
         Catalyst::Exception->throw(
                 "find_user called with nonexistant realm: '$realmname'.");
@@ -143,28 +143,28 @@ sub find_user {
     return $realm->find_user($userinfo, $c);
 }
 
-## Consider making this a public method. - would make certain things easier when 
+## Consider making this a public method. - would make certain things easier when
 ## dealing with things pre-auth restore.
 sub find_realm_for_persisted_user {
     my $c = shift;
-    
+
     my $realm;
     if ($c->can('session')
         and $c->config->{'Plugin::Authentication'}{'use_session'}
-        and $c->session_is_valid 
+        and $c->session_is_valid
         and exists($c->session->{'__user_realm'})) {
-    
+
         $realm = $c->auth_realms->{$c->session->{'__user_realm'}};
         if ($realm->user_is_restorable($c)) {
-            return $realm; 
+            return $realm;
         }
     } else {
         ## we have no choice but to ask each realm whether it has a persisted user.
         foreach my $realmname (@{$c->_auth_realm_restore_order}) {
-            my $ret = $c->auth_realms->{$realmname}->user_is_restorable($c);
-            if ($ret) {
-                return $c->auth_realms->{$realmname};
-            }
+            my $realm = $c->auth_realms->{$realmname}
+                || Catalyst::Exception->throw("Could not find authentication realm '$realmname'");
+            return $realm
+                if $realm->user_is_restorable($c);
         }
     }
     return undef;
@@ -175,17 +175,17 @@ sub auth_restore_user {
 
     my $realm;
     if (defined($realmname)) {
-        $realm = $c->get_auth_realm($realmname); 
+        $realm = $c->get_auth_realm($realmname);
     } else {
         $realm = $c->find_realm_for_persisted_user;
     }
     return undef unless $realm; # FIXME die unless? This is an internal inconsistency
-       
+
     $c->_user( my $user = $realm->restore_user( $c, $frozen_user ) );
-    
+
     # this sets the realm the user originated in.
     $user->auth_realm($realm->name) if $user;
-        
+
     return $user;
 
 }
@@ -206,24 +206,24 @@ sub _authentication_initialize {
     ## let's avoid recreating / configuring everything if we have already done it, eh?
     if ($app->can('_auth_realms')) { return };
 
-    ## make classdata where it is used.  
+    ## make classdata where it is used.
     $app->mk_classdata( '_auth_realms' => {});
-    
-    ## the order to attempt restore in - If we don't have session - we have 
-    ## no way to be sure where a frozen user came from - so we have to 
-    ## ask each realm if it can restore the user.  Unfortunately it is possible 
-    ## that multiple realms could restore the user from the data we have - 
-    ## So we have to determine at setup time what order to ask the realms in.  
+
+    ## the order to attempt restore in - If we don't have session - we have
+    ## no way to be sure where a frozen user came from - so we have to
+    ## ask each realm if it can restore the user.  Unfortunately it is possible
+    ## that multiple realms could restore the user from the data we have -
+    ## So we have to determine at setup time what order to ask the realms in.
     ## The default is to use the user_restore_priority values defined in the realm
-    ## config. if they are not defined - we go by alphabetical order.   Note that 
+    ## config. if they are not defined - we go by alphabetical order.   Note that
     ## the 'default' realm always gets first chance at it unless it is explicitly
     ## placed elsewhere by user_restore_priority.  Remember this only comes
-    ## into play if session is disabled. 
-    
+    ## into play if session is disabled.
+
     $app->mk_classdata( '_auth_realm_restore_order' => []);
 
     my $cfg = $app->config->{'Plugin::Authentication'};
-       my $realmshash;
+    my $realmshash;
     if (!defined($cfg)) {
         if (exists($app->config->{'authentication'})) {
             $cfg = $app->config->{'authentication'};
@@ -232,45 +232,45 @@ sub _authentication_initialize {
             $cfg = {};
         }
     } else {
-               # the realmshash contains the various configured realms.  By default this is
-               # the main $app->config->{'Plugin::Authentication'} hash - but if that is 
-               # not defined, or there is a subkey {'realms'} then we use that.
-               $realmshash = $cfg;
-       }
-       
-       ## If we have a sub-key of {'realms'} then we use that for realm configuration
-       if (exists($cfg->{'realms'})) {
-               $realmshash = $cfg->{'realms'};
-       }
+        # the realmshash contains the various configured realms.  By default this is
+        # the main $app->config->{'Plugin::Authentication'} hash - but if that is
+        # not defined, or there is a subkey {'realms'} then we use that.
+        $realmshash = $cfg;
+    }
+
+    ## If we have a sub-key of {'realms'} then we use that for realm configuration
+    if (exists($cfg->{'realms'})) {
+        $realmshash = $cfg->{'realms'};
+    }
 
     # old default was to force use_session on.  This must remain for that
     # reason - but if use_session is already in the config, we respect its setting.
     if (!exists($cfg->{'use_session'})) {
         $cfg->{'use_session'} = 1;
     }
-    
-    ## if we have a realms hash  
+
+    ## if we have a realms hash
     if (ref($realmshash) eq 'HASH') {
-        
+
         my %auth_restore_order;
         my $authcount = 2;
         my $defaultrealm = 'default';
-               
+
         foreach my $realm (sort keys %{$realmshash}) {
             if (ref($realmshash->{$realm}) eq 'HASH' &&
-                               (exists($realmshash->{$realm}{credential}) || exists($realmshash->{$realm}{class}))) {
-                                       
-                   $app->setup_auth_realm($realm, $realmshash->{$realm});
-            
-                   if (exists($realmshash->{$realm}{'user_restore_priority'})) {
-                       $auth_restore_order{$realm} = $realmshash->{$realm}{'user_restore_priority'};
-                   } else {
-                       $auth_restore_order{$realm} = $authcount++;
-                   }
-                       }
+                (exists($realmshash->{$realm}{credential}) || exists($realmshash->{$realm}{class}))) {
+
+                $app->setup_auth_realm($realm, $realmshash->{$realm});
+
+                if (exists($realmshash->{$realm}{'user_restore_priority'})) {
+                    $auth_restore_order{$realm} = $realmshash->{$realm}{'user_restore_priority'};
+                } else {
+                    $auth_restore_order{$realm} = $authcount++;
+                }
+            }
         }
-        
-        # if we have a 'default_realm' in the config hash and we don't already 
+
+        # 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'}) && !$app->get_auth_realm('default')) {
             if ($app->_set_default_auth_realm($cfg->{'default_realm'})) {
@@ -279,21 +279,21 @@ sub _authentication_initialize {
                 delete($auth_restore_order{$cfg->{'default_realm'}});
             }
         }
-        
+
         ## if the default realm did not have a defined priority in its config - we put it at the front.
         if (!exists($realmshash->{$defaultrealm}{'user_restore_priority'})) {
             $auth_restore_order{'default'} = 1;
         }
-        
+
         @{$app->_auth_realm_restore_order} = sort { $auth_restore_order{$a} <=> $auth_restore_order{$b} } keys %auth_restore_order;
-        
+
     } else {
-        
+
         ## BACKWARDS COMPATIBILITY - if realms is not defined - then we are probably dealing
         ## with an old-school config.  The only caveat here is that we must add a classname
-        
-        ## also - we have to treat {store} as {stores}{default} - because 
-        ## while it is not a clear as a valid config in the docs, it 
+
+        ## also - we have to treat {store} as {stores}{default} - because
+        ## while it is not a clear as a valid config in the docs, it
         ## is functional with the old api. Whee!
         if (exists($cfg->{'store'}) && !exists($cfg->{'stores'}{'default'})) {
             $cfg->{'stores'}{'default'} = $cfg->{'store'};
@@ -304,17 +304,16 @@ sub _authentication_initialize {
             my $realmcfg = {
                 store => { class => $cfg->{'stores'}{$storename} },
             };
-            print STDERR "Foo, ok?\n";
             $app->setup_auth_realm($storename, $realmcfg);
         }
-    } 
-    
+    }
+
 }
 
 # set up realmname.
 sub setup_auth_realm {
     my ($app, $realmname, $config) = @_;
-    
+
     my $realmclass = $config->{class};
 
     if( !$realmclass ) {
@@ -338,25 +337,24 @@ sub setup_auth_realm {
 
 sub auth_realms {
     my $self = shift;
+    $self->_authentication_initialize(); # Ensure _auth_realms created!
     return($self->_auth_realms);
 }
 
 sub get_auth_realm {
     my ($app, $realmname) = @_;
-    
     return $app->auth_realms->{$realmname};
-    
 }
 
 
 # Very internal method.  Vital Valuable Urgent, Do not touch on pain of death.
 # Using this method just assigns the default realm to be the value associated
 # with the realmname provided.  It WILL overwrite any real realm called 'default'
-# so can be very confusing if used improperly.  It's used properly already. 
+# so can be very confusing if used improperly.  It's used properly already.
 # Translation: don't use it.
 sub _set_default_auth_realm {
     my ($app, $realmname) = @_;
-    
+
     if (exists($app->auth_realms->{$realmname})) {
         $app->auth_realms->{'default'} = $app->auth_realms->{$realmname};
     }
@@ -365,15 +363,15 @@ sub _set_default_auth_realm {
 
 sub authenticate {
     my ($app, $userinfo, $realmname) = @_;
-    
+
     if (!$realmname) {
         $realmname = 'default';
     }
-        
+
     my $realm = $app->get_auth_realm($realmname);
-    
+
     ## note to self - make authenticate throw an exception if realm is invalid.
-    
+
     if ($realm) {
         return $realm->authenticate($app, $userinfo);
     } else {
@@ -387,13 +385,13 @@ sub authenticate {
 ## BACKWARDS COMPATIBILITY  -- Warning:  Here be monsters!
 #
 # What follows are backwards compatibility routines - for use with Stores and Credentials
-# that have not been updated to work with C::P::Authentication v0.10.  
+# that have not been updated to work with C::P::Authentication v0.10.
 # These are here so as to not break people's existing installations, but will go away
 # in a future version.
 #
 # The old style of configuration only supports a single store, as each store module
-# sets itself as the default store upon being loaded.  This is the only supported 
-# 'compatibility' mode.  
+# sets itself as the default store upon being loaded.  This is the only supported
+# 'compatibility' mode.
 #
 
 sub get_user {
@@ -417,16 +415,16 @@ sub default_auth_store {
     }
     if ( my $new = shift ) {
         $realm->store($new);
-        
+
         my $storeclass;
         if (ref($new)) {
             $storeclass = ref($new);
         } else {
             $storeclass = $new;
         }
-        
-        # BACKWARDS COMPATIBILITY - if the store class does not define find_user, we define it in terms 
-        # of get_user and add it to the class.  this is because the auth routines use find_user, 
+
+        # BACKWARDS COMPATIBILITY - if the store class does not define find_user, we define it in terms
+        # of get_user and add it to the class.  this is because the auth routines use find_user,
         # and rely on it being present. (this avoids per-call checks)
         if (!$storeclass->can('find_user')) {
             no strict 'refs';
@@ -452,9 +450,9 @@ sub auth_store_names {
 
 sub get_auth_store {
     my ( $self, $name ) = @_;
-    
+
     if ($name ne 'default') {
-        Carp::croak "get_auth_store called on non-default realm '$name'. Only default supported in compatibility mode";        
+        Carp::croak "get_auth_store called on non-default realm '$name'. Only default supported in compatibility mode";
     } else {
         $self->default_auth_store();
     }
@@ -490,7 +488,7 @@ authentication framework.
     /;
 
     # later on ...
-    $c->authenticate({ username => 'myusername', 
+    $c->authenticate({ username => 'myusername',
                        password => 'mypassword' });
     my $age = $c->user->get('age');
     $c->logout;
@@ -509,10 +507,10 @@ given data from the frontend. A Credential and a Store are paired to form a
 'Realm'. A Catalyst application using the authentication framework must have
 at least one realm, and may have several.
 
-To implement authentication in a Catalyst application you need to add this 
-module, and specify at least one realm in the configuration. 
+To implement authentication in a Catalyst application you need to add this
+module, and specify at least one realm in the configuration.
 
-Authentication data can also be stored in a session, if the application 
+Authentication data can also be stored in a session, if the application
 is using the L<Catalyst::Plugin::Session> module.
 
 B<NOTE> in version 0.10 of this module, the interface to this module changed.
@@ -540,7 +538,7 @@ 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 your application
-or other plugins step in.  
+or 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
@@ -548,7 +546,7 @@ 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 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.  
+authentication, or it may be facilitated by a number of plugins.
 
 =head2 The Components In This Framework
 
@@ -622,8 +620,8 @@ This means that our application will begin like this:
         Authentication
     /;
 
-    __PACKAGE__->config( 'Plugin::Authentication' => 
-                {  
+    __PACKAGE__->config( 'Plugin::Authentication' =>
+                {
                     default => {
                         credential => {
                             class => 'Password',
@@ -632,19 +630,19 @@ This means that our application will begin like this:
                         },
                         store => {
                             class => 'Minimal',
-                               users => {
-                                   bob => {
-                                       password => "s00p3r",                                       
-                                       editor => 'yes',
-                                       roles => [qw/edit delete/],
-                                   },
-                                   william => {
-                                       password => "s3cr3t",
-                                       roles => [qw/comment/],
-                                   }
-                               }                       
-                           }
-                       }
+                            users => {
+                                bob => {
+                                    password => "s00p3r",
+                                    editor => 'yes',
+                                    roles => [qw/edit delete/],
+                                },
+                                william => {
+                                    password => "s3cr3t",
+                                    roles => [qw/comment/],
+                                }
+                            }
+                        }
+                    }
                 }
     );
 
@@ -662,7 +660,7 @@ To show an example of this, let's create an authentication controller:
         if (    my $user     = $c->req->params->{user}
             and my $password = $c->req->params->{password} )
         {
-            if ( $c->authenticate( { username => $user, 
+            if ( $c->authenticate( { username => $user,
                                      password => $password } ) ) {
                 $c->res->body( "hello " . $c->user->get("name") );
             } else {
@@ -675,7 +673,7 @@ To show an example of this, let's create an authentication controller:
     }
 
 This code should be self-explanatory. If all the necessary fields are supplied,
-call the C<authenticate> method on the context object. If it succeeds the 
+call the C<authenticate> method on the context object. If it succeeds the
 user is logged in.
 
 The credential verifier will attempt to retrieve the user whose
@@ -689,13 +687,13 @@ check an alternate realm. If this were an admin login, for example, we could
 authenticate on the admin realm by simply changing the C<< $c->authenticate() >>
 call:
 
-    if ( $c->authenticate( { username => $user, 
+    if ( $c->authenticate( { username => $user,
                              password => $password }, 'admin' ) ) {
         $c->res->body( "hello " . $c->user->get("name") );
     } ...
 
 
-Now suppose we want to restrict the ability to edit to a user with an 
+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:
@@ -716,7 +714,7 @@ C<< $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.  
+The above example is somewhat similar to role based access control.
 L<Catalyst::Authentication::Store::Minimal> treats the roles field as
 an array of role names. Let's leverage this. Add the role authorization
 plugin:
@@ -742,8 +740,8 @@ efficient to maintain a hash of users, so you move this data to a database.
 You can accomplish this simply by installing the L<DBIx::Class|Catalyst::Authentication::Store::DBIx::Class> Store and
 changing your config:
 
-    __PACKAGE__->config( 'Plugin::Authentication'} => 
-                    {  
+    __PACKAGE__->config( 'Plugin::Authentication' =>
+                    {
                         default_realm => 'members',
                         members => {
                             credential => {
@@ -753,10 +751,10 @@ changing your config:
                             },
                             store => {
                                 class => 'DBIx::Class',
-                                   user_class => 'MyApp::Users',
-                                   role_column => 'roles'                      
-                               }
-                       }
+                                user_model => 'MyApp::Users',
+                                role_column => 'roles',
+                            }
+                        }
                     }
     );
 
@@ -767,8 +765,8 @@ new source. The rest of your application is completely unchanged.
 =head1 CONFIGURATION
 
     # example
-    __PACKAGE__->config( 'Plugin::Authentication' => 
-                {  
+    __PACKAGE__->config( 'Plugin::Authentication' =>
+                {
                     default_realm => 'members',
 
                     members => {
@@ -779,26 +777,26 @@ new source. The rest of your application is completely unchanged.
                         },
                         store => {
                             class => 'DBIx::Class',
-                           user_class => 'MyApp::Users',
-                           role_column => 'roles'                      
-                       }
-                       },
-                       admins => {
-                           credential => {
-                               class => 'Password',
-                               password_field => 'password',
+                            user_model => 'MyApp::Users',
+                            role_column => 'roles',
+                        }
+                    },
+                    admins => {
+                        credential => {
+                            class => 'Password',
+                            password_field => 'password',
                             password_type => 'clear'
-                           },
-                           store => {
-                               class => '+MyApp::Authentication::Store::NetAuth',
-                               authserver => '192.168.10.17'
-                           }
-                       }
+                        },
+                        store => {
+                            class => '+MyApp::Authentication::Store::NetAuth',
+                            authserver => '192.168.10.17'
+                        }
+                    }
                 }
     );
 
 NOTE: Until version 0.10008 of this module, you would need to put all the
-realms inside a "realms" key in the configuration. Please see 
+realms inside a "realms" key in the configuration. Please see
 L</COMPATIBILITY CONFIGURATION> for more information
 
 =over 4
@@ -822,23 +820,23 @@ that require a realm such as authenticate or find_user.
 
 =item realm refs
 
-The Plugin::Authentication config hash contains the series of realm 
-configurations you want to use for your app. The only rule here is 
-that there must be at least one. A realm consists of a name, which is used 
-to reference the realm, a credential and a store.  You may also put your 
-realm configurations within a subelement called 'realms' if you desire to 
+The Plugin::Authentication config hash contains the series of realm
+configurations you want to use for your app. The only rule here is
+that there must be at least one. A realm consists of a name, which is used
+to reference the realm, a credential and a store.  You may also put your
+realm configurations within a subelement called 'realms' if you desire to
 separate them from the remainder of your configuration.  Note that if you use
-a 'realms' subelement, you must put ALL of your realms within it.   
+a 'realms' subelement, you must put ALL of your realms within it.
 
 You can also specify a realm class to instantiate instead of the default
 L<Catalyst::Authentication::Realm> class using the 'class' element within the
 realm config.
 
-Each realm config contains two hashes, one called 'credential' and one called 
+Each realm config contains two hashes, one called 'credential' and one called
 'store', each of which provide configuration details to the respective modules.
-The contents of these hashes is specific to the module being used, with the 
+The contents of these hashes is specific to the module being used, with the
 exception of the 'class' element, which tells the core Authentication module the
-classname to instantiate.  
+classname to instantiate.
 
 The 'class' element follows the standard Catalyst mechanism of class
 specification. If a class is prefixed with a +, it is assumed to be a complete
@@ -872,25 +870,26 @@ can be much more efficient.
 
 =head2 $c->user_in_realm( $realm )
 
-Works like user_exists, except that it only returns true if a user is both 
-logged in right now and was retrieved from the realm provided.  
+Works like user_exists, except that it only returns true if a user is both
+logged in right now and was retrieved from the realm provided.
 
 =head2 $c->logout( )
 
-Logs the user out. Deletes the currently logged in user from C<< $c->user >> and the session.
+Logs the user out. Deletes the currently logged in user from C<< $c->user >>
+and the session.  It does not delete the session.
 
 =head2 $c->find_user( $userinfo, $realm )
 
-Fetch a particular users details, matching the provided user info, from the realm 
+Fetch a particular users details, matching the provided user info, from the realm
 specified in $realm.
 
 =head2 persist_user()
 
 Under normal circumstances the user data is only saved to the session during
-initial authentication.  This call causes the auth system to save the 
+initial authentication.  This call causes the auth system to save the
 currently authenticated user's data across requests.  Useful if you have
 changed the user data and want to ensure that future requests reflect the
-most current data.  Assumes that at the time of this call, $c->user 
+most current data.  Assumes that at the time of this call, $c->user
 contains the most current data.
 
 =head2 find_realm_for_persisted_user()
@@ -939,7 +938,7 @@ This was a short-lived method to update user information - you should use persis
 =head1 SEE ALSO
 
 This list might not be up to date.  Below are modules known to work with the updated
-API of 0.10 and are therefore compatible with realms.  
+API of 0.10 and are therefore compatible with realms.
 
 =head2 Realms
 
@@ -1009,11 +1008,11 @@ L<Catalyst::Plugin::Authentication::CDBI>.
 
 =head1 INCOMPATABILITIES
 
-The realms-based configuration and functionality of the 0.10 update 
+The realms-based configuration and functionality of the 0.10 update
 of L<Catalyst::Plugin::Authentication> required a change in the API used by
 credentials and stores.  It has a compatibility mode which allows use of
 modules that have not yet been updated. This, however, completely mimics the
-older api and disables the new realm-based features. In other words you cannot 
+older api and disables the new realm-based features. In other words you cannot
 mix the older credential and store modules with realms, or realm-based
 configs. The changes required to update modules are relatively minor and are
 covered in L<Catalyst::Plugin::Authentication::Internals>.  We hope that most
@@ -1022,11 +1021,11 @@ modules will move to the compatible list above very quickly.
 =head1 COMPATIBILITY CONFIGURATION
 
 Until version 0.10008 of this module, you needed to put all the
-realms inside a "realms" key in the configuration. 
+realms inside a "realms" key in the configuration.
 
     # example
-    __PACKAGE__->config( 'Plugin::Authentication'} => 
-                {  
+    __PACKAGE__->config( 'Plugin::Authentication' =>
+                {
                     default_realm => 'members',
                     realms => {
                         members => {
@@ -1043,7 +1042,7 @@ configuration key, then the realms key is still required.
 
 In version 0.10 of L<Catalyst::Plugin::Authentication>, the API
 changed. For app developers, this change is fairly minor, but for
-Credential and Store authors, the changes are significant. 
+Credential and Store authors, the changes are significant.
 
 Please see the documentation in version 0.09 of
 Catalyst::Plugin::Authentication for a better understanding of how the old API
@@ -1052,7 +1051,7 @@ functioned.
 The items below are still present in the plugin, though using them is
 deprecated. They remain only as a transition tool, for those sites which can
 not yet be upgraded to use the new system due to local customizations or use
-of Credential / Store modules that have not yet been updated to work with the 
+of Credential / Store modules that have not yet been updated to work with the
 new API.
 
 These routines should not be used in any application using realms
@@ -1074,7 +1073,7 @@ This is set to C<< $c->config( 'Plugin::Authentication' => { store => # Store} )
 or by using a Store plugin:
 
     # load the Minimal authentication store.
-       use Catalyst qw/Authentication Authentication::Store::Minimal/;
+    use Catalyst qw/Authentication Authentication::Store::Minimal/;
 
 Sets the default store to
 L<Catalyst::Plugin::Authentication::Store::Minimal>.
@@ -1109,13 +1108,24 @@ Jess Robinson
 
 David Kamholz
 
-Tomas Doran (t0m), C<bobtfish@bobtfish.net> 
+Tomas Doran (t0m), C<bobtfish@bobtfish.net>
+
+kmx
+
+Nigel Metheringham
+
+Florian Ragwitz C<rafl@debian.org>
+
+Stephan Jauernick C<stephanj@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.
+Copyright (c) 2005 - 2009
+the Catalyst::Plugin::Authentication L</AUTHORS>
+as listed above.
+
+This program is free software; you can redistribute
+it and/or modify it under the same terms as Perl itself.
 
 =cut
 
index 2343cb1..f81d6e6 100644 (file)
@@ -2,6 +2,7 @@ package Catalyst::Plugin::Authentication::Store::Minimal;
 
 use strict;
 use warnings;
+use MRO::Compat;
 
 use Catalyst::Authentication::Store::Minimal ();
 
@@ -22,20 +23,20 @@ sub setup {
     ###  lib/Catalyst/Authentication/Store/Minimal.pm line 38.
     ###
     ### So only do this compatibility call if:
-    ### 1) we have a {users} config directive 
+    ### 1) we have a {users} config directive
     ###
     ### Ideally we could also check for:
     ### 2) we don't already have a ->userhash
-    ### however, that's an attribute of an object we can't 
+    ### however, that's an attribute of an object we can't
     ### access =/ --kane
-    
+
     my $cfg = $c->config->{'Plugin::Authentication'}->{users}
                 ? $c->config->{'Plugin::Authentication'}
                 : undef;
 
     $c->default_auth_store( Catalyst::Authentication::Store::Minimal->new( $cfg, $c ) ) if $cfg;
-    
-       $c->NEXT::setup(@_);
+
+       $c->next::method(@_);
 }
 
 foreach my $method (qw/ get_user user_supports find_user from_session /) {
index 13fd88f..840692b 100644 (file)
@@ -3,42 +3,44 @@ use warnings;
 
 use Test::More tests => 11;
 use Test::Exception;
-use Test::MockObject;
+use Class::MOP;
+use Class::MOP::Class;
+use Moose::Object;
 
 # 1,2
 my $m; BEGIN { use_ok($m = "Catalyst::Authentication::Credential::Password") }
 can_ok($m, "authenticate");
 
-my $app = Test::MockObject->new;
-my $realm = Test::MockObject->new;
-my $user = Test::MockObject->new;
+my $app_meta = Class::MOP::Class->create_anon_class( superclasses => ['Moose::Object'] );
+my $realm_meta = Class::MOP::Class->create_anon_class( superclasses => ['Moose::Object'] );
+my $user_meta = Class::MOP::Class->create_anon_class( superclasses => ['Moose::Object'] );
 our ($user_get_password_field_name, $user_password );
-$user->mock('get' => sub { $user_get_password_field_name = $_[1]; return $user_password });
+$user_meta->add_method('get' => sub { $user_get_password_field_name = $_[1]; return $user_password });
 
 # 3-6 # Test clear passwords if you mess up the password_field
 {
-    local $user_password = undef;        # The user returns an undef password, 
+    local $user_password = undef;        # The user returns an undef password,
     local $user_get_password_field_name; # as there is no field named 'mistyped'
     my $config = { password_type => 'clear', password_field => 'mistyped' };
-    my $i; lives_ok { $i = $m->new($config, $app, $realm) } 'Construct instance';
+    my $i; lives_ok { $i = $m->new($config, $app_meta->name->new, $realm_meta->name->new) } 'Construct instance';
     ok($i, 'Have instance');
-    my $r = $i->check_password($user, { username => 'someuser', password => 'password' });
-    is($user_get_password_field_name, 'mistyped', 
+    my $r = $i->check_password($user_meta->name->new, { username => 'someuser', password => 'password' });
+    is($user_get_password_field_name, 'mistyped',
         '(Incorrect) field name from config correctly passed to user');
     ok(! $r, 'Authentication unsuccessful' );
 }
 
 # 7-11 # Test clear passwords working, and not working
 {
-    local $user_password = 'mypassword';         
+    local $user_password = 'mypassword';
     local $user_get_password_field_name;
     my $config = { password_type => 'clear', password_field => 'the_password_field' };
-    my $i; lives_ok { $i = $m->new($config, $app, $realm) } 'Construct instance';
+    my $i; lives_ok { $i = $m->new($config, $app_meta->name->new, $realm_meta->name->new) } 'Construct instance';
     ok($i, 'Have instance');
-    my $r = $i->check_password($user, { username => 'someuser', the_password_field => 'mypassword' });
-    is($user_get_password_field_name, 'the_password_field', 
+    my $r = $i->check_password($user_meta->name->new, { username => 'someuser', the_password_field => 'mypassword' });
+    is($user_get_password_field_name, 'the_password_field',
         'Correct field name from config correctly passed to user');
     ok( $r, 'Authentication successful with correct password' );
-    $r = $i->check_password($user, { username => 'someuser', the_password_field => 'adifferentpassword' });
+    $r = $i->check_password($user_meta->name->new, { username => 'someuser', the_password_field => 'adifferentpassword' });
     ok( ! $r, 'Authentication ussuccessful with incorrect password' );
 }
index f2bfa8c..62db266 100644 (file)
@@ -1,26 +1,34 @@
 use strict;
 use warnings;
 
-use Test::More tests => 6;
+use Test::More;
 use Test::Exception;
 
 my $m; BEGIN { use_ok($m = "Catalyst::Authentication::User") }
 
 {
-       package SomeUser;
-       use base $m;
-
-       sub new { bless {}, shift };
-
-       sub supported_features {
-               {
-                       feature => {
-                               subfeature => 1,
-                               unsupported_subfeature => 0,
-                       },
-                       top_level => 1,
-               }
-       }
+    package SomeBaseUser;
+    sub other_method { 'FNAR' };
+}
+
+{
+    package SomeUser;
+    use base $m;
+
+    sub new { bless {}, shift };
+
+    sub supported_features {
+        {
+            feature => {
+                subfeature => 1,
+                unsupported_subfeature => 0,
+            },
+            top_level => 1,
+        }
+    }
+    sub get_object {
+        bless {}, 'SomeBaseUser';
+    }
 }
 
 my $o = SomeUser->new;
@@ -32,11 +40,17 @@ ok( $o->supports(qw/feature subfeature/), "traversal");
 ok( !$o->supports(qw/feature unsupported_subfeature/), "traversal terminating in false");
 
 lives_ok {
-       $o->supports("bad_key");
+    $o->supports("bad_key");
 } "can check for non existent feature";
 
 #dies_ok {
-#      $o->supports(qw/bad_key subfeature/)
+#    $o->supports(qw/bad_key subfeature/)
 #} "but can't traverse into one";
 
+lives_ok {
+    is $o->other_method, 'FNAR', 'Delegation onto user object works';
+} 'Delegation lives';
+
+done_testing;
+
 
diff --git a/t/author/notabs.t b/t/author/notabs.t
new file mode 100644 (file)
index 0000000..70b743a
--- /dev/null
@@ -0,0 +1,5 @@
+use strict;
+use warnings;
+use Test::NoTabs;
+
+all_perl_files_ok;
similarity index 100%
rename from t/pod.t
rename to t/author/pod.t
similarity index 100%
rename from t/pod_coverage.t
rename to t/author/pod_coverage.t
index bc70351..dfc47c0 100644 (file)
@@ -25,69 +25,7 @@ our $admins = {
     }
 };
 
-sub moose : Local {
-       my ( $self, $c ) = @_;
-
-       ok(!$c->user, "no user");
-
-    while ( my ($user, $info) = each %$members ) {
-        
-        ok( 
-            $c->authenticate( 
-                { username => $user, password => $info->{password} }, 
-                'members' 
-            ), 
-            "user $user authentication" 
-        );
-
-        # check existing realms
-        ok( $c->user_in_realm('members'), "user in members realm");
-        ok(!$c->user_in_realm('admins'),  "user not in admins realm");
-
-        # check an invalid realm
-        ok(!$c->user_in_realm('foobar'), "user not in foobar realm");
-
-        # check if we've got the right user
-        is( $c->user, $info, "user object is in proper place");
-
-        $c->logout;
-
-           # sanity check
-        ok(!$c->user, "no more user after logout");
-
-    }
-
-    while ( my ($user, $info) = each %$admins ) {
-        
-        ok( 
-            $c->authenticate( 
-                { username => $user, password => $info->{password} }, 
-                'admins' 
-            ), 
-            "user $user authentication" 
-        );
-
-        # check existing realms
-        ok(!$c->user_in_realm('members'), "user not in members realm");
-        ok( $c->user_in_realm('admins'),  "user in admins realm");
-
-        # check an invalid realm
-        ok(!$c->user_in_realm('foobar'), "user not in foobar realm");
-
-        # check if we've got the right user
-        is( $c->user, $info, "user object is in proper place");
-
-        $c->logout;
-
-           # sanity check
-        ok(!$c->user, "no more user after logout");
-
-    }
-
-       $c->res->body( "ok" );
-}
-
-__PACKAGE__->config->{'Plugin::Authentication'} = {  
+__PACKAGE__->config('Plugin::Authentication' => {
     default_realm => 'members',
     realms => {
         members => {
@@ -98,7 +36,7 @@ __PACKAGE__->config->{'Plugin::Authentication'} = {
             },
             store => {
                 class => 'Minimal',
-                users => $members             
+                users => $members
             }
         },
         admins => {
@@ -109,10 +47,13 @@ __PACKAGE__->config->{'Plugin::Authentication'} = {
             },
             store => {
                 class => 'Minimal',
-                users => $admins               
+                users => $admins
             }
         }
     }
-};
+});
 
 __PACKAGE__->setup;
+
+1;
+
diff --git a/t/lib/AuthRealmTestApp/Controller/Root.pm b/t/lib/AuthRealmTestApp/Controller/Root.pm
new file mode 100644 (file)
index 0000000..290d6cc
--- /dev/null
@@ -0,0 +1,74 @@
+package AuthRealmTestApp::Controller::Root;
+use warnings;
+use strict;
+use base qw/Catalyst::Controller/;
+
+__PACKAGE__->config(namespace => '');
+
+use Test::More;
+use Test::Exception;
+
+sub moose : Local {
+    my ( $self, $c ) = @_;
+
+    ok(!$c->user, "no user");
+
+    while ( my ($user, $info) = each %$AuthRealmTestApp::members ) {
+
+        ok(
+            $c->authenticate(
+                { username => $user, password => $info->{password} },
+                'members'
+            ),
+            "user $user authentication"
+        );
+
+        # check existing realms
+        ok( $c->user_in_realm('members'), "user in members realm");
+        ok(!$c->user_in_realm('admins'),  "user not in admins realm");
+
+        # check an invalid realm
+        ok(!$c->user_in_realm('foobar'), "user not in foobar realm");
+
+        # check if we've got the right user
+        is( $c->user, $info, "user object is in proper place");
+
+        $c->logout;
+
+        # sanity check
+        ok(!$c->user, "no more user after logout");
+
+    }
+
+    while ( my ($user, $info) = each %$AuthRealmTestApp::admins ) {
+
+        ok(
+            $c->authenticate(
+                { username => $user, password => $info->{password} },
+                'admins'
+            ),
+            "user $user authentication"
+        );
+
+        # check existing realms
+        ok(!$c->user_in_realm('members'), "user not in members realm");
+        ok( $c->user_in_realm('admins'),  "user in admins realm");
+
+        # check an invalid realm
+        ok(!$c->user_in_realm('foobar'), "user not in foobar realm");
+
+        # check if we've got the right user
+        is( $c->user, $info, "user object is in proper place");
+
+        $c->logout;
+
+        # sanity check
+        ok(!$c->user, "no more user after logout");
+
+    }
+
+    $c->res->body( "ok" );
+}
+
+1;
+
index 8ff5389..6c40ccd 100644 (file)
@@ -1,6 +1,7 @@
 package AuthRealmTestAppCompat;
 use warnings;
 use strict;
+use base qw/Catalyst/;
 
 ### using A::Store::minimal with new style realms
 ### makes the app blow up, since c::p::a::s::minimal
@@ -13,35 +14,13 @@ use Catalyst qw/
     Authentication::Store::Minimal
 /;
 
-use Test::More;
-use Test::Exception;
-
 our $members = {
     bob => {
         password => "s00p3r"
     },
 };
 
-sub moose : Local {
-       my ( $self, $c ) = @_;
-
-    while ( my ($user, $info) = each %$members ) {
-        
-        my $ok = eval {
-            $c->authenticate( 
-                { username => $user, password => $info->{password} }, 
-                'members' 
-            ), 
-        };
-        
-        ok( !$@,                "Test did not die: $@" );
-        ok( $ok,                "user $user authentication" );
-    }
-
-       $c->res->body( "ok" );
-}
-
-__PACKAGE__->config->{'Plugin::Authentication'} = {  
+__PACKAGE__->config('Plugin::Authentication' => {
     default_realm => 'members',
         members => {
             credential => {
@@ -54,7 +33,9 @@ __PACKAGE__->config->{'Plugin::Authentication'} = {
                 users => $members,
             }
         },
-    
-};
+});
 
 __PACKAGE__->setup;
+
+1;
+
diff --git a/t/lib/AuthRealmTestAppCompat/Controller/Root.pm b/t/lib/AuthRealmTestAppCompat/Controller/Root.pm
new file mode 100644 (file)
index 0000000..8aa6415
--- /dev/null
@@ -0,0 +1,31 @@
+package AuthRealmTestAppCompat::Controller::Root;
+use warnings;
+use strict;
+use base qw/Catalyst::Controller/;
+
+__PACKAGE__->config( namespace => '' );
+
+use Test::More;
+use Test::Exception;
+
+sub moose : Local {
+    my ( $self, $c ) = @_;
+
+    while ( my ($user, $info) = each %$AuthRealmTestAppCompat::members ) {
+
+        my $ok = eval {
+            $c->authenticate(
+                { username => $user, password => $info->{password} },
+                'members'
+            ),
+        };
+
+        ok( !$@,                "Test did not die: $@" );
+        ok( $ok,                "user $user authentication" );
+    }
+
+    $c->res->body( "ok" );
+}
+
+1;
+
index 23f12d1..3d205eb 100644 (file)
@@ -1,6 +1,7 @@
 package AuthRealmTestAppProgressive;
 use warnings;
 use strict;
+use base qw/Catalyst/;
 
 ### using A::Store::minimal with new style realms
 ### makes the app blow up, since c::p::a::s::minimal
@@ -13,9 +14,6 @@ use Catalyst qw/
     Authentication::Store::Minimal
 /;
 
-use Test::More;
-use Test::Exception;
-
 our %members = (
     'members' => {
         bob => { password => "s00p3r" }
@@ -25,7 +23,7 @@ our %members = (
     },
 );
 
-__PACKAGE__->config->{'Plugin::Authentication'} = {
+__PACKAGE__->config('Plugin::Authentication' => {
     default_realm => 'progressive',
     progressive => {
         class  => 'Progressive',
@@ -53,25 +51,9 @@ __PACKAGE__->config->{'Plugin::Authentication'} = {
             users => $members{members},
         }
     },
-};
-
-sub progressive : Local {
-       my ( $self, $c ) = @_;
-
-    foreach my $realm ( keys %members ) {
-        while ( my ( $user, $info ) = each %{$members{$realm}} ) {
-            my $ok = eval {
-                $c->authenticate(
-                    { username => $user, password => $info->{password} },
-                ); 
-            };
-            ok( !$@, "authentication passed." );
-            ok( $ok, "user authenticated" );
-            ok( $c->user_in_realm($realm), "user in proper realm" );
-        }
-    }
-       $c->res->body( "ok" );
-}
+});
 
 __PACKAGE__->setup;
 
+1;
+
diff --git a/t/lib/AuthRealmTestAppProgressive/Controller/Root.pm b/t/lib/AuthRealmTestAppProgressive/Controller/Root.pm
new file mode 100644 (file)
index 0000000..8e48623
--- /dev/null
@@ -0,0 +1,30 @@
+package AuthRealmTestAppProgressive::Controller::Root;
+use warnings;
+use strict;
+use base qw/Catalyst::Controller/;
+
+__PACKAGE__->config(namespace => '');
+
+use Test::More;
+use Test::Exception;
+
+sub progressive : Local {
+    my ( $self, $c ) = @_;
+
+    foreach my $realm ( keys %AuthRealmTestAppProgressive::members ) {
+        while ( my ( $user, $info ) = each %{$AuthRealmTestAppProgressive::members{$realm}} ) {
+            my $ok = eval {
+                $c->authenticate(
+                    { username => $user, password => $info->{password} },
+                ); 
+            };
+            ok( !$@, "authentication passed." );
+            ok( $ok, "user authenticated" );
+            ok( $c->user_in_realm($realm), "user in proper realm" );
+        }
+    }
+    $c->res->body( "ok" );
+}
+
+1;
+
index ad6b862..ce13b00 100644 (file)
@@ -5,93 +5,32 @@ sub for_session { $_[0]->id }
 sub store { $_[0]->{store} }
 
 package AuthSessionTestApp;
+use strict;
+use warnings;
+use base qw/Catalyst/;
+
 use Catalyst qw/
-       Session
-       Session::Store::Dummy
-       Session::State::Cookie
+    Session
+    Session::Store::Dummy
+    Session::State::Cookie
 
-       Authentication
-       Authentication::Store::Minimal
-       Authentication::Credential::Password
+    Authentication
+    Authentication::Store::Minimal
+    Authentication::Credential::Password
 /;
 
-use Test::More;
-use Test::Exception;
-
-use Digest::MD5 qw/md5/;
-
-our $users;
-
-sub moose : Local {
-       my ( $self, $c ) = @_;
-
-       ok(!$c->sessionid, "no session id yet");
-       ok(!$c->user_exists, "no user exists");
-       ok(!$c->user, "no user yet");
-       ok($c->login( "foo", "s3cr3t" ), "can login with clear");
-       is( $c->user, $users->{foo}, "user object is in proper place");
-}
-
-sub elk : Local {
-       my ( $self, $c ) = @_;
-
-       ok( $c->sessionid, "session ID was restored" );
-       ok( $c->user_exists, "user exists" );
-       ok( $c->user, "a user was also restored");
-       is_deeply( $c->user, $users->{foo}, "restored user is the right one (deep test - store might change identity)" );
-       
-       # Rename the user!
-       $users->{bar} = delete $users->{foo};
-}
-
-sub yak : Local {
-    my ( $self, $c ) = @_;
-    ok( $c->sessionid, "session ID was restored after user renamed" );
-    ok( $c->user_exists, "user appears to exist" );
-    ok( !$c->user, "user was not restored");
-    ok(scalar(@{ $c->error }), 'Error recorded');
-    ok( !$c->user_exists, "user no longer appears to exist" );
-}
-
-sub goat : Local {
-    my ( $self, $c ) = @_;
-    ok($c->login( "bar", "s3cr3t" ), "can login with clear (new username)");
-    is( $c->user, $users->{bar}, "user object is in proper place");
-    $c->logout;
-}
-
-sub fluffy_bunny : Local {
-    my ( $self, $c ) = @_;
-
-    ok( $c->session_is_valid, "session ID is restored after logout");
-    ok( !$c->user, "no user was restored after logout");
-       
-    $c->delete_session("bah");
-}
-
-sub possum : Local {
-    my ( $self, $c ) = @_;
-
-       ok( !$c->session_is_valid, "no session ID was restored");
-    $c->session->{definitely_not_a_user} = "moose";
-
-}
-
-sub butterfly : Local {
-    my ( $self, $c ) = @_;
-
-    ok( $c->session_is_valid, "valid session" );
-    ok( !$c->user_exists, "but no user exists" );
-    ok( !$c->user, "no user object either" );
-}
-
-__PACKAGE__->config->{'authentication'}{users} = $users = {
-       foo => User::SessionRestoring->new(
-               id => 'foo',
-               password => "s3cr3t",
-       ),
+our $users = {
+    foo => User::SessionRestoring->new(
+        id => 'foo',
+        password => "s3cr3t",
+    ),
 };
 
+__PACKAGE__->config(authentication => {users => $users});
+
 __PACKAGE__->setup;
 
 $users->{foo}{store} = __PACKAGE__->default_auth_store;
+
+1;
+
diff --git a/t/lib/AuthSessionTestApp/Controller/Root.pm b/t/lib/AuthSessionTestApp/Controller/Root.pm
new file mode 100644 (file)
index 0000000..e9494d4
--- /dev/null
@@ -0,0 +1,77 @@
+package AuthSessionTestApp::Controller::Root;
+use strict;
+use warnings;
+use base qw/Catalyst::Controller/;
+
+__PACKAGE__->config(namespace => '');
+
+use Test::More;
+use Test::Exception;
+
+use Digest::MD5 qw/md5/;
+
+sub moose : Local {
+    my ( $self, $c ) = @_;
+
+    ok(!$c->sessionid, "no session id yet");
+    ok(!$c->user_exists, "no user exists");
+    ok(!$c->user, "no user yet");
+    ok($c->login( "foo", "s3cr3t" ), "can login with clear");
+    is( $c->user, $AuthSessionTestApp::users->{foo}, "user object is in proper place");
+}
+
+sub elk : Local {
+    my ( $self, $c ) = @_;
+
+    ok( $c->sessionid, "session ID was restored" );
+    ok( $c->user_exists, "user exists" );
+    ok( $c->user, "a user was also restored");
+    is_deeply( $c->user, $AuthSessionTestApp::users->{foo}, "restored user is the right one (deep test - store might change identity)" );
+
+    # Rename the user!
+    $AuthSessionTestApp::users->{bar} = delete $AuthSessionTestApp::users->{foo};
+}
+
+sub yak : Local {
+    my ( $self, $c ) = @_;
+    ok( $c->sessionid, "session ID was restored after user renamed" );
+    ok( $c->user_exists, "user appears to exist" );
+    ok( !$c->user, "user was not restored");
+    ok(scalar(@{ $c->error }), 'Error recorded');
+    ok( !$c->user_exists, "user no longer appears to exist" );
+}
+
+sub goat : Local {
+    my ( $self, $c ) = @_;
+    ok($c->login( "bar", "s3cr3t" ), "can login with clear (new username)");
+    is( $c->user, $AuthSessionTestApp::users->{bar}, "user object is in proper place");
+    $c->logout;
+}
+
+sub fluffy_bunny : Local {
+    my ( $self, $c ) = @_;
+
+    ok( $c->session_is_valid, "session ID is restored after logout");
+    ok( !$c->user, "no user was restored after logout");
+
+    $c->delete_session("bah");
+}
+
+sub possum : Local {
+    my ( $self, $c ) = @_;
+
+    ok( !$c->session_is_valid, "no session ID was restored");
+    $c->session->{definitely_not_a_user} = "moose";
+
+}
+
+sub butterfly : Local {
+    my ( $self, $c ) = @_;
+
+    ok( $c->session_is_valid, "valid session" );
+    ok( !$c->user_exists, "but no user exists" );
+    ok( !$c->user, "no user object either" );
+}
+
+1;
+
index 529e32f..ce0144d 100644 (file)
@@ -1,81 +1,41 @@
 package AuthTestApp;
+use strict;
+use warnings;
+use base qw/Catalyst/;
 use Catalyst qw/
-       Authentication
-       Authentication::Store::Minimal
-       Authentication::Credential::Password
+    Authentication
+    Authentication::Store::Minimal
+    Authentication::Credential::Password
 /;
 
-use Test::More;
-use Test::Exception;
-
 use Digest::MD5 qw/md5/;
 use Digest::SHA1 qw/sha1_base64/;
 
-our $users;
-
-sub number_of_elements { return scalar @_ }
-
-sub moose : Local {
-       my ( $self, $c ) = @_;
-
-       is(number_of_elements($c->user), 1, "Array undef");
-       is($c->user, undef, "no user, returns undef");
-       ok(!$c->user, "no user");
-       ok($c->login( "foo", "s3cr3t" ), "can login with clear");
-       is( $c->user, $users->{foo}, "user object is in proper place");
-
-       ok( !$c->user->roles, "no roles for foo" );
-       my @new = qw/foo bar gorch/;
-       $c->user->roles( @new );
-       is_deeply( [ $c->user->roles ], \@new, "roles set as array");
-
-       $c->logout;
-       ok(!$c->user, "no more user, after logout");
-
-       ok($c->login( "bar", "s3cr3t" ), "can login with crypted");
-       is( $c->user, $users->{bar}, "user object is in proper place");
-       $c->logout;
-
-       ok($c->login("gorch", "s3cr3t"), "can login with hashed");
-       is( $c->user, $users->{gorch}, "user object is in proper place");
-       $c->logout;
-
-       ok($c->login("shabaz", "s3cr3t"), "can login with base64 hashed");
-       is( $c->user, $users->{shabaz}, "user object is in proper place");
-       $c->logout;
-
-       ok($c->login("sadeek", "s3cr3t"), "can login with padded base64 hashed");
-       is( $c->user, $users->{sadeek}, "user object is in proper place");
-       $c->logout;
-
-       ok(!$c->login( "bar", "bad pass" ), "can't login with bad password");
-       ok(!$c->user, "no user");
+our $users = {
+    foo => {
+        password => "s3cr3t",
+    },
+    bar => {
+        crypted_password => crypt("s3cr3t", "x8"),
+    },
+    gorch => {
+        hashed_password => md5("s3cr3t"),
+        hash_algorithm => "MD5",
+    },
+    shabaz => {
+        hashed_password => sha1_base64("s3cr3t"),
+        hash_algorithm => "SHA-1"
+    },
+    sadeek => {
+        hashed_password => sha1_base64("s3cr3t").'=',
+        hash_algorithm => "SHA-1"
+    },
+    baz => {},
+};
 
-       throws_ok { $c->login( "baz", "foo" ) } qr/support.*mechanism/, "can't login without any supported mech";
+__PACKAGE__->config('Plugin::Authentication' =>{users => $users});
 
-       $c->res->body( "ok" );
-}
+__PACKAGE__->setup;
 
-__PACKAGE__->config->{'Plugin::Authentication'}{users} = $users = {
-       foo => {
-               password => "s3cr3t",
-       },
-       bar => {
-               crypted_password => crypt("s3cr3t", "x8"),
-       },
-       gorch => {
-               hashed_password => md5("s3cr3t"),
-               hash_algorithm => "MD5",
-       },
-       shabaz => {
-               hashed_password => sha1_base64("s3cr3t"),
-               hash_algorithm => "SHA-1"
-       },
-       sadeek => {
-               hashed_password => sha1_base64("s3cr3t").'=',
-               hash_algorithm => "SHA-1"
-       },
-       baz => {},
-};
+1;
 
-__PACKAGE__->setup;
diff --git a/t/lib/AuthTestApp/Controller/Root.pm b/t/lib/AuthTestApp/Controller/Root.pm
new file mode 100644 (file)
index 0000000..b200c5e
--- /dev/null
@@ -0,0 +1,57 @@
+package AuthTestApp::Controller::Root;
+use strict;
+use warnings;
+use base qw/ Catalyst::Controller /;
+
+__PACKAGE__->config( namespace => '' );
+
+use Test::More;
+use Test::Exception;
+
+use Digest::MD5 qw/md5/;
+use Digest::SHA1 qw/sha1_base64/;
+
+sub number_of_elements { return scalar @_ }
+
+sub moose : Local {
+    my ( $self, $c ) = @_;
+
+    is(number_of_elements($c->user), 1, "Array undef");
+    is($c->user, undef, "no user, returns undef");
+    ok(!$c->user, "no user");
+    ok($c->login( "foo", "s3cr3t" ), "can login with clear");
+    is( $c->user, $AuthTestApp::users->{foo}, "user object is in proper place");
+
+    ok( !$c->user->roles, "no roles for foo" );
+    my @new = qw/foo bar gorch/;
+    $c->user->roles( @new );
+    is_deeply( [ $c->user->roles ], \@new, "roles set as array");
+
+    $c->logout;
+    ok(!$c->user, "no more user, after logout");
+
+    ok($c->login( "bar", "s3cr3t" ), "can login with crypted");
+    is( $c->user, $AuthTestApp::users->{bar}, "user object is in proper place");
+    $c->logout;
+
+    ok($c->login("gorch", "s3cr3t"), "can login with hashed");
+    is( $c->user, $AuthTestApp::users->{gorch}, "user object is in proper place");
+    $c->logout;
+
+    ok($c->login("shabaz", "s3cr3t"), "can login with base64 hashed");
+    is( $c->user, $AuthTestApp::users->{shabaz}, "user object is in proper place");
+    $c->logout;
+
+    ok($c->login("sadeek", "s3cr3t"), "can login with padded base64 hashed");
+    is( $c->user, $AuthTestApp::users->{sadeek}, "user object is in proper place");
+    $c->logout;
+
+    ok(!$c->login( "bar", "bad pass" ), "can't login with bad password");
+    ok(!$c->user, "no user");
+
+    throws_ok { $c->login( "baz", "foo" ) } qr/support.*mechanism/, "can't login without any supported mech";
+
+    $c->res->body( "ok" );
+}
+
+
index ff66626..669cf10 100644 (file)
@@ -1,5 +1,6 @@
 package RemoteTestApp1;
-
+use strict;
+use warnings;
 use Catalyst qw/
    Authentication
 /;
@@ -25,21 +26,7 @@ __PACKAGE__->config(
     },
 );
 
-sub default : Local {
-    my ( $self, $c ) = @_;
-    if ($c->authenticate()) {
-        $c->res->body('User:' . $c->user->{id});
-    }
-    else {
-        $c->res->body('FAIL');
-        $c->res->status(403);
-    }
-}
-
-sub public : Local {
-    my ( $self, $c ) = @_;
-    $c->res->body('OK');
-}
-
 __PACKAGE__->setup;
 
+1;
+
diff --git a/t/lib/RemoteTestApp1/Controller/Root.pm b/t/lib/RemoteTestApp1/Controller/Root.pm
new file mode 100644 (file)
index 0000000..a3c1310
--- /dev/null
@@ -0,0 +1,25 @@
+package RemoteTestApp1::Controller::Root;
+use strict;
+use warnings;
+use base qw/Catalyst::Controller/;
+
+__PACKAGE__->config(namespace => '');
+
+sub default : Local {
+    my ( $self, $c ) = @_;
+    if ($c->authenticate()) {
+        $c->res->body('User:' . $c->user->{username});
+    }
+    else {
+        $c->res->body('FAIL');
+        $c->res->status(403);
+    }
+}
+
+sub public : Local {
+    my ( $self, $c ) = @_;
+    $c->res->body('OK');
+}
+
+1;
+
index 87bb8fb..159020f 100644 (file)
@@ -1,4 +1,6 @@
 package RemoteTestApp2;
+use strict;
+use warnings;
 
 use Catalyst qw/
    Authentication
@@ -17,6 +19,7 @@ __PACKAGE__->config(
                     deny_regexp=> 'denied',
                     cutname_regexp=> 'CN=(.*)/OU=Test',
                     source => 'SSL_CLIENT_S_DN',
+                    username_field => 'my_user_name',
                 },
                 store => {
                     class => 'Null',
@@ -26,21 +29,7 @@ __PACKAGE__->config(
     },
 );
 
-sub default : Local {
-    my ( $self, $c ) = @_;
-    if ($c->authenticate()) {
-        $c->res->body('User:' . $c->user->{id});
-    }
-    else {
-        $c->res->body('FAIL');
-        $c->res->status(403);
-    }
-}
-
-sub public : Local {
-    my ( $self, $c ) = @_;
-    $c->res->body('OK');
-}
-
 __PACKAGE__->setup;
 
+1;
+
diff --git a/t/lib/RemoteTestApp2/Controller/Root.pm b/t/lib/RemoteTestApp2/Controller/Root.pm
new file mode 100644 (file)
index 0000000..dfbcd46
--- /dev/null
@@ -0,0 +1,28 @@
+package RemoteTestApp2::Controller::Root;
+use strict;
+use warnings;
+use base 'Catalyst::Controller';
+
+__PACKAGE__->config(namespace => '');
+
+sub default : Local {
+    my ( $self, $c ) = @_;
+    if ($c->authenticate()) {
+        $c->res->body(
+              'my_user_name:'
+              . $c->user->{my_user_name}
+        );
+    }
+    else {
+        $c->res->body('FAIL');
+        $c->res->status(403);
+    }
+}
+
+sub public : Local {
+    my ( $self, $c ) = @_;
+    $c->res->body('OK');
+}
+
+1;
+
index 70ca676..af9042c 100644 (file)
@@ -1,11 +1,11 @@
 use strict;
 use warnings;
 
-use Test::More; 
+use Test::More;
 
 BEGIN {
     plan skip_all => "Digest::SHA1 is required for this test" unless eval { require Digest::SHA1 };
-       plan "no_plan";
+    plan "no_plan";
 }
 
 use lib 't/lib';
index bf5fe6b..f7131e5 100644 (file)
@@ -1,9 +1,12 @@
 use strict;
 use warnings;
 
-use Test::More tests => 7;
+use Test::More;
 
 use lib 't/lib';
 use Catalyst::Test qw/AuthRealmTestAppProgressive/;
 
 ok(get("/progressive"), "get ok");
+
+done_testing;
+
index 2d43550..7169b46 100644 (file)
@@ -1,6 +1,6 @@
 use strict;
 use warnings;
-use Test::More tests => 10;
+use Test::More;
 
 use lib 't/lib';
 use Catalyst::Test qw/RemoteTestApp1/;
@@ -28,3 +28,6 @@ is( request('/')->content, 'User:namexyz', 'testing "cutname" option 2' );
 
 $RemoteTestEngine::REMOTE_USER = 'CN=/OU=Test/C=Company';
 is( request('/')->content, 'User:CN=/OU=Test/C=Company', 'testing "cutname" option - empty $1 match' );
+
+done_testing;
+
index cc42a54..6b01320 100644 (file)
@@ -1,6 +1,6 @@
 use strict;
 use warnings;
-use Test::More tests => 3;
+use Test::More;
 
 use lib 't/lib';
 use Catalyst::Test qw/RemoteTestApp2/;
@@ -16,4 +16,8 @@ ok( request('/')->is_success, 'testing "source" option' );
 
 $RemoteTestEngine::SSL_CLIENT_S_DN = 'CN=namexyz/OU=Test/C=Company';
 ok( request('/')->is_success, 'testing "source" + "cutname" 1' );
-is( request('/')->content, 'User:namexyz', 'testing "source" + "cutname" 2' );
+is( request('/')->content, "my_user_name:namexyz",
+   'testing "source" + "cutname" 2' );
+
+done_testing;
+
index 65793eb..756605e 100644 (file)
@@ -4,11 +4,10 @@ use warnings;
 use Test::More;
 
 BEGIN {
-       eval { require Test::WWW::Mechanize::Catalyst; require Catalyst::Plugin::Session; require Catalyst::Plugin::Session::State::Cookie };
-       plan skip_all => "This test needs Test::WWW::Mechanize::Catalyst, Catalyst::Plugin::Session and Catalyst::Plugin::Session::State::Cookie installed" if $@;
+    eval { require Test::WWW::Mechanize::Catalyst; require Catalyst::Plugin::Session; require Catalyst::Plugin::Session::State::Cookie };
+    plan skip_all => "This test needs Test::WWW::Mechanize::Catalyst, Catalyst::Plugin::Session and Catalyst::Plugin::Session::State::Cookie installed" if $@;
     plan skip_all => "This test needs Test::WWW::Mechanize::Catalyst >= 0.50, you have only $Test::WWW::Mechanize::Catalyst::VERSION"
         unless $Test::WWW::Mechanize::Catalyst::VERSION >= 0.50;
-    plan tests => 29;
 }
 
 use lib 't/lib';
@@ -22,8 +21,9 @@ $m->get_ok("http://localhost/elk", "get ok");
 $m->get("http://localhost/yak");
 ok(!$m->success, 'Not ok, user unable to be resotred == nasal demons');
 
-$m->get_ok("http://localhost/goat", "get ok");
-$m->get_ok("http://localhost/fluffy_bunny", "get ok");
-$m->get_ok("http://localhost/possum", "get ok");
-$m->get_ok("http://localhost/butterfly", "get ok");
+foreach my $type (qw/ goat fluffy_bunny possum butterfly /) {
+    $m->get_ok("http://localhost/$type", "get $type ok");
+}
+
+done_testing;