2709: Validate proxy ip with PROXY_AUTH_WHITELIST r=mergify[bot] a=Diman0

## What type of PR?

bug fix

## What does this PR do?
The Proxy code validated the real client ip against the proxy auth whitelist. It should be the proxy ip that is checked. That is changed with this PR.

### Related issue(s)
- closes #2708
- #2692

## 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.

- [n/a] 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: Dimitri Huisman <diman@huisman.xyz>
main
bors[bot] 2 years ago committed by GitHub
commit 5044c78740
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -78,8 +78,8 @@ def logout():
Redirect to the url passed in parameter if any; Ensure that this is not an open-redirect too... Redirect to the url passed in parameter if any; Ensure that this is not an open-redirect too...
https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html
""" """
def _has_usable_redirect(): def _has_usable_redirect(is_proxied=False):
if 'homepage' in flask.request.url: if 'homepage' in flask.request.url and not is_proxied:
return None return None
if url := flask.request.args.get('url'): if url := flask.request.args.get('url'):
url = url_unquote(url) url = url_unquote(url)
@ -92,15 +92,16 @@ def _has_usable_redirect():
https://mailu.io/master/configuration.html#header-authentication-using-an-external-proxy https://mailu.io/master/configuration.html#header-authentication-using-an-external-proxy
""" """
def _proxy(): def _proxy():
ip = ipaddress.ip_address(flask.request.remote_addr) proxy_ip = flask.request.headers.get('X-Forwarded-By', flask.request.remote_addr)
ip = ipaddress.ip_address(proxy_ip)
if not any(ip in cidr for cidr in app.config['PROXY_AUTH_WHITELIST']): if not any(ip in cidr for cidr in app.config['PROXY_AUTH_WHITELIST']):
return flask.abort(500, '%s is not on PROXY_AUTH_WHITELIST' % flask.request.remote_addr) return flask.abort(500, '%s is not on PROXY_AUTH_WHITELIST' % proxy_ip)
email = flask.request.headers.get(app.config['PROXY_AUTH_HEADER']) email = flask.request.headers.get(app.config['PROXY_AUTH_HEADER'])
if not email: if not email:
return flask.abort(500, 'No %s header' % app.config['PROXY_AUTH_HEADER']) return flask.abort(500, 'No %s header' % app.config['PROXY_AUTH_HEADER'])
url = _has_usable_redirect() or app.config['WEB_ADMIN'] url = _has_usable_redirect(True) or app.config['WEB_ADMIN']
user = models.User.get(email) user = models.User.get(email)
if user: if user:

@ -231,6 +231,7 @@ http {
auth_request /internal/auth/admin; auth_request /internal/auth/admin;
proxy_set_header X-Real-IP ""; proxy_set_header X-Real-IP "";
proxy_set_header X-Forwarded-For ""; proxy_set_header X-Forwarded-For "";
proxy_set_header X-Forwarded-By: "";
proxy_pass http://$antispam; proxy_pass http://$antispam;
error_page 403 @sso_login; error_page 403 @sso_login;
} }

@ -7,8 +7,10 @@ proxy_hide_header CF-Connecting-IP;
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto; proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
{% if REAL_IP_HEADER and REAL_IP_FROM %} {% if REAL_IP_HEADER and REAL_IP_FROM %}
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-By $realip_remote_addr;
{% else %} {% else %}
proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-For $remote_addr;
proxy_hide_header X-Forwarded-By;
{% endif %} {% endif %}
proxy_http_version 1.1; proxy_http_version 1.1;
proxy_hide_header Forwarded; proxy_hide_header Forwarded;

@ -0,0 +1,3 @@
Proxy authentication was using the real client ip instead of the proxy
IP for checking the PROXY_AUTH_WHITELIST.
Loading…
Cancel
Save