LDAPSERVER was documented as a space separated list, but the whole
string went into a single ldap3.Server. Logins worked (python-ldap
accepts lists), while registration and every write would have failed
with more than one URI.
settings.LDAP_SERVERS is now the split list, used through one ldap3
ServerPool per process: requests go to the first reachable server, a
server that is down is skipped for 60s, connections time out after 5s,
and with all servers down the pool gives up after two passes instead
of retrying forever.
The highest uidNumber was cached in dal/ldap_max_uid_file. That breaks
with more than one replica and is lost on every container restart. The
uniqueness check behind it searched base '' (the root DSE), which
OpenLDAP never matches, so nothing caught a stale file. The error path
also referenced a setting that does not exist.
Now a paged search over ENTIRE_SEARCH_BASE finds the highest uidNumber
on each activation. Numbering is unchanged: the next number is above
both LDAP_DEFAULT_START_UID and every existing uidNumber.
LDAP_MAX_UID_FILE_PATH is no longer used.
Restore root requirements.txt pinned to what production runs
(Django 2.2, last patch 2.2.28) so the upgrade starts from a
reproducible baseline. Restore logs/.keep; the logging config fails
on a fresh clone without the directory.
The tests drive every view over HTTP against the real test LDAP:
login, registration and activation, data and password changes,
password reset, account deletion, the create API and OTP seeds.
Known bugs are recorded as expected failures:
- password reset POST changes any user's password without a token
- LDAP filter injection in reset (user='*' hits the first entry)
- activation link carries the base64-encoded password
- a username from ou=users can be registered again under ou=customers