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 )