--- /dev/null
+#!/usr/bin/perl
+
+package Catalyst::Plugin::Authentication;
+
+use base qw/Class::Accessor::Fast/;
+
+BEGIN { __PACKAGE__->mk_accessors(qw/user/) }
+
+use strict;
+use warnings;
+
+sub set_authenticated {
+ my ( $c, $user ) = @_;
+
+ $c->user($user);
+
+ if ( $c->isa("Catalyst::Plugin::Session")
+ and $c->config->{authentication}{use_session} )
+ {
+ $c->session->{__user} = $user->for_session if $user->supperts("session");
+ $c->session->{__user_class} = ref $user;
+ }
+}
+
+sub logout {
+ my $c = shift;
+
+ $c->user(undef);
+ delete @{ $c->session }{qw/__user __user_class/};
+}
+
+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 ) );
+ }
+ }
+
+ return $c;
+}
+
+sub setup {
+ my $c = shift;
+
+ my $cfg = $c->config->{authentication};
+
+ %$cfg = (
+ use_session => 1,
+ %$cfg,
+ );
+}
+
+__PACKAGE__;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Catalyst::Plugin::Authentication -
+
+=head1 SYNOPSIS
+
+ use Catalyst qw/
+ Authentication
+ Authentication::Store::Foo
+ Authentication::Credential::Password
+ /;
+
+=head1 DESCRIPTION
+
+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
+
+=head1 METHODS
+
+=over 4
+
+=item logout
+
+Delete the currently logged in user from C<user> and the session.
+
+=item user
+
+Returns the currently logged user or undef if there is none.
+
+=back
+
+=head1 INTERNAL METHODS
+
+=over 4
+
+=item set_authenticated $user
+
+Marks a user as authenticated. Should be called from a
+C<Catalyst::Plugin::Authentication::Credential> plugin after successful
+authentication.
+
+This involves setting C<user> and the internal data in C<session> if
+L<Catalyst::Plugin::Session> is loaded.
+
+=item prepare
+
+Revives a user from the session object if there is one.
+
+=item setup
+
+Sets the default configuration parameters.
+
+=item
+
+=back
+
+=head1 CONFIGURATION
+
+=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<Catalyst::Plugin::Authentication> plugin.
+
+=back
+
+=cut
+
+
--- /dev/null
+#!/usr/bin/perl
+
+package Catalyst::Plugin::Authentication::Store;
+
+use strict;
+use warnings;
+
+sub get_user { die "virtual" }
+
+sub user_supports { die "virtual" }
+
+__PACKAGE__;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Catalyst::Plugin::Authentication::Store -
+
+=head1 SYNOPSIS
+
+ use Catalyst::Plugin::Authentication::Store;
+
+=head1 DESCRIPTION
+
+=cut
+
+
--- /dev/null
+#!/usr/bin/perl
+
+package Catalyst::Plugin::Authentication::Store::Minimal;
+use base qw/Catalyst::Plugin::Authentication::Store/;
+
+use strict;
+use warnings;
+
+use Catalyst::Plugin::Authentication::Store::Minimal::Backend;
+
+sub setup {
+ my $c = shift;
+
+ $c->config->{authentication}{store} =
+ Catalyst::Plugin::Authentication::Store::Minimal::Backend->new(
+ $c->config->{authentication}{users} );
+
+}
+
+__PACKAGE__;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Catalyst::Plugin::Authentication::Store::Minimal - Authentication
+database in C<<$c->config>>.
+
+=head1 SYNOPSIS
+
+ use Catalyst qw/
+ Authentication
+ Authentication::Store::Minimal
+ Authentication::Credential::Password
+ /;
+
+ __PACKAGE__->config->{authentication}{users} = {
+ name => {
+ password => "s3cr3t",
+ roles => [qw/admin editor/],
+ ...
+ },
+ };
+
+ sub login : Global {
+ my ( $self, $c ) = @_;
+
+ $c->login( $c->req->param("login"), $c->req->param("password"), );
+ }
+
+=head1 DESCRIPTION
+
+This authentication store plugin lets you create a very quick and dirty user
+database in your application's config hash.
+
+It's purpose is mainly for testing, and it should probably be replaced by a
+more "serious" store for production.
+
+The hash in the config, as well as the user objects/hashes are freely mutable
+at runtime.
+
+This plugin inherits L<Catalyst::Plugin::Authentication::Store>.
+
+=head1 METHODS
+
+=over 4
+
+=item setup
+
+This method will popultate C<< $c->config->{authentication}{store} >> so that
+L<Catalyst::Plugin::Authentication::Store> can use it.
+
+=back
+
+=cut
+
+
--- /dev/null
+#!/usr/bin/perl
+
+package Catalyst::Plugin::Authentication::Store::Minimal::Backend;
+
+use strict;
+use warnings;
+
+use Catalyst::Plugin::Authentication::User::Hash;
+use Scalar::Util ();
+
+sub new {
+ my ( $class, $hash ) = @_;
+
+ bless { hash => $hash }, $class;
+}
+
+sub get_user {
+ my ( $self, $id ) = @_;
+
+ my $user = $self->{hash}{$id};
+
+ bless $user, "Catalyst::Plugin::Authentication::User::Hash"
+ unless Scalar::Util::blessed($user);
+
+ return $user;
+}
+
+sub user_supports {
+ my $self = shift;
+
+ # choose a random user
+ scalar keys %{ $self->{hash} };
+ ( undef, my $user ) = each %{ $self->{hash} };
+
+ $user->supports(@_);
+}
+
+__PACKAGE__;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Catalyst::Plugin::Authentication::Store::Minimal::Backend - Minimal
+authentication storage backend.
+
+=head1 SYNOPSIS
+
+ # you probably just want Store::Minimal under most cases,
+ # but if you insist you can instantiate your own store:
+
+ use Catalyst::Plugin::Authentication::Store::Minimal::Backend;
+
+ use Catalyst qw/
+ Authentication
+ Authentication::Credential::Password
+ /;
+
+ my %users = (
+ user => { password => "s3cr3t" },
+ );
+
+ our $users = Catalyst::Plugin::Authentication::Store::Minimal::Backend->new(\%users);
+
+ sub action : Local {
+ my ( $self, $c ) = @_;
+
+ $c->login( $users->get_user( $c->req->param("login") ),
+ $c->req->param("password") );
+ }
+
+=head1 DESCRIPTION
+
+You probably want L<Catalyst::Plugin::Authentication::Store::Minimal>, unless
+you are mixing several stores in a single app and one of them is Minimal.
+
+Otherwise, this lets you create a store manually.
+
+=head1 METHODS
+
+=over 4
+
+=item new $hash_ref
+
+Constructs a new store object, which uses the supplied hash ref as it's backing
+structure.
+
+=item get_user $id
+
+Keys the hash by $id and returns the value.
+
+If the return value is unblessed it will be blessed as
+L<Catalyst::Plugin::Authentication::User::Hash>.
+
+=item user_supports
+
+Chooses a random user from the hash and delegates to it.
+
+=back
+
+=cut
+
+
--- /dev/null
+#!/usr/bin/perl
+
+package Catalyst::Plugin::Authentication::User;
+
+use strict;
+use warnings;
+
+sub id { die "virtual" }
+
+sub store { die "virtual" }
+
+sub supports { die "virtual" }
+
+__PACKAGE__;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Catalyst::Plugin::Authentication::User - Base class for user objects.
+
+=head1 SYNOPSIS
+
+ package MyStore::User;
+ use base qw/Catalyst::Plugin::Authentication::User/;
+
+=head1 DESCRIPTION
+
+This is the base class for authenticated
+
+=head1 METHODS
+
+=over 4
+
+=item id
+
+A unique ID by which a user can be retrieved from the store.
+
+=item store
+
+Should return a class name that can be used to refetch the user using it's
+ID.
+
+=item supports
+
+An introspection method used to determine what features a user object has, to support credential and authorization plugins.
+
+=item
+
+=back
+
+=cut
+
+
--- /dev/null
+#!/usr/bin/perl
+
+package Catalyst::Plugin::Authentication::User::Hash;
+use base qw/Catalyst::Plugin::Authentication::User/;
+
+use strict;
+use warnings;
+
+sub new {
+ my $class = shift;
+
+ bless { @_ }, $class;
+}
+
+sub AUTOLOAD {
+ my $self = shift;
+ ( my $key ) = ( our $AUTOLOAD =~ m/([^:]*)$/ );
+
+ $self->{$key} = shift if @_;
+ $self->{$key};
+}
+
+my %features = (
+ password => {
+ clear => ["password"],
+ crypted => ["crypted_password"],
+ hashed => ["hashed_password hash_algorithm"],
+ },
+ session => 1,
+);
+
+sub supports {
+ my ( $self, @spec ) = @_;
+
+ my $cursor = \%features;
+
+ # traverse the feature list,
+ for (@spec) {
+ die "bad feature spec: @spec"
+ if ref($cursor) ne "HASH"
+ or !ref( $cursor = $cursor->{$_} );
+ }
+
+ die "bad feature spec: @spec" unless ref $cursor eq "ARRAY";
+
+ # check that all the keys required for a feature are in here
+ foreach my $key (@$cursor) {
+ return undef unless exists $self->{$key};
+ }
+
+ return 1;
+}
+
+sub for_session {
+ my $self = shift;
+
+ return $self; # let's hope we're serialization happy
+}
+
+sub from_session {
+ my ( $self, $c, $user ) = @_;
+
+ return $user; # if we're serialization happy this should work
+}
+
+__PACKAGE__;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Catalyst::Plugin::Authentication::User::Hash - An easy authentication user
+object based on hashes.
+
+=head1 SYNOPSIS
+
+ use Catalyst::Plugin::Authentication::User::Hash;
+
+ Catalyst::Plugin::Authentication::User::Hash->new(
+ password => "s3cr3t",
+ );
+
+=head1 DESCRIPTION
+
+This implementation of authentication user handles is supposed to go hand in
+hand with L<Catalyst::Plugin::Authentication::Store::Minimal>.
+
+=head1 METHODS
+
+=over 4
+
+=item new @pairs
+
+Create a new object with the key-value-pairs listed in the arg list.
+
+=item supports
+
+Checks for existence of keys that correspond with features.
+
+=item for_session
+
+Just returns $self, expecting it to be serializable.
+
+=item from_session
+
+Just passes returns the unserialized object, hoping it's intact.
+
+=item AUTOLOAD
+
+Accessor for the key whose name is the method.
+
+=back
+
+=head1 SEE ALSO
+
+L<Hash::AsObject>
+
+=cut
+
+