Apache-DBI
view release on metacpan or search on metacpan
lib/Apache/AuthDBI.pm view on Meta::CPAN
BEGIN {
my @constants = qw( OK AUTH_REQUIRED FORBIDDEN DECLINED SERVER_ERROR );
if (MP2) {
require Apache2::Access;
require Apache2::Const;
require Apache2::RequestRec;
require Apache2::RequestUtil;
require Apache2::Log;
import Apache2::Const @constants;
}
else {
require Apache::Constants;
import Apache::Constants @constants;
}
}
use strict;
use DBI ();
use Digest::SHA1 ();
use Digest::MD5 ();
sub debug {
print STDERR "$_[1]\n" if $_[0] <= $Apache::AuthDBI::DEBUG;
}
sub push_handlers {
if (MP2) {
require Apache2::ServerUtil;
my $s = Apache2::ServerUtil->server;
$s->push_handlers(@_);
}
else {
Apache->push_handlers(@_);
}
}
# configuration attributes, defaults will be overwritten with values
# from .htaccess.
my %Config = (
'Auth_DBI_data_source' => '',
'Auth_DBI_username' => '',
'Auth_DBI_password' => '',
'Auth_DBI_pwd_table' => '',
'Auth_DBI_uid_field' => '',
'Auth_DBI_pwd_field' => '',
'Auth_DBI_pwd_whereclause' => '',
'Auth_DBI_grp_table' => '',
'Auth_DBI_grp_field' => '',
'Auth_DBI_grp_whereclause' => '',
'Auth_DBI_log_field' => '',
'Auth_DBI_log_string' => '',
'Auth_DBI_authoritative' => 'on',
'Auth_DBI_nopasswd' => 'off',
'Auth_DBI_encrypted' => 'on',
'Auth_DBI_encryption_salt' => 'password',
#Using Two (or more) Methods Will Allow for Fallback to older Methods
'Auth_DBI_encryption_method'=> 'sha1hex/md5/crypt',
'Auth_DBI_uidcasesensitive' => 'on',
'Auth_DBI_pwdcasesensitive' => 'on',
'Auth_DBI_placeholder' => 'off',
'Auth_DBI_expeditive' => 'on',
);
# stores the configuration of current URL.
# initialized during authentication, eventually re-used for authorization.
my $Attr = {};
# global cache: all records are put into one string.
# record separator is a newline. Field separator is $;.
# every record is a list of id, time of last access, password, groups
#(authorization only).
# the id is a comma separated list of user_id, data_source, pwd_table,
# uid_field.
# the first record is a timestamp, which indicates the last run of the
# CleanupHandler followed by the child counter.
my $Cache = time . "$;0\n";
# unique id which serves as key in $Cache.
# the id is generated during authentication and re-used for authorization.
my $ID;
# minimum lifetimes of cache entries in seconds.
# setting the CacheTime to 0 will not use the cache at all.
my $CacheTime = 0;
# supposed to be called in a startup script.
# sets CacheTime to a user defined value.
sub setCacheTime {
my $class = shift;
my $cache_time = shift;
# sanity check
$CacheTime = $cache_time if $cache_time =~ /\d+/;
}
# minimum time interval in seconds between two runs of the PerlCleanupHandler.
# setting CleanupTime to 0 will run the PerlCleanupHandler after every request.
# setting CleanupTime to a negative value will disable the PerlCleanupHandler.
my $CleanupTime = -1;
# supposed to be called in a startup script.
# sets CleanupTime to a user defined value.
sub setCleanupTime {
my $class = shift;
my $cleanup_time = shift;
# sanity check
$CleanupTime = $cleanup_time if $cleanup_time =~ /\-*\d+/;
}
# optionally the string with the global cache can be stored in a shared memory
# segment. the segment will be created from the first child and it will be
# destroyed if the last child exits. the reason for not handling everything
# in the main server is simply, that there is no way to setup
# an ExitHandler which runs in the main server and which would remove the
# shared memory and the semaphore.hence we have to keep track about the
# number of children, so that the last one can do all the cleanup.
# creating the shared memory in the first child also has the advantage,
# that we don't have to cope with changing the ownership. if a shm-function
# fails, the global cache will automatically fall back to one string
# per process.
lib/Apache/AuthDBI.pm view on Meta::CPAN
return (@passwds_to_check);
}
# authorization handler, it is called immediately after the authentication
sub authz {
my $r = shift;
my ($key, $val, $dbh);
my $prefix = "$$ Apache::AuthDBI::authz ";
if ($Apache::AuthDBI::DEBUG > 1) {
my $type = '';
if (MP2) {
$type .= 'initial ' if $r->is_initial_req();
$type .= 'main' if $r->main();
}
else {
$type .= 'initial ' if $r->is_initial_req;
$type .= 'main' if $r->is_main;
}
debug(1, "==========\n$prefix request type = >$type<");
}
# only the first internal request
unless ($r->is_initial_req) {
return MP2 ? Apache2::Const::OK() : Apache::Constants::OK();
}
my $user_result = MP2 ? Apache2::Const::DECLINED() :
Apache::Constants::DECLINED();
my $group_result = MP2 ? Apache2::Const::DECLINED() :
Apache::Constants::DECLINED();
# get username
my $user_sent = $r->user;
debug(2, "$prefix user sent = >$user_sent<");
# here we could read the configuration, but we re-use the configuration
# from the authentication
# parse connect attributes, which may be tilde separated lists
my @data_sources = split /~/, $Attr->{data_source};
my @usernames = split /~/, $Attr->{username};
my @passwords = split /~/, $Attr->{password};
# use ENV{DBI_DSN} if not defined
$data_sources[0] = '' unless $data_sources[0];
# if not configured decline
unless ($Attr->{pwd_table} && $Attr->{uid_field} && $Attr->{grp_field}) {
debug(2, "$prefix not configured, return DECLINED");
return MP2 ? Apache2::Const::DECLINED() :
Apache::Constants::DECLINED();
}
# do we want Windows-like case-insensitivity?
$user_sent = lc $user_sent if $Attr->{uidcasesensitive} eq "off";
# select code to return if authorization is denied:
my $authz_denied;
if (MP2) {
$authz_denied = $Attr->{expeditive} eq 'on' ?
Apache2::Const::FORBIDDEN() : Apache2::Const::AUTH_REQUIRED();
}
else {
$authz_denied = $Attr->{expeditive} eq 'on' ?
Apache::Constants::FORBIDDEN() : Apache::Constants::AUTH_REQUIRED();
}
# check if requirements exists
my $ary_ref = $r->requires;
unless ($ary_ref) {
if ($Attr->{authoritative} eq 'on') {
$r->log_reason("user $user_sent denied, no access rules specified (DBI-Authoritative)", $r->uri);
if ($authz_denied == (MP2 ? Apache2::Const::AUTH_REQUIRED() :
Apache::Constants::AUTH_REQUIRED())) {
$r->note_basic_auth_failure;
}
return $authz_denied;
}
debug (2, "$prefix no requirements and not authoritative, return DECLINED");
return MP2 ? Apache2::Const::DECLINED() :
Apache::Constants::DECLINED();
}
# iterate over all requirement directives and store them according to
# their type (valid-user, user, group)
my($valid_user, $user_requirements, $group_requirements);
foreach my $hash_ref (@$ary_ref) {
while (($key,$val) = each %$hash_ref) {
last if $key eq 'requirement';
}
$val =~ s/^\s*require\s+//;
# handle different requirement-types
if ($val =~ /valid-user/) {
$valid_user = 1;
}
elsif ($val =~ s/^user\s+//g) {
$user_requirements .= " $val";
}
elsif ($val =~ s/^group\s+//g) {
$group_requirements .= " $val";
}
}
$user_requirements =~ s/^ //g if $user_requirements;
$group_requirements =~ s/^ //g if $group_requirements;
{
no warnings qw(uninitialized);
debug(
2,
"$prefix requirements: [valid-user=>$valid_user<] [user=>" .
"$user_requirements<] [group=>$group_requirements<]"
);
}
# check for valid-user
if ($valid_user) {
$user_result = MP2 ? Apache2::Const::OK() : Apache::Constants::OK();
debug(2, "$prefix user_result = OK: valid-user");
}
# check for users
if (($user_result != (MP2 ? Apache2::Const::OK() :
( run in 1.027 second using v1.01-cache-2.11-cpan-0d23b851a93 )