mirror of
https://github.com/azaion/missions.git
synced 2026-06-21 21:41:06 +00:00
refactor: enhance JWT authentication and CORS configuration
Updated JWT authentication to use configuration values instead of hardcoded secrets, improving security and flexibility. Enhanced CORS policy to conditionally allow origins based on configuration settings, with logging for permissive defaults. Updated README to reflect project renaming and clarify service context.
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
# 05 — Identity & Authorization
|
||||
|
||||
**Spec source**: `../../../suite/_docs/10_auth.md` (suite-wide JWT model), `../../../suite/_docs/00_roles_permissions.md` (the `FL` permission code).
|
||||
|
||||
**Implementation status**: ✅ implemented. Single policy `FL` is declared and consumed by every controller.
|
||||
|
||||
> **NOTE (forward-looking)**: post-rename + post-GPS-Denied-removal. Today's `JwtExtensions.cs` also declares a `"GPS"` policy reserved for the (now-removed-from-this-repo) GPS-Denied endpoints. After Jira AZ-EPIC child B7 lands, only `"FL"` remains.
|
||||
|
||||
**Files**: `Auth/JwtExtensions.cs`
|
||||
|
||||
## 1. High-Level Overview
|
||||
|
||||
**Purpose**: Validate JWT bearer tokens issued by the remote `admin` service and expose the named authorization policy (`FL`) used by controllers in the feature components. This service does not issue tokens -- it consumes them.
|
||||
|
||||
**Architectural pattern**: ASP.NET Core extension method (`AddJwtAuth`) configuring `IServiceCollection` at DI time.
|
||||
|
||||
**Upstream dependencies**: None internally.
|
||||
|
||||
**Downstream consumers**: `07_host` (calls `AddJwtAuth(jwtSecret)` once); `01_vehicle_catalog`, `02_mission_planning` (controllers carry `[Authorize(Policy = "FL")]`).
|
||||
|
||||
## 2. Internal Interface
|
||||
|
||||
```csharp
|
||||
public static IServiceCollection AddJwtAuth(this IServiceCollection services, string jwtSecret);
|
||||
```
|
||||
|
||||
Side effects: registers `JwtBearerDefaults.AuthenticationScheme` and one named authorization policy in DI:
|
||||
|
||||
| Policy | Requirement |
|
||||
|--------|-------------|
|
||||
| `"FL"` | JWT contains a `permissions` claim with value `"FL"` |
|
||||
|
||||
## 3. Suite-wide JWT pattern
|
||||
|
||||
This is the canonical "every backend service" identity model in the Azaion suite. Per `../../../suite/_docs/00_top_level_architecture.md` and `../../../suite/_docs/10_auth.md`:
|
||||
|
||||
```
|
||||
┌─────────────────────┐ ┌──────────────────────┐
|
||||
│ Operator UI │ POST /login │ admin (.NET, remote) │
|
||||
│ (React, edge) │ ──────────────► │ central user DB │
|
||||
│ │ ◄────────────── │ mints HS256 JWT │
|
||||
│ │ Bearer JWT │ (claim: permissions)│
|
||||
└──────────┬──────────┘ └──────────────────────┘
|
||||
│ Bearer JWT (the SAME token reused for every service)
|
||||
│
|
||||
├──────────────────► annotations (.NET, edge) -- ANN claim
|
||||
├──────────────────► missions (.NET, edge) -- FL claim ◄── this service
|
||||
├──────────────────► satellite-provider (.NET, remote) -- ADM claim
|
||||
└──────────────────► (any future .NET service)
|
||||
```
|
||||
|
||||
Every service (admin, annotations, missions, satellite-provider, ...) shares one HMAC secret (`JWT_SECRET`) and validates tokens locally with no network round-trip. The user logs in once at the UI; the resulting bearer token is reusable across every service. **This service neither issues tokens nor talks to the central user DB** -- it only validates.
|
||||
|
||||
The `permissions` claim drives per-service `[Authorize(Policy = "...")]` checks. The role -> permission matrix lives in `../../../suite/_docs/00_roles_permissions.md`. All routes here require `FL`.
|
||||
|
||||
## 4. External API
|
||||
|
||||
None directly. Auth contract is observable only via `401 Unauthorized` / `403 Forbidden` on protected routes.
|
||||
|
||||
## 5. Data Access Patterns
|
||||
|
||||
None.
|
||||
|
||||
## 6. Implementation Details
|
||||
|
||||
**Algorithm**: HMAC-SHA256 signature validation via `SymmetricSecurityKey(UTF-8(jwtSecret))`. Matches the suite-wide shared-secret model.
|
||||
|
||||
**Token validation flags**:
|
||||
- `ValidateIssuerSigningKey = true`
|
||||
- `ValidateLifetime = true` (with `ClockSkew = 1 minute` -- tighter than .NET's 5-minute default)
|
||||
- `ValidateIssuer = false`, `ValidateAudience = false` -- `iss` / `aud` NOT enforced (consistent with shared-secret intra-suite model). Per the CMMC L2 scorecard (`../../../suite/_docs/05_security/cmmc_l2_scorecard.md` row 3), this is a known finding tracked at the suite level under AZ-487/AZ-494; the remediation will copy the `satellite-provider` pattern across `annotations` and `missions`.
|
||||
|
||||
**Key Dependencies**:
|
||||
|
||||
| Library | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| `Microsoft.AspNetCore.Authentication.JwtBearer` | 10.0.5 | JWT bearer middleware + handler |
|
||||
| `Microsoft.IdentityModel.Tokens` | (transitive) | `SymmetricSecurityKey`, `TokenValidationParameters` |
|
||||
|
||||
## 7. Extensions and Helpers
|
||||
|
||||
None.
|
||||
|
||||
## 8. Caveats & Edge Cases
|
||||
|
||||
1. **Shared-secret trust model** -- any service that knows `JWT_SECRET` can mint tokens this API will accept. Not safe for multi-tenant or third-party token issuance. Consistent with the rest of the suite; tightening this is suite-wide work, not a per-service decision.
|
||||
2. **No claim type for "user id" is consumed** -- only the `permissions` claim is checked. Services don't know who is calling them; per-user audit trails / business rules cannot be enforced at the service layer today. When a future feature needs an "applied by" attribution this gap will need to close.
|
||||
3. **No offline-grace-window logic in this service** -- `../../../suite/_docs/10_auth.md` describes an offline JWT cache; that lives in the UI / `admin` consumption pattern, not here.
|
||||
4. **Hardcoded fallback secret** in `Program.cs` (`"development-secret-key-min-32-chars!!"`) is dev-only. Production deployments MUST set `JWT_SECRET`.
|
||||
5. **`FL` permission code carries the legacy "Flight" name even after the service rename to `missions`.** The plan documents this explicitly: changing the permission code is a fleet-wide auth change (would break every issued token until new ones are minted) and is **NOT** in this Epic's scope. Tracked as a TODO in `../../../suite/_docs/00_roles_permissions.md`.
|
||||
|
||||
## 9. Dependency Graph
|
||||
|
||||
**Must be implemented after**: nothing.
|
||||
|
||||
**Can be implemented in parallel with**: `04_persistence`, `06_http_conventions`.
|
||||
|
||||
**Blocks**: `07_host`, `01_vehicle_catalog`, `02_mission_planning`.
|
||||
|
||||
## 10. Logging Strategy
|
||||
|
||||
ASP.NET Core's JwtBearer handler logs token validation outcomes at default levels (Information / Debug). Not customized.
|
||||
Reference in New Issue
Block a user