Make OIDC configuration optional so a deployment can start without it #180
Loading…
Reference in a new issue
No description provided.
Delete branch "feature/task-238-optional-oidc"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
AddPlaceMarkOidcnow treats theOidcsection as optional: absent entirely (IConfigurationSection.Exists()false) turns the flow off cleanly — app starts, local sign-in works, OIDC and step-up routes are not mapped. Any key present, however incomplete, is validated exactly as before and is fatal at start-up on the first bad or missing field.ExternalIdentityRepository, andRequestDelegateFactoryfails at endpoint-mapping time (not per request) for an unresolvable handler parameter — mapping it unconditionally was tried and broke start-up outright, not just the two OIDC-only routes.ExternalIdentityRepositorymoved to an unconditional registration inProgram.cs:GET /api/users/me/linked-providersneeds it regardless of whether OIDC is configured today.GET /api/auth/oidc/availability, mapped unconditionally, so the WebUI knows whether to offer "Sign in with SSO" / "Link an external sign-in" / "Unlink" at all rather than risking a 404.docker-compose.yml,user-secrets.example.json,.env.exampleand the README no longer carry theoidc.invalidplaceholders; Compose passesOidc__*through only when set in.env, never with a default, so an unset value is genuinely absent rather than an empty string (which would still count as "present").Oidc:Enabledflag.Test plan
OidcStartupTestscovers all three states: absent starts cleanly and doesn't map OIDC/step-up routes; complete validates and starts as before; a section with a single key still throws.Exists()check, and separately gutting the field validation) before being trusted, then restored.fullprofile stack brought up and torn down on a fresh clone with no.env: API started healthy with noOidc__*in its environment, OIDC routes 404, availability reportsfalse.Verdict: mergeable
Attacked the absent-vs-incomplete line specifically and couldn't break it:
Exists()correctly returns false only when the section has neither a value nor any child — one key set (any of the five), an empty string, or a whitespace value all land inExists()==trueand go throughRequireAbsoluteUrl/RequireNonBlank, which correctly reject blank/whitespace.CreateApi_OidcSectionCarriesOnlyOneKey_StillFailsToStartproves the single-key case;UseTestJwtConfigurationWithoutOidc's own remarks correctly note that setting a value tonullviaUseSettingstill leaves the key present (Exists()true), which is why a separate builder method was needed for the true-absent case — good catch on their part.Oidc:Enabledflag was deliberately rejected in ADR-0154 so there's no separate flag to desync from the five real values.AddPlaceMarkOidc, called beforebuilder.Build(), so it's still register-time, not deferred to first request.docker-compose.yml's bare-key pass-through (Oidc__Authority:with no value/default) is the right mechanism to keep an unset.envvar genuinely absent from the container rather than an empty string — confirmed this is documented Compose behaviour, distinct from${VAR}interpolation, and the PR says it was verified directly against a container besides.CreateApi_OidcSectionAbsentEntirely_StartsCleanlyAndDoesNotMapOidcEndpointsasserts on the actual 404/200 responses, andCreateApi_OidcSectionCarriesOnlyOneKey_StillFailsToStartwould genuinely redden if theExists()gate were inverted or deleted.OidcAvailabilityStatefails closed (Enabledstaysfalseon load failure, retries next visit). SSO/Link are hidden (not disabled) when unavailable, matching the ADR's stated rationale that a disabled control implies "just switch it on" which isn't true here. The previously-linked-identity case is handled correctly and is the part I expected to find broken:Account.razorkeeps Unlink visible but disabled with an explanatory message when OIDC is off but a provider is still linked, rather than either hiding it or offering a dead link —Account_OidcUnavailableWithALinkedProvider_DisablesUnlinkAndExplainsWhyasserts on both thedisabledattribute and the hint text.Answered bywas added and ADR-0154 cites them one-directionally instead.docs/adr/README.mddiff is a clean single-row addition.No findings to act on.