Authorization-code flow with PKCE through an idp adapter (with a fake), ID token validation, identity and roles resolved from the directory with a short cache, refusal of unknown, disabled and locked accounts with one generic page, sessions that end when the account becomes unavailable, sign-out that ends the server-side session, role decorators and the trusted-proxy client address rule. Adds the OIDC_* and PUBLIC_BASE_URL configuration. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N3t4WL7bd9bdHHNjEsxzqC
50 lines
1.4 KiB
Python
50 lines
1.4 KiB
Python
"""The identity-provider interface, its data types and typed errors (AD-1, AD-17)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections.abc import Mapping
|
|
from dataclasses import dataclass
|
|
from typing import Protocol
|
|
|
|
|
|
class IdpError(Exception):
|
|
"""Base class of every error the identity-provider adapter raises."""
|
|
|
|
|
|
class IdpUnavailable(IdpError):
|
|
"""The provider could not be reached or answered with something unusable."""
|
|
|
|
|
|
class LoginRejected(IdpError):
|
|
"""The sign-in response is not valid: wrong state, bad token, provider error."""
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Flow:
|
|
"""What must survive between the redirect and the callback. Kept in the session."""
|
|
|
|
state: str
|
|
nonce: str
|
|
code_verifier: str
|
|
|
|
def as_dict(self) -> dict[str, str]:
|
|
return {"state": self.state, "nonce": self.nonce, "code_verifier": self.code_verifier}
|
|
|
|
@classmethod
|
|
def from_dict(cls, data: Mapping[str, str]) -> Flow:
|
|
return cls(data["state"], data["nonce"], data["code_verifier"])
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Identity:
|
|
username: str # the validated preferred_username claim
|
|
subject: str
|
|
|
|
|
|
class Idp(Protocol):
|
|
def begin(self) -> tuple[str, Flow]:
|
|
"""The address to send the browser to, and the flow to remember."""
|
|
|
|
def complete(self, params: Mapping[str, str], flow: Flow) -> Identity:
|
|
"""Validate the callback's query parameters against the flow; return who signed in."""
|