fix(backend): resolve refresh-token expiry deadlock, missing Jira on normal campaign approval, discarded threat-actor campaign start_date
- /auth/refresh now allows a short grace window past expiry and checks the blacklist, so an active session's silent refresh no longer fails the instant its own token expires - normal manager /approve flow now creates Jira tickets for the campaign and its already-linked tests, matching the admin-only /activate path - GenerateFromActorPayload now accepts start_date and threads it through to the new campaign instead of silently discarding it
This commit is contained in:
@@ -1,7 +1,23 @@
|
||||
"""Tests for authentication endpoints."""
|
||||
|
||||
import uuid
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
import jwt
|
||||
import pytest
|
||||
|
||||
from app.config import settings
|
||||
|
||||
|
||||
def _make_token(username: str, *, expired_seconds_ago: int | None = None) -> str:
|
||||
"""Build a raw JWT mirroring ``create_access_token`` with a controllable exp."""
|
||||
if expired_seconds_ago is None:
|
||||
expire = datetime.now(timezone.utc) + timedelta(minutes=30)
|
||||
else:
|
||||
expire = datetime.now(timezone.utc) - timedelta(seconds=expired_seconds_ago)
|
||||
payload = {"sub": username, "exp": expire, "jti": str(uuid.uuid4())}
|
||||
return jwt.encode(payload, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
|
||||
|
||||
|
||||
def test_login_success(client, admin_user):
|
||||
"""Test successful login returns a token."""
|
||||
@@ -122,3 +138,49 @@ def test_logout_revokes_token(client, admin_user):
|
||||
)
|
||||
assert me.status_code == 401
|
||||
assert me.json()["detail"] == "Token has been revoked"
|
||||
|
||||
|
||||
def test_refresh_without_cookie_fails(client):
|
||||
response = client.post("/api/v1/auth/refresh")
|
||||
assert response.status_code == 403
|
||||
|
||||
|
||||
def test_refresh_valid_token_succeeds(client, admin_user):
|
||||
token = _make_token("admin")
|
||||
client.cookies.set("aegis_token", token)
|
||||
response = client.post("/api/v1/auth/refresh")
|
||||
assert response.status_code == 200
|
||||
assert "access_token" in response.json()
|
||||
|
||||
|
||||
def test_refresh_recently_expired_token_succeeds_within_grace(client, admin_user):
|
||||
"""A token that expired moments ago must still be refreshable.
|
||||
|
||||
This is the core of the refresh-token bug fix: without a grace window,
|
||||
`/auth/refresh` decodes with the same strict expiry check as every
|
||||
other endpoint, so a 401-triggered refresh attempt always also fails.
|
||||
"""
|
||||
token = _make_token("admin", expired_seconds_ago=60)
|
||||
client.cookies.set("aegis_token", token)
|
||||
response = client.post("/api/v1/auth/refresh")
|
||||
assert response.status_code == 200
|
||||
assert "access_token" in response.json()
|
||||
|
||||
|
||||
def test_refresh_long_expired_token_fails(client, admin_user):
|
||||
token = _make_token("admin", expired_seconds_ago=60 * 60)
|
||||
client.cookies.set("aegis_token", token)
|
||||
response = client.post("/api/v1/auth/refresh")
|
||||
assert response.status_code == 403
|
||||
|
||||
|
||||
def test_refresh_blacklisted_token_fails_even_if_not_expired(client, admin_user):
|
||||
from app.auth import blacklist_token
|
||||
|
||||
token = _make_token("admin")
|
||||
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
|
||||
blacklist_token(payload["jti"], float(payload["exp"]))
|
||||
|
||||
client.cookies.set("aegis_token", token)
|
||||
response = client.post("/api/v1/auth/refresh")
|
||||
assert response.status_code == 403
|
||||
|
||||
Reference in New Issue
Block a user