File Coverage

blib/lib/Apache/AuthPOP3.pm
Criterion Covered Total %
statement 19 64 29.6
branch 1 28 3.5
condition 1 6 16.6
subroutine 7 10 70.0
pod 0 3 0.0
total 28 111 25.2


line stmt bran cond sub pod time code
1             package Apache::AuthPOP3;
2              
3 1     1   44019 use warnings;
  1         2  
  1         37  
4 1     1   6 use strict;
  1         2  
  1         76  
5              
6             our $VERSION = '0.02';
7              
8 1   33     215 use constant MP2 => (exists $ENV{MOD_PERL_API_VERSION} and
9 1     1   6 $ENV{MOD_PERL_API_VERSION} >= 2);
  1         6  
10              
11             BEGIN {
12 1 50   1   37 if ($ENV{MOD_PERL}) {
13 0         0 my @constants = qw(OK DECLINED HTTP_UNAUTHORIZED);
14 0         0 if (MP2) {
15             require Apache2::Access; # for note_basic_auth_failure, get_basic_auth_pw, and requires
16             require Apache2::RequestUtil; # for push_handlers, and dir_config
17             require Apache2::RequestRec; # for user, and filename
18             require Apache2::Log; # for log_error
19             require Apache2::Const;
20             Apache2::Const->import(-compile => @constants);
21             } else {
22 0         0 require Apache;
23 0         0 require Apache::Constants;
24 0         0 Apache::Constants->import(@constants);
25             }
26             }
27             }
28              
29 1     1   1063 use Net::POP3;
  1         45731  
  1         54  
30 1     1   1000 use Cache::FileCache;
  1         54951  
  1         50  
31 1     1   9 use Digest::SHA1 qw(sha1_hex);
  1         1  
  1         671  
32              
33             sub handler {
34 0     0 0   my $r = shift;
35              
36 0           $r->push_handlers(PerlAuthzHandler => \&authorize);
37              
38             # check if MailHost config variable is present
39 0 0         return MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED() unless (my $mailhost = $r->dir_config('MailHost'));
40              
41             # get user's authentication credentials
42 0           my ($res, $passwd_sent) = $r->get_basic_auth_pw;
43 0 0         return $res if (MP2 and $res != Apache2::Const::OK() or !MP2 and $res != Apache::Constants::OK());
44 0           my $user_sent = $r->user;
45              
46 0           my $reason = authenticate($mailhost, $user_sent, $passwd_sent);
47 0 0         if ($reason) {
48 0           $r->note_basic_auth_failure;
49 0           $r->log_reason($reason, $r->filename);
50 0           return MP2 ? Apache2::Const::HTTP_UNAUTHORIZED() : Apache::Constants::HTTP_UNAUTHORIZED();
51             }
52              
53 0           return MP2 ? Apache2::Const::OK() : Apache::Constants::OK();
54             }
55              
56             sub authenticate {
57 0     0 0   my ($mailhost, $user_sent, $passwd_sent) = @_;
58              
59 0 0 0       $user_sent and $passwd_sent or return 'either username or password is empty';
60              
61             # cache sha1-ed password
62 0           my $cache = new Cache::FileCache({ 'namespace' => __PACKAGE__, 'default_expires_in' => 120 });
63 0           my $passwd_cached_sha1 = $cache->get($user_sent);
64 0           my $passwd_sent_sha1 = sha1_hex($passwd_sent);
65 0 0         if (defined $passwd_cached_sha1) {
66 0 0         return "user $user_sent: POP3 login failed" if $passwd_cached_sha1 ne $passwd_sent_sha1;
67             } else {
68 0 0         return "user $user_sent: POP3 login failed" unless Net::POP3->new($mailhost)->login($user_sent, $passwd_sent);
69 0           $cache->set($user_sent, $passwd_sent_sha1);
70             }
71              
72 0           return '';
73             }
74              
75             sub authorize {
76 0     0 0   my $r = shift;
77              
78 0 0         return MP2 ? Apache2::Const::DECLINED() : Apache::Constants::DECLINED() unless (my $requires = $r->requires);
79 0           my $user_sent = $r->user;
80              
81 0           for my $entry (@$requires) {
82 0           my ($requirement, @rest) = split /\s+/, $entry->{requirement};
83 0 0         return MP2 ? Apache2::Const::OK() : Apache::Constants::OK() if (lc $requirement eq 'valid-user');
84              
85 0 0         if (lc $requirement eq 'user') {
86 0           foreach (@rest) {
87 0 0         if ($user_sent eq $_) {
88              
89             # change the username seen by apache to the one defined in UserMap
90 0 0         if (my $usermap = $r->dir_config('UserMap')) {
91 0           my %usermap = split /\s*(?:=>|,)\s*/, $usermap;
92 0 0         $r->user($usermap{$user_sent}) if defined $usermap{$user_sent};
93             }
94 0           return MP2 ? Apache2::Const::OK() : Apache::Constants::OK();
95             }
96             }
97 0           $r->log_error("user $user_sent: invalid user");
98             }
99              
100 0           $r->log_error("user $user_sent: failed requirement");
101             }
102              
103 0           $r->note_basic_auth_failure;
104 0           $r->log_reason("user $user_sent: not authorized", $r->filename);
105 0           return MP2 ? Apache2::Const::HTTP_UNAUTHORIZED() : Apache::Constants::HTTP_UNAUTHORIZED();
106             }
107              
108             1;
109              
110             __END__