Adding the new rewrite
This commit is contained in:
1 parent
4aca9f08d1
commit
9b48b01d1d
62 files changed
+4510
-1406
No files matched your search
@@ -0,0 +1,148 @@
|
||||
"""Auth: hash/verify, session token, login/logout, CSRF, setup."""
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from app.auth import (
|
||||
create_session_token,
|
||||
get_stored_admin,
|
||||
hash_password,
|
||||
is_admin_configured,
|
||||
store_admin,
|
||||
verify_password,
|
||||
verify_session_token,
|
||||
)
|
||||
|
||||
|
||||
def test_hash_and_verify_password(fake_redis):
|
||||
h = hash_password("supersecret")
|
||||
assert h.startswith("$argon2")
|
||||
assert verify_password("supersecret", h) is True
|
||||
assert verify_password("wrong", h) is False
|
||||
|
||||
|
||||
def test_verify_password_bad_hash_returns_false(fake_redis):
|
||||
assert verify_password("anything", "not-a-valid-hash") is False
|
||||
|
||||
|
||||
def test_session_token_roundtrip(fake_redis):
|
||||
tok = create_session_token("admin")
|
||||
assert verify_session_token(tok) == "admin"
|
||||
|
||||
|
||||
def test_session_token_rejects_tampered(fake_redis):
|
||||
tok = create_session_token("admin")
|
||||
bad = tok[:-4] + "abcd"
|
||||
assert verify_session_token(bad) is None
|
||||
|
||||
|
||||
def test_store_and_get_admin(fake_redis):
|
||||
store_admin("alice", "pw-strong-1")
|
||||
user, h = get_stored_admin()
|
||||
assert user == "alice"
|
||||
assert h and h.startswith("$argon2")
|
||||
assert is_admin_configured() is True
|
||||
|
||||
|
||||
def test_login_rejects_before_setup(app_client, fake_redis):
|
||||
r = app_client.post(
|
||||
"/api/login",
|
||||
json={"username": "admin", "password": "test"},
|
||||
)
|
||||
assert r.status_code == 409
|
||||
|
||||
|
||||
def test_login_happy_path(app_client, fake_redis):
|
||||
store_admin("admin", "testpassword123")
|
||||
r = app_client.post(
|
||||
"/api/login",
|
||||
json={"username": "admin", "password": "testpassword123"},
|
||||
)
|
||||
assert r.status_code == 200
|
||||
body = r.json()
|
||||
assert body["ok"] is True
|
||||
assert "csrf_token" in body
|
||||
# Cookies set
|
||||
assert "ups_session" in r.cookies
|
||||
assert "csrf_token" in r.cookies
|
||||
|
||||
|
||||
def test_login_bad_password(app_client, fake_redis):
|
||||
store_admin("admin", "testpassword123")
|
||||
r = app_client.post(
|
||||
"/api/login",
|
||||
json={"username": "admin", "password": "wrong"},
|
||||
)
|
||||
assert r.status_code == 401
|
||||
|
||||
|
||||
def test_login_bad_username(app_client, fake_redis):
|
||||
store_admin("admin", "testpassword123")
|
||||
r = app_client.post(
|
||||
"/api/login",
|
||||
json={"username": "notadmin", "password": "testpassword123"},
|
||||
)
|
||||
assert r.status_code == 401
|
||||
|
||||
|
||||
def test_logout_clears_cookies(authed_client):
|
||||
r = authed_client.post("/api/logout")
|
||||
assert r.status_code == 200
|
||||
|
||||
|
||||
def test_setup_creates_admin(app_client, fake_redis):
|
||||
r = app_client.post(
|
||||
"/api/setup",
|
||||
json={"username": "newadmin", "password": "setup-pw-1234"},
|
||||
)
|
||||
assert r.status_code == 200
|
||||
assert is_admin_configured() is True
|
||||
|
||||
|
||||
def test_setup_rejects_when_configured(app_client, fake_redis):
|
||||
store_admin("admin", "already-set-password")
|
||||
r = app_client.post(
|
||||
"/api/setup",
|
||||
json={"username": "newadmin", "password": "setup-pw-1234"},
|
||||
)
|
||||
assert r.status_code == 409
|
||||
|
||||
|
||||
def test_setup_rejects_short_password(app_client, fake_redis):
|
||||
r = app_client.post(
|
||||
"/api/setup",
|
||||
json={"username": "admin", "password": "short"},
|
||||
)
|
||||
assert r.status_code == 422 # pydantic validation
|
||||
|
||||
|
||||
def test_setup_rejects_bad_username(app_client, fake_redis):
|
||||
r = app_client.post(
|
||||
"/api/setup",
|
||||
json={"username": "bad user!", "password": "good-password-1"},
|
||||
)
|
||||
assert r.status_code == 400
|
||||
|
||||
|
||||
def test_protected_endpoint_requires_auth(app_client):
|
||||
r = app_client.get("/api/config/ups")
|
||||
assert r.status_code == 401
|
||||
|
||||
|
||||
def test_csrf_required_for_mutations(app_client, fake_redis):
|
||||
store_admin("admin", "testpassword123")
|
||||
r = app_client.post(
|
||||
"/api/login",
|
||||
json={"username": "admin", "password": "testpassword123"},
|
||||
)
|
||||
assert r.status_code == 200
|
||||
# DELETE without CSRF header
|
||||
r2 = app_client.delete("/api/config/ups/nonexistent")
|
||||
assert r2.status_code == 403
|
||||
|
||||
|
||||
def test_mutations_work_with_csrf(authed_client):
|
||||
# Authed client already has CSRF header set in fixture
|
||||
r = authed_client.delete("/api/config/ups/nonexistent")
|
||||
# Expected 404 because UPS doesn't exist (NOT 401/403)
|
||||
assert r.status_code == 404
|
||||
Reference in new issue
Block a user