2026-09-27 19:03:06 +02:00
|
|
|
---
|
|
|
|
|
id: ADHOC-2026-09-27
|
|
|
|
|
type: workplan
|
|
|
|
|
title: "Fresh MFA no longer backdated to a stale kc_login cookie (INFD-IN-0005)"
|
|
|
|
|
domain: infotech
|
|
|
|
|
repo: key-cape
|
|
|
|
|
status: finished
|
|
|
|
|
owner: claude
|
|
|
|
|
created: "2026-09-27"
|
|
|
|
|
updated: "2026-09-27"
|
2026-09-27 19:17:09 +02:00
|
|
|
state_hub_workstream_id: "5217dd06-73cb-50f8-ba64-528e421b29de"
|
2026-09-27 19:03:06 +02:00
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Stop completeAuthorization from reusing a stale prior session's IssuedAt after real MFA
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
id: ADHOC-2026-09-27-T01
|
|
|
|
|
status: done
|
|
|
|
|
priority: high
|
2026-09-27 19:17:09 +02:00
|
|
|
state_hub_task_id: "ce98e4af-cfaa-5620-8f21-15ade18ee9e8"
|
2026-09-27 19:03:06 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
`informed-decision` intake `INFD-IN-0005` (open, `origin_ref: SECRETS-WP-0010`):
|
|
|
|
|
platform-root's approval of `infd-20260927-b01` was refused by flex-auth's
|
|
|
|
|
`compact_sitting` policy with `policy_denied`, despite platform-root having just
|
|
|
|
|
completed a fresh key-cape MFA sign-in. flex-auth's 900-second review-freshness
|
|
|
|
|
check reads `assurance.at`, which key-cape derives from the PKCE session's
|
|
|
|
|
`AuthTime`.
|
|
|
|
|
|
|
|
|
|
Root cause in `src/internal/server/oidc/authorize.go`,
|
|
|
|
|
`AuthorizeHandler.completeAuthorization`: whenever a `kc_login` cookie already
|
|
|
|
|
existed for the same username, its `IssuedAt` was unconditionally reused as
|
|
|
|
|
`authTime` — even on the two call sites that had just called
|
|
|
|
|
`MFA.ValidateMFAToken` successfully in this exact request (the callback's
|
|
|
|
|
`mfaToken != ""` branch and `serveMFASubmission`). A user who had an older
|
|
|
|
|
browser session and then stepped up with a fresh MFA challenge got the *old*
|
|
|
|
|
session's timestamp stamped onto the *new*, just-proven authentication —
|
|
|
|
|
understating freshness for every downstream binding-grade check, exactly as
|
|
|
|
|
`INFD-IN-0005` describes ("completeAuthorization currently copies a prior
|
|
|
|
|
timestamp... only after actual reauthentication").
|
|
|
|
|
|
|
|
|
|
The reuse itself is correct when MFA was **not** just performed in this
|
|
|
|
|
request (`decision.MFAVerified` carried forward from an existing AAL2 session,
|
|
|
|
|
via `domain.DecideAssurance`) — reporting mint time there would overstate
|
|
|
|
|
freshness (`TestAssuranceReportsAuthenticationTimeNotMintTime`). The two cases
|
|
|
|
|
were conflated under a single `mfaVerified` bool.
|
|
|
|
|
|
|
|
|
|
Fix: added a `freshMFA bool` parameter to `completeAuthorization`, `true` only
|
|
|
|
|
at the two call sites that just validated an MFA token in this request, `false`
|
|
|
|
|
at the carried-forward-assurance call site. `authTime` now falls back to the
|
|
|
|
|
prior session's `IssuedAt` only when `!freshMFA`.
|
|
|
|
|
|
|
|
|
|
Added `TestAuthorizeCallback_MFASubmission_FreshEvenWithStalePriorLoginCookie`,
|
|
|
|
|
which seeds a 4-hour-old `kc_login` cookie for the same user, then submits a
|
|
|
|
|
valid MFA token and asserts the resulting `AuthTime` is within a minute of now.
|
|
|
|
|
Confirmed it fails against the pre-fix code (`AuthTime` ~4h old) and passes
|
|
|
|
|
after. Full suite (`go test ./...`) green, no other test needed adjustment —
|
|
|
|
|
the carried-forward-assurance case (`TestPolicy_...`, `TestLogout_...`,
|
|
|
|
|
`assurance_time_test.go`) is unaffected since none of it exercises a fresh MFA
|
|
|
|
|
submission with a pre-existing cookie for the same user.
|
|
|
|
|
|
|
|
|
|
Does not touch flex-auth (its 900s window is correct; it was consuming a bad
|
|
|
|
|
timestamp) or informed-decision (correctly refuses to interpret the PDP's
|
|
|
|
|
denial). `INFD-IN-0005` can close once informed-decision confirms platform-root
|
|
|
|
|
can approve after a fresh sign-in against this build.
|
2026-09-27 19:35:51 +02:00
|
|
|
|
|
|
|
|
## Discovery/JWKS fetch was missing the split-horizon origin headers
|
|
|
|
|
|
|
|
|
|
```task
|
|
|
|
|
id: ADHOC-2026-09-27-T02
|
|
|
|
|
status: done
|
|
|
|
|
priority: high
|
2026-10-18 10:10:38 +02:00
|
|
|
state_hub_task_id: "7fa0bfc7-0772-57c7-8d6f-641615cab82a"
|
2026-09-27 19:35:51 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Rolling out T01 (image digest `sha256:248e449a...`) broke every KeyCape login,
|
|
|
|
|
including unrelated clients (`user-engine-portal`), with `auth_failure` /
|
|
|
|
|
`provider_metadata_unavailable` at `/api/oidc/token` on the KeyCape side and
|
|
|
|
|
Authelia logging `invalid X-Forwarded-Proto header value 'http'` on
|
|
|
|
|
`GET /.well-known/openid-configuration` from KeyCape's pod IP.
|
|
|
|
|
|
|
|
|
|
Root cause, unrelated to T01's change: `AutheliaAdapter.setPublicOriginHeaders`
|
|
|
|
|
(the NK-WP-0041-T02/path-B fix, key-cape@3b0446e) annotates only the token
|
|
|
|
|
exchange (`newTokenRequest`) with `X-Forwarded-Proto`/`X-Forwarded-Host` so
|
|
|
|
|
Authelia can derive the public issuer for a split-horizon (in-cluster HTTP,
|
|
|
|
|
public HTTPS) deployment. `idTokenVerifier.get` in `verify.go` — used for the
|
|
|
|
|
provider-metadata and JWKS fetches that verify every upstream ID token — never
|
|
|
|
|
got the same treatment; it built a bare request with only an `Accept` header.
|
|
|
|
|
Authelia 4.38 fails closed on the resulting unmarked in-cluster request. This
|
|
|
|
|
gap predates today's session (present since 3b0446e); it surfaced now because
|
|
|
|
|
this was the first login attempted since that image went live.
|
|
|
|
|
|
|
|
|
|
Fix: extracted `setPublicOriginHeaders` from an `AutheliaAdapter` method to a
|
|
|
|
|
package-level function taking the target public base URL explicitly, and gave
|
|
|
|
|
`idTokenVerifier` its own resolved `publicBaseURL` (same
|
|
|
|
|
`BrowserBaseURL`-else-`BaseURL` fallback as the adapter) so `get()` applies
|
|
|
|
|
the same headers. Added `TestDiscoveryFetch_CarriesPublicOriginHeaders`
|
|
|
|
|
(confirmed it fails without the fix, passes with it). Full suite green.
|
|
|
|
|
|
|
|
|
|
New image `key-cape@<pending>` still needs a rollout to `sso-mfa/k8s/keycape/deployment.yaml`
|
|
|
|
|
before platform-root can sign in again.
|