cadrumo.application.auth.sessions module

Persisted AEAT session discovery and verification.

ensure_authenticated_aeat_session() returns AuthenticatedAeatSessionResult after coordinating AuthProviderKind selection, SessionStoreProtocol persistence, and PersistedAuthSession reuse.

See also

application.auth.acquisition_lock

Defines the profile/provider application.auth.acquisition_lock.AuthAcquisitionLockRecord used to serialize live authentication.

application.live.session

Read-only live-entry helper that calls this module only after core.access_gate.gate.AeatAccessGate allows a live read.

adapters.outbound.aeat.auth

Concrete providers and persisted-session store implementations.

class StorageStatePaths(**data)[source]

Bases: BaseModel

Logical storage-state identifier for one provider’s persisted AEAT session.

Parameters:

data (Any)

storage_state: Path
exception CorruptAuthSessionError(message=None, *, context=None, translated_message=None)[source]

Bases: CadrumoError

Raised when persisted session metadata cannot be parsed.

Parameters:
  • message (str | None)

  • context (Mapping[str, object] | None)

  • translated_message (str | None)

Return type:

None

code
exception AuthSessionUnavailableError(message=None, *, context=None, translated_message=None)[source]

Bases: CadrumoError

Raised when no verified active AEAT session can be supplied.

Parameters:
  • message (str | None)

  • context (Mapping[str, object] | None)

  • translated_message (str | None)

Return type:

None

code
exception SessionDeserializationError(message=None, *, context=None, translated_message=None)[source]

Bases: AuthSessionUnavailableError

Raised when a persisted session field cannot be deserialized to the expected type.

Replaces the bare TypeError raised by session_metadata_datetime() so callers catch a typed, registry-bound error that inherits from AuthSessionUnavailableError.

Parameters:
  • message (str | None)

  • context (Mapping[str, object] | None)

  • translated_message (str | None)

Return type:

None

code
exception AuthProfileIdentityMismatchError(message=None, *, context=None, translated_message=None)[source]

Bases: CadrumoError

Raised when the active profile identity cannot own the requested auth session.

Parameters:
  • message (str | None)

  • context (Mapping[str, object] | None)

  • translated_message (str | None)

Return type:

None

code
exception ClaveCredentialsIncompleteError(message=None, *, context=None, translated_message=None)[source]

Bases: CadrumoError

Raised when a Cl@ve mode lacks a credential half the AEAT flow needs.

Distinct from AuthProfileIdentityMismatchError: nothing disagrees here, a credential is simply absent. The operator’s recovery is to record it rather than to switch profile, so the refusal names what is missing and points at the profile it belongs on.

Parameters:
  • message (str | None)

  • context (Mapping[str, object] | None)

  • translated_message (str | None)

Return type:

None

code
class ClaveCredentials(**data)[source]

Bases: BaseModel

Cl@ve credential halves for one provider kind, and where each came from.

dni_nie and numero_soporte are the effective values: the active profile’s when it carries one, the Settings surface’s otherwise, so an operator who configured Cl@ve through the environment keeps working. The profile_ fields record what the profile itself held, because the provider adapters read their credentials from Settings - a profile-borne value only reaches AEAT once it has been bound onto the settings the provider will read.

Parameters:

data (Any)

provider_kind: AuthProviderKind
dni_nie: str
numero_soporte: str
fecha_validez: str
profile_tax_id: str
profile_dni_nie: str
profile_numero_soporte: str
profile_fecha_validez: str
property contraste: str

Return whichever contraste the operator’s document carries.

Cl@ve asks a NIE holder for the numero de soporte and a DNI holder for the validity date, so exactly one of the two is expected to be present and either satisfies the non-QR route.

class AuthenticatedAeatSessionResult(**data)[source]

Bases: BaseModel

Outcome of ensuring an authenticated AEAT session.

