Skip to content

NCBC-4375: Add PasswordAuthenticator.LdapCompatible - #235

Draft
davidkelly wants to merge 1 commit into
NCBC-4331from
NCBC-4375
Draft

davidkelly wants to merge 1 commit into
NCBC-4331from
NCBC-4375

Conversation

@davidkelly

@davidkelly davidkelly commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

The issue in brief

After #232 (NCBC-4331), PasswordAuthenticator never sends SASL PLAIN on a non-TLS connection, because PLAIN sends the password in cleartext. Users with no SCRAM credentials, such as LDAP users, then cannot connect with couchbase://, and have no way to opt in. This PR adds that opt-in: PasswordAuthenticator.LdapCompatible(username, password).

Jira: NCBC-4375. Stacked on #232: the base is NCBC-4331. Review only the last commit. I will retarget it to master after #232 merges.

Change

  • PasswordAuthenticator.LdapCompatible(username, password): a static factory that uses PLAIN on every KV connection, TLS or not. It matches Java's ldapCompatible (builder().onlyEnablePlainSaslMechanism()) and C++'s password_authenticator::ldap_compatible. Its XML docs warn that PLAIN sends the password in cleartext without TLS, and recommend couchbases://.
  • SaslMechanismFactory.CreateLdapCompatibleMechanism, on a non-TLS connection:
    • It requires the server to advertise PLAIN in SASL_LIST_MECHS, as Java does, and otherwise throws AuthenticationFailureException that names the advertised list. If the list is empty (the fetch failed), it still tries PLAIN, and the server decides.
    • It logs a warning that the password is sent in cleartext. The warning is logged once per cluster (the factory is a cluster singleton), so many connections and credential rotations do not flood the log.
  • Over TLS, LdapCompatible behaves the same as the default authenticator: PLAIN, no warning.
  • The default authenticator does not change. PLAIN is never chosen automatically on a non-TLS connection.

Deliberately left out: a general allowed-mechanisms setting (Java's allowedSaslMechanisms / enablePlainSaslMechanism). It is more public API, mostly for edge cases, and enablePlainSaslMechanism brings back the silent downgrade to PLAIN that #232 removed. No SDK RFC defines either API. RFC 0048 mentions mechanisms "enabled by the user" but defines no API for it. We can add it when someone asks.

Tests

  • SaslMechanismFactoryTests (8 new): PLAIN on non-TLS when the server offers it (with and without SCRAM); throws, with no warning, when the server does not offer PLAIN; still tries PLAIN when the list is empty; warns once over three connections; PLAIN with no warning over TLS; the default path never warns.
  • PasswordAuthenticatorTests (3 new): LdapCompatible uses PLAIN on both transports, through the real factory, and keeps the credentials.
  • Each test fails against code with the matching defect: the authenticator ignores the flag, no warn-once guard, no PLAIN-advertised check, a warning over TLS. All tests are synchronous with mocked connections: no threads, timers or sockets. They passed 20/20 repeated runs.
  • Full suite: 3478 passed, 16 skipped, on net8.0 and net10.0.

Release note

PasswordAuthenticator.LdapCompatible(username, password) authenticates with SASL PLAIN on every connection, for users that have no SCRAM credentials, such as LDAP users. On couchbase:// this sends the password in cleartext, and the SDK logs a warning the first time it does. Use couchbases:// when possible.

🤖 Generated with Claude Code

Motivation
==========
NCBC-4331 stops PasswordAuthenticator sending SASL PLAIN on non-TLS
connections. Users with no SCRAM credentials, such as LDAP users, then
cannot connect with couchbase://, and have no way to opt in.

Modification
============
- PasswordAuthenticator.LdapCompatible(username, password) uses PLAIN
  on every KV connection, as Java's ldapCompatible does. Its docs warn
  that PLAIN sends the password in cleartext without TLS.
- On a non-TLS connection the factory requires the server to advertise
  PLAIN, and logs a warning once per cluster that the password is sent
  in cleartext.
- The default authenticator is unchanged. There is no general
  allowed-mechanisms setting.

Results
=======
New unit tests cover PLAIN on both transports, a server that does not
offer PLAIN, and the warning (once, never on TLS, never by default).
Each fails against code with the matching defect.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

FIT performer image

Published:

ghcr.io/couchbase/dotnet-fit-performer:NCBC-4375

Run FIT locally against this PR:

fit run preset <preset-name> --performer dotnet-fit-performer:NCBC-4375

Or run it from the workflow here.

Note

Each push to this PR replaces the image and edits this comment. The image is deleted 7 days after the last push.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant