Implement scoped P06 authentication policy and guarded optional onboarding
Some checks are pending
CI Smoke / host-smoke (push) Waiting to run
CI Smoke / container-smoke (push) Waiting to run
Build and Publish Container Image / build-and-push (push) Successful in 51s
Account journey acceptance / journeys (push) Successful in 7s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a09cbb-87c6-7900-a145-4ce53ba9f1a6
This commit is contained in:
tegwick 2026-09-14 00:00:07 +02:00
parent 0801ec55ac
commit 3bd1827a7f
10 changed files with 298 additions and 8 deletions

View file

@ -18,6 +18,7 @@ class PendingLogin:
verifier: str
created_at: float
recovery: bool = False
return_path: str = "/"
@dataclass
@ -27,6 +28,7 @@ class BrowserSession:
csrf_token: str = ""
id_token: str = ""
recovery: bool = False
return_path: str = "/"
class OIDCClient:
@ -51,11 +53,13 @@ class OIDCClient:
self.pending: dict[str, PendingLogin] = {}
self.sessions: dict[str, BrowserSession] = {}
def begin(self, *, tenant_hint: str | None = None, recovery: bool = False) -> str:
def begin(self, *, tenant_hint: str | None = None, recovery: bool = False, return_path: str = "/") -> str:
if return_path not in {"/", "/platform", "/platform/factor-recovery", "/platform/authentication-policy"}:
raise ValueError("unsupported login return path")
state = secrets.token_urlsafe(32)
verifier = secrets.token_urlsafe(64)
challenge = _b64(hashlib.sha256(verifier.encode("ascii")).digest())
self.pending[state] = PendingLogin(verifier=verifier, created_at=time.time(), recovery=recovery)
self.pending[state] = PendingLogin(verifier=verifier, created_at=time.time(), recovery=recovery, return_path=return_path)
self._prune()
parameters = {
'response_type': 'code',
@ -107,6 +111,7 @@ class OIDCClient:
csrf_token=secrets.token_urlsafe(32),
id_token=token,
recovery=pending.recovery,
return_path=pending.return_path,
)
self._prune()
return session_id