Files
terra-view/tests/test_operator_login.py
T
2026-06-17 19:38:55 +00:00

99 lines
4.5 KiB
Python

# tests/test_operator_login.py
import uuid
from tests.conftest import wire_operator_auth
from backend.operator_auth import (
create_operator, make_operator_cookie, COOKIE_NAME, MAX_LOGIN_FAILURES,
)
def test_login_page_renders(client, db_session, monkeypatch):
wire_operator_auth(monkeypatch, db_session, enabled=True)
r = client.get("/login")
assert r.status_code == 200
assert "password" in r.text.lower()
def test_login_success_sets_cookie_and_redirects(client, db_session, monkeypatch):
create_operator(db_session, "ok@x.com", "Ok", "admin", password="rightpw-9")
wire_operator_auth(monkeypatch, db_session, enabled=True)
r = client.post("/login", data={"email": "ok@x.com", "password": "rightpw-9"},
follow_redirects=False)
assert r.status_code == 303
assert r.headers["location"] == "/"
assert f"{COOKIE_NAME}=" in r.headers.get("set-cookie", "")
def test_login_honors_next(client, db_session, monkeypatch):
create_operator(db_session, "ok@x.com", "Ok", "admin", password="rightpw-9")
wire_operator_auth(monkeypatch, db_session, enabled=True)
r = client.post("/login?next=/settings", data={"email": "ok@x.com", "password": "rightpw-9"},
follow_redirects=False)
assert r.headers["location"] == "/settings"
def test_login_wrong_password_no_cookie_generic_error(client, db_session, monkeypatch):
create_operator(db_session, "ok@x.com", "Ok", "admin", password="rightpw-9")
wire_operator_auth(monkeypatch, db_session, enabled=True)
r = client.post("/login", data={"email": "ok@x.com", "password": "nope"},
follow_redirects=False)
assert r.status_code == 200
assert f"{COOKIE_NAME}=" not in r.headers.get("set-cookie", "")
assert "invalid" in r.text.lower()
def test_login_must_change_redirects_to_change_password(client, db_session, monkeypatch):
create_operator(db_session, "new@x.com", "New", "admin") # generated temp → must_change
from backend.models import OperatorUser
user = db_session.query(OperatorUser).filter_by(email="new@x.com").first()
from backend.auth_passwords import hash_password
user.password_hash = hash_password("temp-pw-1")
db_session.commit()
wire_operator_auth(monkeypatch, db_session, enabled=True)
r = client.post("/login", data={"email": "new@x.com", "password": "temp-pw-1"},
follow_redirects=False)
assert r.status_code == 303
assert r.headers["location"] == "/change-password"
def test_login_lockout_message_after_five(client, db_session, monkeypatch):
create_operator(db_session, "lk@x.com", "Lk", "admin", password="rightpw-9")
wire_operator_auth(monkeypatch, db_session, enabled=True)
for _ in range(MAX_LOGIN_FAILURES):
client.post("/login", data={"email": "lk@x.com", "password": "nope"}, follow_redirects=False)
r = client.post("/login", data={"email": "lk@x.com", "password": "rightpw-9"}, follow_redirects=False)
assert r.status_code == 200
assert "too many" in r.text.lower()
def test_logout_clears_cookie(client, db_session, monkeypatch):
wire_operator_auth(monkeypatch, db_session, enabled=True)
r = client.get("/logout", follow_redirects=False)
assert r.status_code == 303
assert r.headers["location"] == "/login"
set_cookie = r.headers.get("set-cookie", "").lower()
assert COOKIE_NAME.lower() in set_cookie
assert 'max-age=0' in set_cookie or 'expires=thu, 01 jan 1970' in set_cookie
def test_change_password_self_service(client, db_session, monkeypatch):
user, _ = create_operator(db_session, "c@x.com", "C", "admin", password="orig-pw-1")
wire_operator_auth(monkeypatch, db_session, enabled=True)
client.cookies.set(COOKIE_NAME, make_operator_cookie(user.id))
r = client.post("/change-password",
data={"current_password": "orig-pw-1", "new_password": "brand-new-2",
"confirm_password": "brand-new-2"}, follow_redirects=False)
assert r.status_code == 303
from backend.auth_passwords import verify_password
db_session.refresh(user)
assert verify_password("brand-new-2", user.password_hash)
assert user.must_change_password is False
def test_safe_next_blocks_open_redirect():
from backend.routers.operator_auth_routes import _safe_next
assert _safe_next("//evil.com") == "/"
assert _safe_next("/\\evil.com") == "/" # backslash authority bypass
assert _safe_next("https://evil.com") == "/"
assert _safe_next("") == "/"
assert _safe_next("/settings") == "/settings"