package Gantry::Plugins::Uaf;
use strict;
use warnings;
use Gantry;
use Gantry::Utils::Crypt;
use File::Spec;
use base 'Exporter';
our @EXPORT = qw(
uaf_init
uaf_user
uaf_authn
uaf_authz
uaf_inited
uaf_authenicate
do_login
do_logout
);
our $VERSION = '0.03';
my %registered_callbacks;
#-----------------------------------------------------------
# $class->get_callbacks( $namespace )
#-----------------------------------------------------------
sub get_callbacks {
my ( $class, $namespace ) = @_;
return if ( $registered_callbacks{ $namespace }++ );
warn "Your app needs a 'namespace' method which doesn't return 'Gantry'"
if ( $namespace eq 'Gantry' );
return (
{ phase => 'init', callback => \&initialize },
{ phase => 'post_init', callback => \&uaf_authenticate }
);
}
#-----------------------------------------------------------
# initialize
#-----------------------------------------------------------
sub initialize {
my $gobj = shift;
$gobj->uaf_init();
}
sub uaf_init {
my $gobj = shift;
my @parts;
my $filename;
my $uaf_authn = $gobj->fish_config('uaf_authn_module') || 'Gantry::Plugins::Uaf::Authenticate';
my $uaf_authz = $gobj->fish_config('uaf_authz_module') || 'Gantry::Plugins::Uaf::Authorize';
# load our authorization and authentication modules
@parts = split('::', $uaf_authn);
$filename = File::Spec->catfile(@parts) . ".pm";
eval {
require $filename;
$uaf_authn->import();
$gobj->{_UAF_AUTHN_} = $uaf_authn->new($gobj);
}; if ($@) { warn "authn died $@\n"; die "Unable to load $uaf_authn; $@"; }
@parts = split('::', $uaf_authz);
$filename = File::Spec->catfile(@parts) . ".pm";
eval {
require $filename;
$uaf_authz->import();
$gobj->{_UAF_AUTHZ_} = $uaf_authz->new($gobj);
}; if ($@) { warn "authz died $@\n"; die "Unable to load $uaf_authz; $@"; }
$gobj->uaf_inited(1);
}
sub uaf_authenticate {
my $gobj = shift;
my $user;
my $regex = $gobj->uaf_authn->filter;
# authenticate the session, this happens with each access
return if ($gobj->uri =~ /^$regex/);
if ($gobj->uaf_authn->avoid()) {
if ($gobj->session_lock()) {
if (defined($user = $gobj->uaf_authn->is_valid())) {
#
# Uncomment this line of code and you will get an everchanging
# security token. Some internet pundits consider this a
# "good thing". But in an xhr async environment you will get
# a rather nasty race condition. i.e. The browsers don't
# consistently update the cookies from xhr requests. While a
# standard page loads work quite nicely.
#
# --> $gobj->uaf_authn->set_token($user);
#
$gobj->uaf_user($user);
$gobj->session_unlock();
} else {
$gobj->session_unlock();
$gobj->uaf_authn->relocate($gobj->uaf_authn->login_rootp);
}
}
}
}
sub do_login {
my ($gobj, $action) = @_;
$gobj->uaf_authn->login($action);
}
sub do_logout {
my $gobj = shift;
$gobj->uaf_authn->logout();
}
# ---------------------------------------------------------------------
# Accessors
# ---------------------------------------------------------------------
sub uaf_authn {
my $gobj = shift;
return $gobj->{_UAF_AUTHN_};
}
sub uaf_authz {
my $gobj = shift;
return $gobj->{_UAF_AUTHZ_};
}
sub uaf_user {
my ($gobj, $p) = @_;
$gobj->{_UAF_USER_} = $p if (defined($p));
return $gobj->{_UAF_USER_};
}
sub uaf_inited {
my ($gobj, $p) = @_;
$gobj->{_UAF_INITED_} = $p if (defined($p));
return $gobj->{_UAF_INITED_};
}
1;
__END__
=head1 NAME
Gantry::Plugins::Uaf - A User Authentication and Authorization Framework
=head1 SYNOPSIS
In the Apache Perl startup or app.cgi or app.server:
# ...
use MyApp qw{ -Engine=CGI -TemplateEngine=TT Cache Session Uaf};
Inside MyApp.pm:
use Gantry::Plugins::Uaf;
=head1 DESCRIPTION
This plugin mixes in a method that will provide session authentication and
user authorization. Session authentication is based on a valid username and
password. While user authorization is based on application defined rules
which grant access to resources. The goal of this module is to be
simple and flexiable.
To met this goal four objects are defined. They are Authenticate,
Authorize, User and Rule. This package provides basic implementations of
those objects.
The Rule object either grants or denies access to a resource. The access is
anything you want to use. A resource can be anything you define.
The User object consists of username and attributes. You can define as many
and whatever attributes you want. The User object is not tied to any one
datastore.
The base Authenticate object has two users hardcoded within. Those users are
"admin" and "demo", with corresponding passwords. This object handles the
authentication along with basic login and logout functionality.
The base Authorization object has only one rule defined: AllowAll.
Using the default, provided, Authentication and Authorization modules should
allow you get your application up and running in minimal time. Once that is
done, then you can define your User datastore, what your application rules
are and then create your objects. Once you do that, then you can load
your own modules with the following config variables.
uaf_authn_factory - The module name for your Authentication object
uaf_authz_factory - The module name for your Authorization object
The defaults for those are:
Gantry::Plugins::Uaf::Authorize
Gantry::Plugins::Uaf::Authenticate
These modules must be on the Perl include path and are loaded during
Gantry's startup processing. This plugin also requires the Session plugin.
=head1 METHODS
=over 4
=item uaf_authenticate
The method that is called for every url. It controls the authentication
process, loads the User object and sets the scurity token.
=back
=head1 ACCESSORS
=over 4
=item uaf_authn
Returns the handle for the Authentication object.
=item uaf_authz
Returns the handle for the Authorization object.
Example:
=over 4
$manager = $gobj->uaf_authz;
if ($manager->can($user, "read", "data")) {
}
=back
=item uaf_user
Set/Returns the handle for the User object.
Example:
=over 4
$user = $gobj->uaf_user;
$gobj->uaf_user($user);
=back
=back
=head1 PRIVATE METHODS
=over 4
=item get_callbacks
For use by Gantry. Registers the callbacks needed by Uaf
during the PerlHandler Apache phase or its moral equivalent.
=item initialize
This method is called by Gantry it will load and initialize your Authentication
and Authorization modules.
=item do_login
Exposes the url "/login", and calls the login() method of your Authenticaton
module.
=item do_logout
Exposes the url "/logout", and calls the logout() method of your Authentication
module.
=back
=head1 SEE ALSO
Gantry
Gantry::Plugins::Session
Gantry::Plugins::Uaf::Rule
Gantry::Plugins::Uaf::User
Gantry::Plugins::Uaf::Authorize
Gantry::Plugins::Uaf::Authenticate
Gantry::Plugins::Uaf::AuthorizeFactory
=head1 ACKNOWLEGEMENT
This module was heavily influenced by Apache2::SiteControl
written by Tony Kay, Etkay@uoregon.eduE.
=head1 AUTHOR
Kevin L. Esteb
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2008 Kevin L. Esteb
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.6 or,
at your option, any later version of Perl 5 you may have available.
=cut