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"); } $r->note_basic_auth_failure; $r->log_reason("user $user_sent: not authorized", $r->filename); return MP2 ? Apache2::Const::HTTP_UNAUTHORIZED() : Apache::Constants::HTTP_UNAUTHORIZED(); } 1; __END__ =head1 NAME Apache::AuthPOP3 - Authentication and Authorization via POP3 =head1 SYNOPSIS # In httpd.conf or startup.pl: PerlModule Apache::AuthDBI # In httpd.conf or .htaccess: AuthName POP3 AuthType Basic PerlAuthenHandler Apache::AuthPOP3 PerlSetVar MailHost pop.example.com PerlSetVar UserMap pop3user1=>realname1,pop3user2=>realname2 Require user pop3user1 pop3user2 pop3user3 pop3user4 # Require valid-user =head1 DESCRIPTION This module allows authentication and authorization against a POP3 server. Received username and password are looked up in the cache. If nothing was stored in the cache with that particular username and password within the past two minutes, they are passed to the POP3 server and cached once authenticated; SHA1 checksum of password is used in caching. After being authorized, the username or the name that maps to it based on the UserMap configuration is used to set the remote user. =head1 CONFIGURATION =over 4 =item B (Required) Defines the POP3 server to authenticate against. =item B (Optional) If defined, the remote user is set based on this. =back =head1 AUTHOR Sherwin Daganato, C<< >> =head1 SEE ALSO L, L, L =head1 COPYRIGHT & LICENSE Copyright 2006 Sherwin Daganato, all rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut