middleware: handle X-Real-IP in xforwardedfor (#79390)
gitea/hobo/pipeline/head This commit looks good Details

This commit is contained in:
Thomas NOËL 2023-07-05 10:47:48 +02:00 committed by Thomas NOËL
parent c10c7a3919
commit bc2fc251ba
3 changed files with 40 additions and 8 deletions

View File

@ -418,6 +418,10 @@ HOBO_ANONYMOUS_SERVICE_USER_CLASS = 'hobo.rest_authentication.AnonymousAdminServ
THEMES_DIRECTORY = '/usr/share/publik/themes/'
# xforwardedfor middleware configuration
# create request.META['REMOTE_ADDR'] from X-Forwarded-For header
USE_X_FORWARDED_FOR = True
# headers to be used (only ('X-Forwarded-For',) if empty)
USE_X_FORWARDED_FOR_HEADERS = ('X-Real-IP', 'X-Forwarded-For')
EMAIL_BACKEND = 'hobo.emails.backend.EmailBackend'

View File

@ -3,15 +3,22 @@ from django.utils.deprecation import MiddlewareMixin
class XForwardedForMiddleware(MiddlewareMixin):
"""Copy the first address from X-Forwarded-For header to the REMOTE_ADDR meta.
"""If settings.USE_X_FORWARDED_FOR is True, copy the first address from
X-Forwarded-For header to the REMOTE_ADDR meta.
This middleware should only be used if you are sure the header cannot be
Other headers can be used with USE_X_FORWARDED_FOR_HEADERS settings.
This middleware should only be used if you are sure the headers cannot be
forged (behind a reverse proxy for example)."""
def process_request(self, request):
if getattr(settings, 'USE_X_FORWARDED_FOR', False):
if 'x-forwarded-for' in request.headers:
ip = request.headers.get('X-Forwarded-For', '').split(",")[0].strip()
if not getattr(settings, 'USE_X_FORWARDED_FOR', False):
return None
headers = getattr(settings, 'USE_X_FORWARDED_FOR_HEADERS', None) or ('X-Forwarded-For',)
for header in headers:
if header in request.headers:
ip = request.headers.get(header, '').split(",")[0].strip()
if ip:
request.META['REMOTE_ADDR'] = ip
break
return None

View File

@ -3,16 +3,37 @@ from django.db import connection
def test_xforwardedfor(settings, tenants, client):
settings.USE_X_FORWARDED_FOR = True
settings.USE_X_FORWARDED_FOR_HEADERS = None
for tenant in tenants:
settings.ALLOWED_HOSTS.append(tenant.domain_url)
response = client.get(
'/', SERVER_NAME=tenant.domain_url, HTTP_X_FORWARDED_FOR='99.99.99.99, 127.0.0.1'
'/',
SERVER_NAME=tenant.domain_url,
HTTP_X_FORWARDED_FOR='99.99.99.99, 127.0.0.1',
HTTP_X_REAL_IP='5.6.7.8',
)
assert '99.99.99.99' in response.content.decode()
connection.set_schema_to_public()
settings.USE_X_FORWARDED_FOR_HEADERS = ('X-Real-IP', 'X-Forwarded-For')
for tenant in tenants:
response = client.get(
'/',
SERVER_NAME=tenant.domain_url,
HTTP_X_FORWARDED_FOR='99.99.99.99, 127.0.0.1',
HTTP_X_REAL_IP='5.6.7.8',
)
assert '5.6.7.8' in response.content.decode()
connection.set_schema_to_public()
settings.USE_X_FORWARDED_FOR = False
for tenant in tenants:
response = client.get(
'/', SERVER_NAME=tenant.domain_url, HTTP_X_FORWARDED_FOR='99.99.99.99, 127.0.0.1'
'/',
SERVER_NAME=tenant.domain_url,
HTTP_X_FORWARDED_FOR='99.99.99.99, 127.0.0.1',
HTTP_X_REAL_IP='5.6.7.8',
)
assert not '99.99.99.99' in response.content.decode()
assert '99.99.99.99' not in response.content.decode()
assert '5.6.7.8' not in response.content.decode()
connection.set_schema_to_public()