From f70b63e54e4acd867778748498ea06f355211f3f Mon Sep 17 00:00:00 2001 From: Jiri Kozel Date: Mon, 25 Sep 2023 10:44:55 +0200 Subject: [PATCH] Read also X-Forwarded-Proto and -Host --- src/layman/util.py | 31 ++++++++++++++++++++++++++----- src/layman/util_test.py | 15 ++++++++++++++- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/layman/util.py b/src/layman/util.py index c625660e3..1469d0d41 100644 --- a/src/layman/util.py +++ b/src/layman/util.py @@ -59,22 +59,41 @@ def get(self): @dataclass(frozen=True) class XForwardedClass: - def __init__(self, *, prefix=None): + def __init__(self, *, proto=None, host=None, prefix=None): + object.__setattr__(self, '_proto', proto) + object.__setattr__(self, '_host', host) object.__setattr__(self, '_prefix', prefix) + @property + def proto(self): + # pylint: disable=no-member + return self._proto + + @property + def host(self): + # pylint: disable=no-member + return self._host + @property def prefix(self): # pylint: disable=no-member return self._prefix def __bool__(self): - return self.prefix is not None + return self.proto is not None and self.host is not None and self.prefix is not None def __eq__(self, other): - return isinstance(other, XForwardedClass) and self.prefix == other.prefix + return isinstance(other, XForwardedClass) \ + and self.proto == other.proto \ + and self.host == other.host \ + and self.prefix == other.prefix def __repr__(self): parts = [] + if self.proto is not None: + parts.append(('proto', json.dumps(self.proto))) + if self.host is not None: + parts.append(('host', json.dumps(self.host))) if self.prefix is not None: parts.append(('prefix', json.dumps(self.prefix))) parts_str = ', '.join(f"{key}={value}" for key, value in parts) @@ -578,8 +597,10 @@ def ensure_home_dir(): def get_x_forwarded_items(request_headers): - prefix = None + proto_key = 'X-Forwarded-Proto' + host_key = 'X-Forwarded-Host' prefix_key = 'X-Forwarded-Prefix' + prefix = None if prefix_key in request_headers: prefix = request_headers[prefix_key] if not re.match(CLIENT_PROXY_PATTERN, prefix): @@ -590,4 +611,4 @@ def get_x_forwarded_items(request_headers): 'found': prefix, } ) - return XForwardedClass(prefix=prefix) + return XForwardedClass(proto=request_headers.get(proto_key), host=request_headers.get(host_key), prefix=prefix) diff --git a/src/layman/util_test.py b/src/layman/util_test.py index 4eef42188..3f1892dde 100644 --- a/src/layman/util_test.py +++ b/src/layman/util_test.py @@ -139,7 +139,20 @@ def test__url_for(endpoint, internal, params, expected_url): @pytest.mark.parametrize('headers, exp_result', [ pytest.param({'X-Forwarded-Prefix': '/layman-proxy'}, util.XForwardedClass(prefix='/layman-proxy'), - id='simple_header'), + id='prefix_header'), + pytest.param({ + 'X-Forwarded-Proto': 'https', + 'X-Forwarded-Host': 'example.com', + 'X-Forwarded-Prefix': '/another-layman-proxy', + }, util.XForwardedClass(proto='https', host='example.com', prefix='/another-layman-proxy'), id='three_headers'), + pytest.param({ + 'X-Forwarded-Proto': 'https', + 'X-Forwarded-Prefix': '/another-layman-proxy', + }, util.XForwardedClass(proto='https', prefix='/another-layman-proxy'), id='proto_prefix_headers'), + pytest.param({ + 'X-Forwarded-Proto': 'https', + 'X-Forwarded-Host': 'example.com', + }, util.XForwardedClass(proto='https', host='example.com'), id='proto_host_headers'), pytest.param({}, util.XForwardedClass(), id='without_header'), ]) def test_get_x_forwarded_prefix(headers, exp_result):