"""Authenticatie: guard, CSRF, lockout en de trusted-proxy-header.""" import pytest from conftest import login def test_api_vereist_login(anon_client): r = anon_client.get("/api/stacks") assert r.status_code == 401 assert r.get_json()["needs_setup"] is True def test_index_en_healthz_zijn_publiek(anon_client): assert anon_client.get("/healthz").status_code == 200 assert anon_client.get("/").status_code == 200 def test_setup_maakt_account_en_kan_niet_herhaald_worden(anon_client): login(anon_client) r = anon_client.post("/api/auth/setup", json={"username": "tweede", "password": "hunter2hunter2"}) assert r.status_code == 409 def test_setup_weigert_kort_wachtwoord(anon_client): r = anon_client.post("/api/auth/setup", json={"username": "tester", "password": "kort"}) assert r.status_code == 400 assert "10 tekens" in r.get_json()["msg"] def test_login_en_logout(client): login(client) client.post("/api/auth/logout", json={}, headers={"X-CSRF-Token": _csrf(client)}) assert client.get("/api/stacks").status_code == 401 r = client.post("/api/auth/login", json={"username": "tester", "password": "hunter2hunter2"}) assert r.status_code == 200 assert client.get("/api/stacks").status_code == 200 def test_verkeerd_wachtwoord_wordt_geweigerd(client): login(client) client.post("/api/auth/logout", json={}, headers={"X-CSRF-Token": _csrf(client)}) r = client.post("/api/auth/login", json={"username": "tester", "password": "verkeerdverkeerd"}) assert r.status_code == 401 def test_lockout_na_herhaalde_pogingen(client): import core.auth as auth login(client) for _ in range(5): auth.check_login("tester", "foutfoutfout") ok, msg = auth.check_login("tester", "hunter2hunter2") assert not ok assert "Te veel mislukte pogingen" in msg def test_mutatie_zonder_csrf_token_wordt_geweigerd(client): login(client) r = client.post("/api/docker/restart", json={}) assert r.status_code == 403 assert "CSRF" in r.get_json()["msg"] def test_mutatie_met_verkeerd_csrf_token_wordt_geweigerd(client): login(client) r = client.post("/api/docker/restart", json={}, headers={"X-CSRF-Token": "niet-het-echte-token"}) assert r.status_code == 403 def test_state_wijzigende_routes_weigeren_get(client): """Zonder deze regel volstond op een willekeurige website om de container te herstarten.""" login(client) for path in ("/api/docker/restart", "/api/wizard/complete", "/api/wizard/reset", "/api/wizard/sync", "/api/repos/server-up/sync"): assert client.get(path).status_code == 405, path def test_proxy_header_alleen_vanaf_vertrouwd_ip(client, env): core = env["core"] import core.auth as auth a = auth.settings() a.update({"mode": "both", "proxy_header": "Remote-User", "trusted_proxies": ["10.9.9.9"]}) core.patch({"AUTH": a}) # Niet-vertrouwd bron-IP: header wordt genegeerd. r = client.get("/api/stacks", headers={"Remote-User": "indringer"}, environ_overrides={"REMOTE_ADDR": "10.1.1.1"}) assert r.status_code == 401 # Vertrouwde proxy: identiteit wordt geaccepteerd. r = client.get("/api/stacks", headers={"Remote-User": "collega"}, environ_overrides={"REMOTE_ADDR": "10.9.9.9"}) assert r.status_code == 200 def test_proxy_modus_vereist_trusted_proxies(client): csrf = login(client) r = client.put("/api/auth/mode", json={"mode": "proxy", "trusted_proxies": []}, headers={"X-CSRF-Token": csrf}) assert r.status_code == 400 def test_wachtwoordhash_is_niet_omkeerbaar(): import core.auth as auth rec = auth.hash_password("hunter2hunter2") assert "hunter2hunter2" not in str(rec) assert auth.verify_password("hunter2hunter2", rec) assert not auth.verify_password("hunter2hunter3", rec) def _csrf(client): return client.get("/api/auth/me").get_json()["csrf_token"]