use Class::Inspector;
use Catalyst::Authentication::Realm;
-# this optimization breaks under Template::Toolkit
-# use user_exists instead
-#BEGIN {
-# require constant;
-# constant->import(have_want => eval { require Want });
-#}
-our $VERSION = "0.10005";
+our $VERSION = "0.10007_01";
sub set_authenticated {
my ( $c, $user, $realmname ) = @_;
Catalyst::Exception->throw(
"set_authenticated called with nonexistant realm: '$realmname'.");
}
-
- if ( $c->isa("Catalyst::Plugin::Session")
- and $c->config->{'Plugin::Authentication'}{'use_session'}
- and $user->supports("session") )
- {
- $realm->save_user_in_session($c, $user);
- }
$user->auth_realm($realm->name);
+
+ $c->persist_user();
$c->NEXT::set_authenticated($user, $realmname);
}
}
# change this to allow specification of a realm - to verify the user is part of that realm
-# in addition to verifying that they exist.
+# in addition to verifying that they exist.
sub user_exists {
my $c = shift;
- return defined($c->_user) || defined($c->_user_in_session);
+ return defined($c->_user) || defined($c->_find_realm_for_persisted_user);
}
# works like user_exists - except only returns true if user
if (defined($c->_user)) {
return ($c->_user->auth_realm eq $realmname);
- } elsif (defined($c->_user_in_session)) {
- return ($c->session->{__user_realm} eq $realmname);
} else {
- return undef;
+ my $realm = $c->_find_realm_for_persisted_user;
+ if ($realm) {
+ return ($realm->name eq $realmname);
+ } else {
+ return undef;
+ }
}
}
}
}
+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
+ ## the realm can recognize it's frozen user somehow.
+ if ($c->isa("Catalyst::Plugin::Session") &&
+ $c->config->{'Plugin::Authentication'}{'use_session'} &&
+ $c->session_is_valid) {
+
+ $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 -
+## you should use persist_user instead.
+sub update_user_in_session {
+ my $c = shift;
+
+ return $c->persist_user;
+}
+
sub logout {
my $c = shift;
$c->user(undef);
- if (
- $c->isa("Catalyst::Plugin::Session")
- and $c->config->{'Plugin::Authentication'}{'use_session'}
- and $c->session_is_valid
- ) {
- delete @{ $c->session }{qw/__user __user_realm/};
+ my $realm = $c->_find_realm_for_persisted_user;
+ if ($realm) {
+ $realm->remove_persisted_user($c);
}
$c->NEXT::logout(@_);
}
-sub _user_in_session {
+sub _find_realm_for_persisted_user {
my $c = shift;
-
- return unless
- $c->isa("Catalyst::Plugin::Session")
+
+ my $realm;
+ if ($c->isa("Catalyst::Plugin::Session")
and $c->config->{'Plugin::Authentication'}{'use_session'}
- and $c->session_is_valid;
-
- return $c->session->{__user};
+ 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;
+ }
+ } 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};
+ }
+ }
+ }
+ return undef;
}
sub auth_restore_user {
my ( $c, $frozen_user, $realmname ) = @_;
- $frozen_user ||= $c->_user_in_session;
- return unless defined($frozen_user);
-
- $realmname ||= $c->session->{__user_realm};
- return unless $realmname; # FIXME die unless? This is an internal inconsistency
+ my $realm;
+ if (defined($realmname)) {
+ $realm = $c->get_auth_realm($realmname);
+ } else {
+ $realm = $c->_find_realm_for_persisted_user;
+ }
+ return unless $realm; # FIXME die unless? This is an internal inconsistency
- my $realm = $c->get_auth_realm($realmname);
- $c->_user( my $user = $realm->from_session( $c, $frozen_user ) );
+ $c->_user( my $user = $realm->restore_user( $c, $frozen_user ) );
# this sets the realm the user originated in.
- $user->auth_realm($realmname);
+ $user->auth_realm($realm->name);
return $user;
## 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 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
+ ## 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.
+
+ $app->mk_classdata( '_auth_realm_restore_order' => []);
+
my $cfg = $app->config->{'Plugin::Authentication'};
if (!defined($cfg)) {
if (exists($app->config->{'authentication'})) {
}
if (exists($cfg->{'realms'})) {
- foreach my $realm (keys %{$cfg->{'realms'}}) {
+
+ my %auth_restore_order;
+ my $authcount = 2;
+ my $defaultrealm = 'default';
+
+ foreach my $realm (sort keys %{$cfg->{'realms'}}) {
+
$app->setup_auth_realm($realm, $cfg->{'realms'}{$realm});
+
+ if (exists($cfg->{'realms'}{$realm}{'user_restore_priority'})) {
+ $auth_restore_order{$realm} = $cfg->{'realms'}{$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')) {
- $app->_set_default_auth_realm($cfg->{'default_realm'});
+ if ($app->_set_default_auth_realm($cfg->{'default_realm'})) {
+ $defaultrealm = $cfg->{'default_realm'};
+ $auth_restore_order{'default'} = $auth_restore_order{$cfg->{'default_realm'}};
+ delete($auth_restore_order{$cfg->{'default_realm'}});
+ }
+ }
+
+ ## if the default realm did not have a defined priority in it's config - we put it at the front.
+ if (!exists($cfg->{'realms'}{$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
$cfg->{'stores'}{'default'} = $cfg->{'store'};
}
+ push @{$app->_auth_realm_restore_order}, 'default';
foreach my $storename (keys %{$cfg->{'stores'}}) {
my $realmcfg = {
store => { class => $cfg->{'stores'}{$storename} },
};
+ print STDERR "Foo, ok?\n";
$app->setup_auth_realm($storename, $realmcfg);
}
- }
+ }
}
sub get_auth_realm {
my ($app, $realmname) = @_;
+
return $app->auth_realms->{$realmname};
+
}
},
store => {
class => 'Minimal',
- users = {
+ users => {
bob => {
password => "s00p3r",
editor => 'yes',
sub login : Local {
my ( $self, $c ) = @_;
- if ( my $user = $c->req->param("user")
- and my $password = $c->req->param("password") )
+ if ( my $user = $c->req->params->{user}
+ and my $password = $c->req->params->{password"} )
{
if ( $c->authenticate( { username => $user,
password => $password } ) ) {
sub edit : Local {
my ( $self, $c ) = @_;
- $c->detach("unauthorized") unless $c->check_roles("edit");
+ $c->detach("unauthorized") unless $c->check_user_roles("edit");
# do something restricted here
}
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
+currently authenticated users 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
+contains the most current data.
+
=head1 INTERNAL METHODS
These methods are for Catalyst::Plugin::Authentication B<INTERNAL USE> only.
arguments to restore the user via the session. Can be called with arguments
when restoring a user from some other method. Currently not used in this way.
-=head2 $c->save_user_in_session( $user, $realmname )
-
-Used to save the user in a session. Saves $user in session, marked as
-originating in $realmname. Both arguments are required.
-
=head2 $c->auth_realms( )
Returns a hashref containing realmname -> realm instance pairs. Realm
Retrieves the realm instance for the realmname provided.
+=head2 $c->update_user_in_session
+
+This was a short lived method to update user information - you should use persist_user instead.
+
=head1 SEE ALSO
This list might not be up to date. Below are modules known to work with the updated
At the time of writing these plugins have not yet been replaced or updated, but
should be eventually: L<Catalyst::Plugin::Authentication::OpenID>,
-L<Catalyst::Plugin::Authentication::LDAP>,
L<Catalyst::Plugin::Authentication::CDBI::Basic>,
L<Catalyst::Plugin::Authentication::Basic::Remote>.