# Nginx mail proxy module - unexpected behavior re: authentication

**URL:** <https://www.ruby-forum.com/t/nginx-mail-proxy-module-unexpected-behavior-re-authentication/185660>\
**Category:** NGINX\
**Created:** [March 24, 2010, 8:15am UTC](https://www.ruby-forum.com/t/nginx-mail-proxy-module-unexpected-behavior-re-authentication/185660 "2010-03-24T08:15:46Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Naresh\_V](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/c4cdca/32.png) [@Naresh\_V](https://www.ruby-forum.com/u/Naresh_V)\
**Post date:** [March 24, 2010, 8:15am UTC](https://www.ruby-forum.com/t/nginx-mail-proxy-module-unexpected-behavior-re-authentication/185660/1 "2010-03-24T08:15:46Z")

</div>

Hi,

I have a setup with me where I’m using nginx to talk to a redirector  
(embedded perl script) which redirects IMAP/POP communication to the  
appropriate IMAP/POP server based on a simple DB query that says “this  
user’s emails are on that IMAP server”.  
I’m not doing any authentication at this level since according to  
this[1] request-timeline diagram, the authentication request/response  
is done again with the actual IMAP server anyway.

When my IMAP client is trying to authenticate with legitimate username  
and password, nginx - as expected according to the diagram - delegates  
the “. login username@domain password” to the real IMAP server whose  
“. OK” is relayed back to the IMAP client by nginx.  
The problem I’m facing right now is when I provide the wrong password,  
IMAP server returns AUTHENTICATIONFAILED, but nginx thinks it’s an  
invalid response and cuts off the session with the IMAP client.

In nginx error log:

> 2010/03/23 14:43:53 [info] 12550#0: _29 upstream sent invalid response: "_ BAD internal server error" while reading response from upstream, client: xx.xx.xx.xx, server: 0.0.0.0:143, login: “username@domain”, upstream: yy.yy.yy.yy:143

an example telnet session:

[root@nginx ~]# telnet localhost 143  
Trying 127.0.0.1…  
Connected to 127.0.0.1.  
Escape character is ‘^]’.

- OK IMAP4 ready

- login username@domain wrongpassword

- BAD internal server error  
Connection closed by foreign host.  
[root@nginx ~]#

The behaviour I expect is:

[root@nginx ~]# telnet localhost 143  
Trying 127.0.0.1…  
Connected to 127.0.0.1.  
Escape character is ‘^]’.

- OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE  
AUTH=PLAIN AUTH=LOGIN] Dovecot ready.

- login username@domain wrongpassword
- NO [AUTHENTICATIONFAILED] Authentication failed.  
\<telnet session doesn’t close\>

How do I go about configuring nginx to support this?  
‘proxy\_pass\_error\_message on’ didn’t help.  
Where exactly do I look in the source to make the appropriate changes?

Thanks!  
-Naresh.

---

<div class="post-metadata">

**Author:** ![Naresh\_V](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/c4cdca/32.png) [@Naresh\_V](https://www.ruby-forum.com/u/Naresh_V)\
**Post date:** [March 24, 2010, 11:09am UTC](https://www.ruby-forum.com/t/nginx-mail-proxy-module-unexpected-behavior-re-authentication/185660/2 "2010-03-24T11:09:38Z")

</div>

Hello!

On Wed, Mar 24, 2010 at 12:45:13PM +0530, Naresh V wrote:

> the “. login username@domain password” to the real IMAP server whose  
> “. OK” is relayed back to the IMAP client by nginx.  
> The problem I’m facing right now is when I provide the wrong password,  
> IMAP server returns AUTHENTICATIONFAILED, but nginx thinks it’s an  
> invalid response and cuts off the session with the IMAP client.
> 
> In nginx error log:
> 
> > 2010/03/23 14:43:53 [info] 12550#0: _29 upstream sent invalid response: "_ BAD internal server error" while reading response from upstream, client: xx.xx.xx.xx, server: 0.0.0.0:143, login: “username@domain”, upstream: yy.yy.yy.yy:143

Well, you didn’t check password as auth\_http was expected to do,  
and this resulted in nginx complaining about internal error.  
Looks like expected behaviour for me.

> [root@nginx ~]#
> 
> - NO [AUTHENTICATIONFAILED] Authentication failed.  
> \<telnet session doesn’t close\>
> 
> How do I go about configuring nginx to support this?  
> ‘proxy\_pass\_error\_message on’ didn’t help.  
> Where exactly do I look in the source to make the appropriate changes?

In the scenario you suggest nginx does 2 “internal requests” to  
authenticate user: the one to find out it’s backend and one to  
check it’s password. As username client will use after failed  
authentication isn’t known it has to close backend connection  
anyway on failed authentication.

Moreover, in this mode it would be trivial to find out valid  
usernames via timing attack (even if you make sure that messages  
returned by auth\_http and backend match).

Not even talking about the fact that in this scenario you won’t be  
able to use CRAM-MD5/APOP authentication at all.

I believe checking password in auth\_http is fairy trivial and this  
is what should be done instead of an attempt to change the way how  
it works.

Maxim D.

---

<div class="post-metadata">

**Author:** ![Naresh\_V](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/n/c4cdca/32.png) [@Naresh\_V](https://www.ruby-forum.com/u/Naresh_V)\
**Post date:** [March 24, 2010, 11:45am UTC](https://www.ruby-forum.com/t/nginx-mail-proxy-module-unexpected-behavior-re-authentication/185660/3 "2010-03-24T11:45:56Z")

</div>

On 24 March 2010 15:38, Maxim D. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > is done again with the actual IMAP server anyway.
> > 
> > > 2010/03/23 14:43:53 [info] 12550#0: _29 upstream sent invalid response: "_ BAD internal server error" while reading response from upstream, client: xx.xx.xx.xx, server: 0.0.0.0:143, login: “username@domain”, upstream: yy.yy.yy.yy:143
> 
> Well, you didn’t check password as auth\_http was expected to do,  
> and this resulted in nginx complaining about internal error.  
> Looks like expected behaviour for me.

True. It was my mistake. I should’ve checked everything again. The  
“which IMAP server should this user be redirected to” check was  
failing because, unbeknownst to me, the DB where this query was  
running was modified (which I wasn’t aware of and wasn’t expecting).

Previously, I was getting:

2010/03/24 10:26:03 [info] 13356#0: \*14 upstream sent invalid  
response: “NO [AUTHENTICATIONFAILED] Authentication failed.”  
while reading response from upstream, client: xx.xx.xx.xx, server:  
0.0.0.0:143, login: “user@domain”, ups  
tream: yy.yy.yy.yy:143

> > [root@nginx ~]#
> > 
> > - NO [AUTHENTICATIONFAILED] Authentication failed.  
> > anyway on failed authentication.  
> > Yep, with the present architecture I think that’s to be expected.

(  
[![](http://mailman.nginx.org/pipermail/nginx/attachments/20090905/685e1310/attachment.png) ](http://mailman.nginx.org/pipermail/nginx/attachments/20090905/685e1310/attachment.png)  
)

> Moreover, in this mode it would be trivial to find out valid  
> usernames via timing attack (even if you make sure that messages  
> returned by auth\_http and backend match).

True. Also, this way nginx wouldn’t hold open connections for too long  
if this is the redirect imap-proxy for _many_ backend imapds.  
The telnet session with nginx closes on providing the wrong password  
after passing the right error message to me. Which seems like a good  
thing.

> Not even talking about the fact that in this scenario you won’t be  
> able to use CRAM-MD5/APOP authentication at all.
> 
> I believe checking password in auth\_http is fairy trivial and this  
> is what should be done instead of an attempt to change the way how  
> it works.

Since this problem I came here with is solved for now, I’ll stick to  
not doing any authentication at all at the nginx level for now.

Thanks a lot!

-Naresh
