X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FCatalyst%2FPlugin%2FAuthentication.pm;h=c7549c9a8f715f3a72046f58f02ec4b54386eb38;hb=2bcde60544db03f7b64bf0ab54f1a4a78ab17c4f;hp=5823c7f29dd922c2f0dd324b6e023fc13bc4ca2e;hpb=fd359a810b025744f76318e7de44688ea680b4a6;p=catagits%2FCatalyst-Plugin-Authentication.git diff --git a/lib/Catalyst/Plugin/Authentication.pm b/lib/Catalyst/Plugin/Authentication.pm index 5823c7f..c7549c9 100644 --- a/lib/Catalyst/Plugin/Authentication.pm +++ b/lib/Catalyst/Plugin/Authentication.pm @@ -5,27 +5,67 @@ package Catalyst::Plugin::Authentication; use base qw/Class::Accessor::Fast Class::Data::Inheritable/; BEGIN { - __PACKAGE__->mk_accessors(qw/user/); - __PACKAGE__->mk_classdata(qw/default_auth_store/); + __PACKAGE__->mk_accessors(qw/_user/); + __PACKAGE__->mk_classdata($_) for qw/_auth_stores _auth_store_names/; } use strict; use warnings; -our $VERSION = "0.01"; +use Tie::RefHash; +use Class::Inspector; + +#BEGIN { +# require constant; +# constant->import(have_want => eval { require Want }); +#} + +our $VERSION = "0.03"; 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->supports("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 1 if have_want() && Want::want("BOOL"); + return $c->auth_restore_user($user); + } + + return $user; +} + +sub user_exists { + my $c = shift; + return defined($c->_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 { @@ -36,8 +76,10 @@ sub logout { if ( $c->isa("Catalyst::Plugin::Session") and $c->config->{authentication}{use_session} ) { - delete @{ $c->session }{qw/__user __user_class/}; + delete @{ $c->session }{qw/__user __user_store/}; } + + $c->NEXT::logout(@_); } sub get_user { @@ -56,32 +98,97 @@ sub get_user { sub prepare { my $c = shift->NEXT::prepare(@_); - if ( $c->isa("Catalyst::Plugin::Session") - and $c->default_auth_store + if ( $c->isa("Catalyst::Plugin::Session") and !$c->user ) { - if ( $c->sessionid and my $user = $c->session->{__user} ) { - $c->user( $c->session->{__user_class}->from_session( $c, $user ) ); - $c->request->user( $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 ) = @_; + + return + unless $c->isa("Catalyst::Plugin::Session") + and $c->config->{authentication}{use_session} + and $c->sessionid; + + $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; + + $self->_auth_store_names || do { + tie my %hash, 'Tie::RefHash'; + $self->_auth_store_names( \%hash ); + } +} + +sub default_auth_store { + my $self = shift; + + if ( my $new = shift ) { + $self->register_auth_stores( default => $new ); + } + + $self->get_auth_store("default"); +} + __PACKAGE__; __END__ @@ -90,42 +197,143 @@ __END__ =head1 NAME -Catalyst::Plugin::Authentication - +Catalyst::Plugin::Authentication - Infrastructure plugin for the Catalyst +authentication framework. =head1 SYNOPSIS - use Catalyst qw/ - Authentication - Authentication::Store::Foo - Authentication::Credential::Password - /; + 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->logout; =head1 DESCRIPTION -The authentication plugin is used by the various authentication and -authorization plugins in catalyst. +The authentication plugin provides generic user support. It is the basis +for both authentication (checking the user is who they claim to be), and +authorization (allowing the user to do what the system authorises them to do). -It defines the notion of a logged in user, and provides integration with the +Using authentication is split into two parts. A Store is used to actually +store the user information, and can store any amount of data related to +the user. Multiple stores can be accessed from within one application. +Credentials are used to verify users, using the store, given data from +the frontend. + +To implement authentication in a catalyst application you need to add this +module, plus at least one store and one credential module. + +Authentication data can also be stored in a session, if the application +is using the L module. =head1 METHODS =over 4 +=item user + +Returns the currently logged in user or undef if there is none. + +=item user_exists + +Whether or not a user is logged in right now. + +The reason this method exists is that C<<$c->user>> may needlessly load the +user from the auth store. + +If you're just going to say + + if ( $c->user_user ) { + # foo + } else { + $c->forward("login"); + } + +it should be more efficient than C<<$c->user>> when a user is marked in the session +but C<< $c->user >> hasn't been called yet. + =item logout Delete the currently logged in user from C and the session. -=item user +=item get_user $uid -Returns the currently logged user or undef if there is none. +Fetch a particular users details, defined by the given ID, via the default store. -=item get_user $uid +=back + +=head1 CONFIGURATION -Delegate C to the default store. +=over 4 + +=item use_session + +Whether or not to store the user's logged in state in the session, if the +application is also using the L plugin. This +value is set to true per default. + +=item store + +If multiple stores are being used, set the module you want as default here. + +=item stores + +If multiple stores are being used, you need to provide a name for each store +here, as a hash, the keys are the names you wish to use, and the values are +the the names of the plugins. + + # example + __PACKAGE__->config( authentication => { + store => 'Catalyst::Plugin::Authentication::Store::HtPasswd', + stores => { + 'dbic' => 'Catalyst::Plugin::Authentication::Store::DBIC' + } + }); + +=back + +=head1 METHODS FOR STORE MANAGEMENT + +=over 4 =item default_auth_store -Returns C<< $c->config->{authentication}{store} >>. +Return the store whose name is 'default'. + +This is set to C<< $c->config->{authentication}{store} >> if that value exists, +or by using a Store plugin: + + use Catalyst qw/Authentication Authentication::Store::Minimal/; + +Sets the default store to +L. + + +=item get_auth_store $name + +Return the store whose name is $name. + +=item get_auth_store_name $store + +Return the name of the store $store. + +=item auth_stores + +A hash keyed by name, with the stores registered in the app. + +=item auth_store_names + +A ref-hash keyed by store, which contains the names of the stores. + +=item register_auth_stores %stores_by_name + +Register stores into the application. =back @@ -142,6 +350,15 @@ authentication. This involves setting C and the internal data in C if L is loaded. +=item auth_restore_user $user + +Used to restore a user from the session, by C 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. @@ -154,17 +371,26 @@ Sets the default configuration parameters. =back -=head1 CONFIGURATION +=head1 SEE ALSO -=over 4 +L, +L, +L, +L. -=item use_session +=head1 AUTHORS -Whether or not to store the user's logged in state in the session, if the -application is also using the L plugin. +Yuval Kogman, C -=back +Jess Robinson -=cut +David Kamholz +=head1 COPYRIGHT & LICNESE + + Copyright (c) 2005 the aforementioned authors. All rights + reserved. This program is free software; you can redistribute + it and/or modify it under the same terms as Perl itself. + +=cut