Nginx As imap4/pop3 Proxy Using Apache As Auth Server Backend

It’s been a long times since i wrote my last article, i’ve been bussy with real life things.
As usual, I’ll get right to the subject of how to configure nginx as POP3/IMAP proxy server.

Nginx IP                 = 192.168.1.1
Postfix User Database IP = 192.168.1.5 (postfix + courier server + apache backend)

nginx server configuration

mail {
    server_name mail-proxy.example.com;
    # apache external backend
    auth_http  192.168.1.5:8081/auth.php;
    proxy  on;
    proxy_pass_error_message on;

    imap_capabilities "IMAP4rev1" "UIDPLUS" "IDLE" "LITERAL +" "QUOTA";

    pop3_auth plain apop cram-md5;
    pop3_capabilities "LAST" "TOP" "USER" "PIPELINING" "UIDL";

    ssl_certificate /etc/nginx/ssl_keys/db.mail-proxy.crt;
    ssl_certificate_key /etc/nginx/ssl_keys/db.mail-proxy.key;
    ssl_session_timeout 5m;
    ssl_protocols SSLv2 SSLv3 TLSv1;
    ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
    ssl_prefer_server_ciphers on;

    server {
      listen      143;
      protocol    imap;
      starttls    on;
      auth_http_header X-Auth-Port 143;
      auth_http_header User-Agent "Nginx POP3/IMAP4 proxy";
    }

    server {
      protocol    pop3;
      listen      110;
      starttls    on;
      pop3_auth   plain;
      auth_http_header X-Auth-Port 110;
      auth_http_header User-Agent "Nginx POP3/IMAP4 proxy";
    }

    server {
      listen      993;
      ssl         on;
      protocol    imap;
      auth_http_header X-Auth-Port 993;
      auth_http_header User-Agent "Nginx POP3/IMAP4 proxy";
    }

    server {
      protocol    pop3;
      listen      995;
      ssl         on;
      pop3_auth   plain;
      auth_http_header X-Auth-Port 995;
      auth_http_header User-Agent "Nginx POP3/IMAP4 proxy";
    }
}


apache server configuration
First, we create a custom log format in apache server, which is useful to show the ip address of the user. nginx pass it in the form of Client-IP header.

LogFormat "\"%{Client-IP}i %{X-Auth-Port}i\" %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" cached

httpd.conf

CustomLog  /var/log/httpd/authserver-access_log cached

auth.php

<?php
/*
Nginx sends headers as
Auth-User: somuser
Auth-Pass: somepass
On my php app server these are seen as
HTTP_AUTH_USER and HTTP_AUTH_PASS
*/

if (!isset($_SERVER["HTTP_AUTH_USER"] ) || !isset($_SERVER["HTTP_AUTH_PASS"] )) {
 fail();
}

$username=$_SERVER["HTTP_AUTH_USER"] ;
$userpass=$_SERVER["HTTP_AUTH_PASS"] ;
$protocol=$_SERVER["HTTP_AUTH_PROTOCOL"] ;

$backend_port=110;
if ($protocol=="imap") {
 $backend_port=143;
}

if ($protocol=="smtp") {
 $backend_port=25;
}

if (!authuser($username,$userpass)) {
 fail();
 exit;
}

$userserver=getmailserver($username);
pass($userserver, $backend_port);

// Authentication block
function authuser($user,$pass)
{
 // You can put a query for authentication with the DB here.
 // Since auth will be done post-proxy, we're just returning true
 return true;
}

// MySQL connection function
function mysqlconn($user,$query) {
$mail_dbuser="postfix-user";
$mail_dbpass="mypassword";
$mail_db="postfix-db";
$mail_dbhost="localhost";

mysql_connect($mail_dbhost,$mail_dbuser,$mail_dbpass);
@mysql_select_db($mail_db) or die( "Unable to select database");

$res1 = mysql_query($query);

$res = mysql_fetch_array($res1);
$res2 = $res['active'];
return $res2;
mysql_close();

}

// getmailserver function
function getmailserver($user) {
$query = "select active from mailbox where username='$user'";
$active = mysqlconn($user,$query);

if (!isset($active)) {
 fail();
} elseif ($active == "1") {
 $server = "192.168.1.5";
 return $server;
} elseif ($active == "0") {
 fail();
}
mysql_close();

}

function fail() {
 header("Auth-Status: Invalid login or password");
 exit;
}

function pass($server,$port) {
header("Auth-Status: OK");
header("Auth-Server: $server");
header("Auth-Port: $port");
exit;
}

?>

Testing

# telnet mail-proxy.example.com 110
Trying xxx.xxx.xxx.xxx...
Connected to mail-proxy.example.com.
Escape character is '^]'.
+OK POP3 ready
user user@example.com
+OK
pass password
+OK logged in.

Log

"xxx.xxx.xxx.xxx 110" - - [31/Aug/2012:20:26:00 +0700] "GET /auth.php HTTP/1.0" 200 - "-" "Nginx POP3/IMAP4 proxy"

SSL/STARTTLS

openssl s_client -connect mail-proxy.example.com:993
---snip---
New, TLSv1/SSLv3, Cipher is DHE-RSA-AES256-SHA
Server public key is 4096 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
SSL-Session:
---snip---
    Start Time: 1346419294
    Timeout   : 300 (sec)
    Verify return code: 18 (self signed certificate)
---
* OK IMAP4 ready
. login user@example.com mypass
. OK LOGIN Ok.
. logout
* BYE Courier-IMAP server shutting down
. OK LOGOUT completed
closed

Log

"xxx.xxx.xxx.xxx 110" - - [31/Aug/2012:20:26:00 +0700] "GET /auth.php HTTP/1.0" 200 - "-" "Nginx POP3/IMAP4 proxy"

2 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *