#413 · Directory accounts lose access when someone leaves the directory (#408)
- timeline-app
- pull request
Closes #408 ## What changes Directory (LDAP / Active Directory) membership used to be checked only at sign-in, so sessions (up to 14 days) and API keys (up to a year) outlived someone's removal from the directory or `LDAP_REQUIRED_GROUP`. Now the server checks directory accounts periodically and ends that access. - **`server/directory-check.mjs`** (new): every `LDAP_CHECK_MINUTES` the server reads every `ldap` identity and asks the directory which are still there (`Directory.present`). An account whose entry is gone, out of `LDAP_REQUIRED_GROUP`, or disabled has its sessions, API keys, desktop sign-ins and challenges ended through `AccountSecurity.endAccess`, the same path security changes and #406's release use, in one transaction under the account lock. - **`server/ldap.mjs`**: `Directory.present(subjects)` binds with the service account and searches by `objectGUID` (bytes re-ordered back from `subjectOf`'s text), `entryUUID`, or a base read at the DN for `dn:` subjects. It searches 100 at a time in one OR filter under `LDAP_BASE_DN`, combined with the group filter (now factored out as `groupFilter`, nested groups included). "Disabled" reuses nothing existing because there was nothing to reuse. It is only AD's `userAccountControl` ACCOUNTDISABLE bit, read when the attribute is present, so other directories are unaffected. `LDAP_CHECK_MINUTES` is parsed and validated in `directoryFromEnv` with the other LDAP settings. A directory sign-in clears the "left" mark. - **Schema**: `oc_identities.left_at` (when the check found the person gone) and `oc_site_settings.directory_checked_at` (the shared schedule). - **`server/platform.mjs`**: starts the check beside retention, standing and IndexNow. ## Design choices - **Interval**: `LDAP_CHECK_MINUTES`, default 60, `0` turns it off, a whole number or startup is refused. Each process looks every 5 minutes (or every interval when that is shorter) whether a check is due. A session-level advisory lock (as `retention.mjs` takes) plus `directory_checked_at` means one check per interval however many processes share the database. - **Once per departure**: `left_at` is set in the same transaction that ends access, and only accounts with it unset are acted on. Repeated runs therefore do nothing for people already gone, including an account that also has a password and signed in again with it, which is not signed out hourly. A later check that finds the person again, or their next directory sign-in, clears it, so a second departure is acted on again. - **How administrators learn of it**: a log line per account (`Directory check: ended the sessions and API keys of ( )`) and an `oc_admin_audit` row, action `directory-left`, with the reason and subject. The account itself is the actor, as `reset-admin-password.mjs` does. There is no new UI. - **No auto-suspend**: a directory-only account already cannot sign in once the directory refuses it, and it comes back by itself if the person is re-added. `is_disabled` is the administrators' and moderators' decision, which hides profiles and has no automatic undo. Suspending it automatically would also make a misconfiguration much more damaging. The docs keep "suspend in /admin" as the way to cut access at once. - **Outages never sign anyone out**: an unreachable directory, a failed service bind, or any failed search (a wrong base DN fails as NoSuchObject) makes the run change nothing and log `Directory check skipped: … Nobody was signed out; the next run tries again.` - **Mass-removal guard**: if a run would newly end access for more than half of the accounts not already marked left, and for more than 5 of them, it is treated as a misconfiguration (a wrong base DN or group). It changes nothing and logs `N of M directory accounts would lose access at once, which looks like a misconfigured LDAP_BASE_DN or LDAP_REQUIRED_GROUP …`. A departure that large is left to administrators. - Per the issue, every account with an `ldap` identity is checked, including ones th…
Sources
Open #413 · Directory accounts lose access when someone leaves the directory (#408) in the timeline