feat(caddy): send Forgejo's sign-in link straight to Kanidm #290
Inga granskare
Etiketter
Inga etiketter
area/backups
area/ci
area/control-panel
area/identity
area/infra
area/observability
area/payments
area/security
area/storage
area/web
blocked
needs-info
needs-triage
ready-for-implementation
type
bug
type
chore
type
docs
type
epic
type
feature
type
task
wontfix
Ingen milstolpe
Inget projekt
Inga tilldelade
1 deltagare
Notiser
Förfallodatum
Inget förfallodatum satt.
Beroenden
Inga beroenden satta
Referens
bitborg/bitborg-infra!290
Läser in…
Hänvisa till i nytt ärende
Ingen beskrivning angiven.
Ta bort grenen "feat/login-straight-to-oidc"
Borttagning av en gren är permanent. Även om den borttagna grenen kan fortsätta existera en kort tid innan den faktiskt tas bort, kan det INTE ångras i de flesta fall. Vill du fortsätta?
Answers the operator's question: yes, it is possible — but only in the reverse proxy.
Why not in Forgejo
There is no
app.inisetting. forgejo#732 requests exactly this and is unmerged, because an instance may have several auth sources so "the" provider is not well defined in general. Upstream's own suggestion is a reverse-proxy rewrite.With
ENABLE_INTERNAL_SIGNIN = falsethere is no local form, so/user/loginrenders a heading and a single button pointing at/user/oauth2/Bitborg%20Auth. Every web login costs a click on a page with nothing to decide.Deep links survive — verified before building it
The real risk was that the OIDC start route would drop
redirect_to, so someone clicking "sign in to comment on this issue" would land on the dashboard instead. Forgejo's login page stashes that parameter in a cookie; the question was whether/user/oauth2/<source>does the same.It does:
The parameter is genuinely read and persisted, and the control proves it is not an unconditional cookie. Passing
{query}through preserves it.Had this gone the other way I would have recommended against the change rather than shipping a silent regression on every deep link.
Two escape hatches
This redirect sits on the documented break-glass path — your
app.inicomment names re-enablingENABLE_INTERNAL_SIGNINas the recovery route when OIDC login is broken. A blanket redirect would bounce you into the broken OIDC in exactly that emergency. So:forgejo_enable_internal_signinis true, so re-enabling local sign-in through Ansible removes the redirect with it./user/login?local=1is never redirected, which still works ifapp.iniwas edited by hand on the host without running Ansible — the likely case when OIDC is down and Ansible is not the tool you reach for.GETonly, so nothing POSTing to/user/loginis affected.Verification
--syntax-checkclean;ansible-lint roles/caddy/passes on the production profile.Dry-run
--check --diff --tags caddy:changed=2— the Caddyfile render and the consequent Caddy restart. Renders as:Safety net: the role's existing
Validate the rendered Caddyfiletask runscaddy validateand fails before the config is used, so a matcher-syntax mistake aborts the play instead of taking down all four public hosts. It is acommand, so--checkskips it and the apply is its first real exercise.Post-apply checks
https://git.gitborg.se/user/login→ lands on Kanidm, not on the button page./user/login?redirect_to=%2Fexplore%2Frepos→ after signing in, you end up on /explore/repos, not the dashboard. This is the one worth actually doing./user/login?local=1→ still shows Forgejo's page. The break-glass hatch.Related
Independent of bitborg-infra#289, which fixes a different fault: the Kanidm dashboard tile pointed at Forgejo's logged-out root and signed nobody in. That was a dead link; this is a working link with a redundant click.
With ENABLE_INTERNAL_SIGNIN false there is no local login form, so /user/login renders a heading and a single button linking to /user/oauth2/<source>. Every web login therefore costs an extra click on a page with nothing to decide. Forgejo cannot skip that page itself. Upstream issue 732 asks for exactly this and is unmerged, because an instance may have several auth sources and picking one is not well defined in general. Upstream's own suggestion is a reverse-proxy rewrite, which is what this is. VERIFIED BEFORE BUILDING IT that deep links survive. Forgejo's login page stashes ?redirect_to= in a cookie so you land where you were heading; the concern was that the OIDC start route would drop it, sending someone who clicked "sign in to comment on this issue" to the dashboard instead. It does not: GET /user/oauth2/Gitborg%20Auth?redirect_to=%2Fexplore%2Frepos → set-cookie: redirect_to=%2Fexplore%2Frepos GET /user/oauth2/Gitborg%20Auth → no redirect_to cookie at all So the parameter is genuinely read and persisted, and passing {query} through preserves it. Two escape hatches, because this redirect sits on the documented break-glass path and could otherwise block the emergency it is most likely to be needed in: 1. The whole block is templated out when forgejo_enable_internal_signin is true, so re-enabling local sign-in through Ansible removes the redirect with it. 2. /user/login?local=1 is never redirected, which still works if app.ini was edited by hand on the host without running Ansible — the likely case when OIDC is broken and Ansible is not the tool reaching for. GET only, so nothing POSTing to /user/login is affected. The role's existing "Validate the rendered Caddyfile" task is the safety net for the matcher syntax: it runs caddy validate and fails before the config is used, so a mistake aborts the play rather than taking down all four public hosts. That task is a command, so --check skips it and the apply is its first real exercise.