From 65133a960af543687c00c09068cdbdf10c2f7ff1 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 28 Sep 2021 10:38:37 +0200 Subject: [PATCH] Prevent traceback when using non-email in login There's a traceback when the username used to log via SMTPAUTH in is not an email address: === before === ``` [...] ERROR in app: Exception on /internal/auth/email [GET] Traceback (most recent call last): File "/usr/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1179, in _execute_context context = constructor(dialect, self, conn, *args) File "/usr/lib/python3.9/site-packages/sqlalchemy/engine/default.py", line 719, in _init_compiled param.append(processors[key](compiled_params[key])) File "/usr/lib/python3.9/site-packages/sqlalchemy/sql/type_api.py", line 1201, in process return process_param(value, dialect) File "/app/mailu/models.py", line 60, in process_bind_param localpart, domain_name = value.lower().rsplit('@', 1) ValueError: not enough values to unpack (expected 2, got 1) [...] [parameters: [{'%(140657157923216 param)s': 'foobar'}]] ``` === after === ``` [...] WARNING in nginx: Invalid user 'foobar': (builtins.ValueError) invalid email address (no "@") ``` --- core/admin/mailu/internal/nginx.py | 23 ++++++++++++++--------- core/admin/mailu/models.py | 2 ++ 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/core/admin/mailu/internal/nginx.py b/core/admin/mailu/internal/nginx.py index 167341e2..f011bf5a 100644 --- a/core/admin/mailu/internal/nginx.py +++ b/core/admin/mailu/internal/nginx.py @@ -5,6 +5,7 @@ import re import urllib import ipaddress import socket +import sqlalchemy.exc import tenacity SUPPORTED_AUTH_METHODS = ["none", "plain"] @@ -90,15 +91,19 @@ def handle_authentication(headers): except: app.logger.warn(f'Received undecodable user/password from nginx: {raw_user_email!r}/{raw_password!r}') else: - user = models.User.query.get(user_email) - ip = urllib.parse.unquote(headers["Client-Ip"]) - if check_credentials(user, password, ip, protocol): - server, port = get_server(headers["Auth-Protocol"], True) - return { - "Auth-Status": "OK", - "Auth-Server": server, - "Auth-Port": port - } + try: + user = models.User.query.get(user_email) + except sqlalchemy.exc.StatementError as exc: + exc = str(exc).split('\n', 1)[0] + app.logger.warn(f'Invalid user {user_email!r}: {exc}') + else: + if check_credentials(user, password, urllib.parse.unquote(headers["Client-Ip"]), protocol): + server, port = get_server(headers["Auth-Protocol"], True) + return { + "Auth-Status": "OK", + "Auth-Server": server, + "Auth-Port": port + } status, code = get_status(protocol, "authentication") return { "Auth-Status": status, diff --git a/core/admin/mailu/models.py b/core/admin/mailu/models.py index f93b158f..01711a60 100644 --- a/core/admin/mailu/models.py +++ b/core/admin/mailu/models.py @@ -57,6 +57,8 @@ class IdnaEmail(db.TypeDecorator): def process_bind_param(self, value, dialect): """ encode unicode domain part of email address to punycode """ + if not '@' in value: + raise ValueError('invalid email address (no "@")') localpart, domain_name = value.lower().rsplit('@', 1) if '@' in localpart: raise ValueError('email local part must not contain "@"')