Repository: Mailu/Mailu

Issue:
AUTH_RATELIMIT_IP not working on imap/pop3/smtp
## Environment & Versions
### Environment
 - [x] docker-compose
 - [x] kubernetes
 - [x] docker swarm (not tested)

### Versions
- 1.9

## Description
Currently, `AUTH_RATELIMIT_IP` seems to have no effect when logging in using imap/pop3/smtp.

## Replication Steps
1. Start a new (local) mailu server (no certs needed) using the web generator and set `AUTH_RATELIMIT_IP` to `3/hour`.
2. `telnet localhost 143` -> `login nobody@example.com PASSWORD`
3. repeat step 2 three times.

## Expected behaviour
On the last login, the server should respond with `. NO Temporary authentication failure (rate-limit)`.
Instead, it's possible to to repeat the login attempt, until `AUTH_RATELIMIT_USER` hits. 

## Additional information
When the user gets into `AUTH_RATELIMIT_IP` using the web interface, imap/pop3/smtp login attempts are stopped as expected.

## Logs
```
❯ telnet localhost 143
Telnet escape character is '^Q'.
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^Q'.
* OK IMAP4 ready
. login nobody@example.com PASSWORD
. NO Authentication credentials invalid
Connection closed by foreign host.
❯ telnet localhost 143
Telnet escape character is '^Q'.
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^Q'.
* OK IMAP4 ready
. login nobody@example.com PASSWORD
. NO Authentication credentials invalid
Connection closed by foreign host.
❯ telnet localhost 143
Telnet escape character is '^Q'.
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^Q'.
* OK IMAP4 ready
. login nobody@example.com PASSWORD
. NO Authentication credentials invalid
Connection closed by foreign host.
❯ telnet localhost 143
Telnet escape character is '^Q'.
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^Q'.
* OK IMAP4 ready
. login nobody@example.com PASSWORD
. NO Authentication credentials invalid
Connection closed by foreign host.
```

I'll provide a PR.


Discussion:

Resolving patch:
diff --git a/core/admin/mailu/internal/nginx.py b/core/admin/mailu/internal/nginx.py
--- a/core/admin/mailu/internal/nginx.py
+++ b/core/admin/mailu/internal/nginx.py
@@ -94,11 +94,11 @@ def handle_authentication(headers):
         else:
             try:
                 user = models.User.query.get(user_email) if '@' in user_email else None
-                is_valid_user = user is not None
             except sqlalchemy.exc.StatementError as exc:
                 exc = str(exc).split('\n', 1)[0]
                 app.logger.warn(f'Invalid user {user_email!r}: {exc}')
             else:
+                is_valid_user = user is not None
                 ip = urllib.parse.unquote(headers["Client-Ip"])
                 if check_credentials(user, password, ip, protocol, headers["Auth-Port"]):
                     server, port = get_server(headers["Auth-Protocol"], True)
diff --git a/core/admin/mailu/internal/views/auth.py b/core/admin/mailu/internal/views/auth.py
--- a/core/admin/mailu/internal/views/auth.py
+++ b/core/admin/mailu/internal/views/auth.py
@@ -32,7 +32,7 @@ def nginx_authentication():
     for key, value in headers.items():
         response.headers[key] = str(value)
     is_valid_user = False
-    if response.headers.get("Auth-User-Exists"):
+    if response.headers.get("Auth-User-Exists") == "True":
         username = response.headers["Auth-User"]
         if utils.limiter.should_rate_limit_user(username, client_ip):
             # FIXME could be done before handle_authentication()


Test patch: