feat: read the lockout threshold and window in the password policy

The password change must stay below the domain's lockout threshold. The policy now carries lockout_threshold and lockout_window, from the domain or from the fine-grained policy that applies. AD-2's read allow-list names the new attributes.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N3t4WL7bd9bdHHNjEsxzqC
This commit is contained in:
2026-10-18 09:55:10 +02:00
co-authored by Claude Sonnet 5.5
parent ead56709bc
commit b87ffae94c
7 changed files with 24 additions and 1 deletions
@@ -218,6 +218,8 @@ class LdapDirectory:
history_length=int(_text(domain, "pwdHistoryLength") or 0),
min_age=_interval(_text(domain, "minPwdAge")) or timedelta(0),
max_age=_interval(_text(domain, "maxPwdAge")),
lockout_threshold=int(_text(domain, "lockoutThreshold") or 0),
lockout_window=_interval(_text(domain, "lockoutObservationWindow")),
)
pso_dn = _text(entry[1], "msDS-ResultantPSO")
if not pso_dn:
@@ -234,6 +236,8 @@ class LdapDirectory:
min_age=_interval(_text(attrs, "msDS-MinimumPasswordAge")) or timedelta(0),
max_age=_interval(_text(attrs, "msDS-MaximumPasswordAge")),
fine_grained=True,
lockout_threshold=int(_text(attrs, "msDS-LockoutThreshold") or 0),
lockout_window=_interval(_text(attrs, "msDS-LockoutObservationWindow")),
)
def update_attributes(self, sam: str, changes: dict[str, str | None]) -> None: