General

Proxy IMAP/POP n-vías con consultas LDAP utilizando Perl y nginx

En un sistema de correo corporativo geográficamente distribuido, los buzones de correo se suelen servir desde el MDA más cercano al usuario. Como resultado, suelen haber dos o más servidores IMAP (o POP3) por región sirviendo correos a usuarios finales. Si el usuario se desplaza a otra región, debe configurar el cliente de correo electrónico de forma apropiada para revisar su buzón, o utilizar un cliente de correo Web (como IMP de Horde) que permita hacer login en todos los servidores.Sin embargo, cuando se requiere que el usuario acceda a su buzón remotamente (sin considerar VPN en este momento) con un dispositivo lector de correos (como un Blackberry) se presentan dos problemas; el primero es presentar el servicio en la capa de aplicación (para evitar usar NAT, por ejemplo) y el segundo es el de dirigir la consulta al MDA que corresponda. Lo primero es fácil de resolver con cosas como imapproxy o Courier. Lo segundo es el tema en cuestión de este post.nginx, un ligero servidor Web diseñado originalmente para ser un proxy HTTP, tiene la capacidad de servir como proxy IMAP (POP, SMTP también). nginx sabe IMAP y puede transformar una solicitud de inicio de sesión (0 login USER PASS) en una consulta HTTP para un servicio de autenticación:

GET ... HTTP/1.0Host: localhostAuth-Method: plainAuth-User: USERAuth-Pass: PASSAuth-Protocol: imapAuth-Login-Attempt: 1Client-IP: 127.0.0.1

Por lo tanto, es posible hacer un script (en cualquier lenguaje, FWIW) servido por HTTP que lea las cabeceras de esta petición y responda con información útil para continuar con la sesión IMAP utilizando una respuesta HTTP de este tipo (por supuesto, Auth-Status también puede ser Invalid):

HTTP/1.0 200 OKAuth-Status: OKAuth-Server: 10.10.10.10Auth-Port: 143

La parte divertida es cuando se usa Perl para el asunto, porque nginx embebe Perl bajo la clase nginx y es posible escribir un mecanismo de autenticación directamente como una subclase de nginx. La clase tiene acceso a todas las cabeceras de la petición y puede inyectar cabeceras y contenido a la respuesta, por lo que podemos cambiar la cabecera Auth-Server, por ejemplo, dependiendo de la lógica de nuestro script. En el caso que nos ocupa, escribiríamos una cabecera correspondiente al MDA donde está el buzón del usuario consultando un campo en LDAP.Algo muy básico podría ser esto:

package Auth;use nginx;use Net::LDAP;our $ip={};$ip->{'serverA'} = "10.10.10.10";$ip->{'serverB'} = "10.20.10.10";sub handler {  my $r = shift;  my $ldap = Net::LDAP->new( 'ldap-server' );  my $mesg = $ldap->bind;  $mesg = $ldap->search ( base => 'dc=tu,dc=base', filter => '(&(uid=' . $r->header_in("Auth-User") . '))' );  my $goto = $mesg->entry(0)->get_value('atributoLDAPconDireccion');  $r->header_out( "Auth-Status", "OK" ) ;  $r->header_out( "Auth-Server", $mail_server_ip->{$goto} );  $r->header_out( "Auth-Port", "143");  $r->send_http_header("text/html");  retu OK;}1;

nginx también debe ser configurado apropiadamente para utilizar la clase de autenticación y activar el proxy IMAP. El servidor web debe ser configurado con las opciones --with-mail y --with-http_perl_module. Aun estoy buscando la mejor forma de hacer distribuible esta configuración en el paquete que mantengo para Debian y Ubuntu (ya que nginx es muy pwd centered)Con un servidor nginx correctamente compilado, y con la clase de autenticación lista, basta agregar en /etc/nginx/nginx.conf algo como:

http {  ...    perl_modules  /etc/nginx/perl/lib;    perl_require  Auth.pm;    server {        location /auth {            perl  Auth::handler;        }    }}mail {    auth_http  127.0.0.1:80/auth;    imap_capabilities  "IMAP4rev1"  "UIDPLUS";    server {        listen     143;        protocol   imap;        proxy      on;    }}
Standard

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s