import json from base64 import b64encode from fastapi.testclient import TestClient from itsdangerous import TimestampSigner from cert_portal.app import create_app from cert_portal.auth_oidc import SESSION_USER_KEY, claims_username, session_user_from_token from cert_portal.directory import DirectoryUser from cert_portal.exceptions import UserNotFoundError from cert_portal.issue import IssuedProfile from cert_portal.profile import APPLE_CONFIG_TYPE SESSION_COOKIE = "cert_portal_session" NICK = { "sub": "abc", "username": "nick@example.test", "email": "nick@example.test", "name": "Nick", } def _client(settings, lookup, issuer=None): app = create_app(settings, lookup_user=lookup, issuer=issuer) return TestClient(app) def _sign_in(client: TestClient, settings, user: dict) -> None: """Starlette 1.x TestClient no longer has session_transaction; sign the cookie.""" signer = TimestampSigner(str(settings.session_secret)) payload = b64encode(json.dumps({SESSION_USER_KEY: user}).encode("utf-8")) client.cookies.set(SESSION_COOKIE, signer.sign(payload).decode("utf-8")) def test_health(settings, directory_user): client = _client(settings, lambda username: directory_user) response = client.get("/health") assert response.status_code == 200 assert response.json()["status"] == "ok" def test_home_unauthenticated_shows_login(settings, directory_user): client = _client(settings, lambda username: directory_user) response = client.get("/") assert response.status_code == 200 assert "Sign in with SSO" in response.text def test_help_requires_login(settings, directory_user): client = _client(settings, lambda username: directory_user) response = client.get("/help", follow_redirects=False) assert response.status_code == 302 assert response.headers["location"] == "/" def test_home_authenticated_shows_sid(settings, directory_user): client = _client(settings, lambda username: directory_user) _sign_in(client, settings, NICK) response = client.get("/") assert response.status_code == 200 assert directory_user.sid in response.text assert "Download certificate profile" in response.text def test_home_directory_error(settings): def lookup(username: str) -> DirectoryUser: raise UserNotFoundError("No Active Directory user matched your sign-in name.") client = _client(settings, lookup) _sign_in( client, settings, { "sub": "abc", "username": "missing@example.test", "email": "missing@example.test", "name": "Missing", }, ) response = client.get("/") assert "No Active Directory user" in response.text def test_download_returns_signed_mobileconfig(settings, directory_user): class FakeIssuer: def issue(self, user: DirectoryUser) -> IssuedProfile: return IssuedProfile( signed_mobileconfig=b"\x30fake-cms", filename="nick@example.test.mobileconfig", upn=user.upn, sid=user.sid, ) client = _client(settings, lambda username: directory_user, issuer=FakeIssuer()) _sign_in(client, settings, NICK) response = client.post("/download") assert response.status_code == 200 assert response.content == b"\x30fake-cms" assert response.headers["content-type"].startswith(APPLE_CONFIG_TYPE) assert "nick@example.test.mobileconfig" in response.headers["content-disposition"] def test_download_requires_session(settings, directory_user): client = _client(settings, lambda username: directory_user) response = client.post("/download", follow_redirects=False) assert response.status_code == 302 def test_help_authenticated(settings, directory_user): client = _client(settings, lambda username: directory_user) _sign_in(client, settings, NICK) response = client.get("/help") assert response.status_code == 200 assert "Private key on the server" in response.text def test_login_oidc_failure_shows_error(settings, directory_user): client = _client(settings, lambda username: directory_user) response = client.get("/login") assert response.status_code == 502 assert "Could not start sign-in" in response.text def test_username_claim_fallback(): assert claims_username({"email": "a@b.c"}, "email") == "a@b.c" assert claims_username({"preferred_username": "a"}, "email") == "a" def test_session_user_from_token(): token = {"userinfo": {"sub": "1", "email": "a@b.c", "name": "A"}} user = session_user_from_token(token, "email") assert user["username"] == "a@b.c" assert user["name"] == "A"