{"record":{"id":"ededf6935cd6d954","repo":"BookStackApp/BookStack","slug":"isanonymous-trans-errors-ldap-fail-anonymous","errorCode":null,"errorMessage":"($isAnonymous ? trans('errors.ldap_fail_anonymous') : trans('errors.ldap_fail_authed'))","messagePattern":"\\(\\$isAnonymous \\? trans\\('errors\\.ldap_fail_anonymous'\\) : trans\\('errors\\.ldap_fail_authed'\\)\\)","errorType":"exception","errorClass":"LdapException","httpStatus":null,"severity":"critical","filePath":"app/Access/LdapService.php","lineNumber":207,"sourceCode":"     *\n     * @param resource|\\LDAP\\Connection $connection\n     *\n     * @throws LdapException\n     */\n    protected function bindSystemUser($connection): void\n    {\n        $ldapDn = $this->config['dn'];\n        $ldapPass = $this->config['pass'];\n\n        $isAnonymous = ($ldapDn === false || $ldapPass === false);\n        if ($isAnonymous) {\n            $ldapBind = $this->ldap->bind($connection);\n        } else {\n            $ldapBind = $this->ldap->bind($connection, $ldapDn, $ldapPass);\n        }\n\n        if (!$ldapBind) {\n            throw new LdapException(($isAnonymous ? trans('errors.ldap_fail_anonymous') : trans('errors.ldap_fail_authed')));\n        }\n    }\n\n    /**\n     * Get the connection to the LDAP server.\n     * Creates a new connection if one does not exist.\n     *\n     * @throws LdapException\n     *\n     * @return resource|\\LDAP\\Connection\n     */\n    protected function getConnection()\n    {\n        if ($this->ldapConnection !== null) {\n            return $this->ldapConnection;\n        }\n\n        // Check LDAP extension in installed","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/BookStackApp/BookStack/blob/18f8469a1c72f8cc8497e9372635e6dea5028071/app/Access/LdapService.php#L189-L225","documentation":"LdapException thrown by LdapService::bindSystemUser when the LDAP bind call fails. The message distinguishes anonymous binding (ldap_fail_anonymous) from authenticated binding with a DN/password (ldap_fail_authed), pointing at either bad credentials or an LDAP server refusing the bind.","triggerScenarios":"bindSystemUser (called via getUserWithAttributes and getParentsOfGroup) runs and $this->ldap->bind() returns false: wrong LDAP admin DN/password configured, anonymous bind attempted but disallowed by the server, or the bind user lacks permission.","commonSituations":"Typo or password rotation of the LDAP bind/admin credentials in config; server configuration disallows anonymous binds (common default in AD/OpenLDAP); special characters in the DN/password mishandled; LDAP service account locked out or expired.","solutions":["Verify the LDAP bind DN and password in the LDAP configuration are correct and current","If using anonymous bind, enable anonymous bind on the LDAP server or configure a dedicated bind user","Test credentials with ldapsearch/ldapwhoami outside the app to isolate the issue","Check the bind account is not locked/expired and has read access to the search base"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"$test = @ldap_connect($config['server']);\n$ok = $test && @ldap_bind($test, $config['dn'], $config['pass']);\nif (!$ok) { throw new RuntimeException('LDAP bind credentials invalid'); }","typeGuard":null,"tryCatchPattern":"try {\n    $user = $ldapService->getUserWithAttributes($username);\n} catch (\\BookStack\\Exceptions\\LdapException $e) {\n    report($e);\n    return back()->with('error', trans('errors.ldap_fail_authed'));\n}","preventionTips":["Store bind credentials in env/config secrets and rotate deliberately","Test binds with ldapwhoami after any credential or server change","Avoid anonymous binds; use a dedicated read-only service account"],"tags":["ldap","bind","authentication"],"backgroundTag":"ldap-bind-failed","analyzedSha":"18f8469a1c72f8cc8497e9372635e6dea5028071","analyzedAt":"2026-09-02T19:49:33.068Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}