def _do_sasl_handshake(self): req_klass = self._version_info.pick_best(SaslHandShakeRequest) sasl_handshake = req_klass(self._sasl_mechanism) response = yield from self.send(sasl_handshake) error_type = Errors.for_code(response.error_code) if error_type is not Errors.NoError: error = error_type(self) self.close(reason=CloseReason.AUTH_FAILURE, exc=error) raise error if self._sasl_mechanism not in response.enabled_mechanisms: exc = Errors.UnsupportedSaslMechanismError( 'Kafka broker does not support %s sasl mechanism. ' 'Enabled mechanisms are: %s' % (self._sasl_mechanism, response.enabled_mechanisms)) self.close(reason=CloseReason.AUTH_FAILURE, exc=exc) raise exc assert self._sasl_mechanism == 'PLAIN' if self._security_protocol == 'SASL_PLAINTEXT': self.log.warning('Sending username and password in the clear') authenticator = self.authenticator_plain() auth_bytes = None while True: try: payload = authenticator.send(auth_bytes) except StopIteration: break if req_klass.API_VERSION == 0: auth_bytes = yield from self._send_sasl_token(payload) else: req_klass = self._version_info.pick_best( SaslAuthenticateRequest) req = req_klass(payload) resp = yield from self.send(req) error_type = Errors.for_code(resp.error_code) if error_type is not Errors.NoError: exc = error_type(resp.error_message) self.close(reason=CloseReason.AUTH_FAILURE, exc=exc) raise exc auth_bytes = resp.sasl_auth_bytes self.log.info('Authenticated as %s via PLAIN', self._sasl_plain_username)
async def _do_sasl_handshake(self): # NOTE: We will only fallback to v0.9 gssapi scheme if user explicitly # stated, that api_version is "0.9" if self._version_hint and self._version_hint < (0, 10): handshake_klass = None assert self._sasl_mechanism == 'GSSAPI', ( "Only GSSAPI supported for v0.9") else: handshake_klass = self._version_info.pick_best( SaslHandShakeRequest) sasl_handshake = handshake_klass(self._sasl_mechanism) response = await self.send(sasl_handshake) error_type = Errors.for_code(response.error_code) if error_type is not Errors.NoError: error = error_type(self) self.close(reason=CloseReason.AUTH_FAILURE, exc=error) raise error if self._sasl_mechanism not in response.enabled_mechanisms: exc = Errors.UnsupportedSaslMechanismError( 'Kafka broker does not support %s sasl mechanism. ' 'Enabled mechanisms are: %s' % (self._sasl_mechanism, response.enabled_mechanisms)) self.close(reason=CloseReason.AUTH_FAILURE, exc=exc) raise exc assert self._sasl_mechanism in ('PLAIN', 'GSSAPI', 'SCRAM-SHA-256', 'SCRAM-SHA-512', 'OAUTHBEARER') if self._security_protocol == 'SASL_PLAINTEXT' and \ self._sasl_mechanism == 'PLAIN': self.log.warning('Sending username and password in the clear') if self._sasl_mechanism == 'GSSAPI': authenticator = self.authenticator_gssapi() elif self._sasl_mechanism.startswith('SCRAM-SHA-'): authenticator = self.authenticator_scram() elif self._sasl_mechanism == 'OAUTHBEARER': authenticator = self.authenticator_oauth() else: authenticator = self.authenticator_plain() if handshake_klass is not None and sasl_handshake.API_VERSION > 0: auth_klass = self._version_info.pick_best(SaslAuthenticateRequest) else: auth_klass = None auth_bytes = None expect_response = True while True: res = await authenticator.step(auth_bytes) if res is None: break payload, expect_response = res # Before Kafka 1.0.0 Authentication bytes for SASL were send # without a Kafka Header, only with Length. This made error # handling hard, so they made SaslAuthenticateRequest to properly # pass error messages to clients on source of error. if auth_klass is None: auth_bytes = await self._send_sasl_token( payload, expect_response) else: req = auth_klass(payload) resp = await self.send(req) error_type = Errors.for_code(resp.error_code) if error_type is not Errors.NoError: exc = error_type(resp.error_message) self.close(reason=CloseReason.AUTH_FAILURE, exc=exc) raise exc auth_bytes = resp.sasl_auth_bytes if self._sasl_mechanism == 'GSSAPI': self.log.info('Authenticated as %s via GSSAPI', self.sasl_principal) elif self._sasl_mechanism == 'OAUTHBEARER': self.log.info('Authenticated via OAUTHBEARER') else: self.log.info('Authenticated as %s via PLAIN', self._sasl_plain_username)