skip to content

In an LDAP SASL Bind, what does a saslBindInProgress (14) response mean, and what must the client send next?

level: middleimportance: should knowfreq 42%

answer

  1. the answer is not final
  2. one round trip is not always enough
  3. 14 is not a failure
  4. serverSaslCreds carries the other half
  5. same mechanism name every step

basics

~20 s

saslBindInProgress (14) means the SASL Bind is not finished: the server has taken one step and is asking for another. The client reads serverSaslCreds [7], computes its next credentials, and sends a new BindRequest naming the same mechanism.

solid answer

~40 s

A simple bind is one request and one response. A SASL bind may be several, and `saslBindInProgress (14)` is how the server says so: it is not a failure and not a success, it is "continue". The server's half of the step travels in `serverSaslCreds [7]` on the `BindResponse`; the client feeds that to the mechanism, takes the mechanism's next output, and sends **another** `BindRequest` whose `sasl [3]` value names the **same** mechanism with the new credentials. The loop ends on `success (0)` — which may itself still carry `serverSaslCreds [7]`, because some mechanisms authenticate the server to the client too — or on any other result code, which leaves the session anonymous. The session is not bound at any intermediate step.

code

pseudocode · 21 lines
pseudocode
credentials = mechanism.initial_output()

loop
    send BindRequest(version = 3,
                     name = "",
                     sasl { mechanism: chosen_mechanism,
                            credentials: credentials })

    receive BindResponse as response

    if response.resultCode = saslBindInProgress (14)
        credentials = mechanism.next_output(response.serverSaslCreds)
        continue                      -- same mechanism name, new credentials

    if response.resultCode = success (0)
        mechanism.finish(response.serverSaslCreds)   -- may be absent
        session is bound
        stop

    session remains anonymous
    stop

go deeper

for a junior

Recall that a bind can be a conversation rather than a single request, and that a result code of 14 means the exchange is still running rather than that something went wrong.

for a middle

Explain the loop: serverSaslCreds carries the server's half, the client replies with the same mechanism name and new credentials, and only success (0) binds the session.

for a senior

Show you can read a capture correctly - three BindRequests in a row are one exchange, not three retries - and that you check serverSaslCreds on the successful response rather than discarding it.

for a principal

Consider what a multi-round-trip bind costs an estate: latency on every new connection, whether connections are pooled and reused, and how mechanism availability is governed as servers change what they offer.

## Why a bind can take more than one round trip With `simple [0]` there is nothing to negotiate: the client sends a password and the server accepts or refuses it. `sasl [3]` is different. `SaslCredentials` carries a **mechanism** name and an optional opaque **credentials** octet string, and what goes in that string is entirely the mechanism's business. Some mechanisms finish in one message. Others need a conversation — a value from the server, a computed reply, sometimes another exchange after that. LDAP therefore needs a way for a `BindResponse` to mean "not yet", and that is `saslBindInProgress (14)`. The field that carries the server's contribution is `serverSaslCreds [7]`, an optional octet string on the `BindResponse`. It exists only because of this: there is nowhere else in the response for mechanism data to live. ## The loop, step by step 1. The client picks a mechanism, ideally one the server listed in the root DSE's `supportedSASLMechanisms` attribute, which is readable while still anonymous. 2. It sends a `BindRequest` with `sasl [3]`, that mechanism name, and the mechanism's initial credentials if it has any. 3. The server answers. If the result code is `saslBindInProgress (14)`, the exchange continues and `serverSaslCreds [7]` holds the server's half of this step. 4. The client hands that value to the mechanism, takes the mechanism's next output, and sends a **new** `BindRequest` — same `sasl [3]` choice, same mechanism name, new credentials. Each is a fresh `LDAPMessage` with its own `messageID`. 5. Steps 3 and 4 repeat as many times as the mechanism requires. 6. The exchange ends on `success (0)` — the session is now bound — or on any other result code, in which case the session is anonymous. Two details are routinely missed. **The mechanism name must not change between steps**: changing it does not continue the exchange, it aborts the old one and starts a new bind. And **`success (0)` may still carry `serverSaslCreds [7]`**, holding the mechanism's final server-side value; a client that discards it on success may have skipped the half of the exchange that authenticates the *server* to it. ## What is the session's state while this is going on? Anonymous. Receipt of the first `BindRequest` reset the session, and only a `success (0)` installs an identity. A client cannot send a search "halfway through" a bind and get the identity it is in the middle of proving. There is also no way to cancel the exchange with an Abandon: the Abandon operation does not apply to Bind. A client that wants out has two moves, and both leave it anonymous: - send a `BindRequest` with a **different** mechanism name in `SaslCredentials`, or with an `AuthenticationChoice` other than `sasl [3]` — this aborts the exchange in progress; - drop the session. ## Mechanisms, named and not explained What this leaf owns is *which mechanism a bind names*, not how any mechanism works internally. Worth being able to name: - **`SASL EXTERNAL`** — takes its identity from a layer already established beneath LDAP, and carries no secret of its own. - **`SASL PLAIN`** — carries an authorization identity, an authentication identity and a password in one credentials value. - **`SASL ANONYMOUS`** — a named mechanism for claiming no identity, distinct from the anonymous authentication mechanism of simple bind. - **`SASL DIGEST-MD5`** — a challenge-based mechanism of its era, and a good illustration of why `supportedSASLMechanisms` matters: what a server offers changes over time. - **GSSAPI** — the mechanism family through which a Kerberos exchange is carried into a bind. The ticket machinery behind it is a separate subject and none of it belongs in an answer about LDAP Bind. ## The interview version The question behind the question is whether you think authentication is always request-and-answer. Candidates who have only used a directory through one library call assume a bind is atomic, then cannot explain a client that appears to "retry the bind three times" in a capture — which is not a retry at all, it is one exchange. Being able to say "`saslBindInProgress (14)` is a continuation, the server's half is in `serverSaslCreds [7]`, and the mechanism name stays the same" settles it in a sentence.

  • How does a client get out of a SASL Bind exchange it has already started?
    Not with an Abandon — that operation does not apply to Bind. It sends a `BindRequest` carrying a different mechanism name, or an `AuthenticationChoice` other than `sasl [3]`, which aborts the exchange in progress; or it drops the session. Either way the session is anonymous until some Bind answers `success (0)`.
  • Why does a success (0) BindResponse sometimes still carry serverSaslCreds [7]?
    Because some mechanisms authenticate in both directions, and the server's final value is the half that proves the server to the client. It travels on the successful response because there is no later message to put it in. A client that ignores it has authenticated one way only.
  • What happens if a client changes the mechanism name halfway through an exchange?
    The exchange in progress is aborted rather than continued — that is the defined way to back out of a SASL bind. The new name starts a fresh bind attempt from the beginning, and the session is anonymous in between, so it is not a recovery path for a mechanism that failed mid-conversation.

saying these in an interview costs you the question

  • Reads saslBindInProgress (14) as a failed bind
  • Assumes every SASL bind is one request and one response
  • Changes the mechanism name between steps of one exchange
  • Expects the server's half somewhere other than serverSaslCreds
  • Thinks the session is partly bound between steps
  • Says the client can abandon a Bind that is mid-exchange