Description
The SaslAuthenticate wire response is Key Version CorrelationId ResponseCode SaslOpaqueData (verified in the server: parse_response_body(?COMMAND_SASL_AUTHENTICATE, <<ResponseCode:16, ChallengeBin/binary>>) — the challenge is encoded as a string).
SaslAuthenticateResponseV1 extends SimpleCorrelatedResponseV1, which parses only the first four fields and immediately throws ProtocolException on any non-OK code. So a legitimate SASL_CHALLENGE (0x0a) response — the normal flow for challenge-response mechanisms such as SCRAM — surfaces as an exception before the challenge payload can even be read. The SaslOpaqueData field is also silently dropped on the OK path.
Where
src/Response/SaslAuthenticateResponseV1.php:9
src/Response/SimpleCorrelatedResponseV1.php:35-60 (shared parser, throws on non-OK)
Why it matters
Challenge-based SASL mechanisms cannot be implemented on top of this response class; the library is effectively PLAIN-only (fine today) but the response parser is a trap for any future SCRAM/external-mechanism extension.
Suggested fix
Give SaslAuthenticateResponseV1 a dedicated fromStreamBuffer() that reads responseCode + an optional challenge string, exposes getChallenge(): ?string, and treats SASL_CHALLENGE as a non-fatal parse result rather than throwing.
Description
The
SaslAuthenticatewire response isKey Version CorrelationId ResponseCode SaslOpaqueData(verified in the server:parse_response_body(?COMMAND_SASL_AUTHENTICATE, <<ResponseCode:16, ChallengeBin/binary>>)— the challenge is encoded as astring).SaslAuthenticateResponseV1extendsSimpleCorrelatedResponseV1, which parses only the first four fields and immediately throwsProtocolExceptionon any non-OK code. So a legitimateSASL_CHALLENGE(0x0a) response — the normal flow for challenge-response mechanisms such as SCRAM — surfaces as an exception before the challenge payload can even be read. TheSaslOpaqueDatafield is also silently dropped on the OK path.Where
src/Response/SaslAuthenticateResponseV1.php:9src/Response/SimpleCorrelatedResponseV1.php:35-60(shared parser, throws on non-OK)Why it matters
Challenge-based SASL mechanisms cannot be implemented on top of this response class; the library is effectively PLAIN-only (fine today) but the response parser is a trap for any future SCRAM/external-mechanism extension.
Suggested fix
Give
SaslAuthenticateResponseV1a dedicatedfromStreamBuffer()that readsresponseCode+ an optional challengestring, exposesgetChallenge(): ?string, and treatsSASL_CHALLENGEas a non-fatal parse result rather than throwing.