feat: add LDAP authentication as per-tenant login method

Add LDAP as a third authentication option alongside local password and
Microsoft Entra ID SSO. Per-tenant configuration supports Active Directory,
OpenLDAP, and FreeIPA with configurable attribute mapping, search-then-bind
and direct-bind methods, encrypted bind credentials (AES-256-GCM),
profile sync on login, and user auto-provisioning via external identity
linking.

Includes admin UI for connection settings with test-connection button,
login page LDAP form, 25 new PHPUnit tests, and de/en translations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-25 07:26:04 +01:00
parent a0d816caaa
commit d1eeac6692
22 changed files with 2325 additions and 18 deletions

View File

@@ -1355,5 +1355,63 @@
"Environment": "Environment",
"Modules": "Modules",
"Version": "Version",
"Breadcrumb": "Breadcrumb"
"Breadcrumb": "Breadcrumb",
"LDAP Authentication": "LDAP Authentication",
"LDAP Username": "LDAP Username",
"Sign in with LDAP": "Sign in with LDAP",
"LDAP login is not available for this tenant.": "LDAP login is not available for this tenant.",
"Your email domain is not allowed for LDAP login on this tenant.": "Your email domain is not allowed for LDAP login on this tenant.",
"LDAP server is not reachable. Please try again later.": "LDAP server is not reachable. Please try again later.",
"Your LDAP account does not have an email address configured.": "Your LDAP account does not have an email address configured.",
"LDAP host is required": "LDAP host is required",
"LDAP base DN is required": "LDAP base DN is required",
"LDAP port must be between 1 and 65535": "LDAP port must be between 1 and 65535",
"Search filter must contain %s placeholder": "Search filter must contain %s placeholder",
"LDAP-only login requires a complete configuration": "LDAP-only login requires a complete configuration",
"Direct bind method requires a username format": "Direct bind method requires a username format",
"Bind DN could not be encrypted": "Bind DN could not be encrypted",
"Bind password could not be encrypted": "Bind password could not be encrypted",
"Tenant LDAP settings could not be saved": "Tenant LDAP settings could not be saved",
"Bind DN could not be decrypted": "Bind DN could not be decrypted",
"Bind password could not be decrypted": "Bind password could not be decrypted",
"LDAP login": "LDAP login",
"LDAP setup is incomplete": "LDAP setup is incomplete",
"LDAP connection settings": "LDAP connection settings",
"Enable LDAP login for this tenant": "Enable LDAP login for this tenant",
"LDAP Host": "LDAP Host",
"Encryption": "Encryption",
"None (not recommended)": "None (not recommended)",
"Verify TLS certificate": "Verify TLS certificate",
"Base DN": "Base DN",
"Bind DN (service account)": "Bind DN (service account)",
"Bind password": "Bind password",
"Clear bind password": "Clear bind password",
"Test connection": "Test connection",
"Search and bind settings": "Search and bind settings",
"Bind method": "Bind method",
"Search then bind (recommended)": "Search then bind (recommended)",
"Direct bind": "Direct bind",
"User search filter": "User search filter",
"Search scope": "Search scope",
"Subtree (recursive)": "Subtree (recursive)",
"One level": "One level",
"Network timeout (seconds)": "Network timeout (seconds)",
"Direct bind username format": "Direct bind username format",
"Unique ID attribute": "Unique ID attribute",
"Attribute mapping and sync": "Attribute mapping and sync",
"Map application fields to LDAP directory attributes.": "Map application fields to LDAP directory attributes.",
"Profile sync on LDAP login": "Profile sync on LDAP login",
"Allow LDAP-only login (disable local password login)": "Allow LDAP-only login (disable local password login)",
"Sync email": "Sync email",
"AD: objectGUID, OpenLDAP: entryUUID, FreeIPA: ipaUniqueID": "AD: objectGUID, OpenLDAP: entryUUID, FreeIPA: ipaUniqueID",
"Login could not be completed. Please contact your administrator.": "Login could not be completed. Please contact your administrator.",
"Only for direct bind. Use %s as placeholder. Example: %s@corp.example.com or uid=%s,ou=People,dc=example,dc=com": "Only for direct bind. Use %s as placeholder. Example: %s@corp.example.com or uid=%s,ou=People,dc=example,dc=com",
"Optional allow-list, comma or newline separated.": "Optional allow-list, comma or newline separated.",
"Please enter your username and password.": "Please enter your username and password.",
"Port": "Port",
"Search-then-bind uses a service account to find the user DN first, then binds with the user credentials.": "Search-then-bind uses a service account to find the user DN first, then binds with the user credentials.",
"Use %s as placeholder for the username. Examples: (&(objectClass=user)(sAMAccountName=%s)) for AD, (&(objectClass=inetOrgPerson)(uid=%s)) for OpenLDAP": "Use %s as placeholder for the username. Examples: (&(objectClass=user)(sAMAccountName=%s)) for AD, (&(objectClass=inetOrgPerson)(uid=%s)) for OpenLDAP",
"Username or password not valid": "Username or password not valid",
"Write-only. Leave empty to keep current value.": "Write-only. Leave empty to keep current value.",
"Your account is deactivated.": "Your account is deactivated."
}