We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Insufficient input validation in  /internal endpoint
It seems like it is possible to crash a thread of flask by sending an invalid utf-8 username.
As far as i can see, this can not be used to gain access (should be validated).

Here are logs to reproduce this.

[error] 56#56: *1312970 auth http server 127.0.0.1:8000 did not send server or port while in http auth state, client: xx.xx.xx.xx, server: 0.0.0.0:25, login: "xxxxxxxxx\ufffdn@xxxx.xxxx"

GET /internal/auth/email HTTP/1.0" 500 290 "-" "-"

ERROR in app: Exception on /internal/auth/email [GET]
Traceback (most recent call last):
  File "/usr/lib/python3.7/site-packages/flask/app.py", line 2292, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/lib/python3.7/site-packages/flask/app.py", line 1815, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/lib/python3.7/site-packages/flask/app.py", line 1718, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/lib/python3.7/site-packages/flask/_compat.py", line 35, in reraise
    raise value
  File "/usr/lib/python3.7/site-packages/flask/app.py", line 1813, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/lib/python3.7/site-packages/flask/app.py", line 1799, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/usr/lib/python3.7/site-packages/flask_limiter/extension.py", line 544, in __inner
    return obj(*a, **k)
  File "/app/mailu/internal/views/auth.py", line 18, in nginx_authentication
    headers = nginx.handle_authentication(flask.request.headers)
  File "/app/mailu/internal/nginx.py", line 45, in handle_authentication
    user_email = raw_user_email.encode("iso8859-1").decode("utf8")
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xed in position 6: invalid continuation byte

xx.xx.xx.xx - - [xx/xx/xxxx:xx:xx:xx +0000] "GET /internal/auth/email HTTP/1.0" 500 290 "-" "-"


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `core/admin/mailu/internal/nginx.py`
Content:
```
1 from mailu import models
2 from flask import current_app as app
3 
4 import re
5 import urllib
6 import ipaddress
7 import socket
8 import tenacity
9 
10 SUPPORTED_AUTH_METHODS = ["none", "plain"]
11 
12 
13 STATUSES = {
14     "authentication": ("Authentication credentials invalid", {
15         "imap": "AUTHENTICATIONFAILED",
16         "smtp": "535 5.7.8",
17         "pop3": "-ERR Authentication failed"
18     }),
19     "encryption": ("Must issue a STARTTLS command first", {
20         "smtp": "530 5.7.0"
21     }),
22 }
23 
24 def check_credentials(user, password, ip, protocol=None):
25     if not user or not user.enabled or (protocol == "imap" and not user.enable_imap) or (protocol == "pop3" and not user.enable_pop):
26         return False
27     is_ok = False
28     # webmails
29     if len(password) == 64 and ip == app.config['WEBMAIL_ADDRESS']:
30         if user.verify_temp_token(password):
31             is_ok = True
32     # All tokens are 32 characters hex lowercase
33     if not is_ok and len(password) == 32:
34         for token in user.tokens:
35             if (token.check_password(password) and
36                 (not token.ip or token.ip == ip)):
37                     is_ok = True
38                     break
39     if not is_ok and user.check_password(password):
40         is_ok = True
41     return is_ok
42 
43 def handle_authentication(headers):
44     """ Handle an HTTP nginx authentication request
45     See: http://nginx.org/en/docs/mail/ngx_mail_auth_http_module.html#protocol
46     """
47     method = headers["Auth-Method"]
48     protocol = headers["Auth-Protocol"]
49     # Incoming mail, no authentication
50     if method == "none" and protocol == "smtp":
51         server, port = get_server(protocol, False)
52         if app.config["INBOUND_TLS_ENFORCE"]:
53             if "Auth-SSL" in headers and headers["Auth-SSL"] == "on":
54                 return {
55                     "Auth-Status": "OK",
56                     "Auth-Server": server,
57                     "Auth-Port": port
58                 }
59             else:
60                 status, code = get_status(protocol, "encryption")
61                 return {
62                     "Auth-Status": status,
63                     "Auth-Error-Code" : code,
64                     "Auth-Wait": 0
65                 }
66         else:
67             return {
68                 "Auth-Status": "OK",
69                 "Auth-Server": server,
70                 "Auth-Port": port
71             }
72     # Authenticated user
73     elif method == "plain":
74         server, port = get_server(headers["Auth-Protocol"], True)
75         # According to RFC2616 section 3.7.1 and PEP 3333, HTTP headers should
76         # be ASCII and are generally considered ISO8859-1. However when passing
77         # the password, nginx does not transcode the input UTF string, thus
78         # we need to manually decode.
79         raw_user_email = urllib.parse.unquote(headers["Auth-User"])
80         user_email = raw_user_email.encode("iso8859-1").decode("utf8")
81         raw_password = urllib.parse.unquote(headers["Auth-Pass"])
82         password = raw_password.encode("iso8859-1").decode("utf8")
83         ip = urllib.parse.unquote(headers["Client-Ip"])
84         service_port = int(urllib.parse.unquote(headers["Auth-Port"]))
85         if service_port == 25:
86             return {
87                 "Auth-Status": "AUTH not supported",
88                 "Auth-Error-Code": "502 5.5.1",
89                 "Auth-Wait": 0
90             }
91         user = models.User.query.get(user_email)
92         if check_credentials(user, password, ip, protocol):
93             return {
94                 "Auth-Status": "OK",
95                 "Auth-Server": server,
96                 "Auth-Port": port
97             }
98         else:
99             status, code = get_status(protocol, "authentication")
100             return {
101                 "Auth-Status": status,
102                 "Auth-Error-Code": code,
103                 "Auth-Wait": 0
104             }
105     # Unexpected
106     return {}
107 
108 
109 def get_status(protocol, status):
110     """ Return the proper error code depending on the protocol
111     """
112     status, codes = STATUSES[status]
113     return status, codes[protocol]
114 
115 def extract_host_port(host_and_port, default_port):
116     host, _, port = re.match('^(.*?)(:([0-9]*))?$', host_and_port).groups()
117     return host, int(port) if port else default_port
118 
119 def get_server(protocol, authenticated=False):
120     if protocol == "imap":
121         hostname, port = extract_host_port(app.config['IMAP_ADDRESS'], 143)
122     elif protocol == "pop3":
123         hostname, port = extract_host_port(app.config['POP3_ADDRESS'], 110)
124     elif protocol == "smtp":
125         if authenticated:
126             hostname, port = extract_host_port(app.config['AUTHSMTP_ADDRESS'], 10025)
127         else:
128             hostname, port = extract_host_port(app.config['SMTP_ADDRESS'], 25)
129     try:
130         # test if hostname is already resolved to an ip adddress
131         ipaddress.ip_address(hostname)
132     except:
133         # hostname is not an ip address - so we need to resolve it
134         hostname = resolve_hostname(hostname)
135     return hostname, port
136 
137 @tenacity.retry(stop=tenacity.stop_after_attempt(100),
138                 wait=tenacity.wait_random(min=2, max=5))
139 def resolve_hostname(hostname):
140     """ This function uses system DNS to resolve a hostname.
141     It is capable of retrying in case the host is not immediately available
142     """
143     return socket.gethostbyname(hostname)
144
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

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
@@ -71,16 +71,6 @@
             }
     # Authenticated user
     elif method == "plain":
-        server, port = get_server(headers["Auth-Protocol"], True)
-        # According to RFC2616 section 3.7.1 and PEP 3333, HTTP headers should
-        # be ASCII and are generally considered ISO8859-1. However when passing
-        # the password, nginx does not transcode the input UTF string, thus
-        # we need to manually decode.
-        raw_user_email = urllib.parse.unquote(headers["Auth-User"])
-        user_email = raw_user_email.encode("iso8859-1").decode("utf8")
-        raw_password = urllib.parse.unquote(headers["Auth-Pass"])
-        password = raw_password.encode("iso8859-1").decode("utf8")
-        ip = urllib.parse.unquote(headers["Client-Ip"])
         service_port = int(urllib.parse.unquote(headers["Auth-Port"]))
         if service_port == 25:
             return {
@@ -88,20 +78,33 @@
                 "Auth-Error-Code": "502 5.5.1",
                 "Auth-Wait": 0
             }
-        user = models.User.query.get(user_email)
-        if check_credentials(user, password, ip, protocol):
-            return {
-                "Auth-Status": "OK",
-                "Auth-Server": server,
-                "Auth-Port": port
-            }
+        # According to RFC2616 section 3.7.1 and PEP 3333, HTTP headers should
+        # be ASCII and are generally considered ISO8859-1. However when passing
+        # the password, nginx does not transcode the input UTF string, thus
+        # we need to manually decode.
+        raw_user_email = urllib.parse.unquote(headers["Auth-User"])
+        raw_password = urllib.parse.unquote(headers["Auth-Pass"])
+        try:
+            user_email = raw_user_email.encode("iso8859-1").decode("utf8")
+            password = raw_password.encode("iso8859-1").decode("utf8")
+        except:
+            app.logger.warn(f'Received undecodable user/password from nginx: {raw_user_email!r}/{raw_password!r}')
         else:
-            status, code = get_status(protocol, "authentication")
-            return {
-                "Auth-Status": status,
-                "Auth-Error-Code": code,
-                "Auth-Wait": 0
-            }
+            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
+                }
+        status, code = get_status(protocol, "authentication")
+        return {
+            "Auth-Status": status,
+            "Auth-Error-Code": code,
+            "Auth-Wait": 0
+        }
     # Unexpected
     return {}

{"golden_diff": "diff --git a/core/admin/mailu/internal/nginx.py b/core/admin/mailu/internal/nginx.py\n--- a/core/admin/mailu/internal/nginx.py\n+++ b/core/admin/mailu/internal/nginx.py\n@@ -71,16 +71,6 @@\n             }\n     # Authenticated user\n     elif method == \"plain\":\n-        server, port = get_server(headers[\"Auth-Protocol\"], True)\n-        # According to RFC2616 section 3.7.1 and PEP 3333, HTTP headers should\n-        # be ASCII and are generally considered ISO8859-1. However when passing\n-        # the password, nginx does not transcode the input UTF string, thus\n-        # we need to manually decode.\n-        raw_user_email = urllib.parse.unquote(headers[\"Auth-User\"])\n-        user_email = raw_user_email.encode(\"iso8859-1\").decode(\"utf8\")\n-        raw_password = urllib.parse.unquote(headers[\"Auth-Pass\"])\n-        password = raw_password.encode(\"iso8859-1\").decode(\"utf8\")\n-        ip = urllib.parse.unquote(headers[\"Client-Ip\"])\n         service_port = int(urllib.parse.unquote(headers[\"Auth-Port\"]))\n         if service_port == 25:\n             return {\n@@ -88,20 +78,33 @@\n                 \"Auth-Error-Code\": \"502 5.5.1\",\n                 \"Auth-Wait\": 0\n             }\n-        user = models.User.query.get(user_email)\n-        if check_credentials(user, password, ip, protocol):\n-            return {\n-                \"Auth-Status\": \"OK\",\n-                \"Auth-Server\": server,\n-                \"Auth-Port\": port\n-            }\n+        # According to RFC2616 section 3.7.1 and PEP 3333, HTTP headers should\n+        # be ASCII and are generally considered ISO8859-1. However when passing\n+        # the password, nginx does not transcode the input UTF string, thus\n+        # we need to manually decode.\n+        raw_user_email = urllib.parse.unquote(headers[\"Auth-User\"])\n+        raw_password = urllib.parse.unquote(headers[\"Auth-Pass\"])\n+        try:\n+            user_email = raw_user_email.encode(\"iso8859-1\").decode(\"utf8\")\n+            password = raw_password.encode(\"iso8859-1\").decode(\"utf8\")\n+        except:\n+            app.logger.warn(f'Received undecodable user/password from nginx: {raw_user_email!r}/{raw_password!r}')\n         else:\n-            status, code = get_status(protocol, \"authentication\")\n-            return {\n-                \"Auth-Status\": status,\n-                \"Auth-Error-Code\": code,\n-                \"Auth-Wait\": 0\n-            }\n+            user = models.User.query.get(user_email)\n+            ip = urllib.parse.unquote(headers[\"Client-Ip\"])\n+            if check_credentials(user, password, ip, protocol):\n+                server, port = get_server(headers[\"Auth-Protocol\"], True)\n+                return {\n+                    \"Auth-Status\": \"OK\",\n+                    \"Auth-Server\": server,\n+                    \"Auth-Port\": port\n+                }\n+        status, code = get_status(protocol, \"authentication\")\n+        return {\n+            \"Auth-Status\": status,\n+            \"Auth-Error-Code\": code,\n+            \"Auth-Wait\": 0\n+        }\n     # Unexpected\n     return {}\n", "issue": "Insufficient input validation in  /internal endpoint\nIt seems like it is possible to crash a thread of flask by sending an invalid utf-8 username.\r\nAs far as i can see, this can not be used to gain access (should be validated).\r\n\r\nHere are logs to reproduce this.\r\n\r\n[error] 56#56: *1312970 auth http server 127.0.0.1:8000 did not send server or port while in http auth state, client: xx.xx.xx.xx, server: 0.0.0.0:25, login: \"xxxxxxxxx\\ufffdn@xxxx.xxxx\"\r\n\r\nGET /internal/auth/email HTTP/1.0\" 500 290 \"-\" \"-\"\r\n\r\nERROR in app: Exception on /internal/auth/email [GET]\r\nTraceback (most recent call last):\r\n  File \"/usr/lib/python3.7/site-packages/flask/app.py\", line 2292, in wsgi_app\r\n    response = self.full_dispatch_request()\r\n  File \"/usr/lib/python3.7/site-packages/flask/app.py\", line 1815, in full_dispatch_request\r\n    rv = self.handle_user_exception(e)\r\n  File \"/usr/lib/python3.7/site-packages/flask/app.py\", line 1718, in handle_user_exception\r\n    reraise(exc_type, exc_value, tb)\r\n  File \"/usr/lib/python3.7/site-packages/flask/_compat.py\", line 35, in reraise\r\n    raise value\r\n  File \"/usr/lib/python3.7/site-packages/flask/app.py\", line 1813, in full_dispatch_request\r\n    rv = self.dispatch_request()\r\n  File \"/usr/lib/python3.7/site-packages/flask/app.py\", line 1799, in dispatch_request\r\n    return self.view_functions[rule.endpoint](**req.view_args)\r\n  File \"/usr/lib/python3.7/site-packages/flask_limiter/extension.py\", line 544, in __inner\r\n    return obj(*a, **k)\r\n  File \"/app/mailu/internal/views/auth.py\", line 18, in nginx_authentication\r\n    headers = nginx.handle_authentication(flask.request.headers)\r\n  File \"/app/mailu/internal/nginx.py\", line 45, in handle_authentication\r\n    user_email = raw_user_email.encode(\"iso8859-1\").decode(\"utf8\")\r\nUnicodeDecodeError: 'utf-8' codec can't decode byte 0xed in position 6: invalid continuation byte\r\n\r\nxx.xx.xx.xx - - [xx/xx/xxxx:xx:xx:xx +0000] \"GET /internal/auth/email HTTP/1.0\" 500 290 \"-\" \"-\"\r\n\n", "before_files": [{"content": "from mailu import models\nfrom flask import current_app as app\n\nimport re\nimport urllib\nimport ipaddress\nimport socket\nimport tenacity\n\nSUPPORTED_AUTH_METHODS = [\"none\", \"plain\"]\n\n\nSTATUSES = {\n    \"authentication\": (\"Authentication credentials invalid\", {\n        \"imap\": \"AUTHENTICATIONFAILED\",\n        \"smtp\": \"535 5.7.8\",\n        \"pop3\": \"-ERR Authentication failed\"\n    }),\n    \"encryption\": (\"Must issue a STARTTLS command first\", {\n        \"smtp\": \"530 5.7.0\"\n    }),\n}\n\ndef check_credentials(user, password, ip, protocol=None):\n    if not user or not user.enabled or (protocol == \"imap\" and not user.enable_imap) or (protocol == \"pop3\" and not user.enable_pop):\n        return False\n    is_ok = False\n    # webmails\n    if len(password) == 64 and ip == app.config['WEBMAIL_ADDRESS']:\n        if user.verify_temp_token(password):\n            is_ok = True\n    # All tokens are 32 characters hex lowercase\n    if not is_ok and len(password) == 32:\n        for token in user.tokens:\n            if (token.check_password(password) and\n                (not token.ip or token.ip == ip)):\n                    is_ok = True\n                    break\n    if not is_ok and user.check_password(password):\n        is_ok = True\n    return is_ok\n\ndef handle_authentication(headers):\n    \"\"\" Handle an HTTP nginx authentication request\n    See: http://nginx.org/en/docs/mail/ngx_mail_auth_http_module.html#protocol\n    \"\"\"\n    method = headers[\"Auth-Method\"]\n    protocol = headers[\"Auth-Protocol\"]\n    # Incoming mail, no authentication\n    if method == \"none\" and protocol == \"smtp\":\n        server, port = get_server(protocol, False)\n        if app.config[\"INBOUND_TLS_ENFORCE\"]:\n            if \"Auth-SSL\" in headers and headers[\"Auth-SSL\"] == \"on\":\n                return {\n                    \"Auth-Status\": \"OK\",\n                    \"Auth-Server\": server,\n                    \"Auth-Port\": port\n                }\n            else:\n                status, code = get_status(protocol, \"encryption\")\n                return {\n                    \"Auth-Status\": status,\n                    \"Auth-Error-Code\" : code,\n                    \"Auth-Wait\": 0\n                }\n        else:\n            return {\n                \"Auth-Status\": \"OK\",\n                \"Auth-Server\": server,\n                \"Auth-Port\": port\n            }\n    # Authenticated user\n    elif method == \"plain\":\n        server, port = get_server(headers[\"Auth-Protocol\"], True)\n        # According to RFC2616 section 3.7.1 and PEP 3333, HTTP headers should\n        # be ASCII and are generally considered ISO8859-1. However when passing\n        # the password, nginx does not transcode the input UTF string, thus\n        # we need to manually decode.\n        raw_user_email = urllib.parse.unquote(headers[\"Auth-User\"])\n        user_email = raw_user_email.encode(\"iso8859-1\").decode(\"utf8\")\n        raw_password = urllib.parse.unquote(headers[\"Auth-Pass\"])\n        password = raw_password.encode(\"iso8859-1\").decode(\"utf8\")\n        ip = urllib.parse.unquote(headers[\"Client-Ip\"])\n        service_port = int(urllib.parse.unquote(headers[\"Auth-Port\"]))\n        if service_port == 25:\n            return {\n                \"Auth-Status\": \"AUTH not supported\",\n                \"Auth-Error-Code\": \"502 5.5.1\",\n                \"Auth-Wait\": 0\n            }\n        user = models.User.query.get(user_email)\n        if check_credentials(user, password, ip, protocol):\n            return {\n                \"Auth-Status\": \"OK\",\n                \"Auth-Server\": server,\n                \"Auth-Port\": port\n            }\n        else:\n            status, code = get_status(protocol, \"authentication\")\n            return {\n                \"Auth-Status\": status,\n                \"Auth-Error-Code\": code,\n                \"Auth-Wait\": 0\n            }\n    # Unexpected\n    return {}\n\n\ndef get_status(protocol, status):\n    \"\"\" Return the proper error code depending on the protocol\n    \"\"\"\n    status, codes = STATUSES[status]\n    return status, codes[protocol]\n\ndef extract_host_port(host_and_port, default_port):\n    host, _, port = re.match('^(.*?)(:([0-9]*))?$', host_and_port).groups()\n    return host, int(port) if port else default_port\n\ndef get_server(protocol, authenticated=False):\n    if protocol == \"imap\":\n        hostname, port = extract_host_port(app.config['IMAP_ADDRESS'], 143)\n    elif protocol == \"pop3\":\n        hostname, port = extract_host_port(app.config['POP3_ADDRESS'], 110)\n    elif protocol == \"smtp\":\n        if authenticated:\n            hostname, port = extract_host_port(app.config['AUTHSMTP_ADDRESS'], 10025)\n        else:\n            hostname, port = extract_host_port(app.config['SMTP_ADDRESS'], 25)\n    try:\n        # test if hostname is already resolved to an ip adddress\n        ipaddress.ip_address(hostname)\n    except:\n        # hostname is not an ip address - so we need to resolve it\n        hostname = resolve_hostname(hostname)\n    return hostname, port\n\n@tenacity.retry(stop=tenacity.stop_after_attempt(100),\n                wait=tenacity.wait_random(min=2, max=5))\ndef resolve_hostname(hostname):\n    \"\"\" This function uses system DNS to resolve a hostname.\n    It is capable of retrying in case the host is not immediately available\n    \"\"\"\n    return socket.gethostbyname(hostname)\n", "path": "core/admin/mailu/internal/nginx.py"}], "after_files": [{"content": "from mailu import models\nfrom flask import current_app as app\n\nimport re\nimport urllib\nimport ipaddress\nimport socket\nimport tenacity\n\nSUPPORTED_AUTH_METHODS = [\"none\", \"plain\"]\n\n\nSTATUSES = {\n    \"authentication\": (\"Authentication credentials invalid\", {\n        \"imap\": \"AUTHENTICATIONFAILED\",\n        \"smtp\": \"535 5.7.8\",\n        \"pop3\": \"-ERR Authentication failed\"\n    }),\n    \"encryption\": (\"Must issue a STARTTLS command first\", {\n        \"smtp\": \"530 5.7.0\"\n    }),\n}\n\ndef check_credentials(user, password, ip, protocol=None):\n    if not user or not user.enabled or (protocol == \"imap\" and not user.enable_imap) or (protocol == \"pop3\" and not user.enable_pop):\n        return False\n    is_ok = False\n    # webmails\n    if len(password) == 64 and ip == app.config['WEBMAIL_ADDRESS']:\n        if user.verify_temp_token(password):\n            is_ok = True\n    # All tokens are 32 characters hex lowercase\n    if not is_ok and len(password) == 32:\n        for token in user.tokens:\n            if (token.check_password(password) and\n                (not token.ip or token.ip == ip)):\n                    is_ok = True\n                    break\n    if not is_ok and user.check_password(password):\n        is_ok = True\n    return is_ok\n\ndef handle_authentication(headers):\n    \"\"\" Handle an HTTP nginx authentication request\n    See: http://nginx.org/en/docs/mail/ngx_mail_auth_http_module.html#protocol\n    \"\"\"\n    method = headers[\"Auth-Method\"]\n    protocol = headers[\"Auth-Protocol\"]\n    # Incoming mail, no authentication\n    if method == \"none\" and protocol == \"smtp\":\n        server, port = get_server(protocol, False)\n        if app.config[\"INBOUND_TLS_ENFORCE\"]:\n            if \"Auth-SSL\" in headers and headers[\"Auth-SSL\"] == \"on\":\n                return {\n                    \"Auth-Status\": \"OK\",\n                    \"Auth-Server\": server,\n                    \"Auth-Port\": port\n                }\n            else:\n                status, code = get_status(protocol, \"encryption\")\n                return {\n                    \"Auth-Status\": status,\n                    \"Auth-Error-Code\" : code,\n                    \"Auth-Wait\": 0\n                }\n        else:\n            return {\n                \"Auth-Status\": \"OK\",\n                \"Auth-Server\": server,\n                \"Auth-Port\": port\n            }\n    # Authenticated user\n    elif method == \"plain\":\n        service_port = int(urllib.parse.unquote(headers[\"Auth-Port\"]))\n        if service_port == 25:\n            return {\n                \"Auth-Status\": \"AUTH not supported\",\n                \"Auth-Error-Code\": \"502 5.5.1\",\n                \"Auth-Wait\": 0\n            }\n        # According to RFC2616 section 3.7.1 and PEP 3333, HTTP headers should\n        # be ASCII and are generally considered ISO8859-1. However when passing\n        # the password, nginx does not transcode the input UTF string, thus\n        # we need to manually decode.\n        raw_user_email = urllib.parse.unquote(headers[\"Auth-User\"])\n        raw_password = urllib.parse.unquote(headers[\"Auth-Pass\"])\n        try:\n            user_email = raw_user_email.encode(\"iso8859-1\").decode(\"utf8\")\n            password = raw_password.encode(\"iso8859-1\").decode(\"utf8\")\n        except:\n            app.logger.warn(f'Received undecodable user/password from nginx: {raw_user_email!r}/{raw_password!r}')\n        else:\n            user = models.User.query.get(user_email)\n            ip = urllib.parse.unquote(headers[\"Client-Ip\"])\n            if check_credentials(user, password, ip, protocol):\n                server, port = get_server(headers[\"Auth-Protocol\"], True)\n                return {\n                    \"Auth-Status\": \"OK\",\n                    \"Auth-Server\": server,\n                    \"Auth-Port\": port\n                }\n        status, code = get_status(protocol, \"authentication\")\n        return {\n            \"Auth-Status\": status,\n            \"Auth-Error-Code\": code,\n            \"Auth-Wait\": 0\n        }\n    # Unexpected\n    return {}\n\n\ndef get_status(protocol, status):\n    \"\"\" Return the proper error code depending on the protocol\n    \"\"\"\n    status, codes = STATUSES[status]\n    return status, codes[protocol]\n\ndef extract_host_port(host_and_port, default_port):\n    host, _, port = re.match('^(.*?)(:([0-9]*))?$', host_and_port).groups()\n    return host, int(port) if port else default_port\n\ndef get_server(protocol, authenticated=False):\n    if protocol == \"imap\":\n        hostname, port = extract_host_port(app.config['IMAP_ADDRESS'], 143)\n    elif protocol == \"pop3\":\n        hostname, port = extract_host_port(app.config['POP3_ADDRESS'], 110)\n    elif protocol == \"smtp\":\n        if authenticated:\n            hostname, port = extract_host_port(app.config['AUTHSMTP_ADDRESS'], 10025)\n        else:\n            hostname, port = extract_host_port(app.config['SMTP_ADDRESS'], 25)\n    try:\n        # test if hostname is already resolved to an ip adddress\n        ipaddress.ip_address(hostname)\n    except:\n        # hostname is not an ip address - so we need to resolve it\n        hostname = resolve_hostname(hostname)\n    return hostname, port\n\n@tenacity.retry(stop=tenacity.stop_after_attempt(100),\n                wait=tenacity.wait_random(min=2, max=5))\ndef resolve_hostname(hostname):\n    \"\"\" This function uses system DNS to resolve a hostname.\n    It is capable of retrying in case the host is not immediately available\n    \"\"\"\n    return socket.gethostbyname(hostname)\n", "path": "core/admin/mailu/internal/nginx.py"}]}