"""Rollen: admin mag alles, operator beheert stacks, viewer leest alleen.""" import pytest from conftest import login def _maak(client, csrf, naam, rol, wachtwoord="eenlangwachtwoord"): r = client.post("/api/auth/users", json={"username": naam, "password": wachtwoord, "role": rol}, headers={"X-CSRF-Token": csrf}) assert r.status_code == 200, r.get_json() def _login_als(client, naam, wachtwoord="eenlangwachtwoord") -> str: r = client.post("/api/auth/login", json={"username": naam, "password": wachtwoord}) assert r.status_code == 200, r.get_json() return r.get_json()["csrf_token"] def test_eerste_account_is_beheerder(client): login(client) assert client.get("/api/auth/me").get_json()["role"] == "admin" def test_bestaand_account_zonder_rol_geldt_als_beheerder(client, env): """Accounts van vóór deze versie hebben geen `role`-veld.""" login(client) import core.auth as auth a = auth.settings() a["users"]["tester"].pop("role", None) env["core"].patch({"AUTH": a}) assert auth.role_of("tester") == "admin" def test_viewer_mag_lezen_maar_niets_wijzigen(client): csrf = login(client) _maak(client, csrf, "kijker", "viewer") kijker_csrf = _login_als(client, "kijker") assert client.get("/api/stacks").status_code == 200 assert client.get("/api/auth/me").get_json()["role"] == "viewer" r = client.post("/api/stacks/web/start", headers={"X-CSRF-Token": kijker_csrf}) assert r.status_code == 403 assert "rol" in r.get_json()["msg"] def test_operator_mag_stacks_maar_geen_instellingen(client): csrf = login(client) _maak(client, csrf, "beheerder2", "operator") op_csrf = _login_als(client, "beheerder2") # Stackacties mogen: 404 betekent 'route bereikt, stack bestaat niet'. r = client.post("/api/stacks/web/start", headers={"X-CSRF-Token": op_csrf}) assert r.status_code != 403 # Instellingen niet. for pad, methode in (("/api/settings", "put"), ("/api/networks", "post"), ("/api/auth/users", "post"), ("/api/repos", "post"), ("/api/docker/restart", "post")): r = getattr(client, methode)(pad, json={}, headers={"X-CSRF-Token": op_csrf}) assert r.status_code == 403, f"{methode.upper()} {pad} → {r.status_code}" def test_operator_mag_backups_maken_en_terugzetten(client): csrf = login(client) _maak(client, csrf, "op", "operator") op_csrf = _login_als(client, "op") r = client.post("/api/backups/web/create", headers={"X-CSRF-Token": op_csrf}) assert r.status_code != 403 def test_iedereen_mag_eigen_wachtwoord_wijzigen(client): csrf = login(client) _maak(client, csrf, "kijker", "viewer") kijker_csrf = _login_als(client, "kijker") r = client.post("/api/auth/password", json={"current": "eenlangwachtwoord", "new": "nogeenlangwachtwoord"}, headers={"X-CSRF-Token": kijker_csrf}) assert r.status_code == 200 def test_wachtwoord_wijzigen_behoudt_de_rol(client): """Rechtenescalatie: het hele gebruikersrecord werd vervangen bij een wachtwoordwijziging, waardoor de rol wegviel. Omdat een ontbrekende rol als admin geldt (voor oude accounts), promoveerde een viewer zichzelf zo tot beheerder.""" csrf = login(client) _maak(client, csrf, "kijker", "viewer") kijker_csrf = _login_als(client, "kijker") r = client.post("/api/auth/password", json={"current": "eenlangwachtwoord", "new": "nogeenlangwachtwoord"}, headers={"X-CSRF-Token": kijker_csrf}) assert r.status_code == 200 import core.auth as auth assert auth.role_of("kijker") == "viewer" assert client.get("/api/auth/me").get_json()["role"] == "viewer" # En nog steeds geen toegang tot beheeracties. assert client.put("/api/settings", json={}, headers={"X-CSRF-Token": kijker_csrf}).status_code == 403 def test_viewer_mag_uitloggen(client): csrf = login(client) _maak(client, csrf, "kijker", "viewer") kijker_csrf = _login_als(client, "kijker") assert client.post("/api/auth/logout", json={}, headers={"X-CSRF-Token": kijker_csrf}).status_code == 200 def test_laatste_beheerder_kan_niet_gedegradeerd_worden(client): csrf = login(client) _maak(client, csrf, "op", "operator") r = client.put("/api/auth/users/tester/role", json={"role": "viewer"}, headers={"X-CSRF-Token": csrf}) assert r.status_code == 400 assert "laatste beheerder" in r.get_json()["msg"] def test_laatste_beheerder_kan_niet_verwijderd_worden(client): csrf = login(client) _maak(client, csrf, "op", "operator") r = client.delete("/api/auth/users/tester", headers={"X-CSRF-Token": csrf}) assert r.status_code == 400 def test_degraderen_mag_met_een_tweede_beheerder(client): csrf = login(client) _maak(client, csrf, "admin2", "admin") r = client.put("/api/auth/users/tester/role", json={"role": "operator"}, headers={"X-CSRF-Token": csrf}) assert r.status_code == 200 import core.auth as auth assert auth.role_of("tester") == "operator" def test_onbekende_rol_wordt_geweigerd(client): csrf = login(client) r = client.post("/api/auth/users", json={"username": "x", "password": "eenlangwachtwoord", "role": "superuser"}, headers={"X-CSRF-Token": csrf}) assert r.status_code == 400 def test_proxy_gebruiker_krijgt_de_ingestelde_rol(client, env): csrf = login(client) client.put("/api/auth/mode", json={"mode": "both", "proxy_header": "Remote-User", "trusted_proxies": ["10.9.9.9"], "proxy_role": "viewer"}, headers={"X-CSRF-Token": csrf}) client.post("/api/auth/logout", json={}, headers={"X-CSRF-Token": csrf}) r = client.get("/api/auth/me", headers={"Remote-User": "collega"}, environ_overrides={"REMOTE_ADDR": "10.9.9.9"}) assert r.get_json()["role"] == "viewer" def test_lokaal_account_wint_van_proxy_rol(client, env): """Komt de proxy-naam overeen met een bestaand account, dan geldt díé rol.""" csrf = login(client) _maak(client, csrf, "collega", "operator") client.put("/api/auth/mode", json={"mode": "both", "proxy_header": "Remote-User", "trusted_proxies": ["10.9.9.9"], "proxy_role": "viewer"}, headers={"X-CSRF-Token": csrf}) client.post("/api/auth/logout", json={}, headers={"X-CSRF-Token": csrf}) r = client.get("/api/auth/me", headers={"Remote-User": "collega"}, environ_overrides={"REMOTE_ADDR": "10.9.9.9"}) assert r.get_json()["role"] == "operator"