Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
c19bb69
An LDAP search that does not end with success is refused as an outage…
wshallwshall Oct 16, 2026
6f2f4f5
The start-up credential probe runs off the event loop (BACKLOG #3164)
wshallwshall Oct 16, 2026
251080a
Directory role and disable notices name the directory, not an adminis…
wshallwshall Oct 16, 2026
c2337e6
TOTP enrolment follow-ups from PR 2080 (BACKLOG #3164 #3121 #3113)
wshallwshall Oct 16, 2026
c6113d9
LDAP result-code refusal: referral checked inside the helper, picklab…
wshallwshall Oct 16, 2026
d2c88da
Review round one on the D1 auth follow-ups (BACKLOG #3164 #3121 #3113)
wshallwshall Oct 16, 2026
1d5ff35
D1 round-two follow-ups: the enrolment refusal row survives any revok…
wshallwshall Oct 16, 2026
3010fd9
The nested group search is paged, and an unknown LDAP result code is …
wshallwshall Oct 16, 2026
c67c178
A self-service session revoke that ends nothing writes one audit row …
wshallwshall Oct 16, 2026
c8fae10
OIDC step-up wave 1 follow-ups from engine PR 2078 (BACKLOG #3145)
wshallwshall Oct 16, 2026
6512a27
Paging refuses a later page that drops its control; Who am I and bind…
wshallwshall Oct 16, 2026
7a6961a
The step-up header test reads the shared constant through auth_models…
wshallwshall Oct 16, 2026
6fcd43b
The API client's sign-in and queued elevations wait 30 seconds (BACKL…
wshallwshall Oct 16, 2026
aaa9f56
Simplify pass: one store-fault set, one step-up header name, one boun…
wshallwshall Oct 16, 2026
9ed8226
One ldap3 error boundary decides a decode fault by origin; refused pa…
wshallwshall Oct 17, 2026
834697e
Review round one on the D2 auth follow-ups (BACKLOG #3260 #3145 #2950)
wshallwshall Oct 17, 2026
2cae56b
Review round one: Who am I value decode, socket close on a search, un…
wshallwshall Oct 17, 2026
e6511df
The revocation-guard census lists the shared IdP opener wrapper as a …
wshallwshall Oct 17, 2026
ebd88b2
Handover for the third limb: proposed PR title and consolidated banne…
wshallwshall Oct 17, 2026
cf6b2b7
Revert the socket close on the search path: ldap3's with-exit reopens…
wshallwshall Oct 17, 2026
87c0405
Review round one: the search-close docstring names what the close did…
wshallwshall Oct 17, 2026
b666975
Merge b257-3010d: BACKLOG #3010 (four limbs: c6113d94, 6512a27d, ebd8…
wshallwshall Oct 17, 2026
2d1ddf1
A directory reconcile pass that newly grants Administrator raises adm…
wshallwshall Oct 17, 2026
f9df1af
UNKEYED reconcile follow-ups: referrals count the probes asked, an ou…
wshallwshall Oct 17, 2026
1027a1a
The reconcile-path store-fault set takes aiosqlite's closed-connectio…
wshallwshall Oct 17, 2026
7aae0c7
Simplify pass: the judged-nothing UNKEYED strikes are built only wher…
wshallwshall Oct 17, 2026
d7e3e9e
Review round one on the D3 reconcile follow-ups (BACKLOG #3141 #3170)
wshallwshall Oct 17, 2026
ed6efa2
Review round two: the docs stop over-claiming what an aborted pass do…
wshallwshall Oct 17, 2026
b1eccda
Merge origin/main into the b257 D1-D3 auth chain
wshallwshall Oct 17, 2026
71addac
Review round one on the b257-dchain merge: count and strike wording
wshallwshall Oct 17, 2026
258e2e5
Merge batch/b257-3010 into b257-d3b (base for the reconcile follow-ups)
wshallwshall Oct 17, 2026
42dd6eb
Reconciler: configuration refusals page, bind referrals refer, fault …
wshallwshall Oct 17, 2026
e11a6b2
Docs and changelogs for the reconcile follow-ups (BACKLOG #3010, #3170)
wshallwshall Oct 17, 2026
e109956
Review round one on D3b: quiet service release, context-class bind re…
wshallwshall Oct 17, 2026
d8d955a
D3b handover: PR title and banner text (BACKLOG #3010 #3170)
wshallwshall Oct 17, 2026
7554d41
Lock notice: a full queue reads mailed false, an actor index for the …
wshallwshall Oct 17, 2026
4bb5965
Docs: the reconciler's configuration-refusal alert, and what each ste…
wshallwshall Oct 17, 2026
00cb6f5
Review round one on D4: Postgres keys a prefix of the actor, honest d…
wshallwshall Oct 17, 2026
8bbae9b
D4 handover: PR title and banner text (BACKLOG #3120)
wshallwshall Oct 17, 2026
239d8fa
Audit actor-only reads get an (actor, id) index back their id-order p…
wshallwshall Oct 17, 2026
8d37f34
Review round one on D4b: schema-exact Postgres probe, near-prefix sec…
wshallwshall Oct 17, 2026
a67d105
D4b handover: PR title and banner text (BACKLOG #3120)
wshallwshall Oct 17, 2026
2fd439f
Login supersession follows a time-bounded retired-hash lineage (BACKL…
wshallwshall Oct 17, 2026
6810a14
Review round one on D5: link time read after the re-key, wider slack,…
wshallwshall Oct 17, 2026
323c42f
D5 handover: review round two fixes, PR title and banner text (BACKLO…
wshallwshall Oct 17, 2026
1ca569a
Merge origin/main d8214ae80 into b257-dchain
wshallwshall Oct 17, 2026
0c56e08
Merge b257-dchain-up into the b257-d5 tail, bringing it onto main d82…
wshallwshall Oct 17, 2026
31154fb
CONFIGURATION.md: oidc_flow_ttl_seconds also sets the session lineage…
wshallwshall Oct 17, 2026
8b4c280
CONFIGURATION.md and the breaker comment: say what the lineage, OIDC-…
wshallwshall Oct 17, 2026
120eedf
CONFIGURATION.md and the breaker comment: correct the refusal split t…
wshallwshall Oct 17, 2026
3c8fdf6
Merge origin/main (064700f2d) into b257-dchain
wshallwshall Oct 17, 2026
3fd8211
Merge b257-dchain (main 064700f2d) into b257-dtail
wshallwshall Oct 17, 2026
edca1de
Merge origin/main (3f1f884d9) into b257-dchain
wshallwshall Oct 17, 2026
70f6c45
Bind the step-up floor marker into the refuse partial once
wshallwshall Oct 17, 2026
79e5f90
Merge b257-dchain (main 3f1f884d9) into b257-dtail
wshallwshall Oct 17, 2026
ebabd31
Correct the shutdown-drain pointers the dchain merge wrote
wshallwshall Oct 17, 2026
84cfc79
State the lock-notice shutdown cost once, and correct its threshold
wshallwshall Oct 17, 2026
74becfb
A security notifier closing or closed refuses a notice rather than re…
wshallwshall Oct 17, 2026
6677c8e
Review round one on the closing refusal: record the drop, scrub the l…
wshallwshall Oct 17, 2026
f7ba6d6
b257-mailfix handover: PR title unchanged, ledger banner addendum (BA…
wshallwshall Oct 17, 2026
d89d00e
A closed security notifier refuses to start again; the throttle line …
wshallwshall Oct 17, 2026
b0d1704
Review on the restart refusal: wording that holds in every order (BAC…
wshallwshall Oct 17, 2026
515d1c3
Merge origin/main into b257-dchain (fourth main merge)
wshallwshall Oct 17, 2026
1d7573d
Merge b257-dchain (with main b4fab8564) into b257-dtail
wshallwshall Oct 17, 2026
9fd48a0
A self-revoke that loses the rotation race writes the miss row
wshallwshall Oct 17, 2026
1248224
Merge origin/main into b257-dchain (main 0ed70dcd4)
wshallwshall Oct 17, 2026
e6b962f
Merge b257-dchain (main 0ed70dcd4 and review fix) into b257-dtail
wshallwshall Oct 17, 2026
43abc1a
Merge origin/main into b257-dchain
wshallwshall Oct 18, 2026
057d02a
Merge b257-dchain into b257-dtail
wshallwshall Oct 18, 2026
9e65ba5
Reconcile the SQL Server busy-pool test and the drain comment after t…
wshallwshall Oct 18, 2026
a4f88a4
Merge origin/main (d2a3454eb, with the LDAP search refusal landed) in…
wshallwshall Oct 18, 2026
3faa362
Review on the dtail merge: the referral-bind test no longer calls an …
wshallwshall Oct 18, 2026
5ffe45d
Merge origin/main (6d6986fdd, the auth chain squash and the paging de…
wshallwshall Oct 19, 2026
fd7884f
Review on the main merge: name the configuration refusal where the pa…
wshallwshall Oct 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 26 additions & 13 deletions changelog.d/3010.security.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
- **An LDAP search that does not end with success is an outage, never "no such account".** Each
search the engine sends refuses any result code but success, with or without entries. That
includes busy, unavailable, unwillingToPerform and adminLimitExceeded. It includes a time or size
limit, and noSuchObject on a missing search base. Before, such a search read as no entries. The
session reconciler would then have struck a present account toward revocation. A busy nested
group search read as fewer groups. The reconciler now reads these as unavailable, which never
revokes. A sign-in writes `auth.login_error` naming the code, and `check-privileges` names the
code for the bind-account read. These refusals name the operation and the code, never the
directory's diagnostic message. Other directory errors keep the text they had.
- **An LDAP search that does not end with success is never "no such account".** Each search the
engine sends refuses any result code but success, with or without entries. That includes busy,
unavailable, unwillingToPerform and adminLimitExceeded. It includes a time or size limit, and
noSuchObject on a missing search base. Before, such a search read as no entries. The session
reconciler would then have struck a present account toward revocation. A busy nested group
search read as fewer groups. A sign-in now writes `auth.login_error` naming the code, and
`check-privileges` names the code for the bind-account read. These refusals name the operation
and the code, never the directory's diagnostic message. Other directory errors keep the text
they had.
**The session reconciler tells a configuration refusal from an outage.** noSuchObject,
invalidDNSyntax and insufficientAccessRights point at the configuration: a search base that was
deleted or moved, or that the service account may not read. Such a refusal leaves that account
unjudged and never revokes it. Every pass with one logs an ERROR naming the code, audits
`auth.ad_reconcile_misconfigured`, and raises `ad_reconcile_aborted` with reason
`directory_misconfigured` under the source `directory-reconciler-misconfigured`. A pass where
every lookup is refused, faulted or fails, at least one refused and none referred, aborts as
`directory_misconfigured`. Before, a deleted search base read as "not found" for every account,
which tripped the mass-revoke breaker on a large enough estate. Nothing resolves the new alert
automatically; an operator does. Any other code is an outage, which never revokes and pages
nobody. A second-factor step-up or a passkey assertion, which probes the directory before it
grants, refuses a refused account with outcome `misconfigured`. The password step-up and the
federated step-up refuse it as `directory_unavailable`, as they do any directory error.
**Not covered:** ldap3 fetches a ranged `memberOf` with follow-up searches of its own, and those
are not refused.
**The cost:** a code that recurs on every pass, such as a deleted search base, stops revocation
and the role re-diff for as long as it lasts. It warns once per process for each operation and
code, and latches no alert.
and the role re-diff for as long as it lasts. A configuration code alerts; any other code warns
once per process for each operation and code, and latches no alert.
**The nested group search is paged**, at 500 entries per page. So an account in more groups than
a directory's unpaged cap no longer fails sign-in with sizeLimitExceeded. AD's cap, MaxPageSize,
is 1000 by default. A page that does not end with success refuses the whole search. So does a
Expand All @@ -34,7 +47,7 @@
**A bind response carrying a referral is a referral.** ldap3 cannot decode one. The boundary
refuses it as a referral, naming no host. A sign-in writes `auth.login_error`, and the session
reconciler reads it as referred and raises the `ad_reconcile_aborted` alert with reason
`directory_referral`, as on any referral. That alert's text points at the two search bases, not
at `[auth].ad_bind_dn`.
`directory_referral`, as on any referral. That alert's text names the two search bases and
`[auth].ad_bind_dn`, any of which may name another domain of the forest.
Before, a sign-in that met one failed with an unhandled error, and the reconciler read it as a
probe fault. (vault `BACKLOG #3010`)
12 changes: 12 additions & 0 deletions changelog.d/3028.security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
- **A sign-in now ends the session its presented token became, when an elevation finished first.**
A console sign-in ends the session its browser presented. An elevation in another tab that
finished during the sign-in used to leave that token naming no session, so the session lived on
under its new token. Each rotation now records which token hash replaced the old one, in its own
store transaction, in a new `session_lineage` table on SQLite, Postgres and SQL Server. The
supersession follows those links to the live session and ends it, in the same transaction as the
revoke, for `[auth].oidc_flow_ttl_seconds` plus 120 seconds after each rotation; the session reaper
deletes older links. A retired token still authenticates nothing: no session read consults the
links. `docs/SECURITY.md` states the bound that remains, and ADR 0210 records the design.
On the server backends the schema change moves the ADR 0064 schema hash: under their default
`[store].schema_management`, `external`, the engine refuses to open until `provision-schema` has
run; under `auto` the next open runs the DDL.
21 changes: 21 additions & 0 deletions changelog.d/3120.security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
- **A lock notice the relay's full queue drops no longer holds the next one back.** The security
notifier now says whether it queued a notice, and the `auth.lock_notice` row records
`mailed: false` for one it dropped, so the next lock of the kind mails again rather than staying
quiet for 24 hours. The same holds at shutdown: a lock notice that reaches the notifier once it
has begun to close, which a cut shutdown drain allows, is refused and recorded `mailed: false`
rather than reported queued for a mail that is never sent. The relay also records such a drop,
with the new undelivered-notice reason `closing`. A send that fails later, on the
relay's own task, still leaves `mailed: true`; `docs/SECURITY.md` states that residual.
**The lock notice's throttle read has an index.** A new `ix_audit_actor` index on
`audit_log(actor, action, id)`, on SQLite, Postgres and SQL Server, lets the read find one
account's rows instead of walking every recent notice row of every account. On Postgres it keys
the first 200 characters of the actor, since a whole overlong value would fail the audit write.
A companion `ix_audit_actor_id` index on `audit_log(actor, id)`, keyed the same way, keeps the
reads filtered by actor without an action equality (`GET /audit?actor=`, its export pages,
`/me/security-events`)
from sorting all of an actor's rows to return the newest few.
On the server backends the schema change moves the ADR 0064 schema hash: under their default
`[store].schema_management`, `external`, the engine refuses to open until `provision-schema` has
run; under `auto` the next open runs the DDL.
**Declined, with residuals in `docs/SECURITY.md`:** two mails across engine shards serving their
own API ports, the timing of the content-free failure lines, and a cap on pending notice tasks.
23 changes: 12 additions & 11 deletions changelog.d/3170.security.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
- **The session reconciler counts a referral over the lookups it sent, and strikes an id-less row
on every pass.** A directory row with no `objectGUID` is judged without a lookup, so no referral
can answer it. The referral's `auth.ad_reconcile_referred` audit row now carries the `asked`
field in place of `probed`, and that row, the referral's latched message and its
`ad_reconcile_aborted` alert count only the lookups the pass sent. The breaker's own alert still
counts every account it judged. Such a row is also struck now on a pass that is a directory
outage or aborted on referrals or probe faults, as on any other pass. Such a pass still revokes
nothing. Only a
pass that is not aborted can, once the row's strikes reach the threshold and the row is in that
pass's probe budget, so while every pass aborts its sessions last to their own expiry. Its revocation still counts toward the mass-revoke breaker, as before.
(`vault BACKLOG #3170`)
- **The session reconciler counts a referral or a probe fault over the lookups it sent, and strikes
an id-less row on every pass.** A directory row with no `objectGUID` is judged without a lookup,
so no referral or fault can answer it. The `auth.ad_reconcile_referred` and
`auth.ad_reconcile_faulted` audit rows now carry the `asked` field in place of `probed`. Each
row, its latched message and its `ad_reconcile_aborted` alert count only the lookups the pass
sent. The breaker's alert still counts every account the pass judged, its denominator.
An id-less row is now struck on every pass, as on a pass that judged the directory's answers.
That includes a directory outage, and a pass aborted because every lookup was referred, faulted
or failed. No aborted pass revokes the row. Only a pass that is not aborted can, once the row's
strikes reach the threshold and the row is in that pass's probe budget. So while every pass
aborts, its sessions last to their own expiry. Its revocation still counts toward the
mass-revoke breaker, as before. (`vault BACKLOG #3170`)
Loading
Loading