Parameters:
provider_kind: AuthProviderKind
session: SkipValidation[AeatSession]
assertion: SkipValidation[AeatLoginAssertion]
reused_persisted_session: bool
acquired_lock: AuthAcquisitionLockRecord | None
reset_lock: AuthAcquisitionLockStatus | None
removed_sessions: tuple[Path, ...]
fresh: bool
class PersistedAuthSession(**data)[source]

Bases: BaseModel

Provider-neutral view of encrypted AEAT session metadata.

Parameters:

data (Any)

provider_kind: AuthProviderKind
identity_nif: str
authenticated_at: datetime
idle_deadline: datetime
is_expired(now)[source]

Return True if the idle deadline has elapsed at now.

Return type:

bool

Parameters:

now (datetime)

storage_state_paths(kind=None, *, bucket_id=None)[source]

Return the logical storage-state identifier for kind.

Returns a StorageStatePaths carrying the stable logical object key for the provider’s encrypted session state.

Return type:

StorageStatePaths

Parameters:
load_persisted_session(settings, kind=None)[source]

Load persisted AEAT session metadata for kind or the active provider.

Returns a PersistedAuthSession.

Return type:

PersistedAuthSession | None

Parameters:
delete_persisted_session(settings, kind=None, *, bucket_id=None)[source]

Remove persisted encrypted sessions for kind or every session-bearing provider.

A kind of None sweeps every provider that actually persists a browser session (the _STEM_BY_KIND set). Reserved catalogue slots are not AuthProviderKind members and therefore never enter this storage loop; operator --all scope may name them for idempotent configuration cleanup without manufacturing session paths for unsupported providers.

Return type:

list[Path]

Parameters:
persisted_session_exists(settings, kind, *, bucket_id=None)[source]

Return whether kind has persisted session state in bucket_id.

Return type:

bool

Parameters:
async ensure_authenticated_aeat_session(settings, *, certificate_secret_backend_factory, kind=None, fresh=False, reset_lock=False, operation='auth-ensure-session', target_url=None, browser_session_factory, certificate_credentials=None, operator_scope_ports, profile_decode_context)[source]

Serialize and fail-close the central live-session writer.

Return type:

AuthenticatedAeatSessionResult

Parameters:
session_metadata_datetime(value, *, field)[source]
Return type:

datetime

Parameters:
resolve_clave_credentials(provider_kind, *, settings, facts)[source]

Resolve the Cl@ve halves for provider_kind, profile first.

The single home for the profile-beats-settings precedence. Both the live session entry and the operator readiness surfaces resolve through here, so a status surface cannot report a credential as unconfigured that the session entry would happily authenticate with.

Returns None for the certificate provider, which authenticates with an installed certificate and needs neither Cl@ve field.

Return type:

ClaveCredentials | None

Parameters:
bind_clave_credentials_to_settings(settings, credentials, *, route)[source]

Return settings carrying the profile’s Cl@ve credentials.

The outbound providers read their credentials from Settings, so a value the profile holds is inert until it is bound here. When the profile carries nothing the caller’s settings are returned unchanged, which keeps the environment-configured path byte-identical.

Return type:

Settings

Parameters:
class ClaveAuthFacts(**data)[source]

Bases: BaseModel

Authentication facts read from the active profile record.

Parameters:

data (Any)

tax_id: str
dni_nie: str
numero_soporte: str
fecha_validez: str
clave_movil_route: ClaveMovilRoute | None
profile_setup_state: ProfileSetupState | None
clave_auth_facts_from_profile_values(values, *, profile_setup_state=None)[source]

Read the auth facts out of a profile’s schema-path value mapping.

The projection a readiness surface already holds is enough to resolve a credential, so this lets those surfaces reuse the resolver without opening the profile record a second time. identity.tax_id is read here only in its canonical path form; the lifecycle reader applies the selector fallback before calling this.

profile_status distinguishes a profile that has NOT YET recorded its fiscal identity from one whose identity was recorded and later cleared. Only the record carries that, so a caller holding just a value mapping leaves it unset and is treated as the stricter case.

Return type:

ClaveAuthFacts

Parameters: