feat(auth): EasyAuth browser identity as a source inside entra mode (spike, isolation)#42
Draft
colombod wants to merge 1 commit into
Draft
feat(auth): EasyAuth browser identity as a source inside entra mode (spike, isolation)#42colombod wants to merge 1 commit into
colombod wants to merge 1 commit into
Conversation
3815e58 to
3f39a4d
Compare
7abce16 to
8218590
Compare
3f39a4d to
2eb73ab
Compare
8218590 to
8dd171f
Compare
2eb73ab to
262ff71
Compare
12c1e92 to
af46484
Compare
…spike, isolation) Add Azure EasyAuth X-MS-CLIENT-PRINCIPAL-ID as a third identity source inside auth_mode=entra, coexisting with delegated-user and service Bearer JWTs, all resolving via the same entra_identities oid->contributor map. Bearer-wins precedence; scalar-only header extraction; EntraResolver.resolve_principal_id (GUID/all-zeros/unmapped -> 401/403); fail-closed trust_easyauth_principal flag + startup composition gate; Settings frozen=True; named EasyAuthResolveFn Protocol. Hardening from adversarial + council review: strict bool/str validation of entra_identities entries (admin/id), duplicate principal-id header -> 401, co-presence WARNING, no-header 401 logging. TB-7: additive _assert_capability_routes_not_exempt boot guard (no exempt route may carry require_read/require_write) + strict-xfail pins on read/write empty-state; the fail-closed _is_write_capable tightening is deferred to Step 3 (CI-enforced by the xfail tripwire). No _is_write_capable/authz decision-logic change here. Isolation-verified: 1810 passed, 2 skipped, 2 xfailed, 0 failed (no DB/network). Needs-Azure parts (role:web service, anon->302, Test B sole-ingress) deferred. 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
af46484 to
f53b9a9
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add EasyAuth (Azure platform-identity middleware) as a third identity source inside
auth_mode=entra, coexisting with delegated-user Bearer JWTs and service-account Bearer JWTs. The spike covers the isolation half — config, trust gate, resolver, middleware, hardening fixes — but defers the real Azure topology half (actual role:web EasyAuth service deployment + anon→302 gate).This PR is stacked on #41 (Neo4j client split). Base branch is
step1-neo4j-client-split; merge order must preserve the stack.Changes
Config & Trust Gate
trust_easyauth_principal(bool, default=false, fail-closed) inAuthSettingstrust_easyauth_principal=truerequiresauth_mode=entra(no other mode supports EasyAuth)Identity Extraction
EntraResolver.resolve_principal_id: New resolver inside entra mode_extract_easyauth_oid: Scalar-only extraction fromX-MS-CLIENT-PRINCIPAL-IDheaderGUID_RE/ALL_ZEROS_GUIDvalidation rules (prevents spoofed/zero OIDs → 401)Middleware & Auth Flow
auth_event=easyauth_header_with_bearer(signal to rates/tune in ops)Adversarial Hardening
isinstance(bool)Test Infrastructure (Step 3 Pre-Flight)
_assert_capability_routes_not_exempt: ensures no exempt route carriesrequire_read/require_write(prevents conftest-fixture fail-open, addresses:appvs:asgi_appfootgun)test_authz_empty_state.py: pinned xfail on read/write/admin empty-state tests; will flip to XPASS→FAIL when/is_write_capabletightening lands in Step 3 (enforces the blocker; triple-checks won't be silently missed)Testing & Review
Tracked Blockers (Must Land Before Merge/Deploy)
[Step 3 BLOCKER, CI-enforced] Tighten
_is_write_capableto fail-closed on absent scope state (currently default-allow). The strict-xfail pair intest_authz_empty_state.pywill flip to XPASS→FAIL the suite the moment this lands, forcing removal of the markers. Do it in the SAME commit that moves routes (dead-letter →require_admin,/statusbehind auth), M2 matrix (~1200 tests) re-verified. Also: fix conftestclientfixture to route throughasgi_app(stop relying on default-allow) and address the:appvs:asgi_appdual-export footgun (prod must serveasgi_app).[DEPLOY gate, HIGH]
trust_easyauth_principal=trueMUST NOT ship until Test B (deploy-time sole-ingress + edge header-stripping probe) is a HARD gate with a defined failure response (alert/auto-disable) + prod config gated on a recorded recent pass. App does NO crypto verify of the header — the config startup gate only checks auth_mode+web_ui, NOT that EasyAuth is really the ingress. Accepted known bet (same as Team Pulse), but the gate must be real.[Step 3 ops — signal tuning] Co-presence WARNING (auth_event=easyauth_header_with_bearer) may fire on normal browser+bearer traffic → decide metric/rate-limit vs WARNING so it stays actionable.
[Step 3 UX — onboarding paths] identity_unbound 403 needs an actionable onboarding/contact path; no-header 401 is least-informative for the most-innocent failure; session-lifecycle UX TBD.
NEEDS AZURE (deferred to Step 2 Azure half)
This PR is the isolation half — config, trust, resolvers, tests in a single process. The real Azure topology half lives in a separate work item (Step 2 Azure half):
role: webEasyAuth service (not this repo — infrastructure-level)53aa4ffd(enable ID-token implicit grant + add.auth/login/aad/callbackredirect URI)oidGenerated with Amplifier
Co-Authored-By: Amplifier 240397093+microsoft-amplifier@users.noreply.github.com