A shift-planning service's LDAP Bind is refused: what do invalidCredentials (49), inappropriateAuthentication (48) and strongerAuthRequired (8) each tell you?
answer
- four codes, four different fixes
- not all of them are about the secret
- one code covers two causes on purpose
- where the distinction still leaks
- the session afterwards is anonymous
basics
~20 sinvalidCredentials (49) means the name and password pair was not accepted. inappropriateAuthentication (48) means credentials are required where none were supplied. strongerAuthRequired (8) means the mechanism is understood but policy demands a stronger one. Each implies a different fix.
solid answer
~40 sBind failures are not interchangeable, and the result code is most of the diagnosis. `invalidCredentials (49)` says the presented pair was rejected — and deliberately does not say whether the DN was wrong or the password was, because telling them apart would let a caller enumerate which entries exist. `inappropriateAuthentication (48)` says the server requires credentials from a client that bound anonymously or supplied none. `authMethodNotSupported (7)` says the mechanism named is not implemented here — read `supportedSASLMechanisms` rather than guessing. `strongerAuthRequired (8)` says the mechanism is understood but policy will not accept it for this identity. A related code, `confidentialityRequired (13)`, is the server objecting to the connection rather than to the mechanism, which is a different subject. Whichever code arrives, the session is left anonymous.
code
asn1 · 16 linesLDAPResult ::= SEQUENCE {
resultCode ENUMERATED {
success (0),
authMethodNotSupported (7),
strongerAuthRequired (8),
confidentialityRequired (13),
inappropriateAuthentication (48),
invalidCredentials (49),
... },
matchedDN LDAPDN,
diagnosticMessage LDAPString,
referral [3] Referral OPTIONAL }
BindResponse ::= [APPLICATION 1] SEQUENCE {
COMPONENTS OF LDAPResult,
serverSaslCreds [7] OCTET STRING OPTIONAL }go deeper
Recall that a refused LDAP Bind comes back as a numbered result code, and that not every refusal means a wrong password. Knowing invalidCredentials (49) by name is enough at this level.
Explain what each code asserts and which fix it implies, and why one code deliberately covers both an unknown DN and a wrong password.
Demonstrate the production reading: a pooled connection silently anonymous after a failed re-bind, diagnosticMessage leaking a distinction the result code hid, and branching on the code rather than on a message string.
Decide how much authentication detail crosses the boundary from directory to application logs to users, and what an estate-wide mechanism policy costs the clients that will meet strongerAuthRequired (8) first.
## Four codes, four different fixes When a bind is refused, the instinct is "wrong password". The protocol is more precise than that, and a `BindResponse` carries the whole of `LDAPResult` to say so. | result code | what the server is saying | what changes the outcome | |---|---|---| | `invalidCredentials (49)` | the presented name and password pair was not accepted | a correct password for a DN that exists | | `inappropriateAuthentication (48)` | this client bound anonymously or without credentials where the server requires some | supplying credentials instead of none | | `authMethodNotSupported (7)` | the authentication method or mechanism named is not supported here | naming a mechanism the server actually offers | | `strongerAuthRequired (8)` | the server requires stronger authentication to complete the operation | choosing a mechanism policy accepts | The practical value of the table is that three of the four rows are **not about the secret at all**. A team that resets a directory entry's password in response to `authMethodNotSupported (7)` has changed something irrelevant and will be back tomorrow. ## Why 49 is deliberately vague `invalidCredentials (49)` covers two genuinely different situations — a DN that names no entry, and a DN that does with the wrong password — and the protocol answers both identically on purpose. If the codes differed, any caller could walk a list of candidate DNs and learn which ones exist from the result code alone, without ever holding a password. Two mechanical points support this and are worth knowing: - **`matchedDN` is empty for this code.** That field is populated only for the small set of result codes about a name that could not be resolved; for `invalidCredentials (49)` it carries an empty string, so it leaks nothing. - **`diagnosticMessage` is where the distinction escapes.** It is free text, it is meant for operators, and a directory can be configured to put "no such entry" in it. An operator reading a server log wants exactly that; a client that relays `diagnosticMessage` into a caller-visible error has re-published the distinction the result code was careful to hide. The advice that follows is short: log `diagnosticMessage` on the service side, and return nothing derived from it to the caller. ## The two "you asked wrongly" codes `inappropriateAuthentication (48)` and `strongerAuthRequired (8)` both mean the credential was not the problem — the *way* it was offered was. - **48** is the server telling a client that bound anonymously, or supplied no credentials, that it requires some. The classic sighting is a client that fell back to an anonymous bind after a configuration value came back empty, and is now failing on the work it does after the bind rather than on the bind itself. - **8** is the server saying it understood the mechanism perfectly and its policy will not accept it for this identity. Identical credentials can bind on one deployment and be refused with `8` on another; nothing about the client is broken, and changing the password will not help. `authMethodNotSupported (7)` is blunter still: the server does not implement what was named. The fix is to read `supportedSASLMechanisms` from the root DSE — which an anonymous client can do — and pick from it, rather than hard-coding a mechanism name and discovering per deployment which directories have it. One code in the neighbourhood is about the connection rather than the mechanism: `confidentialityRequired (13)`. Recognise it, note that it points at how the connection is protected rather than at how the bind authenticates, and take it no further in an answer about Bind. ## The state left behind, and why it matters most here Whatever code comes back, **the session is anonymous**. The reset happened when the server received the `BindRequest`, not when it judged it. For a long-lived pooled connection this is the difference between an outage and a silent one: the bind failure may be caught, logged and retried somewhere, while the connection itself is handed back to the pool with no identity. Later searches on it run as an unauthenticated caller and come back short rather than erroring, so the symptom surfaces as "some press operators are missing from the shift list" rather than as an authentication failure anywhere. The operational habit that prevents it: treat any non-`success (0)` `BindResponse` as invalidating that connection, not merely as a failed call. ## Answering this in an interview Name the codes, then name the fix each one implies, then say the two things true of all of them: the session is anonymous afterwards, and the code is the diagnosis — anything more specific that reached the caller came out of `diagnosticMessage` and probably should not have.
- Why does a directory return the same invalidCredentials (49) for an unknown DN and a wrong password?Because distinguishing them would tell an unauthenticated caller which entries exist, from the result code alone and without holding any password. `matchedDN` is empty for this code, so the only place the distinction can escape is `diagnosticMessage` — which operators want in a server log and callers must not receive.
- The same credentials bind on one deployment and return strongerAuthRequired (8) on another. What changed?Policy, not the credential. The second directory understood the mechanism and will not accept it for that identity, so it is asking for a stronger one. Resetting or re-typing the password changes nothing; naming a mechanism the deployment accepts does.
- A pooled connection's re-bind failed and was logged. Why do searches on it later return too few entries instead of erroring?Because the failed Bind left that connection anonymous rather than closed. The searches are valid requests from an unauthenticated caller, so the directory answers them with whatever such a caller may see — a short result set, not an error. Any non-`success (0)` BindResponse should invalidate the connection.
saying these in an interview costs you the question
- Reads every bind refusal as a wrong password
- Says invalidCredentials (49) means the DN does not exist
- Expects matchedDN to name the entry that failed to bind
- Treats strongerAuthRequired (8) as a credential problem
- Relays diagnosticMessage straight back to the caller
- Assumes a refused bind leaves the earlier identity usable