feat: Add monitoring for X-Forwarded-For header length (#30090)

This commit is contained in:
Tim McCormack
2022-03-18 15:31:27 +00:00
committed by GitHub
parent 699afeb731
commit c3bc68abc1
3 changed files with 82 additions and 0 deletions

View File

@@ -3,7 +3,9 @@ Middleware to use the X-Forwarded-For header as the request IP.
Updated the libray to use HTTP_HOST and X-Forwarded-Port as
SERVER_NAME and SERVER_PORT.
"""
from django.utils.deprecation import MiddlewareMixin
from edx_django_utils.monitoring import set_custom_attribute
class XForwardedForMiddleware(MiddlewareMixin):
@@ -19,6 +21,11 @@ class XForwardedForMiddleware(MiddlewareMixin):
Process the given request, update the value of REMOTE_ADDR, SERVER_NAME and SERVER_PORT based
on X-Forwarded-For, HTTP_HOST and X-Forwarded-Port headers
"""
# Give some observability into X-Forwarded-For length. Useful
# for monitoring in case of unexpected changes, etc.
xff = request.META.get('HTTP_X_FORWARDED_FOR')
xff_len = xff.count(',') + 1 if xff else 0
set_custom_attribute('header.x-forwarded-for.count', xff_len)
for field, header in [("HTTP_X_FORWARDED_FOR", "REMOTE_ADDR"), ("HTTP_HOST", "SERVER_NAME"),
("HTTP_X_FORWARDED_PORT", "SERVER_PORT")]:

View File

@@ -0,0 +1,75 @@
"""
Tests for XForwardedForMiddleware.
"""
from unittest.mock import call, patch
import ddt
from django.test import TestCase
from django.test.client import RequestFactory
from openedx.core.lib.x_forwarded_for.middleware import XForwardedForMiddleware
@ddt.ddt
class TestXForwardedForMiddleware(TestCase):
"""Tests for middleware's overrides."""
@ddt.unpack
@ddt.data(
# With no added headers, just see the test server's defaults.
(
{},
{
'SERVER_NAME': 'testserver',
'SERVER_PORT': '80',
'REMOTE_ADDR': '127.0.0.1',
},
),
# With headers supplied by the request (Host) and a proxy
# (X-Forwarded-Port), see the name and port overridden.
(
{
'HTTP_HOST': 'example.com',
'HTTP_X_FORWARDED_PORT': '443',
},
{
'SERVER_NAME': 'example.com',
'SERVER_PORT': '443',
},
),
# REMOTE_ADDR can also be overridden
(
{'HTTP_X_FORWARDED_FOR': '7.8.9.0, 1.2.3.4'},
{
'REMOTE_ADDR': '7.8.9.0',
},
),
)
def test_overrides(self, add_meta, expected_meta_include):
"""
Test that parts of request.META can be overridden by HTTP headers.
"""
request = RequestFactory().get('/somewhere')
request.META.update(add_meta)
XForwardedForMiddleware().process_request(request)
assert request.META.items() >= expected_meta_include.items()
@ddt.unpack
@ddt.data(
(None, 0),
('1.2.3.4', 1),
('7.8.9.0, 1.2.3.4, 5.5.5.5', 3),
)
@patch("openedx.core.lib.x_forwarded_for.middleware.set_custom_attribute")
def test_xff_metrics(self, xff, expected_count, mock_set_custom_attribute):
request = RequestFactory().get('/somewhere')
if xff is not None:
request.META['HTTP_X_FORWARDED_FOR'] = xff
XForwardedForMiddleware().process_request(request)
mock_set_custom_attribute.assert_has_calls([call('header.x-forwarded-for.count', expected_count)])