Apache-AuthenCache
view release on metacpan or search on metacpan
AuthenCache.pm view on Meta::CPAN
# Get response and password
my($res, $passwd_sent) = $r->get_basic_auth_pw;
return $res if $res; # e.g. HTTP_UNAUTHORIZED
# Get username
my $user_sent = $r->connection->user;
# If the user left the username field blank, we must catch it and DECLINE
# for the downstream handler
unless ($user_sent) {
return DECLINED;
}
$r->log->debug("handler: username=$user_sent");
# Do we want Windows-like case-insensitivity?
if ($casesensitive eq 'off') {
$user_sent = lc($user_sent);
}
# Create or retreive the cache (if already created)
# Use the Realm name ($auth_name) for different caches for each realm
my $cache = IPC::Cache->new({ namespace => $auth_name });
my $passwd = $cache->get($user_sent);
# Is the user in the cache
if ($passwd) {
$r->log->debug("handler: using cached passwd for $user_sent");
# Allow no password
if ($nopasswd eq 'on' and not length($passwd)) {
$r->log->debug("handler: no password required; returning DONE");
# Must return DECLINED so that user has a chance to put in
# no password
return DONE;
}
# If nopasswd is off, reject user
unless (length($passwd_sent) and length($passwd)) {
$r->log->debug("handler: user $user_sent: empty password(s) rejected" .
$r->uri);
# Must return DECLINED so that user has a chance to put in a
# new password
return DECLINED;
}
# Is crypt is needed
if ($encrypted eq 'on') {
my $salt = substr($passwd, 0, 2);
$passwd_sent = crypt($passwd_sent, $salt);
}
unless ($passwd_sent eq $passwd) {
$r->log->debug("AuthenCache::handler: user $user_sent: " .
"password mismatch" . $r->uri);
# Must return DECLINED so that user has a chance to put in a
# new password
return DECLINED;
}
# Password matches so end stage
# The required patch was not introduced in 1.26. It is no longer
# promised to be included in any timeframe. Commenting out.
# if ($mod_perl::VERSION > 1.25) {
# I should be able to use the below lines and be done with it.
# Since set_handlers() doesn't work properly until 1.26
# (according to Doug MacEachern) I have to work around it by
# cobbling together cheat sheets for the subsequent handlers
# in this phase. I get the willies about the security implications
# in a general environment where you might be using someone else's
# handlers upstream or downstream...
$r->log->debug("handler: user in cache and password matches; ",
"returning OK and clearing authen handler stack");
$r->set_handlers(PerlAuthenHandler => undef);
# } else {
# $r->log->debug("handler: user in cache and password matches; ",
# "returning OK and setting notes");
# $r->notes('AuthenCache' => 'hit');
#}
return OK;
} # End if()
# User not in cache
$r->log->debug("handler: user/group not in cache; returning DECLINED");
return DECLINED;
}
###############################################################################
###############################################################################
# manage_cache: insert new entries into the cache
###############################################################################
###############################################################################
sub manage_cache {
my $r = shift;
return OK unless $r->is_initial_req; # only the first internal request
# Get response and password
my ($res, $passwd_sent) = $r->get_basic_auth_pw;
return $res if $res; # e.g. HTTP_UNAUTHORIZED
# Get username
my $user_sent = $r->connection->user;
$r->log->debug("manage_cache: username=$user_sent");
# The required patch was not introduced in 1.26. It is no longer
# promised to be included in any timeframe. Commenting out.
# unless ($mod_perl::VERSION > 1.25) {
# The below test is dubious. I'm putting it in as a hack around the
# problems with set_handlers not working quite right until 1.26 is
# released (according to Doug MacEachern).
my $cache_result = $r->notes('AuthenCache');
if ($cache_result eq 'hit') {
$r->log->debug("manage_cache: upstream cache hit for username=",
"$user_sent");
return OK;
# }
}
# Get configuration
my $no_passwd = $r->dir_config('AuthenCache_NoPasswd') || 'off';
my $encrypted = $r->dir_config('AuthenCache_Encrypted') || 'on';
my $casesensitive = $r->dir_config('AuthenCache_CaseSensitive') || 'on';
my $cache_time_limit = $r->dir_config('AuthenCache_CacheTime');
my $auth_name = $r->auth_name;
# Do we want Windows-like case-insensitivity?
if ($casesensitive eq 'off') {
$user_sent = lc($user_sent);
$passwd_sent = lc($passwd_sent);
}
# Do we need to crypt the password?
if ($encrypted eq 'on') {
my @alphabet = ('a' .. 'z', 'A' .. 'Z', '0' .. '9', '.', '/');
my $salt = join ('', @alphabet[rand (64), rand (64)]);
$passwd_sent = crypt($passwd_sent, $salt);
}
# Add the user to the cache
# Use the Realm name to have different caches for each realm
my $cache = IPC::Cache->new({ namespace => $auth_name });
$cache->set($user_sent, $passwd_sent, $cache_time_limit);
$r->log->debug("manage_cache: added $user_sent to the cache");
return OK;
}
1;
__END__
# Documentation - try 'pod2text AuthenCache.pm'
=head1 NAME
Apache::AuthenCache - Authentication caching used in conjuction
with a primary authentication module (Apache::AuthenDBI,
Apache::AuthenLDAP, etc.)
=head1 SYNOPSIS
# In your httpd.conf
PerlModule Apache::AuthenCache
# In httpd.conf or .htaccess:
( run in 0.629 second using v1.01-cache-2.11-cpan-df04353d9ac )