[Catalyst-commits] r6541 - in trunk/Catalyst-Plugin-Authentication: . lib/Catalyst/Plugin lib/Catalyst/Plugin/Authentication lib/Catalyst/Plugin/Authentication/Credential lib/Catalyst/Plugin/Authentication/Store lib/Catalyst/Plugin/Authentication/Store/Minimal lib/Catalyst/Plugin/Authentication/User

matthewt at dev.catalyst.perl.org matthewt at dev.catalyst.perl.org
Tue Jul 17 17:57:33 GMT 2007


Author: matthewt
Date: 2007-07-17 17:57:33 +0100 (Tue, 17 Jul 2007)
New Revision: 6541

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/Store/Minimal.pm
   trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/Store/Minimal/Backend.pm
   trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/User.pm
   trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/User/Hash.pm
Log:
 r33939 at cain (orig r5489):  jayk | 2006-11-10 22:29:07 +0000
 Updates to authentication system.  Initial import of modifications.
 POD documentation NOT complete yet... so this is a RTFS import
 



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

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:40:30 UTC (rev 6540)
+++ trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/Credential/Password.pm	2007-07-17 16:57:33 UTC (rev 6541)
@@ -9,36 +9,105 @@
 use Catalyst::Exception ();
 use Digest              ();
 
