lldap and OpenLDAP's memberof overlay omit memberOf from "*", so every
lldap login fell through to the default group. Request memberOf by name
when the schema defines it, and on non-AD directories also search the
directory root for groupOfNames/groupOfUniqueNames entries listing the
user, since groups often sit outside the user search base and the
overlay tracks only one group class.
Also: skip ldap3's anonymous schema read after StartTLS, which AD and
Samba AD reject, so StartTLS works there; reword a server's StartTLS
refusal with an LDAPS hint; stop the bundle sanitizer masking part of
an OID as an IP; skip the sync right after auto-provisioning so the
default-group warning logs once.
Add `# pragma: allowlist secret` markers to the three lines GitGuardian
flagged (ldap_server_url, ldap_bind_dn, admin_password) and pull the
duplicated AdminPass1! literal into a single test_password variable so
the marker only needs to live in one place.
All values are test fixtures (test directory + admin password used only
by the LDAP provisioning integration suite), not real credentials.
Reporter @Fuechslein flagged that disabling LDAP auto-provision left admins
with no UI path to onboard new users — the create-user form had zero LDAP
awareness and the only workaround was hand-editing the database.
Add a Local / LDAP tab toggle to the create-user modal (hidden when LDAP is
disabled). The LDAP tab is a debounced directory search (≥2 chars, 300ms)
that returns up to 25 matches via the service-account bind, annotated with
already_provisioned so existing usernames render disabled. Clicking
"Provision user" re-resolves via the service bind and creates the user
through the same _provision_ldap_user helper the auto-provision login path
uses, so group mapping, default-group fallback, and email sync are identical
regardless of which path created the user.
The picker component is shared across all four create-user modal paths
(UsersPage basic + advanced, SettingsPage basic + advanced).
Two ldap3 schema-check workarounds were needed for OpenLDAP installs:
- Open the search connection with check_names=False so ldap3 doesn't reject
the cross-schema OR filter (sAMAccountName/displayName are AD-only)
- Request attributes=["*"] because ldap3's build_attribute_selection
validates each named attribute against the server schema regardless of
check_names, and only the * wildcard is in its hard-coded exclusion list
Login/lookup paths keep check_names=True so typos in user_filter still fail
loudly.
Backend
- New routes: GET /auth/ldap/search, POST /auth/ldap/provision (both gated
by USERS_CREATE; 503 details include ldap3 exception class + message)
- Extract _open_service_connection + _extract_user_info helpers so
authenticate_ldap_user, lookup_ldap_user, and search_ldap_users share the
bind and attribute-extraction logic
Frontend
- New LdapUserPicker component (debounced search, result list, provision
mutation, already-provisioned guard, error surface)
- Tab toggle wired into UsersPage and SettingsPage modals, plus
CreateUserAdvancedAuthModal props
- 14 i18n keys added to en.ts (other locales fall back to English)