Apache-AuthPOP3

 view release on metacpan or  search on metacpan

lib/Apache/AuthPOP3.pm  view on Meta::CPAN

package Apache::AuthPOP3;

use warnings;
use strict;

our $VERSION = '0.02';

use constant MP2 => (exists $ENV{MOD_PERL_API_VERSION} and 
                     $ENV{MOD_PERL_API_VERSION} >= 2);

BEGIN {
  if ($ENV{MOD_PERL}) {
    my @constants = qw(OK DECLINED HTTP_UNAUTHORIZED);
    if (MP2) {
      require Apache2::Access;      # for note_basic_auth_failure, get_basic_auth_pw, and requires
      require Apache2::RequestUtil; # for push_handlers, and dir_config
      require Apache2::RequestRec;  # for user, and filename
      require Apache2::Log;         # for log_error
      require Apache2::Const;
      Apache2::Const->import(-compile => @constants);
    } else {
      require Apache;
      require Apache::Constants;
      Apache::Constants->import(@constants);
    }
  }
}

use Net::POP3;
use Cache::FileCache;
use Digest::SHA1 qw(sha1_hex);

sub handler {
  my $r = shift;

  $r->push_handlers(PerlAuthzHandler => \&authorize);

  # check if MailHost config variable is present
  return MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED() unless (my $mailhost = $r->dir_config('MailHost'));

  # get user's authentication credentials
  my ($res, $passwd_sent) = $r->get_basic_auth_pw;
  return $res if (MP2 and $res != Apache2::Const::OK() or !MP2 and $res != Apache::Constants::OK());
  my $user_sent = $r->user;

  my $reason = authenticate($mailhost, $user_sent, $passwd_sent);
  if ($reason) {
    $r->note_basic_auth_failure;
    $r->log_reason($reason, $r->filename);
    return MP2 ? Apache2::Const::HTTP_UNAUTHORIZED() : Apache::Constants::HTTP_UNAUTHORIZED();
  }

  return MP2 ? Apache2::Const::OK() : Apache::Constants::OK();
}

sub authenticate {
  my ($mailhost, $user_sent, $passwd_sent) = @_;

  $user_sent and $passwd_sent or return 'either username or password is empty';

  # cache sha1-ed password
  my $cache = new Cache::FileCache({ 'namespace' => __PACKAGE__, 'default_expires_in' => 120 });
  my $passwd_cached_sha1 = $cache->get($user_sent);
  my $passwd_sent_sha1 = sha1_hex($passwd_sent);
  if (defined $passwd_cached_sha1) {
    return "user $user_sent: POP3 login failed" if $passwd_cached_sha1 ne $passwd_sent_sha1;
  } else {
    return "user $user_sent: POP3 login failed" unless Net::POP3->new($mailhost)->login($user_sent, $passwd_sent);
    $cache->set($user_sent, $passwd_sent_sha1);
  }

  return '';
}

sub authorize {
  my $r = shift;

  return MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED() unless (my $requires = $r->requires);
  my $user_sent = $r->user;

  for my $entry (@$requires) {
    my ($requirement, @rest) = split /\s+/, $entry->{requirement};
    return MP2 ? Apache2::Const::OK() : Apache::Constants::OK() if (lc $requirement eq 'valid-user');

    if (lc $requirement eq 'user') {
      foreach (@rest) { 
        if ($user_sent eq $_) {

          # change the username seen by apache to the one defined in UserMap
          if (my $usermap = $r->dir_config('UserMap')) {
            my %usermap = split /\s*(?:=>|,)\s*/, $usermap;
            $r->user($usermap{$user_sent}) if defined $usermap{$user_sent};
          }
          return MP2 ? Apache2::Const::OK() : Apache::Constants::OK();
        }
      }
      $r->log_error("user $user_sent: invalid user");
    }

    $r->log_error("user $user_sent: failed requirement");
  }



( run in 0.461 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )