Accept the proxy user header only from trusted addresses
In proxy mode, each client that reached the port could send the user header. PROXY_AUTH_TRUSTED_IPS now lists the addresses and networks that can send it. The default is the loopback and private addresses, so a request that comes straight from the internet cannot log in.
This commit is contained in:
@@ -173,12 +173,57 @@ def test_proxy_header(client, monkeypatch):
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("trusted", "address", "accepted"),
|
||||
[
|
||||
(None, "127.0.0.1", True),
|
||||
(None, "::1", True),
|
||||
(None, "172.18.0.3", True),
|
||||
(None, "192.168.1.20", True),
|
||||
(None, "fd00::5", True),
|
||||
(None, "::ffff:10.1.2.3", True),
|
||||
(None, "203.0.113.9", False),
|
||||
(None, "2001:db8::1", False),
|
||||
(None, "", False),
|
||||
(["172.18.0.3"], "172.18.0.3", True),
|
||||
(["172.18.0.3"], "172.18.0.4", False),
|
||||
(["172.18.0.3"], "127.0.0.1", False),
|
||||
(["10.0.0.0/8", "fd00::/64"], "fd00::7", True),
|
||||
(["10.0.0.0/8", "fd00::/64"], "192.168.1.20", False),
|
||||
],
|
||||
)
|
||||
def test_only_a_trusted_address_can_send_the_proxy_header(client, monkeypatch, caplog, trusted, address, accepted):
|
||||
monkeypatch.setattr(config, "AUTH_METHOD", "proxy")
|
||||
if trusted is not None:
|
||||
monkeypatch.setattr(config, "PROXY_AUTH_TRUSTED_IPS", trusted)
|
||||
environ = {"REMOTE_ADDR": address}
|
||||
response = client.get("/api/stories", headers={"X-Remote-User": "alice"}, environ_base=environ)
|
||||
assert response.status_code == (200 if accepted else 401)
|
||||
assert (
|
||||
client.get("/api/auth/check", headers={"X-Remote-User": "alice"}, environ_base=environ).json["authenticated"]
|
||||
is accepted
|
||||
)
|
||||
assert ("which is not in PROXY_AUTH_TRUSTED_IPS" in caplog.text) is not accepted
|
||||
# A change needs the header too, from the same address.
|
||||
change = client.post(
|
||||
"/api/stories", json={"urls": []}, headers={**H, "X-Remote-User": "alice"}, environ_base=environ
|
||||
)
|
||||
assert change.status_code == (200 if accepted else 401)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("setting", "value", "error"),
|
||||
[
|
||||
("AUTH_METHOD", "cwa", "AUTH_METHOD=cwa needs CWA_URL or CWA_DB_PATH"),
|
||||
("AUTH_METHOD", "cwa-login", "AUTH_METHOD must be none, local, cwa or proxy, not 'cwa-login'"),
|
||||
("PROXY_AUTH_USER_HEADER", "", "AUTH_METHOD=proxy needs PROXY_AUTH_USER_HEADER"),
|
||||
("PROXY_AUTH_TRUSTED_IPS", [], "AUTH_METHOD=proxy needs PROXY_AUTH_TRUSTED_IPS, the addresses of the proxy"),
|
||||
(
|
||||
"PROXY_AUTH_TRUSTED_IPS",
|
||||
["10.0.0.5", "proxy.local"],
|
||||
"PROXY_AUTH_TRUSTED_IPS must be a list of addresses and networks: "
|
||||
"'proxy.local' does not appear to be an IPv4 or IPv6 network",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_incomplete_login_settings_refuse_every_request(client, monkeypatch, setting, value, error):
|
||||
|
||||
Reference in New Issue
Block a user