Repository: Mailu/Mailu

Issue:
admin_1 errors in the logs
I'm seeing a lot of errors in the docker-compose logs:

```
admin_1      | 2018-09-06T03:27:32.130634316Z   File "/usr/local/lib/python3.7/site-packages/sqlalchemy/engine/default.py", line 667, in _init_compiled
admin_1      | 2018-09-06T03:27:32.130647067Z     param.append(processors[key](compiled_params[key]))
admin_1      | 2018-09-06T03:27:32.130651784Z   File "/usr/local/lib/python3.7/site-packages/sqlalchemy/sql/type_api.py", line 1160, in process
admin_1      | 2018-09-06T03:27:32.130656339Z     return process_param(value, dialect)
admin_1      | 2018-09-06T03:27:32.130660848Z   File "/app/mailu/models.py", line 38, in process_bind_param
admin_1      | 2018-09-06T03:27:32.130678553Z     localpart, domain_name = value.split('@')
admin_1      | 2018-09-06T03:27:32.130682552Z ValueError: not enough values to unpack (expected 2, got 1)
admin_1      | 2018-09-06T03:27:32.130686500Z 
admin_1      | 2018-09-06T03:27:32.130690498Z The above exception was the direct cause of the following exception:
admin_1      | 2018-09-06T03:27:32.130694402Z 
admin_1      | 2018-09-06T03:27:32.130698152Z Traceback (most recent call last):
admin_1      | 2018-09-06T03:27:32.130701929Z   File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1982, in wsgi_app
admin_1      | 2018-09-06T03:27:32.130706019Z     response = self.full_dispatch_request()
admin_1      | 2018-09-06T03:27:32.130728757Z   File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1614, in full_dispatch_request
admin_1      | 2018-09-06T03:27:32.130734376Z     rv = self.handle_user_exception(e)
admin_1      | 2018-09-06T03:27:32.130738349Z   File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1517, in handle_user_exception
admin_1      | 2018-09-06T03:27:32.130742416Z     reraise(exc_type, exc_value, tb)
admin_1      | 2018-09-06T03:27:32.130746585Z   File "/usr/local/lib/python3.7/site-packages/flask/_compat.py", line 33, in reraise
admin_1      | 2018-09-06T03:27:32.130750772Z     raise value
admin_1      | 2018-09-06T03:27:32.130754541Z   File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1612, in full_dispatch_request
admin_1      | 2018-09-06T03:27:32.130758592Z     rv = self.dispatch_request()
admin_1      | 2018-09-06T03:27:32.130762451Z   File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1598, in dispatch_request
admin_1      | 2018-09-06T03:27:32.130766443Z     return self.view_functions[rule.endpoint](**req.view_args)
admin_1      | 2018-09-06T03:27:32.130770363Z   File "/usr/local/lib/python3.7/site-packages/flask_limiter/extension.py", line 544, in __inner
admin_1      | 2018-09-06T03:27:32.130774389Z     return obj(*a, **k)
admin_1      | 2018-09-06T03:27:32.130778164Z   File "/app/mailu/internal/views.py", line 18, in nginx_authentication
admin_1      | 2018-09-06T03:27:32.130782201Z     headers = nginx.handle_authentication(flask.request.headers)
admin_1      | 2018-09-06T03:27:32.130785989Z   File "/app/mailu/internal/nginx.py", line 40, in handle_authentication
admin_1      | 2018-09-06T03:27:32.130789994Z     user = models.User.query.get(user_email)
admin_1      | 2018-09-06T03:27:32.130797166Z   File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/query.py", line 882, in get
admin_1      | 2018-09-06T03:27:32.130801365Z     ident, loading.load_on_ident)
admin_1      | 2018-09-06T03:27:32.130805123Z   File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/query.py", line 916, in _get_impl
admin_1      | 2018-09-06T03:27:32.130809141Z     return fallback_fn(self, key)
admin_1      | 2018-09-06T03:27:32.130812954Z   File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/loading.py", line 232, in load_on_ident
admin_1      | 2018-09-06T03:27:32.130817023Z     return q.one()
admin_1      | 2018-09-06T03:27:32.130820651Z   File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/query.py", line 2848, in one
admin_1      | 2018-09-06T03:27:32.130828433Z     ret = self.one_or_none()
admin_1      | 2018-09-06T03:27:32.130832204Z   File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/query.py", line 2818, in one_or_none
admin_1      | 2018-09-06T03:27:32.130836182Z     ret = list(self)
admin_1      | 2018-09-06T03:27:32.130839817Z   File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/query.py", line 2889, in __iter__
admin_1      | 2018-09-06T03:27:32.130843800Z     return self._execute_and_instances(context)
admin_1      | 2018-09-06T03:27:32.130847637Z   File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/query.py", line 2912, in _execute_and_instances
admin_1      | 2018-09-06T03:27:32.130851651Z     result = conn.execute(querycontext.statement, self._params)
admin_1      | 2018-09-06T03:27:32.130855429Z   File "/usr/local/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 948, in execute
admin_1      | 2018-09-06T03:27:32.130859405Z     return meth(self, multiparams, params)
admin_1      | 2018-09-06T03:27:32.130863160Z   File "/usr/local/lib/python3.7/site-packages/sqlalchemy/sql/elements.py", line 269, in _execute_on_connection
admin_1      | 2018-09-06T03:27:32.130867285Z     return connection._execute_clauseelement(self, multiparams, params)
admin_1      | 2018-09-06T03:27:32.130871120Z   File "/usr/local/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1060, in _execute_clauseelement
admin_1      | 2018-09-06T03:27:32.130875220Z     compiled_sql, distilled_params
admin_1      | 2018-09-06T03:27:32.130879000Z   File "/usr/local/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1132, in _execute_context
admin_1      | 2018-09-06T03:27:32.130883223Z     None, None)
admin_1      | 2018-09-06T03:27:32.130886963Z   File "/usr/local/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1413, in _handle_dbapi_exception
admin_1      | 2018-09-06T03:27:32.130891179Z     exc_info
admin_1      | 2018-09-06T03:27:32.130894835Z   File "/usr/local/lib/python3.7/site-packages/sqlalchemy/util/compat.py", line 203, in raise_from_cause
admin_1      | 2018-09-06T03:27:32.130898868Z     reraise(type(exception), exception, tb=exc_tb, cause=cause)
admin_1      | 2018-09-06T03:27:32.130902641Z   File "/usr/local/lib/python3.7/site-packages/sqlalchemy/util/compat.py", line 186, in reraise
admin_1      | 2018-09-06T03:27:32.130906662Z     raise value.with_traceback(tb)
admin_1      | 2018-09-06T03:27:32.130910358Z   File "/usr/local/lib/python3.7/site-packages/sqlalchemy/engine/base.py", line 1127, in _execute_context
admin_1      | 2018-09-06T03:27:32.130915002Z     context = constructor(dialect, self, conn, *args)
admin_1      | 2018-09-06T03:27:32.130918761Z   File "/usr/local/lib/python3.7/site-packages/sqlalchemy/engine/default.py", line 667, in _init_compiled
admin_1      | 2018-09-06T03:27:32.130922838Z     param.append(processors[key](compiled_params[key]))
admin_1      | 2018-09-06T03:27:32.130926576Z   File "/usr/local/lib/python3.7/site-packages/sqlalchemy/sql/type_api.py", line 1160, in process
admin_1      | 2018-09-06T03:27:32.130930646Z     return process_param(value, dialect)
admin_1      | 2018-09-06T03:27:32.130934389Z   File "/app/mailu/models.py", line 38, in process_bind_param
admin_1      | 2018-09-06T03:27:32.130938334Z     localpart, domain_name = value.split('@')
admin_1      | 2018-09-06T03:27:32.130949412Z sqlalchemy.exc.StatementError: (builtins.ValueError) not enough values to unpack (expected 2, got 1) [SQL: 'SELECT user.created_at AS user_created_at, user.updated_at AS user_updated_at, user.comment AS user_comment, user.localpart AS user_localpart, user.password AS user_password, user.quota_bytes AS user_quota_bytes, user.global_admin AS user_global_admin, user.enabled AS user_enabled, user.enable_imap AS user_enable_imap, user.enable_pop AS user_enable_pop, user.forward_enabled AS user_forward_enabled, user.forward_destination AS user_forward_destination, user.forward_keep AS user_forward_keep, user.reply_enabled AS user_reply_enabled, user.reply_subject AS user_reply_subject, user.reply_body AS user_reply_body, user.reply_enddate AS user_reply_enddate, user.displayed_name AS user_displayed_name, user.spam_enabled AS user_spam_enabled, user.spam_threshold AS user_spam_threshold, user.domain_name AS user_domain_name, user.email AS user_email \nFROM user \nWHERE user.email = ?'] [parameters: [{'%(140175638833808 param)s': 'scan'}]]
```



