async def _process_auth(self, plugin_name, auth_packet): if plugin_name == b"mysql_native_password": # https://dev.mysql.com/doc/internals/en/ # secure-password-authentication.html#packet-Authentication:: # Native41 data = _scramble(self._password.encode('latin1'), auth_packet.read_all()) elif plugin_name == b"mysql_old_password": # https://dev.mysql.com/doc/internals/en/ # old-password-authentication.html data = _scramble_323(self._password.encode('latin1'), auth_packet.read_all()) + b'\0' elif plugin_name == b"mysql_clear_password": # https://dev.mysql.com/doc/internals/en/ # clear-text-authentication.html data = self._password.encode('latin1') + b'\0' else: raise OperationalError( 2059, "Authentication plugin '%s' not configured" % plugin_name ) self.write_packet(data) pkt = await self._read_packet() pkt.check_error() self._auth_plugin_used = plugin_name return pkt
def _request_authentication(self): self.client_flag |= CAPABILITIES if self.server_version.startswith('5'): self.client_flag |= MULTI_RESULTS if self._user is None: raise ValueError("Did not specify a username") charset_id = charset_by_name(self._charset).id user = self._user if isinstance(self._user, str): user = self._user.encode(self._encoding) data_init = (struct.pack('<i', self.client_flag) + struct.pack("<I", 1) + int2byte(charset_id) + int2byte(0) * 23) next_packet = 1 data = data_init + user + b'\0' + _scramble( self._password.encode('latin1'), self.salt) if self._db: db = self._db if isinstance(self._db, str): db = self._db.encode(self._encoding) data += db + int2byte(0) data = pack_int24(len(data)) + int2byte(next_packet) + data next_packet += 2 # logger.debug(dump_packet(data)) self._write_bytes(data) auth_packet = yield from self._read_packet() # if old_passwords is enabled the packet will be 1 byte long and # have the octet 254 if auth_packet.is_eof_packet(): # send legacy handshake data = _scramble_323(self._password.encode('latin1'), self.salt) + b'\0' data = pack_int24(len(data)) + int2byte(next_packet) + data self._write_bytes(data) auth_packet = self._read_packet()
def _request_authentication(self): self.client_flag |= CAPABILITIES if int(self.server_version.split('.', 1)[0]) >= 5: self.client_flag |= MULTI_RESULTS if self._user is None: raise ValueError("Did not specify a username") charset_id = charset_by_name(self._charset).id user = self._user if isinstance(self._user, str): user = self._user.encode(self._encoding) data_init = struct.pack('<iIB23s', self.client_flag, 1, charset_id, b'') next_packet = 1 data = data_init + user + b'\0' + _scramble( self._password.encode('latin1'), self.salt) if self._db: db = self._db if isinstance(self._db, str): db = self._db.encode(self._encoding) data += db + int2byte(0) data = pack_int24(len(data)) + int2byte(next_packet) + data next_packet += 2 # logger.debug(dump_packet(data)) self._write_bytes(data) auth_packet = yield from self._read_packet() # if old_passwords is enabled the packet will be 1 byte long and # have the octet 254 if auth_packet.is_eof_packet(): # send legacy handshake data = _scramble_323(self._password.encode('latin1'), self.salt) + b'\0' data = pack_int24(len(data)) + int2byte(next_packet) + data self._write_bytes(data) auth_packet = self._read_packet()
def _request_authentication(self): self.client_flag |= CLIENT.CAPABILITIES if int(self.server_version.split('.', 1)[0]) >= 5: self.client_flag |= CLIENT.MULTI_RESULTS if self._user is None: raise ValueError("Did not specify a username") charset_id = charset_by_name(self._charset).id user = self._user if isinstance(self._user, str): user = self._user.encode(self._encoding) data_init = struct.pack('<iIB23s', self.client_flag, 1, charset_id, b'') data = data_init + user + b'\0' + _scramble( self._password.encode('latin1'), self.salt) # TODO: sync auth code with changes in PyMySQL if self._db: db = self._db if isinstance(self._db, str): db = self._db.encode(self._encoding) data += db + int2byte(0) self.write_packet(data) auth_packet = yield from self._read_packet() # if old_passwords is enabled the packet will be 1 byte long and # have the octet 254 if auth_packet.is_eof_packet(): # send legacy handshake data = _scramble_323(self._password.encode('latin1'), self.salt) + b'\0' self.write_packet(data) auth_packet = self._read_packet()
def _request_authentication(self): if int(self.server_version.split('.', 1)[0]) >= 5: self.client_flag |= CLIENT.MULTI_RESULTS if self.user is None: raise ValueError("Did not specify a username") charset_id = charset_by_name(self.charset).id if isinstance(self.user, text_type): self.user = self.user.encode(self.encoding) data_init = struct.pack('<iIB23s', self.client_flag, 1, charset_id, b'') if self.ssl and self.server_capabilities & CLIENT.SSL: self.write_packet(data_init) child_gr = greenlet.getcurrent() main = child_gr.parent assert main is not None, "Execut must be running in child greenlet" def finish(future): if future._exc_info is not None: child_gr.throw(future.exception()) else: child_gr.switch(future.result()) future = self.socket.start_tls(False, self.ctx, server_hostname=self.host) self._loop.add_future(future, finish) self._rfile = self.socket = main.switch() data = data_init + self.user + b'\0' authresp = b'' if self._auth_plugin_name in ('', 'mysql_native_password'): authresp = _scramble(self.password.encode('latin1'), self.salt) if self.server_capabilities & CLIENT.PLUGIN_AUTH_LENENC_CLIENT_DATA: data += lenenc_int(len(authresp)) + authresp elif self.server_capabilities & CLIENT.SECURE_CONNECTION: data += struct.pack('B', len(authresp)) + authresp else: # pragma: no cover - not testing against servers without secure auth (>=5.0) data += authresp + b'\0' if self.db and self.server_capabilities & CLIENT.CONNECT_WITH_DB: if isinstance(self.db, text_type): self.db = self.db.encode(self.encoding) data += self.db + b'\0' if self.server_capabilities & CLIENT.PLUGIN_AUTH: name = self._auth_plugin_name if isinstance(name, text_type): name = name.encode('ascii') data += name + b'\0' self.write_packet(data) auth_packet = self._read_packet() # if authentication method isn't accepted the first byte # will have the octet 254 if auth_packet.is_auth_switch_request(): # https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchRequest auth_packet.read_uint8() # 0xfe packet identifier plugin_name = auth_packet.read_string() if self.server_capabilities & CLIENT.PLUGIN_AUTH and plugin_name is not None: auth_packet = self._process_auth(plugin_name, auth_packet) else: # send legacy handshake data = _scramble_323(self.password.encode('latin1'), self.salt) + b'\0' self.write_packet(data) auth_packet = self._read_packet()
def _request_authentication(self): # https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse if int(self.server_version.split('.', 1)[0]) >= 5: self.client_flag |= CLIENT.MULTI_RESULTS if self.user is None: raise ValueError("Did not specify a username") charset_id = charset_by_name(self.charset).id if isinstance(self.user, str): _user = self.user.encode(self.encoding) data_init = struct.pack('<iIB23s', self.client_flag, 1, charset_id, b'') data = data_init + _user + b'\0' authresp = b'' if self._auth_plugin_name in ('', 'mysql_native_password'): authresp = _scramble(self._password.encode('latin1'), self.salt) if self.server_capabilities & CLIENT.PLUGIN_AUTH_LENENC_CLIENT_DATA: data += lenenc_int(len(authresp)) + authresp elif self.server_capabilities & CLIENT.SECURE_CONNECTION: data += struct.pack('B', len(authresp)) + authresp else: # pragma: no cover # not testing against servers without secure auth (>=5.0) data += authresp + b'\0' if self._db and self.server_capabilities & CLIENT.CONNECT_WITH_DB: if isinstance(self._db, str): db = self._db.encode(self.encoding) else: db = self._db data += db + b'\0' if self.server_capabilities & CLIENT.PLUGIN_AUTH: name = self._auth_plugin_name if isinstance(name, str): name = name.encode('ascii') data += name + b'\0' self.write_packet(data) auth_packet = yield from self._read_packet() # if authentication method isn't accepted the first byte # will have the octet 254 if auth_packet.is_auth_switch_request(): # https://dev.mysql.com/doc/internals/en/ # connection-phase-packets.html#packet-Protocol::AuthSwitchRequest auth_packet.read_uint8() # 0xfe packet identifier plugin_name = auth_packet.read_string() if (self.server_capabilities & CLIENT.PLUGIN_AUTH and plugin_name is not None): auth_packet = self._process_auth(plugin_name, auth_packet) else: # send legacy handshake data = _scramble_323(self._password.encode('latin1'), self.salt) + b'\0' self.write_packet(data) auth_packet = yield from self._read_packet()
async def _request_authentication(self): # https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse if int(self.server_version.split('.', 1)[0]) >= 5: self.client_flag |= CLIENT.MULTI_RESULTS if self.user is None: raise ValueError("Did not specify a username") if self._ssl_context: # capablities, max packet, charset data = struct.pack('<IIB', self.client_flag, 16777216, 33) data += b'\x00' * (32 - len(data)) self.write_packet(data) # Stop sending events to data_received self._writer.transport.pause_reading() # Get the raw socket from the transport raw_sock = self._writer.transport.get_extra_info('socket', default=None) if raw_sock is None: raise RuntimeError("Transport does not expose socket instance") raw_sock = raw_sock.dup() self._writer.transport.close() # MySQL expects TLS negotiation to happen in the middle of a # TCP connection not at start. Passing in a socket to # open_connection will cause it to negotiate TLS on an existing # connection not initiate a new one. self._reader, self._writer = await asyncio.open_connection( sock=raw_sock, ssl=self._ssl_context, loop=self._loop, server_hostname=self._host ) charset_id = charset_by_name(self.charset).id if isinstance(self.user, str): _user = self.user.encode(self.encoding) data_init = struct.pack('<iIB23s', self.client_flag, 1, charset_id, b'') data = data_init + _user + b'\0' authresp = b'' auth_plugin = self._client_auth_plugin if not self._client_auth_plugin: # Contains the auth plugin from handshake auth_plugin = self._server_auth_plugin if auth_plugin in ('', 'mysql_native_password'): authresp = _scramble(self._password.encode('latin1'), self.salt) elif auth_plugin in ('', 'mysql_clear_password'): authresp = self._password.encode('latin1') + b'\0' if self.server_capabilities & CLIENT.PLUGIN_AUTH_LENENC_CLIENT_DATA: data += lenenc_int(len(authresp)) + authresp elif self.server_capabilities & CLIENT.SECURE_CONNECTION: data += struct.pack('B', len(authresp)) + authresp else: # pragma: no cover # not testing against servers without secure auth (>=5.0) data += authresp + b'\0' if self._db and self.server_capabilities & CLIENT.CONNECT_WITH_DB: if isinstance(self._db, str): db = self._db.encode(self.encoding) else: db = self._db data += db + b'\0' if self.server_capabilities & CLIENT.PLUGIN_AUTH: name = auth_plugin if isinstance(name, str): name = name.encode('ascii') data += name + b'\0' self._auth_plugin_used = auth_plugin self.write_packet(data) auth_packet = await self._read_packet() # if authentication method isn't accepted the first byte # will have the octet 254 if auth_packet.is_auth_switch_request(): # https://dev.mysql.com/doc/internals/en/ # connection-phase-packets.html#packet-Protocol::AuthSwitchRequest auth_packet.read_uint8() # 0xfe packet identifier plugin_name = auth_packet.read_string() if (self.server_capabilities & CLIENT.PLUGIN_AUTH and plugin_name is not None): auth_packet = await self._process_auth( plugin_name, auth_packet) else: # send legacy handshake data = _scramble_323(self._password.encode('latin1'), self.salt) + b'\0' self.write_packet(data) auth_packet = await self._read_packet()
def _request_authentication(self): self.client_flag |= CLIENT.CAPABILITIES if int(self.server_version.split(".", 1)[0]) >= 5: self.client_flag |= CLIENT.MULTI_RESULTS if self.user is None: raise ValueError("Did not specify a username") charset_id = charset_by_name(self.charset).id if isinstance(self.user, text_type): self.user = self.user.encode(self.encoding) data_init = struct.pack("<iIB23s", self.client_flag, 1, charset_id, b"") next_packet = 1 if self.ssl: data = pack_int24(len(data_init)) + int2byte(next_packet) + data_init next_packet += 1 self._write_bytes(data) child_gr = greenlet.getcurrent() main = child_gr.parent assert main is not None, "Execut must be running in child greenlet" def finish(future): try: stream = future.result() child_gr.switch(stream) except Exception as e: child_gr.throw(e) cert_reqs = ssl.CERT_NONE if self.ca is None else ssl.CERT_REQUIRED future = self.socket.start_tls( None, { "keyfile": self.key, "certfile": self.cert, "ssl_version": ssl.PROTOCOL_TLSv1, "cert_reqs": ssl.CERT_REQUIRED, "ca_certs": cert_reqs, }, ) IOLoop.current().add_future(future, finish) self.socket = main.switch() self._rfile = self.socket data = data_init + self.user + b"\0" + _scramble(self.password.encode("latin1"), self.salt) if self.db: if isinstance(self.db, text_type): self.db = self.db.encode(self.encoding) data += self.db + int2byte(0) data = pack_int24(len(data)) + int2byte(next_packet) + data next_packet += 2 if DEBUG: dump_packet(data) self._write_bytes(data) auth_packet = self._read_packet() # if old_passwords is enabled the packet will be 1 byte long and # have the octet 254 if auth_packet.is_eof_packet(): # send legacy handshake data = _scramble_323(self.password.encode("latin1"), self.salt) + b"\0" data = pack_int24(len(data)) + int2byte(next_packet) + data self._write_bytes(data) auth_packet = self._read_packet()