package Gantry::Control::C::Authz::PageBasedBase;
use strict;
use Gantry::Control;
use constant MP2 => (
exists $ENV{MOD_PERL_API_VERSION} and
$ENV{MOD_PERL_API_VERSION} >= 2
);
# must explicitly import for mod_perl2
BEGIN {
if (MP2) {
require Gantry::Engine::MP20;
Gantry::Engine::MP20->import();
}
}
############################################################
# Functions #
############################################################
######################################################################
# Main Execution Begins Here #
######################################################################
sub handler : method {
my ( $self, $r ) = @_;
my $user_model = $self->user_model;
my $group_members_model = $self->group_members_model();
# Check Exclude paths
if ( $r->dir_config( 'exclude_path' ) ) {
foreach my $p ( split( /\s*;\s*/, $r->dir_config( 'exclude_path' ) ) ) {
if ( $r->path_info =~ /^$p$/ ) {
return( $self->status_const( 'OK' ) );
}
}
} # end if exclude_path
my $requires = $r->requires;
# If we don't have any requirements get out !
return( $self->status_const( 'DECLINED' ) ) if ( ! $requires );
# Who's the user ?
my $user = $r->user;
# get the uri and fill @p.
my @p = split( '/', $r->uri );
@p = 'index.html' if ( scalar( @p ) < 1 );
# Get the users groups and put them in a hash.
my ( %groups, %group_ids, $uperm, $gperm, $wperm, $uid, $oid, $gid );
if( $user ) {
my @user_row = $user_model->search( user_name => $user );
# set user id
$uid = $user_row[0]->id;
# get groups for user
my @group_rows = $group_members_model->search(
user_id => $user_row[0]->id
);
foreach ( @group_rows ) {
$groups{$_->group_id->name} = 1;
$group_ids{$_->group_id} = 1;
}
} # end: if user
# make the check uri database calls here.
( $uperm, $gperm, $wperm, $oid, $gid ) = $self->lookup_uri( @p );
# This should actually be Forbidden I believe.
if ( $self->status_const( 'OK' )
ne $self->do_requires( $requires, $user, \%groups ) ) {
return( $self->status_const( 'FORBIDDEN' ) );
}
# compare against world
return( $self->status_const( 'OK' ) ) if ( ( dec2bin( $wperm ) )[0] );
# compare against group
if ( defined $group_ids{$gid} ) {
return( $self->status_const( 'OK' ) ) if ( ( dec2bin( $gperm ) )[0] );
}
# compare against user
if ( $oid == $uid ) {
return( $self->status_const( 'OK' ) ) if ( ( dec2bin( $uperm ) )[0] );
}
# This should actually be Forbidden I believe.
# fail if all else dosen't work :( -- bye
$r->note_basic_auth_failure;
return( $self->status_const( 'FORBIDDEN' ) );
} # END $self->handler
#-------------------------------------------------
# do_requires( $requires, $user, $groups )
#-------------------------------------------------
sub do_requires {
my ( $self, $requires, $user, $groups ) = @_;
for my $req_ent ( @$requires ) {
my ( $req, @rest ) = split( /\s+/, $req_ent->{requirement} );
# This is kinda odd. Do I really need this ?
if ( lc( $req ) eq 'valid-user' ) {
return( $self->status_const( 'OK' ) );
}
elsif( lc( $req ) eq 'user' ) {
for my $valid_user ( @rest ) {
return( $self->status_const( 'OK' ) )
if ( $user eq $valid_user );
}
}
elsif( lc( $req ) eq 'group' ) {
for my $valid_group ( @rest ) {
return( $self->status_const( 'OK' ) )
if ( exists $$groups{$valid_group} );
}
}
}
} # END do_requires
#-------------------------------------------------
# $self->lookup_uri( @p )
#-------------------------------------------------
sub lookup_uri {
my ( $self, @p ) = @_;
# Sane staring point, nothing works ;)
my ( $uperm, $gperm, $wperm, $oid, $gid ) = ( 0, 0, 0, 0, 0 );
# Leave now if no @p
return( $uperm, $gperm, $wperm, $oid, $gid ) if ( scalar( @p ) < 1 );
# Figure out what the uri is.
my $uri = join( '/', @p );
$uri = "/$uri" if ( $uri !~ /^\// );
# Do the lookup.
my @page_row = Gantry::Control::Model::auth_pages->search( uri => $uri );
# If we find it set the vals.
if ( @page_row ) {
( $uperm, $gperm, $wperm, $oid, $gid ) = (
$page_row[0]->user_perm,
$page_row[0]->group_perm,
$page_row[0]->world_perm,
$page_row[0]->owner_id,
$page_row[0]->group_id
);
}
else {
# Take one down and pass it around
pop( @p );
( $uperm, $gperm, $wperm, $oid, $gid ) = $self->lookup_uri( @p );
}
# Return what we have.
return( $uperm, $gperm, $wperm, $oid, $gid );
} # end lookup_uri
#-------------------------------------------------
# $self->import( $self, @options )
#-------------------------------------------------
sub import {
my ( $self, @options ) = @_;
my( $engine, $tplugin );
foreach (@options) {
# Import the proper engine
if (/^-Engine=(.*)$/) {
$engine = "Gantry::Engine::$1";
eval "use $engine";
if ( $@ ) {
die "unable to load engine $1 ($@)";
}
}
}
} # end: import
# EOF
1;
__END__
=head1 NAME
Gantry::Control::C::Authz::PageBasedBase - Page based access control.
=head1 SYNOPSIS
use Gantry::Control::C::Authz::PageBasedSubClass;
=head1 DESCRIPTION
This handler is the authorization portion for page based authorization.
It will authenticate only users who have been allowed from the
administrative interface into a particular uri. The module returns
FORBIDDEN if you do not have access to a particular uri.
=head1 APACHE
This is a sample of how to set up Authorization only on a location.
AuthType Basic
AuthName "Manual"
PerlSetVar dbconn "dbi:Pg:dbname=..."
PerlSetVar dbuser ""
PerlSetVar dbpass ""
PerlSetVar dbcommit off
PerlAuthenHandler Gantry::C::Control::AuthenSubClass
PerlAuthzHandler Gantry::C::Control::Authz::PageBasedSubClass
require valid-user
Choose a subclass to match your other database ORM scheme. Use
Gantry::C::Control::Authz::PageBasedCDBI if you use Class::DBI (or something
descended from it), otherwise use Gantry::C::Control::Authz::PageBasedRegular.
=head1 DATABASE
These are the authentication tables that this handler uses.
create table "auth_pages" (
"id" int4 primary key default nextval('auth_pages_seq') NOT NULL,
"user_perm" int4,
"group_perm" int4,
"world_perm" int4,
"owner_id" int4,
"group_id" int4,
"uri" varchar,
"title" varchar
);
create table "auth_groups" (
"id" int4 primary key default nextval('auth_groups_seq') NOT NULL,
"name" varchar,
"description" text
);
create table "auth_group_members" (
"id" int4 primary key default nextval('auth_group_members_seq')
NOT NULL,
"user_id" int4,
"group_id" int4
);
=head1 METHODS
=over 4
=item handler
The mod_perl page based authz handler.
=item do_requires
For internal use.
=item lookup_uri
For internal use.
=back
=head1 SEE ALSO
Gantry::Control::C::Pages(3), Gantry::Control::C::Authz(3),
Gantry::Control(3), Gantry(3)
=head1 LIMITATIONS
Pages must be defined for this to work, otherwise everything returns
FORBIDDEN to the user.
=head1 AUTHOR
Tim Keefer
=head1 COPYRIGHT
Copyright (c) 2005-6, Tim Keefer.
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