Allow plugins loaded after C::P::Authentication to hook into 'set_authenticated'
[catagits/Catalyst-Plugin-Authentication.git] / lib / Catalyst / Plugin / Authentication.pm
index 8f78848..7887cad 100644 (file)
@@ -2,37 +2,71 @@
 
 package Catalyst::Plugin::Authentication;
 
-use base qw/Class::Accessor::Fast/;
+use base qw/Class::Accessor::Fast Class::Data::Inheritable/;
 
-BEGIN { __PACKAGE__->mk_accessors(qw/user/) }
+BEGIN {
+    __PACKAGE__->mk_accessors(qw/_user/);
+    __PACKAGE__->mk_classdata($_) for qw/_auth_stores _auth_store_names/;
+}
 
 use strict;
 use warnings;
 
-sub default_auth_store {
-       my $c = shift;
-       $c->config->{authentication}{store};
-}
+use Tie::RefHash;
+use Class::Inspector;
+
+our $VERSION = "0.01";
 
 sub set_authenticated {
     my ( $c, $user ) = @_;
 
     $c->user($user);
+    $c->request->{user} = $user;    # compatibility kludge
 
     if (    $c->isa("Catalyst::Plugin::Session")
-        and $c->config->{authentication}{use_session} )
+        and $c->config->{authentication}{use_session}
+        and $user->supports("session") )
     {
-        $c->session->{__user} = $user->for_session
-          if $user->supperts("session");
-        $c->session->{__user_class} = ref $user;
+        $c->save_user_in_session($user);
+    }
+
+       $c->NEXT::set_authenticated( $user );
+}
+
+sub user {
+    my $c = shift;
+
+    if (@_) {
+        return $c->_user(@_);
+    }
+
+    my $user = $c->_user;
+
+    if ( $user and !Scalar::Util::blessed($user) ) {
+        return $c->auth_restore_user($user);
     }
+
+    return $user;
+}
+
+sub save_user_in_session {
+    my ( $c, $user ) = @_;
+
+    my $store = $user->store || ref $user;
+    $c->session->{__user_store} = $c->get_auth_store_name($store) || $store;
+    $c->session->{__user} = $user->for_session;
 }
 
 sub logout {
     my $c = shift;
 
     $c->user(undef);
-    delete @{ $c->session }{qw/__user __user_class/};
+
+    if (    $c->isa("Catalyst::Plugin::Session")
+        and $c->config->{authentication}{use_session} )
+    {
+        delete @{ $c->session }{qw/__user __user_store/};
+    }
 }
 
 sub get_user {
@@ -52,26 +86,91 @@ sub prepare {
     my $c = shift->NEXT::prepare(@_);
 
     if (    $c->isa("Catalyst::Plugin::Session")
-        and $c->config->{authentication}{use_session}
         and !$c->user )
     {
-        if ( $c->sessionid and my $user = $c->session->{__user} ) {
-            $c->user( $c->session->{__user_class}->from_session( $c, $user ) );
+        if ( $c->sessionid and my $frozen_user = $c->session->{__user} ) {
+            $c->_user($frozen_user);
         }
     }
 
     return $c;
 }
 
+sub auth_restore_user {
+    my ( $c, $frozen_user, $store_name ) = @_;
+
+    $store_name  ||= $c->session->{__user_store};
+    $frozen_user ||= $c->session->{__user};
+
+    my $store = $c->get_auth_store($store_name);
+    $c->_user( my $user = $store->from_session( $c, $frozen_user ) );
+
+    return $user;
+
+}
+
 sub setup {
     my $c = shift;
 
-    my $cfg = $c->config->{authentication};
+    my $cfg = $c->config->{authentication} || {};
 
     %$cfg = (
         use_session => 1,
         %$cfg,
     );
+
+    $c->register_auth_stores(
+        default => $cfg->{store},
+        %{ $cfg->{stores} || {} },
+    );
+
+    $c->NEXT::setup(@_);
+}
+
+sub get_auth_store {
+    my ( $self, $name ) = @_;
+    $self->auth_stores->{$name} || ( Class::Inspector->loaded($name) && $name );
+}
+
+sub get_auth_store_name {
+    my ( $self, $store ) = @_;
+    $self->auth_store_names->{$store};
+}
+
+sub register_auth_stores {
+    my ( $self, %new ) = @_;
+
+    foreach my $name ( keys %new ) {
+        my $store = $new{$name} or next;
+        $self->auth_stores->{$name}       = $store;
+        $self->auth_store_names->{$store} = $name;
+    }
+}
+
+sub auth_stores {
+    my $self = shift;
+    $self->_auth_stores(@_) || $self->_auth_stores( {} );
+}
+
+sub auth_store_names {
+    my $self = shift;
+
+    unless ( $self->_auth_store_names ) {
+        tie my %hash, 'Tie::RefHash';
+        $self->_auth_store_names( \%hash );
+    }
+
+    $self->_auth_store_names;
+}
+
+sub default_auth_store {
+    my $self = shift;
+
+    if ( my $new = shift ) {
+        $self->register_auth_stores( default => $new );
+    }
+
+    $self->get_auth_store("default");
 }
 
 __PACKAGE__;
@@ -82,7 +181,8 @@ __END__
 
 =head1 NAME
 
-Catalyst::Plugin::Authentication - 
+Catalyst::Plugin::Authentication - Infrastructure plugin for the Catalyst
+authentication framework.
 
 =head1 SYNOPSIS
 
@@ -97,7 +197,8 @@ Catalyst::Plugin::Authentication -
 The authentication plugin is used by the various authentication and
 authorization plugins in catalyst.
 
-It defines the notion of a logged in user, and provides integration with the 
+It defines the notion of a logged in user, and provides integration with the
+L<Catalyst::Plugin::Session> plugin, 
 
 =head1 METHODS
 
@@ -134,6 +235,15 @@ authentication.
 This involves setting C<user> and the internal data in C<session> if
 L<Catalyst::Plugin::Session> is loaded.
 
+=item auth_restore_user $user
+
+Used to restore a user from the session, by C<user> only when it's actually
+needed.
+
+=item save_user_in_session $user
+
+Used to save the user in a session.
+
 =item prepare
 
 Revives a user from the session object if there is one.