M15: synchronize contracts and acceptance
This commit is contained in:
@@ -62,6 +62,34 @@ def test_logout_invalidates_session(ops_client):
|
||||
assert after.status_code == 401
|
||||
|
||||
|
||||
def test_logout_rejects_a_cookie_even_if_the_browser_retains_it(ops_client):
|
||||
from app.core.config import get_settings
|
||||
|
||||
cookie_name = get_settings().session_cookie_name
|
||||
stolen_token = ops_client.cookies.get(cookie_name)
|
||||
assert stolen_token
|
||||
|
||||
logout = ops_client.post("/api/v1/auth/logout")
|
||||
assert logout.status_code == 200
|
||||
|
||||
# Simulate the browser cookie race (or a copied cookie): server-side revocation is
|
||||
# authoritative and must reject the original signed token independently of deletion.
|
||||
ops_client.cookies.set(cookie_name, stolen_token)
|
||||
assert ops_client.get("/api/v1/auth/session").status_code == 401
|
||||
|
||||
# Remove the deliberately injected hostless cookie before exercising a normal browser
|
||||
# login. Otherwise httpx sends it alongside the real testserver cookie, which is not a
|
||||
# state a browser can create for the same origin/path pair.
|
||||
ops_client.cookies.clear()
|
||||
|
||||
# A fresh login in the same second receives a distinct signed token and remains valid.
|
||||
fresh_login = ops_client.post(
|
||||
"/api/v1/demo/login", json={"role": "operations_manager"}
|
||||
)
|
||||
assert fresh_login.status_code == 200
|
||||
assert ops_client.get("/api/v1/auth/session").status_code == 200
|
||||
|
||||
|
||||
def test_logout_without_a_session_is_safe(client):
|
||||
response = client.post("/api/v1/demo/logout")
|
||||
assert response.status_code == 200
|
||||
|
||||
Reference in New Issue
Block a user