-sub login {
-    my ( $c, $user, $password, @rest ) = @_;
+sub new {
+    my ($class, $config, $app) = @_;
+    
+    my $self = { %{$config} };
+    $self->{'password_field'} ||= 'password';
+    $self->{'password_type'}  ||= 'clear';
+    $self->{'password_hash_type'} ||= 'SHA-1';
+    
+    if (!grep /$$self{'password_type'}/, ('clear', 'hashed', 'salted_hash', 'crypted', 'self_check')) {
+        Catalyst::Exception->throw(__PACKAGE__ . " used with unsupported password type: " . $self->{'password_type'});
+    }
 
-    for ( $c->request ) {
-        unless (
-            defined($user)
-                or
-            $user = $_->param("login")
-                 || $_->param("user")
-                 || $_->param("username")
-        ) {
-            $c->log->debug(
-                "Can't login a user without a user object or user ID param")
-                  if $c->debug;
-            return;
+    bless $self, $class;
+}
+
+sub authenticate {
+    my ( $self, $c, $authstore, $authinfo ) = @_;
+
+    my $user_obj = $authstore->find_user($authinfo, $c);
+    if ($user_obj) {
+        if ($self->check_password($user_obj, $authinfo)) {
+            return $user_obj;
         }
+    } else {
+        $c->log->debug("Unable to locate user matching user info provided");
+        return;
+    }
+}
 
-        unless (
-            defined($password)
-                or
-            $password = $_->param("password")
-                     || $_->param("passwd")
-                     || $_->param("pass")
-        ) {
-            $c->log->debug("Can't login a user without a password")
-              if $c->debug;
-            return;
+sub check_password {
+    my ( $self, $user, $authinfo ) = @_;
+    
+    if ($self->{'password_type'} eq 'self_check') {
+        return $user->check_password($authinfo->{$self->{'password_field'}});
+    } else {
+        my $password = $authinfo->{$self->{'password_field'}};
+        my $storedpassword = $user->get($self->{'password_field'});
+        
+        if ($self->{password_type} eq 'clear') {
+            return $password eq $storedpassword;
+        }  elsif ($self->{'password_type'} eq 'crypted') {            
+            return $storedpassword eq crypt( $password, $storedpassword );
+        } elsif ($self->{'password_type'} eq 'salted_hash') {
+            require Crypt::SaltedHash;
+            my $salt_len = $self->{'password_salt_len'} ? $self->{'password_salt_len'} : 0;
+            return Crypt::SaltedHash->validate( $storedpassword, $password,
+                $salt_len );
+        } elsif ($self->{'password_type'} eq 'hashed') {
+
+             my $d = Digest->new( $self->{'password_hash_type'} );
+             $d->add( $self->{'password_pre_salt'} || '' );
+             $d->add($password);
+             $d->add( $self->{'password_post_salt'} || '' );
+
+             my $computed    = $d->clone()->digest;
+             my $b64computed = $d->clone()->b64digest;
+             return ( ( $computed eq $storedpassword )
+                   || ( unpack( "H*", $computed ) eq $storedpassword )
+                   || ( $b64computed eq $storedpassword)
+                   || ( $b64computed.'=' eq $storedpassword) );
         }
     }
+}
 
+## 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
+## 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.
+
+sub login {
+    my ( $c, $user, $password, @rest ) = @_;
+    
+    unless (
+        defined($user)
+            or
+        $user = $c->request->param("login")
+             || $c->request->param("user")
+             || $c->request->param("username")
+    ) {
+        $c->log->debug(
+            "Can't login a user without a user object or user ID param")
+              if $c->debug;
+        return;
+    }
+
+    unless (
+        defined($password)
+            or
+        $password = $c->request->param("password")
+                 || $c->request->param("passwd")
+                 || $c->request->param("pass")
+    ) {
+        $c->log->debug("Can't login a user without a password")
+          if $c->debug;
+        return;
+    }
+    
     unless ( Scalar::Util::blessed($user)
         and $user->isa("Catalyst::Plugin::Authentication::User") )
     {
@@ -64,11 +133,13 @@
           if $c->debug;
         return;
     }
+    
 }
 
+## also deprecated.  Here for compatibility with older credentials which do not inherit from C::P::A::Password
 sub _check_password {
     my ( $c, $user, $password ) = @_;
-
+    
     if ( $user->supports(qw/password clear/) ) {
         return $user->password eq $password;
     }

Modified: trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/Store/Minimal/Backend.pm
===================================================================
--- trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/Store/Minimal/Backend.pm	2007-07-17 16:40:30 UTC (rev 6540)
+++ trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/Store/Minimal/Backend.pm	2007-07-17 16:57:33 UTC (rev 6541)
@@ -9,9 +9,9 @@
 use Scalar::Util ();
 
 sub new {
-    my ( $class, $hash ) = @_;
+    my ( $class, $config, $app) = @_;
 
-    bless { hash => $hash }, $class;
+    bless { hash => $config }, $class;
 }
 
 sub from_session {
@@ -19,25 +19,28 @@
 
 	return $id if ref $id;
 
-	$self->get_user( $id );
+	$self->find_user( { id => $id } );
 }
 
-sub get_user {
-    my ( $self, $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 
+## combinations of data.  See C::P::Authentication::Store::DBIx::Class for a better example
+sub find_user {
+    my ( $self, $userinfo, $c ) = @_;
 
-    return unless exists $self->{hash}{$id};
+    my $id = $userinfo->{'id'};
+    
+    return unless exists $self->{'hash'}{$id};
 
-    my $user = $self->{hash}{$id};
+    my $user = $self->{'hash'}{$id};
 
     if ( ref $user ) {
         if ( Scalar::Util::blessed($user) ) {
-			$user->store( $self );
 			$user->id( $id );
             return $user;
         }
         elsif ( ref $user eq "HASH" ) {
             $user->{id} ||= $id;
-            $user->{store} ||= $self;
             return bless $user, "Catalyst::Plugin::Authentication::User::Hash";
         }
         else {
@@ -64,6 +67,18 @@
     $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 }  
+# no new code should be written using get_user as it is deprecated.
+sub get_user {
+    my ( $self, $id ) = @_;
+    $self->find_user({id => $id});
+}
+
+
+
 __PACKAGE__;
 
 __END__

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:40:30 UTC (rev 6540)
+++ trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/Store/Minimal.pm	2007-07-17 16:57:33 UTC (rev 6541)
@@ -11,8 +11,8 @@
     my $c = shift;
 
     $c->default_auth_store(
-        Catalyst::Plugin::Authentication::Store::Minimal::Backend->new(
-            $c->config->{authentication}{users}
+        Catalyst::Plugin::Authentication::Store::Minimal::Backend->new( 
+            $c->config->{authentication}{users}, $c
         )
     );
 

Modified: trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/User/Hash.pm
===================================================================
--- trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/User/Hash.pm	2007-07-17 16:40:30 UTC (rev 6540)
+++ trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/User/Hash.pm	2007-07-17 16:57:33 UTC (rev 6541)
@@ -24,10 +24,11 @@
     $self->_accessor( "id", @_ );
 }
 
-sub store {
-    my $self = shift;
-    $self->_accessor( "store", @_ ) || ref $self;
-}
+## deprecated. Let the base class handle this.
+#    sub store {
+#        my $self = shift;
+#        $self->_accessor( "store", @_ ) || ref $self;
+#    }
 
 sub _accessor {
     my $self = shift;

Modified: trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/User.pm
===================================================================
--- trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/User.pm	2007-07-17 16:40:30 UTC (rev 6540)
+++ trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication/User.pm	2007-07-17 16:57:33 UTC (rev 6541)
@@ -5,10 +5,18 @@
 use strict;
 use warnings;
 
-sub id { die "virtual" }
 
-sub store { die "virtual" }
+## chances are you want to override this.
+sub id { shift->get('id'); }
 
+## returns the realm the user came from - not a good idea to override this.
+sub auth_realm {
+    my $self = shift;
+    $self->{'realm'};
+}
+
+
+
 sub supports {
     my ( $self, @spec ) = @_;
 
@@ -25,6 +33,47 @@
     return $cursor;
 }
 
+## REQUIRED.
+## get should return the value of the field specified as it's single argument from the underlying
+## user object.  This is here to provide a simple, standard way of accessing individual elements of a user
+## object - ensuring no overlap between C::P::A::User methods and actual fieldnames.
+## this is not the most effecient method, since it uses introspection.  If you have an underlying object
+## you most likely want to write this yourself.
+sub get {
+    my ($self, $field) = @_;
+    
+    my $object;
+    if ($object = $self->get_object && $object->can($field)) {
+        return $object->$field();
+    } else {
+        return undef;
+    }
+}
+
+## REQUIRED.
+## get_object should return the underlying user object.  This is for when more advanced uses of the 
+## user is required.  Modifications to the existing user, etc.  Changes in the object returned
+## by this routine may not be reflected in the C::P::A::User object - if this is required, re-authenticating
+## the user is probably the best route to take.
+## note that it is perfectly acceptable to return $self in cases where there is no underlying object.
+sub get_object {
+    return shift;
+}
+
+## this is an internal routine.  I suggest you don't rely on it's presence. 
+## sets the realm the user came from.
+sub _set_auth_realm {
+    my ($self, $realmname) = @_;
+    $self->{'realm'} = $realmname;
+}
+
+## Backwards Compatibility
+## you probably want auth_realm, in fact.  but this does work for backwards compatibility.
+sub store { 
+    my ($self) = @_;
+    return $self->auth_realm->{store};
+}
+
 __PACKAGE__;
 
 __END__

Modified: trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication.pm
===================================================================
--- trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication.pm	2007-07-17 16:40:30 UTC (rev 6540)
+++ trunk/Catalyst-Plugin-Authentication/lib/Catalyst/Plugin/Authentication.pm	2007-07-17 16:57:33 UTC (rev 6541)
@@ -6,7 +6,7 @@
 
 BEGIN {
     __PACKAGE__->mk_accessors(qw/_user/);
-    __PACKAGE__->mk_classdata($_) for qw/_auth_stores _auth_store_names/;
+    __PACKAGE__->mk_classdata($_) for qw/_auth_realms/;
 }
 
 use strict;
@@ -22,19 +22,27 @@
 #	constant->import(have_want => eval { require Want });
 #}
 
-our $VERSION = "0.09";
+our $VERSION = "0.10";
 
 sub set_authenticated {
-    my ( $c, $user ) = @_;
+    my ( $c, $user, $realmname ) = @_;
 
     $c->user($user);
     $c->request->{user} = $user;    # compatibility kludge
 
-    if ( $c->_should_save_user_in_session($user) ) {
-        $c->save_user_in_session($user);
+    if (!$realmname) {
+        $realmname = 'default';
     }
-
-    $c->NEXT::set_authenticated($user);
+    
+    if (    $c->isa("Catalyst::Plugin::Session")
+        and $c->config->{authentication}{use_session}
+        and $user->supports("session") )
+    {
+        $c->save_user_in_session($realmname, $user);
+    }
+    $user->_set_auth_realm($realmname);
+    
+    $c->NEXT::set_authenticated($user, $realmname);
 }
 
 sub _should_save_user_in_session {
@@ -72,17 +80,28 @@
     }
 }
 
+# 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->_user_in_session);
 }
 
+
 sub save_user_in_session {
-    my ( $c, $user ) = @_;
+    my ( $c, $realmname, $user ) = @_;
 
-    my $store = $user->store || ref $user;
-    $c->session->{__user_store} = $c->get_auth_store_name($store) || $store;
-    $c->session->{__user} = $user->for_session;
+    $c->session->{__user_realm} = $realmname;
+    
+    # we want to ask the backend for a user prepared for the session.
+    # but older modules split this functionality between the user and the
+    # backend.  We try the store first.  If not, we use the old method.
+    my $realm = $c->get_auth_realm($realmname);
+    if ($realm->{'store'}->can('for_session')) {
+        $c->session->{__user} = $realm->{'store'}->for_session($c, $user);
+    } else {
+        $c->session->{__user} = $user->for_session;
+    }
 }
 
 sub logout {
@@ -90,31 +109,30 @@
 
     $c->user(undef);
 
-    if ( $c->_should_load_user_from_session ) {
-        $c->_delete_user_from_session();
+    if (
+        $c->isa("Catalyst::Plugin::Session")
+        and $c->config->{authentication}{use_session}
+        and $c->session_is_valid
+    ) {
+        delete @{ $c->session }{qw/__user __user_realm/};
     }
     
     $c->NEXT::logout(@_);
 }
 
-sub _delete_user_from_session {
-    my $c = shift;
-    delete @{ $c->session }{qw/__user __user_store/};
+sub find_user {
+    my ( $c, $userinfo, $realmname ) = @_;
+    
+    $realmname ||= 'default';
+    my $realm = $c->get_auth_realm($realmname);
+    if ( $realm->{'store'} ) {
+        return $realm->{'store'}->find_user($userinfo, $c);
+    } else {
+        $c->log->debug('find_user: unable to locate a store matching the requested realm');
+    }
 }
 
-sub get_user {
-    my ( $c, $uid, @rest ) = @_;
 
-    if ( my $store = $c->default_auth_store ) {
-        return $store->get_user( $uid, @rest );
-    }
-    else {
-        Catalyst::Exception->throw(
-                "The user id $uid was passed to an authentication "
-              . "plugin, but no default store was specified" );
-    }
-}
-
 sub _user_in_session {
     my $c = shift;
 
@@ -132,84 +150,260 @@
 }
 
 sub auth_restore_user {
-    my ( $c, $frozen_user, $store_name ) = @_;
+    my ( $c, $frozen_user, $realmname ) = @_;
 
     $frozen_user ||= $c->_user_in_session;
     return unless defined($frozen_user);
 
-    $store_name  ||= $c->_store_in_session;
-    return unless $store_name; # FIXME die unless? This is an internal inconsistency
+    $realmname  ||= $c->session->{__user_realm};
+    return unless $realmname; # FIXME die unless? This is an internal inconsistency
 
-    my $store = $c->get_auth_store($store_name);
-
-    $c->_user( my $user = $store->from_session( $c, $frozen_user ) );
-
+    my $realm = $c->get_auth_realm($realmname);
+    $c->_user( my $user = $realm->{'store'}->from_session( $c, $frozen_user ) );
+    
+    # this sets the realm the user originated in.
+    $user->_set_auth_realm($realmname);
     return $user;
 
 }
 
+# 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 $cfg = $c->config->{authentication} ||= {};
+    $c->_authentication_initialize();
+    $c->NEXT::setup(@_);
+}
 
+## the actual initialization routine. whee.
+sub _authentication_initialize {
+    my $c = shift;
+
+    if ($c->_auth_realms) { return };
+    
+    my $cfg = $c->config->{'authentication'} || {};
+
     %$cfg = (
         use_session => 1,
         %$cfg,
     );
 
-    $c->register_auth_stores(
-        default => $cfg->{store},
-        %{ $cfg->{stores} || {} },
-    );
+    my $realmhash = {};
+    $c->_auth_realms($realmhash);
+    
+    ## 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});
+        }
 
-    $c->NEXT::setup(@_);
+        #  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'});
+        }
+    } else {
+        foreach my $storename (keys %{$cfg->{'stores'}}) {
+            my $realmcfg = {
+                store => $cfg->{'stores'}{$storename},
+            };
+            $c->setup_auth_realm($storename, $realmcfg);
+        }
+    }
+    
 }
 
-sub get_auth_store {
-    my ( $self, $name ) = @_;
-    $self->auth_stores->{$name} || ( Class::Inspector->loaded($name) && $name );
+
+# set up realmname.
+sub setup_auth_realm {
+    my ($app, $realmname, $config) = @_;
+    
+    $app->log->debug("Setting up $realmname");
+    if (!exists($config->{'store'}{'class'})) {
+        Carp::croak "Couldn't setup the authentication realm named '$realmname', no class defined";
+    } 
+        
+    # use the 
+    my $storeclass = $config->{'store'}{'class'};
+    
+    ## follow catalyst class naming - a + prefix means a fully qualified class, otherwise it's
+    ## taken to mean C::P::A::Store::(specifiedclass)::Backend
+    if ($storeclass !~ /^\+(.*)$/ ) {
+        $storeclass = "Catalyst::Plugin::Authentication::Store::${storeclass}::Backend";
+    } else {
+        $storeclass = $1;
+    }
+    
+
+    # a little niceness - since most systems seem to use the password credential class, 
+    # if no credential class is specified we use password.
+    $config->{credential}{class} ||= "Catalyst::Plugin::Authentication::Credential::Password";
+
+    my $credentialclass = $config->{'credential'}{'class'};
+    
+    ## follow catalyst class naming - a + prefix means a fully qualified class, otherwise it's
+    ## taken to mean C::P::A::Credential::(specifiedclass)
+    if ($credentialclass !~ /^\+(.*)$/ ) {
+        $credentialclass = "Catalyst::Plugin::Authentication::Credential::${credentialclass}";
+    } else {
+        $credentialclass = $1;
+    }
+    
+    # if we made it here - we have what we need to load the classes;
+    Catalyst::Utils::ensure_class_loaded( $credentialclass );
+    Catalyst::Utils::ensure_class_loaded( $storeclass );
+    
+    # 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';
+        *{"${storeclass}::find_user"} = sub {
+                                                my ($self, $info) = @_;
+                                                my @rest = @{$info->{rest}} if exists($info->{rest});
+                                                $self->get_user($info->{id}, @rest);
+                                            };
+    }
+    
+    $app->auth_realms->{$realmname}{'store'} = $storeclass->new($config->{'store'}, $app);
+    if ($credentialclass->can('new')) {
+        $app->auth_realms->{$realmname}{'credential'} = $credentialclass->new($config->{'credential'}, $app);
+    } else {
+        # if the credential class is not actually a class - has no 'new' operator, we wrap it, 
+        # once again - to allow our code to be simple at runtime and allow non-OO packages to function.
+        my $wrapperclass = 'Catalyst::Plugin::Authentication::Credential::Wrapper';
+        Catalyst::Utils::ensure_class_loaded( $wrapperclass );
+        $app->auth_realms->{$realmname}{'credential'} = $wrapperclass->new($config->{'credential'}, $app);
+    }
 }
 
-sub get_auth_store_name {
-    my ( $self, $store ) = @_;
-    $self->auth_store_names->{$store};
+sub auth_realms {
+    my $self = shift;
+    return($self->_auth_realms);
 }
 
-sub register_auth_stores {
-    my ( $self, %new ) = @_;
+sub get_auth_realm {
+    my ($app, $realmname) = @_;
+    return $app->auth_realms->{$realmname};
+}
 
-    foreach my $name ( keys %new ) {
-        my $store = $new{$name} or next;
-        $self->auth_stores->{$name}       = $store;
-        $self->auth_store_names->{$store} = $name;
+sub set_default_auth_realm {
+    my ($app, $realmname) = @_;
+    
+    if (exists($app->auth_realms->{$realmname})) {
+        $app->auth_realms->{'default'} = $app->auth_realms->{$realmname};
     }
+    return $app->get_auth_realm('default');
 }
 
-sub auth_stores {
-    my $self = shift;
-    $self->_auth_stores(@_) || $self->_auth_stores( {} );
+sub authenticate {
+    my ($app, $userinfo, $realmname) = @_;
+    
+    if (!$realmname) {
+        $realmname = 'default';
+    }
+        
+    my $realm = $app->get_auth_realm($realmname);
+    
+    if ($realm && exists($realm->{'credential'})) {
+        my $user = $realm->{'credential'}->authenticate($app, $realm->{store}, $userinfo);
+        if ($user) {
+            $app->set_authenticated($user, $realmname);
+            return $user;
+        }
+    } else {
+        $app->log->debug("The realm requested, '$realmname' does not exist," .
+                         " or there is no credential associated with it.")
+    }
+    return 0;
 }
 
-sub auth_store_names {
-    my $self = shift;
+## 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.  
+# 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.  
+#
 
-    $self->_auth_store_names || do {
-        tie my %hash, 'Tie::RefHash';
-        $self->_auth_store_names( \%hash );
-      }
+sub get_user {
+    my ( $c, $uid, @rest ) = @_;
+
+    return $c->find_user( {'id' => $uid, 'rest'=>\@rest }, 'default' );
 }
 
+##
+## this should only be called when using old-style authentication plugins.  IF this gets
+## called in a new-style config - it will OVERWRITE the store of your default realm.  Don't do it.
+## also - this is a partial setup - because no credential is instantiated... in other words it ONLY
+## works with old-style auth plugins and C::P::Authentication in compatibility mode.  Trying to combine
+## this with a realm-type config will probably crash your app.
 sub default_auth_store {
     my $self = shift;
 
     if ( my $new = shift ) {
-        $self->register_auth_stores( default => $new );
+        $self->auth_realms->{'default'}{'store'} = $new;
+        my $storeclass = ref($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, 
+        # and rely on it being present. (this avoids per-call checks)
+        if (!$storeclass->can('find_user')) {
+            no strict 'refs';
+            *{"${storeclass}::find_user"} = sub {
+                                                    my ($self, $info) = @_;
+                                                    my @rest = @{$info->{rest}} if exists($info->{rest});
+                                                    $self->get_user($info->{id}, @rest);
+                                                };
+        }
     }
 
-    $self->get_auth_store("default");
+    return $self->get_auth_realm('default')->{'store'};
 }
 
+## BACKWARDS COMPATIBILITY
+## this only ever returns a hash containing 'default' - as that is the only
+## supported mode of calling this.
+sub auth_store_names {
+    my $self = shift;
+
+    my %hash = (  $self->get_auth_realm('default')->{'store'} => 'default' );
+}
+
+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";        
+    } else {
+        $self->default_auth_store();
+    }
+}
+
+sub get_auth_store_name {
+    my ( $self, $store ) = @_;
+    return 'default';
+}
+
+# sub auth_stores is only used internally - here for completeness
+sub auth_stores {
+    my $self = shift;
+
+    my %hash = ( 'default' => $self->get_auth_realm('default')->{'store'});
+}
+
+
+
+
+
+
 __PACKAGE__;
 
 __END__
@@ -225,14 +419,11 @@
 
     use Catalyst qw/
         Authentication
-        Authentication::Store::Foo
-        Authentication::Credential::Password
     /;
 
     # later on ...
-    # ->login is provided by the Credential::Password module
-    $c->login('myusername', 'mypassword');
-    my $age = $c->user->age;
+    $c->authenticate({ username => 'myusername', password => 'mypassword' });
+    my $age = $c->user->get('age');
     $c->logout;
 
 =head1 DESCRIPTION




More information about the Catalyst-commits mailing list