mirror of
https://github.com/azaion/admin.git
synced 2026-06-21 15:21:10 +00:00
a77b3f8a59
Refreshes _docs/02_document/ to reflect the cycle-2 auth-modernization
+ CMMC hardening landings (AZ-531..AZ-538). Authoritative source for
the ripple set is ripple_log_cycle2.md.
Covered:
- architecture.md (section 1 rewritten, ADRs 6-9 added)
- data_model.md (sessions, audit_events, user columns, migrations)
- system-flows.md (F1 rewritten; F11-F17 added; F2/F7/F9 minor)
- module-layout.md (cycle-2 sub-component table)
- diagrams/flows/flow_login.md (dual-token + MFA)
- components/{01_data_layer,03_auth_and_security,05_admin_api}
- modules/ (12 new, 8 modified — full Argon2id/ES256/MFA/refresh
/mission/session/audit/jwks rollup)
- tests/{blackbox,security,traceability-matrix}
Step 13 (Update Docs) output for cycle 2.
Co-authored-by: Cursor <cursoragent@cursor.com>
4.2 KiB
4.2 KiB
Module: Azaion.Services.MissionTokenService
Purpose
Issues long-lived (≤ 12 h) single-use access tokens for offline UAV missions. Distinct from AuthService.CreateToken because:
- Lifetime is per-mission (
planned_duration_h + 1 hbuffer), not the 15-minute interactive policy. - Audience is narrowed to
satellite-provider, not the broad admin audience. - No refresh: a single token covers the entire flight, then dies.
- Carries mission-specific claims (
mission_id,aircraft_id,valid_region,permissions).
Added in cycle 2 (2026-05-14) by AZ-533 (Epic AZ-529). Solves the "10 h offline UAV vs. 15 min interactive access token" tension without weakening interactive-session security.
Public Interface
IMissionTokenService
| Method | Signature | Description |
|---|---|---|
Issue |
Task<MissionSessionResponse> Issue(Guid pilotUserId, MissionSessionRequest request, CancellationToken ct = default) |
Validates the request, persists a class='mission' row in sessions, mints an ES256 access token bound to that session id, returns the token + expiry + session id. |
Internal Logic
- Validation:
mission_idmust match^M-\d{4}-\d{2}-\d{2}-\d{3}$(compiled regex).planned_duration_h∈[0.1, 12.0]— anything outside throwsBusinessException(InvalidMissionRequest)(HTTP 400).aircraft_idmust exist inuserswithRole=CompanionPC; otherwiseBusinessException(AircraftNotFound).
- Session row first, then token — the row is inserted before the JWT is minted so revocation lookups can never miss a token already in the wild.
- Lifetime =
planned_duration_h + 1.0(the 1-hour buffer covers post-flight reconnect grace). - Family handling — mission sessions are their own family (
family_id = id); they never rotate. - Token claims:
sub= pilotUserId,sid= session id,jti= unique token id,mission_id,aircraft_id,token_class="mission", optionalpermissions(multi-valued), optionalvalid_region(JSON-typed claim). Audience pinned tosatellite-provider. - Auto-revoke on reconnect is implemented in
Program.csviaISessionService.RevokeMissionsForAircraft, fired from/loginand/token/refreshwhenever the caller is aCompanionPCuser.
Dependencies
IDbFactory— admin connection for inserting the mission session row, read connection for the aircraft existence checkIJwtSigningKeyProvider— ES256 active keyIOptions<JwtConfig>— issuerSessionentity,SessionClasses.MissionconstantMissionSessionRequest/MissionSessionResponseDTOs
Consumers
Program.cs/sessions/mission(requires interactive auth; per AZ-533 the AC-6 step-up MFA gate is a TODO until org-wide MFA adoption)
Data Models
Operates on the Session entity (class='mission', aircraft_id set, refresh_hash null).
Configuration
JwtConfig.Issuer— issuer claim of the minted token.- Hard-coded constants:
MissionAudience = "satellite-provider"— verifier-side audience gate.MaxDurationHours = 12.0,MinDurationHours = 0.1.LifetimeBufferHours = 1.0.
External Integrations
PostgreSQL via IDbFactory. Token consumed by the satellite-provider workspace (verifier-side enforcement of mission_id/aircraft_id/valid_region is filed under that workspace).
Security
- Long-lived tokens are inherently dangerous if leaked. Hardware binding (mTLS / DPoP /
cnf) is the long-term answer; documented as a known risk in_docs/05_security/security_report.md. - The narrowed audience (
satellite-provider) prevents a stolen mission token from being usable against the admin API itself; admin endpoints still requireJwtConfig.Audience. - The
valid_regionbbox is informational untilsatellite-providerenforces it (cross-workspace coordination ticket). - Mission tokens are auto-revoked the moment the aircraft reconnects (
/loginor/token/refreshfrom aCompanionPCuser). Verifiers polling/sessions/revokedsee the revocation within their poll interval (≤ 30 s).
Tests
e2e/Azaion.E2E/Tests/MissionTokenTests.cs— AC-1 (correct lifetime + claims), AC-2 (12h cap), AC-3 (scope claims), AC-4 (auto-revoke on reconnect), AC-5 (auth required).