shotover/shotover-proxy

kafka protocol handle SaslHandshakeRequest v0

Opened this issue · 0 comments

As per the spec: https://kafka.apache.org/protocol.html#sasl_handshake
image
When SaslHandshakeRequest is v0 it will send SaslAuthenticate messages without the kafka header or body, just the raw sasl message.

Our implementation works fine for v1 but we do not handle the v0 at all and we get protocol level parsing failures instead.

The CPP driver and java driver both use v1.
But the latest python driver 2.0.2 still uses v0 and I think its reasonable that we need to support a python driver released at this time even if they upgrade to v1 in the near future.

Possible solution:

To handle this we will need to add state to our codec.

  1. if message is SaslHandshakeRequest and version is v0 then set expect_raw_sasl = true
  2. if expect_raw_sasl then parse sasl messages enough to packetize them into shotover messages. I dont believe SASL provides any framing, so we would need to attempt to parse every sasl mechanism type, so if we hit an unknown mechanism we will be unable to tell when it ends.
    • Alternatively we could could just yeet bytes into shotover messages without ensuring that they form a distinct message. This way 1 sasl request could be split into multiple requests. Technically this would break transform invariants since some of these requests would have no responses. But the reason for those invariants is to avoid memory leaking until the connection is closed. Since SASL auth only occurs once we can get away with such memory leaks for a backwards compatibility case. We also need to ensure the logic for assigning request_id's to responses wont blow up with multiple requests going through like this.
  3. I'm not sure how to determine when the raw sasl messages end, we'll have to look deeper into the sasl protocol, but when that occurs set expect_raw_sasl = false
  4. We'll need a new variant in KafkaFrame for when a transform attempts to parse a raw sasl message: KafkaFrame { Request { .. }, Response { .. }, RawSasl(Bytes) }

For a SASL crate, this one looks alright https://github.com/dequbed/rsasl
SASL spec: https://datatracker.ietf.org/doc/html/rfc4422

For writing an integration test, refer to #1267 for how to setup a python dependency.