Discussion:
I have this error in my logs too.
It happens when bots try random logins. In your provided log they try the user "scan".

So I tested it with a manual connection to my mailu instance.  If I try to login with an account without domain I get the same log and the server response with an internal server error:
```
. OK completed
> a001 LOGIN joe password
* BAD internal server error
closed
```
If I try a username with domain (joe@example.com) I got the right response:
```
. OK completed
a001 LOGIN joe@example.com password
a001 NO Authentication credentials invalid
closed
```

So I think logins with user accounts without domain name cause the bug.

Resolving patch:
diff --git a/core/admin/mailu/models.py b/core/admin/mailu/models.py
--- a/core/admin/mailu/models.py
+++ b/core/admin/mailu/models.py
@@ -35,11 +35,14 @@ class IdnaEmail(db.TypeDecorator):
     impl = db.String(255, collation="NOCASE")
 
     def process_bind_param(self, value, dialect):
-        localpart, domain_name = value.split('@')
-        return "{0}@{1}".format(
-            localpart,
-            idna.encode(domain_name).decode('ascii'),
-        )
+        try:
+            localpart, domain_name = value.split('@')
+            return "{0}@{1}".format(
+                localpart,
+                idna.encode(domain_name).decode('ascii'),
+            )
+        except ValueError:
+            pass
 
     def process_result_value(self, value, dialect):
         localpart, domain_name = value.split('@')


Test patch: