feat(auth): LDAP and SSO users keep their source; directory TLS is real (#5036)
CI / lint (push) Successful in 2s
CI / integration (push) Successful in 44s
CI / unit (push) Failing after 1m5s
CI / publish (push) Skipped

#5036 "SSO and LDAP: users keep their auth source, no merging into local
accounts, is_active checked, LDAP TLS real and filter escaped".

- users gain auth_source (local/ldap/oidc) and external_id (migration 0027).
  A provider account is found by (source, subject) only: the LDAP entry DN
  or the OIDC sub. A first sign-in whose username or email another account
  holds is refused with a message naming why; a disabled user stays out.
- Local passwords sign in local accounts only.
- LDAP: port 636 is LDAPS, otherwise StartTLS before any bind; the server
  certificate is checked against the system CAs or a CA pasted in
  Settings -> Auth. The login name is escaped into the filter (RFC 4515),
  and an empty password is refused before the directory sees it.
- OIDC: the ID token must carry this sign-in's nonce and the userinfo sub.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-06 11:10:40 -04:00
co-authored by Claude Opus 5.5
parent b1da073677
commit f944cdb9b0
11 changed files with 405 additions and 41 deletions
+12
View File
@@ -117,6 +117,18 @@
<label for="ldap-tls" style="margin:0;white-space:nowrap;">StartTLS</label>
</div>
</div>
<p style="font-size:0.75rem;color:var(--text-muted);margin:-0.4rem 0 1rem;">Port 636 connects with LDAPS; any other port with StartTLS ticked
upgrades the connection before any password is sent. Without either, passwords cross
the network in the clear. The server's certificate is checked.</p>
<div class="form-group">
<label>CA certificate (PEM, optional)</label>
<textarea name="ldap.ca_cert" rows="4" placeholder="-----BEGIN CERTIFICATE-----"
style="font-family:monospace;font-size:0.8rem;">{{ settings['ldap.ca_cert'] }}</textarea>
<p style="font-size:0.75rem;color:var(--text-muted);margin-top:0.2rem;">The certificate
authority that signed the directory's certificate, when it is not one the system already
trusts (a private or self-signed CA).</p>
</div>
<div class="form-group">
<label>Service account bind DN</label>