1
0
mirror of https://github.com/Mailu/Mailu.git synced 2024-12-12 10:45:38 +02:00
3366: Fix #3364 r=mergify[bot] a=nextgens

## What type of PR?

bug-fix

## What does this PR do?

Fix a bug preventing percent characters from being used in passwords

### Related issue(s)
- closes #3364 

## Prerequisites
Before we can consider review and merge, please make sure the following list is done and checked.
If an entry in not applicable, you can check it or remove it from the list.

- [ ] In case of feature or enhancement: documentation updated accordingly
- [x] Unless it's docs or a minor change: add [changelog](https://mailu.io/master/contributors/workflow.html#changelog) entry file.


Co-authored-by: Florent Daigniere <nextgens@freenetproject.org>
This commit is contained in:
bors-mailu[bot] 2024-08-09 14:27:52 +00:00 committed by GitHub
commit b5106d4ce8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 22 additions and 24 deletions

View File

@ -91,20 +91,14 @@ def handle_authentication(headers):
# Authenticated user
elif method in ['plain', 'login']:
is_valid_user = False
# 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"])
user_email = 'invalid'
password = 'invalid'
try:
user_email = raw_user_email.encode("iso8859-1").decode("utf8")
password = raw_password.encode("iso8859-1").decode("utf8")
user_email = urllib.parse.unquote(headers["Auth-User"])
password = urllib.parse.unquote(headers["Auth-Pass"])
ip = urllib.parse.unquote(headers["Client-Ip"])
except:
app.logger.warn(f'Received undecodable user/password from nginx: {raw_user_email!r}/{raw_password!r}')
app.logger.warn(f'Received undecodable user/password from front: {headers.get("Auth-User", "")!r}')
else:
try:
user = models.User.query.get(user_email) if '@' in user_email else None

View File

@ -29,7 +29,6 @@ def nginx_authentication():
response.headers['Auth-Status'] = status
response.headers['Auth-Error-Code'] = code
return response
raw_password = urllib.parse.unquote(headers['Auth-Pass']) if 'Auth-Pass' in headers else ''
headers = nginx.handle_authentication(flask.request.headers)
response = flask.Response()
for key, value in headers.items():
@ -50,14 +49,8 @@ def nginx_authentication():
if not is_port_25:
utils.limiter.exempt_ip_from_ratelimits(client_ip)
elif is_valid_user:
password = None
try:
password = raw_password.encode("iso8859-1").decode("utf8")
except:
app.logger.warn(f'Received undecodable password for {username} from nginx: {raw_password!r}')
utils.limiter.rate_limit_user(username, client_ip, password=None)
else:
utils.limiter.rate_limit_user(username, client_ip, password=password)
password = urllib.parse.unquote(headers.get('Auth-Pass', ''))
utils.limiter.rate_limit_user(username, client_ip, password=password)
elif not is_from_webmail:
utils.limiter.rate_limit_ip(client_ip, username)
return response

View File

@ -10,18 +10,28 @@ local http_client = dovecot.http.client {
max_attempts = 3;
}
-- on the other end we use urllib.parse.unquote()
function urlEncode(str)
return str:gsub("[^%w_.-~]", function(c)
return string.format("%%%02X", string.byte(c))
end)
end
function auth_passdb_lookup(req)
local auth_request = http_client:request {
url = "http://{{ ADMIN_ADDRESS }}:8080/internal/auth/email";
}
auth_request:add_header('Auth-Port', req.local_port)
auth_request:add_header('Auth-User', req.user)
local user = urlEncode(req.user)
auth_request:add_header('Auth-User', user)
if req.password ~= nil
then
auth_request:add_header('Auth-Pass', req.password)
local password = urlEncode(req.password)
auth_request:add_header('Auth-Pass', password)
end
auth_request:add_header('Auth-Protocol', req.service)
auth_request:add_header('Client-IP', req.remote_ip)
local client_ip = urlEncode(req.remote_ip)
auth_request:add_header('Client-Ip', client_ip)
auth_request:add_header('Client-Port', req.remote_port)
auth_request:add_header('Auth-SSL', req.secured)
auth_request:add_header('Auth-Method', req.mechanism)

View File

@ -8,5 +8,5 @@ docker compose -f tests/compose/core/docker-compose.yml exec -T admin flask mail
docker compose -f tests/compose/core/docker-compose.yml exec -T admin flask mailu admin admin mailu.io 'password' --mode=update || exit 1
docker compose -f tests/compose/core/docker-compose.yml exec -T admin flask mailu user user mailu.io 'password' || exit 1
docker compose -f tests/compose/core/docker-compose.yml exec -T admin flask mailu user 'user/with/slash' mailu.io 'password' || exit 1
docker compose -f tests/compose/core/docker-compose.yml exec -T admin flask mailu user 'user_UTF8' mailu.io 'password€' || exit 1
docker compose -f tests/compose/core/docker-compose.yml exec -T admin flask mailu user 'user_UTF8' mailu.io 'pass%e9word€' || exit 1
echo "User testing successful!"

View File

@ -8,7 +8,7 @@ import managesieve
SERVER='localhost'
USERNAME='user_UTF8@mailu.io'
PASSWORD='password€'
PASSWORD='pass%e9word€'
#https://github.com/python/cpython/issues/73936
#SMTPlib does not support UTF8 passwords.
USERNAME_ASCII='user@mailu.io'
@ -139,4 +139,4 @@ if __name__ == '__main__':
test_SMTP(SERVER, USERNAME_ASCII, PASSWORD_ASCII)
test_managesieve(SERVER, USERNAME, PASSWORD)
#https://github.com/python/cpython/issues/73936
#SMTPlib does not support UTF8 passwords.
#SMTPlib does not support UTF8 passwords.

View File

@ -0,0 +1 @@
Fix a bug preventing percent characters from being used in passwords