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