From 7f33c3e8083419fb143785a357017fcfce7b3eb2 Mon Sep 17 00:00:00 2001 From: Tom Elliott Date: Tue, 18 Aug 2026 07:38:55 -0500 Subject: [PATCH] Document the local login page, single logout, and forced redirect FOG 1.6 can now be told to send everyone straight to an identity provider, and to end the provider's session when FOG's ends. Both are per-provider settings on the OIDC plugin, both ship off, and one of them can lock every administrator out of a server. ## A page of its own for management/login.php The forced-redirect setting is only safe because there is one URL that always renders FOG's own login form and can never be redirected. That is not a footnote in a plugin page: somebody reaching for it is locked out, in a hurry, and cannot go looking. It needs to be findable by searching for what they are experiencing, which is why the page carries aliases for "break-glass login", "emergency login", "bypass SSO login" and the plain filename. What it covers, in the order somebody would need it: the URL first, then why it exists, then -- because the name invites the wrong reading -- what it does NOT relax. It is the same login: same password check, same roles, same audit trail. The only difference is where the page will and will not send you. Two things there that are easy to get wrong and expensive to discover late: - An account FOG PROVISIONED cannot use it. Those are created with a random token nobody has ever seen, so there is no password to type. Only accounts an administrator created keep a local password. That distinction is the whole of a break-glass plan, so the page says to check it rather than assume it. - The floor FOG enforces preserves, it does not require. An install that has deliberately moved every administrator to a directory has nothing left for it to protect, and this page will not help them. Better said out loud than discovered during an outage. ## The two OIDC settings Both in oidc.md, next to the behaviour they change: - Signing out, including the post-logout redirect URI that has to be registered at the provider and where to put it in Keycloak, Entra and Okta. Providers refuse an unregistered one and show their own error page, which looks exactly like FOG being broken. - Sending everyone straight to the provider, opening with the warning rather than closing with it, and naming the escape hatch inside the warning. Also: why two flagged providers refuse to redirect at all rather than silently picking one. The interaction between them gets its own section, because it is the question an admin will actually have: with single logout ON, logging out returns you to the ordinary login page, which redirects, and the provider -- having genuinely lost its session -- asks who you are. With it OFF, that journey would sign you straight back in, so FOG lands you on the local login page instead. Six new troubleshooting rows for the symptoms these produce, all of which present as "the login page is broken" rather than as a setting. Written against plugin v1.6.10; the post-logout URI callout names the v1.6.9 value it replaces, because an install that enabled single logout at that version has a stale registration at its provider. --- docs/management/web/index.md | 1 + docs/management/web/local-login.md | 179 +++++++++++++++++++++++++++++ docs/management/web/oidc.md | 130 +++++++++++++++++++++ 3 files changed, 310 insertions(+) create mode 100644 docs/management/web/local-login.md diff --git a/docs/management/web/index.md b/docs/management/web/index.md index fc8c0d2..8af865d 100644 --- a/docs/management/web/index.md +++ b/docs/management/web/index.md @@ -22,6 +22,7 @@ Documentation related to how to use the web management ui. - [[site-scoping|Site Scoping]] - [[ldap|LDAP Authentication]] - [[oidc|OpenID Connect Sign-in]] +- [[local-login|The Local Login Page]] - [[ad-integration|Active Directory Integration]] **Imaging Objects** diff --git a/docs/management/web/local-login.md b/docs/management/web/local-login.md new file mode 100644 index 0000000..699609c --- /dev/null +++ b/docs/management/web/local-login.md @@ -0,0 +1,179 @@ +--- +title: The Local Login Page +aliases: + - Local Login + - login.php + - Break-glass Login + - Emergency Login + - Backdoor Login + - Bypass SSO Login +description: One URL that always shows FOG's own username and password form, whatever your identity provider is doing +context_id: local-login +tags: + - 1_6-changes + - management + - users + - security + - oidc + - ldap + - web-ui + - web-management +--- + +# The Local Login Page + +## The URL + +``` +https://fog.example.com/fog/management/login.php +``` + +This page **always** shows FOG's own username and password form. It cannot +be redirected to an identity provider, it does not consult one, and no +plugin can change that. + +>[!note] This page describes FOG 1.6 +>`management/login.php` landed during 1.6 development. On 1.5 there is no +>equivalent, and no setting that would need one. + +Bookmark it now, before you need it. Somebody locked out of a FOG server is +in no position to go looking for a URL, and this is not one you would guess. + +## Why it exists + +FOG can be configured to send everyone straight to an identity provider — +see [[oidc#Sending everyone straight to the provider|Sending everyone straight to the provider]]. +On an install where every account lives at the provider, that is the right +setting: FOG's password box cannot accept those credentials, so all it does +is add a click. + +It is also the setting that can lock every administrator out of a server at +once. If the provider becomes unreachable, its certificate expires, its +client secret is rotated, its discovery document breaks, or its issuer was +mistyped, then a login page that unconditionally redirects has no way back +— including for the local account that exists for exactly this situation. + +`login.php` is the way back. + +## What it does and does not do + +| | | +|---|---| +| **Does** | Show FOG's normal login form and sign you in with a local username and password | +| **Does** | Keep working when your identity provider is down, misconfigured, or removed | +| **Does not** | Bypass any password check, permission, role, or site scope | +| **Does not** | Let an account owned by a provider sign in with a password — that account has no local password to use | +| **Does not** | Offer the provider buttons, because on a broken provider they are what you are escaping | + +It is the **same** login. Same form, same session, same CSRF protection, +same audit trail, same [[roles|roles]]. The only difference is where the +page will and will not send you. + +>[!warning] It is not a way around authentication +>The name "break-glass" describes when you reach for it, not what it +>relaxes. Everything still has to be a valid FOG account with a valid +>password, and everything it can do is still governed by its roles. There +>is nothing here to protect that the login form does not already protect. + +## Who can actually use it + +An account can sign in here if it has a **local password**. In practice: + +- **Accounts an administrator created** — yes, always. Creating an account + in FOG sets a password, and signing into it through a provider later does + not take that password away. +- **Accounts FOG provisioned** (created on first sign-in by + [[oidc#Who is allowed in|Create Users On First Login]], or by + [[ldap|LDAP]]) — **no**. They are created with a random token nobody has + ever seen, so there is no password to type. They can only be reached + through the directory that made them. + +That distinction is the whole of your break-glass plan, and it is worth +checking rather than assuming. + +## Make sure at least one account can use it + +FOG enforces a floor, and you will meet it as a refusal: + +- You **cannot delete** the last administrator who can sign in with a local + password, even when other administrators exist through a directory. +- You **cannot convert** that account to an external identity either. + +Both are refused with *"This would leave no account able to administer FOG +without its identity provider."* To get past either, give another +administrator account a local password first. + +The floor preserves; it does not require. An install that has deliberately +moved every administrator to a directory has nothing left for this to +protect, and FOG will not start refusing that install's operations to +defend a property it already gave up. **If that is your install, this page +will not help you** — so decide on purpose rather than by drift. + +>[!note] Check it before you need it +>Sign out, open `login.php`, and log in with a local administrator account. +>Do it once, now, and again whenever you change how people sign in. A +>break-glass plan nobody has tested is a plan you find out about during the +>outage. + +## Why it is safe to leave reachable + +An obvious worry: if this page ignores the redirect, is it a way around +single sign-on? + +No. Removing the redirect does not remove a *check*. The redirect is a +convenience — it saves a click for people whose credentials live at the +provider. What decides whether somebody gets in is the password and the +roles, and those are identical on both pages. Somebody with no FOG account +and no FOG password gets nothing here, exactly as they get nothing on +`index.php`. + +If you need people to be *unable* to sign in with a password, that is a +different control: give those accounts an external identity, which removes +their local password. Do that per account. Do not rely on the login page +being hard to reach. + +## How the guarantee is built + +Worth knowing, because it explains why this page keeps working when the +thing that broke is the plugin itself. + +FOG's login page offers plugins one opportunity to redirect an anonymous +visitor somewhere else. `login.php` marks the request as a local login +before FOG's login page runs, and the login page only offers that +opportunity when the mark is **absent**. + +So on this URL a plugin is not asked and then overruled — **it is never +asked at all**. A plugin that is misconfigured, half-installed, throwing +errors, or in the middle of failing to reach a provider cannot take this +page down with it, because nothing on this page calls into it. + +It is also not a second copy of the login form. `login.php` reuses the real +one, so it cannot drift from it and a fix to one is a fix to both. + +## When FOG sends you here by itself + +You will also arrive here without asking, in two situations. Both are cases +where returning to the normal login page would bounce you back out to a +provider that cannot help: + +- **A sign-in was refused.** The reason is shown on this page. Returning to + a provider that just said no would be a loop. +- **You logged out on an install that redirects to a provider, with + [[oidc#Signing out|Single Logout]] off.** Your provider session is still + alive, so the normal login page would sign you straight back in. You are + signed out of FOG; you are still signed in at the provider. + +With Single Logout **on**, logging out does not land you here — the +provider session is genuinely ended, so FOG returns you to the normal login +page and the provider asks for credentials. + +## Related + +- [[oidc|OpenID Connect Sign-in]] — the redirect setting this page exists + to survive, and where to turn it on +- [[oidc#Break-glass|OIDC break-glass rules]] — which accounts keep a local + password +- [[ldap|LDAP Authentication]] — the other directory FOG can provision + accounts from +- [[users|User Management]] — where to give an administrator a local + password diff --git a/docs/management/web/oidc.md b/docs/management/web/oidc.md index 1b7db32..3479568 100644 --- a/docs/management/web/oidc.md +++ b/docs/management/web/oidc.md @@ -8,6 +8,8 @@ aliases: - Entra ID Login - Keycloak Login - Google Workspace Login + - Single Logout + - Forced SSO description: How the OpenID Connect plugin lets people sign in to FOG with an identity provider, and which role each one receives context_id: oidc tags: @@ -58,6 +60,8 @@ turn off — see [[#Break-glass]]. | **Username Claim** | Which claim names the FOG account. Defaults to `preferred_username` | | **Group Claim** | Which claim carries group membership. Defaults to `groups` | | **Enabled** | Off until you switch it on | +| **Single Logout** | Signing out of FOG also ends the session at the provider. Off by default — see [[#Signing out]] | +| **Redirect Login To This Provider** | Send everyone straight to the provider instead of showing FOG's login form. Off by default — read [[#Sending everyone straight to the provider]] before ticking it | You do not enter the authorization, token or key endpoints. FOG reads them from `/.well-known/openid-configuration` on every sign-in, @@ -322,6 +326,122 @@ Deleting a mapping revokes it too, at everyone's next sign-in. FOG keeps a record of what it granted each person precisely so that removing a mapping does what it looks like it does. +## Signing out + +By default, **Log out** ends FOG's session and nothing else. Your provider's +own session is untouched, so clicking the provider button again signs the +same person straight back in with no prompt. That is the standard behaviour +of single sign-on and is often what people expect. + +It is a problem in one case: an account owned by a provider cannot sign in +with a local password, so on a shared computer there is no way to hand over +to somebody else short of clearing cookies. + +Tick **Single Logout** on the provider to end the provider's session too. +It ships **off**, deliberately: it is only the right answer where FOG is +the only application behind that provider. If you share an identity +provider with your mail, your ticket system and your VPN, then signing out +of FOG signing people out of all of them is a surprise reaching +applications FOG has nothing to do with. + +### Register the post-logout redirect URI + +The provider needs to know where to send people after it ends their +session, and — like the sign-in redirect URI — it will only accept a value +you have registered in advance. Most providers refuse an unregistered one +and show their own error page instead of coming back, which looks exactly +like FOG being broken. + +FOG shows the exact value on the provider's page, next to the setting. +Copy it from there. It looks like: + +``` +https://fog.example.com/fog/management/index.php +``` + +Where to put it: **Keycloak** — the client's *Valid post logout redirect +URIs*. **Entra ID** — the app registration's *Front-channel logout URL*. +**Okta** — the application's *Sign-out redirect URIs*. + +>[!warning] This value changed in plugin v1.6.10 +>On v1.6.9 it was `…/management/login.php`. If you turned Single Logout on +>at that version, re-register the new value — providers that follow the +>spec refuse an unregistered one and show their own error page instead of +>coming back to FOG. + +That is FOG's ordinary login page, and on an install that also has the +redirect below turned on it sends you back to the provider. That is the +point: the provider session was just ended, so it asks who you are instead +of waving you through. Signing out and signing in as somebody else is one +journey. + +If the provider publishes no `end_session_endpoint`, FOG cannot do this at +all. It logs that to the web server's error log and signs you out of FOG +only, which is otherwise indistinguishable from the setting being off. + +## Sending everyone straight to the provider + +On an install where every account lives at your provider, FOG's username +and password box is a dead end — it cannot accept those credentials, so all +it does is add a click. Tick **Redirect Login To This Provider** and an +anonymous visitor goes straight to the provider instead. + +>[!warning] Read this before you tick it +>This setting can lock every administrator out of your server. If the +>provider becomes unreachable, its certificate expires, its client secret +>is rotated, or its issuer was mistyped, a login page that unconditionally +>redirects has no way back through a browser. +> +>**The way back is [[local-login|The Local Login Page]]:** +>`https://fog.example.com/fog/management/login.php`, which always shows +>FOG's own form and can never be redirected. FOG prints that URL next to +>the checkbox. Bookmark it, and confirm a local administrator can sign in +>there, before you turn this on. + +It ships **off**, and a newly created provider always has it off. + +Three things it deliberately does not do: + +- **It does not affect anyone already signed in.** The redirect happens + only when an anonymous visitor is about to be shown the login form. +- **It does not interfere with the sign-in coming back.** The callback is a + different route and is never redirected. +- **It does not trap you in a loop when the provider refuses.** A failed + sign-in lands on the local login page with the reason attached, rather + than bouncing straight back out to the provider that just said no. + +### Two providers cannot both do it + +If more than one enabled provider has this ticked, FOG **refuses to +redirect at all** and shows its normal login form, naming the providers +involved in the web server's error log. + +That is on purpose. The login page cannot redirect to two places, and +silently picking one would send everybody to a provider that was never +chosen — on the one page you are least able to debug. Showing the form is a +working login for everybody and visibly not what you asked for. + +If you want this behaviour, pick one provider and untick the others. + +### Logging out with this on + +**Turn [[#Signing out|Single Logout]] on as well.** With both on, signing +out ends the provider session and returns you here, which sends you back to +the provider — and because its session is genuinely gone, it asks for +credentials. That is the behaviour people expect from "log out". + +If Single Logout is **off**, that same journey would sign you straight back +in: your provider session is untouched, so the redirect is answered +silently. FOG avoids that by sending you to +[[local-login|the local login page]] instead. You are signed out of FOG, +still signed in at the provider, and looking at a form rather than back +where you started — correct, but a little surprising, and the reason to +turn Single Logout on. + +A **failed** sign-in always lands on the local login page too, whatever +these settings say. Bouncing back to a provider that just refused you is a +loop. + ## Break-glass **Local password login can never be turned off.** There is no setting @@ -329,6 +449,11 @@ for it. That is deliberate: an expired client secret, a mistyped issuer or a provider outage must not be able to lock you out of your own server. +It has its own page, because it is the thing to reach for when everything +here has gone wrong: [[local-login|The Local Login Page]], at +`https://fog.example.com/fog/management/login.php`. That URL always shows +FOG's own form and can never be redirected to a provider. + Two rules back it up, and you will meet them as refusals: - **You cannot delete the last administrator who can sign in with a @@ -387,6 +512,11 @@ administrator made keeps whatever API setting it already had. | *Unknown identity provider*, on a provider that is configured and enabled | The provider row failed validation, or the sign-in URL arrived without its `?provider=` parameter. Both were fixed during 1.6 development; update the server and the bundled plugins. | | *That identity provider is not enabled* | Checked on the way back as well as on the way out, so disabling a provider ends sign-ins already in progress. | | Signs in fine but sees nothing | No mapped group, or the group value does not match what the provider sends. See [[#Getting the group values right]]. | +| The login page never appears — it always goes to the provider | **Redirect Login To This Provider** is on. Use [[local-login\|the local login page]] to get in and untick it. | +| The login page still appears although the redirect is ticked | More than one enabled provider has it ticked, so FOG refused to choose. Check the web server's error log; untick all but one. | +| Logging out leaves you signed in — the provider button lets you straight back | **Single Logout** is off. That is the default. | +| Log out ends at the provider's error page instead of returning to FOG | The post-logout redirect URI is not registered at the provider. See [[#Register the post-logout redirect URI]]. | +| Log out signs you out but does not end the provider session, with **Single Logout** on | The provider publishes no `end_session_endpoint`. FOG logs this to the web server's error log. | Anything the person in the browser should not see — a signature failure, an unreachable endpoint, a refused subject — is written to the web