{"record":{"id":"c74cbb95dfe6b900","repo":"SonarSource/sonarqube","slug":"when-using-sasl-property-ldap-binddn-is-required","errorCode":null,"errorMessage":"When using SASL - property ldap.bindDn is required","messagePattern":"When using SASL - property ldap\\.bindDn is required","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"server/sonar-auth-ldap/src/main/java/org/sonar/auth/ldap/LdapContextFactory.java","lineNumber":223,"sourceCode":"\n  public boolean isSasl() {\n    return AUTH_METHOD_DIGEST_MD5.equals(authentication) ||\n      AUTH_METHOD_CRAM_MD5.equals(authentication) ||\n      AUTH_METHOD_GSSAPI.equals(authentication);\n  }\n\n  public boolean isGssapi() {\n    return AUTH_METHOD_GSSAPI.equals(authentication);\n  }\n\n  /**\n   * Tests connection.\n   *\n   * @throws LdapException if unable to open connection\n   */\n  public void testConnection() {\n    if (StringUtils.isBlank(username) && isSasl()) {\n      throw new IllegalArgumentException(\"When using SASL - property ldap.bindDn is required\");\n    }\n    try {\n      createBindContext();\n      LOG.info(\"Test LDAP connection on {}: OK\", providerUrl);\n    } catch (NamingException e) {\n      LOG.info(\"Test LDAP connection: FAIL\");\n      throw new LdapException(\"Unable to open LDAP connection\", e);\n    }\n  }\n\n  public String getProviderUrl() {\n    return providerUrl;\n  }\n\n  public String getReferral() {\n    return referral;\n  }\n","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-auth-ldap/src/main/java/org/sonar/auth/ldap/LdapContextFactory.java#L205-L241","documentation":"testConnection in LdapContextFactory validates that SASL authentication can proceed: SASL requires a bind DN (username). If the username is blank while the authentication scheme is SASL (CRAM-MD5/DIGEST-MD5/GSS-API), it throws IllegalArgumentException with this message before attempting any connection.","triggerScenarios":"Calling testConnection when sonar.authenticator.ldap.authentication is sasl (or auto-detected as SASL) but sonar.authenticator.ldap.bindDn is unset or blank.","commonSituations":"Switching from simple to SASL authentication and forgetting bindDn; relying on GSS-API/Kerberos without setting the principal as bindDn; copying a simple-auth config template that has bindDn commented out.","solutions":["Set sonar.authenticator.ldap.bindDn (and bindPassword) to the principal used for SASL binding.","If you intended simple authentication, set sonar.authenticator.ldap.authentication=simple.","For Kerberos/GSS-API, set bindDn to the Kerberos principal name."],"exampleFix":"// before: SASL without bindDn\nsonar.authenticator.ldap.authentication: DIGEST-MD5\n// after: provide the bind principal\nsonar.authenticator.ldap.authentication: DIGEST-MD5\nsonar.authenticator.ldap.bindDn: cn=sonar,ou=service,dc=example,dc=org","handlingStrategy":"validation","validationCode":"String auth = config.get(\"sonar.authenticator.ldap.authentication\").orElse(\"simple\");\nboolean sasl = auth.equalsIgnoreCase(\"CRAM-MD5\") || auth.equalsIgnoreCase(\"DIGEST-MD5\") || auth.equalsIgnoreCase(\"GSS-API\");\nif (sasl && config.get(\"sonar.authenticator.ldap.bindDn\").map(String::isBlank).orElse(true)) {\n  throw new IllegalStateException(\"SASL authentication requires sonar.authenticator.ldap.bindDn\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always set bindDn/bindPassword when authentication is anything other than simple/anonymous.","For Kerberos, use the service principal as bindDn.","Diff config against a known-good sample when switching auth schemes."],"tags":["ldap","sasl","binddn","configuration-validation"],"backgroundTag":"missing-required-config-field","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}