Heiko et al,
Inspired by Heiko's suggestion I have brewed up the following which
appears to work.
I now have:
Exim authentication -> Perl -> HTTP -> Nginx -> PHP ->
MySQL/MariaDB backend
and it works a treat.
*Authenticators in Exim*
In Exim we have a PLAIN and a LOGIN authenticator that calls a Perl
subroutine exim_auth() - like this:
auth_plain:
driver = plaintext
public_name = PLAIN
server_condition =
${perl{exim_auth}{$auth2}{$auth3}{$sender_host_address}}
server_prompts = :
server_set_id = $auth2
auth_login:
driver = plaintext
public_name = LOGIN
server_condition =
${perl{exim_auth}{$auth1}{$auth2}{$sender_host_address}}
server_prompts = Username:: : Password::
server_set_id = $auth1
*Exim Perl authenticator shim*
In /etc/exim/exim.conf I have:
#
# Perl authenticator
#
perl_startup = do '/srv/auth_policy_server/perl/exim_auth.pl'
perl_at_start = true
perl_taintmode = true
and the code:
#!/usr/bin/perl
#
# exim_auth.pl -- A PERL shim between Exim authenticator and Web
Services authentication policy server.
#
# ABSTRACT
#
# Exim authenticator via PERL. Called with three arguments from Exim:
#
# 1. Username
# 2. Password
# 3. Remote IP address
#
#
use strict;
use warnings;
use LWP::UserAgent ();
sub exim_auth {
my $email = $_[0];
my $password = $_[1];
my $remote = $_[2];
# new instance of LWP user agent
my $ua = LWP::UserAgent->new(
agent => 'EximAuth/0.01',
timeout => 3
);
# create form data
my %form;
$form{'email'} = $email;
$form{'password'} = $password;
$form{'remote'} = $remote;
# post the form data
my $response = $ua->post('
http://localhost/exim.php', \%form);
# get response and map to success/fail
return ($response->code() eq '204') ? 1 : 0;
}
which basically takes the three arguments, drops them into a form and
uses method POST to dispatch the request to Nginx on the same host.
Nginx returns:
204: No content (auth success)
403: Forbidden (auth failure)
400: Bad request (all other errors)
which is reflected back into the server_condition as true/false.
*LEMP backend*
A PHP/Nginx/MySQL backend receives the form, does the authentication and
GeoIP policy stuff, logs the transaction and outcome and returns the
HTTP response code.
Mike
On 17/03/2020 08:18, Heiko Schlittermann via Exim-users wrote:
> Mike Tubby via Exim-users <exim-users@???> (Di 17 Mär 2020 01:51:55 CET):
>> All,
>>
>> Dovecot IMAP/POP3 server has a built-in Authentication Policy sub-system
>> whereby it can make a web-services call to to an Authentication Policy
>> Server:
>>
>> 1. command: on connect, before authentication
>> 2. command: on connect, after authentication
>> 3. report: on final outcome of policy + authentication
>>
>> It would be "really good"(tm) if Exim could implement a similar
>> concept/service/API as it would allow me to leverage GEOIP against possible
>> attackers of some (protected) services and report back in to a common
>> database of failed connections for (a) GEOIP policy or (b) username/password
> Maybe I'm missing the point, but something *like* this comes into my
> mind immediatly: (at least as POC it should be ok)
>
> PLAIN:
> driver = plaintext
> server_condition = ${perl{do_auth}{$auth1}{$auth2}{$sender_host_address}}
>
> And provide a Perl subrouting do_auth, that does the actual
> authentication.
>
> But then, of course, you've to implement the actual auth in the perl
> function.
>
> Maybe even that would work, but I'm not sure if we're flexible enough
> with the ACL
>
> begin acl
>
> acl_auth:
> require = <pre-auth>
> require = <auth>
> require = <report>
> accept
>
> begin authenticators
>
> PLAIN:
> driver = plaintext
> server_condition = acl_auth
>
> Best regards from Dresden/Germany
> Viele Grüße aus Dresden
> Heiko Schlittermann
> --
> SCHLITTERMANN.de ---------------------------- internet & unix support -
> Heiko Schlittermann, Dipl.-Ing. (TU) - {fon,fax}: +49.351.802998{1,3} -
> gnupg encrypted messages are welcome --------------- key ID: F69376CE -
>