Example #1
0
    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)
Example #2
0
    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)