OIDC: refresh the account from the provider on every sign-in - #16
Merged
Conversation
The display name was written once, by _provisionUser(), and never again. Rename somebody in the directory and FOG kept showing the name they had on the day they first signed in -- forever, with nothing an admin could do about it short of editing the row by hand. Reported against the lab Keycloak: first/last name corrected there, FOG kept rendering the old value on every subsequent login. That is not what a directory-backed account means. The provider is the source of truth for who this is, and a value copied once starts drifting immediately. The LDAP plugin already gets this right -- ldappluginhook.hook.php sets name, display, api and authsource on every login, new row or not -- so this is the OIDC plugin catching up to the behaviour beside it rather than a new idea. Two fields are deliberately NOT refreshed: - uName. The username is what oidcIdentity is keyed against for accounts that predate their link, and renaming a FOG account out from under its history, tasks and audit rows is a migration, not a login side effect. A provider-side rename keeps working anyway, because the binding is the subject. - uAuthSource. Stamping it would take local password login away from an account an admin created, which is the opposite of break-glass. _provisionUser() stamps the rows this plugin made; those are the only ones that get it. uAllowAPI IS re-asserted, and that is a real behaviour change worth naming: the provider's setting now wins over a FOG-side edit at the next sign-in. It matches LDAP, and it means "can these accounts use the API" is answered in one place instead of drifting per user. An empty or absent name claim leaves the stored value alone rather than blanking it -- Google omits it on some scope combinations. The save is conditional, so an unchanged sign-in costs no write and leaves no history row. tests/oidc-profile-refresh.test.php pins both call sites (refreshing on the subject-linked path but not the name-linked one is the original bug wearing a fix), the two fields that must not be written, the fallback VALUE rather than merely the presence of its guard, and the conditional save. Comments stripped first. Six mutations, six caught. Closes part of #15's neighbourhood; single logout is separate.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The display name was written once, by
_provisionUser(), and never again. Rename somebody in the directory and FOG keeps showing the name they had on the day they first signed in — forever, with nothing an admin can do short of editing the row by hand.Reported against the lab Keycloak: first/last name corrected there to
Tom Elliott, FOG kept renderingtelliott Lab Useron every subsequent login.That is not what a directory-backed account means. The provider is the source of truth for who this is, and a value copied once starts drifting immediately.
Not a bug in LDAP
Worth stating since it's the obvious next question: the LDAP plugin already gets this right.
ldap/hooks/ldappluginhook.hook.php:238-241setsname,display,apiandauthsourceon every login, new row or not. So this is the OIDC plugin catching up to the behaviour beside it, not a shared defect.Two fields deliberately NOT refreshed
uNameoidcIdentityis keyed against for accounts that predate their link, and renaming a FOG account out from under its history, tasks and audit rows is a migration, not a login side effect. A provider-side rename keeps working anyway — the binding is the subject.uAuthSource_provisionUser()stamps the rows this plugin made; those are the only ones that get it.One real behaviour change
uAllowAPIis re-asserted from the provider, so the provider's setting now wins over a FOG-side edit at the next sign-in. It matches LDAP, and it means "can these accounts use the API" is answered in one place instead of drifting per user. Flagging it because someone who has hand-enabled API access on an OIDC account will see it revert.Edge cases handled
nameclaim leaves the stored value alone rather than blanking it — Google omits it on some scope combinations, and?? ''yields''for a provider that sends"name": "", which is not the same as absent.Gate
tests/oidc-profile-refresh.test.php, 7 assertions, comments stripped first (this file's own docblocks name every token asserted on).Two that took a second attempt to get right:
_resolveUser()reaches an existing FOG row down two different branches — subject-linked, and link-on-first-sign-in. Refreshing on one but not the other is the original bug wearing a fix, and which branch you are on is invisible from the UI.if ('' === $display)exists passes a version that keeps the branch and assigns''inside it — exactly the bug, with the guard still visible in the diff. That mutation survived the first version of this test.Six mutations tried, six caught.
sh tests/run-all.sh→ 4 passed, 0 failed.