Sprint 7+8: Journey UX fixes + identity envelope shared middleware

Sprint 7 — Deep journey fixes:
  S7-T01: Trust & Signing empty state with "Go to Signing Keys" CTA
  S7-T02: Notifications 3-step setup guide (channel→rule→test)
  S7-T03: Topology validate step skip — "Skip Validation" when API fails,
    with validateSkipped signal matching agentSkipped pattern
  S7-T04: VEX export note on Risk Report tab linking to VEX Ledger

Sprint 8 — Identity envelope shared middleware (ARCHITECTURE):
  S8-T01: New UseIdentityEnvelopeAuthentication() extension in
    StellaOps.Router.AspNet. Reads X-StellaOps-Identity-Envelope headers,
    verifies HMAC-SHA256 via GatewayIdentityEnvelopeCodec, creates
    ClaimsPrincipal with sub/tenant/scopes/roles. 5min clock skew.
  S8-T02: Concelier refactored — removed 78 lines of inline impl,
    now uses shared one-liner
  S8-T03: Scanner — UseIdentityEnvelopeAuthentication() added
  S8-T04: JobEngine — UseIdentityEnvelopeAuthentication() added
  S8-T05: Timeline — UseIdentityEnvelopeAuthentication() added
  S8-T06: Integrations — UseIdentityEnvelopeAuthentication() added
  S8-T07: docs/modules/router/IDENTITY_ENVELOPE_MIDDLEWARE.md

All services now authenticate ReverseProxy requests via gateway envelope.
Scanner scan submit should now work with authenticated identity.

Angular: 0 errors. .NET (6 services): 0 errors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
master
2026-03-16 18:27:46 +02:00
parent 1acc87a25d
commit 4d8a48a05f
14 changed files with 482 additions and 142 deletions

View File

@@ -0,0 +1,22 @@
# Sprint 20260316-007 — Deep Journey Remaining Fixes
## Topic & Scope
- Fix the 4 remaining UX issues found during deep journey testing (J-05 through J-08).
- Trust & Signing empty state, Notifications empty state, Topology validate skip, VEX export visibility.
- Working directory: `src/Web/StellaOps.Web/`.
## Delivery Tracker
### S7-T01 - Trust & Signing empty state guidance
Status: TODO
### S7-T02 - Notifications empty state guidance
Status: TODO
### S7-T03 - Topology wizard validate step skip
Status: TODO
### S7-T04 - VEX export button visibility
Status: TODO
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2026-03-16 | Sprint created from deep journey findings J-05 to J-08. | Developer |

View File

@@ -0,0 +1,29 @@
# Sprint 20260316-008 — Identity Envelope Shared Middleware (Architecture)
## Topic & Scope
- Extract identity envelope pre-auth middleware from Concelier into shared `StellaOps.Router.AspNet` extension.
- Apply to all 5 services: Concelier (refactor), Scanner, JobEngine, Timeline, Integrations.
- This unblocks scan submit (J-04) and all future ReverseProxy-routed authenticated endpoints.
- Working directory: `src/Router/__Libraries/StellaOps.Router.AspNet/`, `src/*/Program.cs`.
## Delivery Tracker
### S8-T01 - Create shared middleware extension
Status: TODO
### S8-T02 - Refactor Concelier to use shared extension
Status: TODO
### S8-T03 - Add to Scanner
Status: TODO
### S8-T04 - Add to JobEngine
Status: TODO
### S8-T05 - Add to Timeline
Status: TODO
### S8-T06 - Add to Integrations
Status: TODO
### S8-T07 - Document the pattern
Status: TODO
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2026-03-16 | Sprint created from architecture finding. | Developer |

View File

@@ -0,0 +1,113 @@
# Identity Envelope Middleware
## What
`UseIdentityEnvelopeAuthentication()` is a shared ASP.NET Core middleware that reads
gateway-signed identity envelope headers and hydrates `HttpContext.User` with the
enclosed claims. It lives in `StellaOps.Router.AspNet` and is consumed by every
downstream microservice that receives proxied requests from the Router gateway.
## Why
When the Router gateway forwards a request via YARP ReverseProxy, it strips the
original `Authorization: Bearer <jwt>` header. Instead, it signs the authenticated
user's identity into two custom headers:
- `X-StellaOps-Identity-Envelope` -- Base64URL-encoded JSON payload
- `X-StellaOps-Identity-Envelope-Signature` -- HMAC-SHA256 signature
Downstream services need a way to recover the caller's identity from these headers
without each service re-implementing the same verification logic. The shared
middleware eliminates duplication and ensures consistent claim mapping everywhere.
## How to use
In the service's `Program.cs`, register the middleware **before** `UseAuthentication()`:
```csharp
using StellaOps.Router.AspNet;
// ...
app.UseIdentityEnvelopeAuthentication(); // <-- must come first
app.UseAuthentication();
app.UseAuthorization();
```
The service's `.csproj` must reference `StellaOps.Router.AspNet` (which transitively
brings in `StellaOps.Router.Common` containing the codec).
## Configuration
The middleware reads the HMAC-SHA256 signing key from one of two sources (first wins):
| Source | Key |
|---|---|
| `IConfiguration` | `Router:IdentityEnvelopeSigningKey` |
| Environment variable | `STELLAOPS_IDENTITY_ENVELOPE_SIGNING_KEY` |
In the docker-compose environment the key is injected via `x-router-microservice-defaults`
so all services share the same value automatically.
## Claim mapping
When a valid, non-expired envelope is verified, the middleware creates a
`ClaimsPrincipal` with authentication type `StellaRouterEnvelope` and the following
claims:
| Claim type | Source |
|---|---|
| `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier` | `envelope.Subject` |
| `sub` | `envelope.Subject` |
| `stellaops:tenant` | `envelope.Tenant` |
| `tenant` | `envelope.Tenant` |
| `stellaops:project` | `envelope.Project` |
| `project` | `envelope.Project` |
| `scope` (one per scope) | `envelope.Scopes` |
| `http://schemas.microsoft.com/ws/2008/06/identity/claims/role` (one per role) | `envelope.Roles` |
## Architecture flow
```
Browser
|
| Authorization: Bearer <jwt>
v
Gateway (StellaOps.Gateway.WebService)
| 1. Validates JWT
| 2. Signs identity into envelope headers (HMAC-SHA256)
| 3. Strips Authorization header
| 4. Forwards via YARP ReverseProxy
v
Downstream Service (Scanner, JobEngine, Timeline, Integrations, Concelier, ...)
| UseIdentityEnvelopeAuthentication()
| 1. Reads X-StellaOps-Identity-Envelope + Signature headers
| 2. Verifies HMAC-SHA256 signature
| 3. Checks clock skew (5 min tolerance)
| 4. Hydrates HttpContext.User
v
UseAuthentication() / UseAuthorization()
(standard ASP.NET pipeline continues with the hydrated principal)
```
## Error handling
The middleware never throws. All failures (missing headers, missing key, bad signature,
expired envelope) are logged at Warning level under the `StellaOps.IdentityEnvelope`
logger category. The request continues unauthenticated, allowing the standard JWT
bearer handler to attempt authentication normally.
## Adopted services
| Service | File |
|---|---|
| Concelier | `src/Concelier/StellaOps.Concelier.WebService/Program.cs` |
| Scanner | `src/Scanner/StellaOps.Scanner.WebService/Program.cs` |
| JobEngine | `src/JobEngine/StellaOps.JobEngine/StellaOps.JobEngine.WebService/Program.cs` |
| Timeline | `src/Timeline/StellaOps.Timeline.WebService/Program.cs` |
| Integrations | `src/Integrations/StellaOps.Integrations.WebService/Program.cs` |
## Source
- Middleware extension: `src/Router/__Libraries/StellaOps.Router.AspNet/IdentityEnvelopeMiddlewareExtensions.cs`
- Envelope model and codec: `src/Router/__Libraries/StellaOps.Router.Common/Identity/GatewayIdentityEnvelope.cs`