Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

caching_sha2_password full auth on MySQL 8.0 does not work over unix sockets #673

Closed
1 task done
Nothing4You opened this issue Jan 17, 2022 · 2 comments · Fixed by #695
Closed
1 task done

caching_sha2_password full auth on MySQL 8.0 does not work over unix sockets #673

Nothing4You opened this issue Jan 17, 2022 · 2 comments · Fixed by #695
Labels
bug pymysql-port Awaiting or implementing port of PyMySQL change
Milestone

Comments

@Nothing4You
Copy link
Collaborator

Nothing4You commented Jan 17, 2022

Describe the bug

As per MySQL 8.0 docs caching_sha2_password requires a "secure" connection:

To connect to the server using an account that authenticates with the caching_sha2_password plugin, you must use either a secure connection or an unencrypted connection that supports password exchange using an RSA key pair, as described later in this section.

If the connection is secure, an RSA key pair is unnecessary and is not used. This applies to TCP connections encrypted using TLS, as well as Unix socket-file and shared-memory connections. The password is sent as cleartext but cannot be snooped because the connection is secure.

If we can authenticate by fast path authentication works fine:

if n == 3:
logger.debug("caching sha2: succeeded by fast path.")
pkt = await self._read_packet()
pkt.check_error() # pkt must be OK packet
return pkt

However, if we fall back to full auth, we only send the password when the connection has an SSL context.
On unix sockets we don't have an SSL context, but the connection is still secure.

logger.debug("caching sha2: Trying full auth...")
if self._ssl_context:

To Reproduce

  1. Set up MySQL 8.0 server via homebrew
  2. Run the following script
import asyncio
import datetime
import logging

import aiomysql


logger = logging.getLogger(__name__)


async def main():
    conn = await aiomysql.connect(
        unix_socket="/tmp/mysql.sock",
        user="root",
        password="rootpw",
        db="test_pymysql",
    )

    async with conn.cursor() as cur:
        res = await cur.execute("select 1+1")
        print(res)

    conn.close()


if __name__ == "__main__":
    logging.basicConfig(
        level=logging.DEBUG,
        format="%(asctime)s - %(levelname)8s - %(name)s:%(funcName)s - %(message)s",
    )

    logging.Formatter.formatTime = (
        lambda self, record, datefmt: datetime.datetime.fromtimestamp(
            record.created, datetime.timezone.utc
        )
        .astimezone()
        .isoformat()
    )

    asyncio.run(main())

Expected behavior

Authentication succeeds even when not cached.

Logs/tracebacks

$ python unix-test-password.py
2022-01-17T09:04:37.071060+01:00 -    DEBUG - asyncio:__init__ - Using selector: KqueueSelector
2022-01-17T09:04:37.072641+01:00 -    DEBUG - aiomysql:caching_sha2_password_auth - caching sha2: Trying full auth...
Traceback (most recent call last):
  File "/Users/user/dev/aiomysql/aiomysql/connection.py", line 501, in _connect
    await self._request_authentication()
  File "/Users/user/dev/aiomysql/aiomysql/connection.py", line 804, in _request_authentication
    await self.caching_sha2_password_auth(auth_packet)
  File "/Users/user/dev/aiomysql/aiomysql/connection.py", line 911, in caching_sha2_password_auth
    pkt = await self._read_packet()  # Request public key
  File "/Users/user/dev/aiomysql/aiomysql/connection.py", line 591, in _read_packet
    packet.check_error()
  File "/Users/user/dev/aiomysql/__pypackages__/3.7/lib/pymysql/protocol.py", line 220, in check_error
    err.raise_mysql_exception(self._data)
  File "/Users/user/dev/aiomysql/__pypackages__/3.7/lib/pymysql/err.py", line 109, in raise_mysql_exception
    raise errorclass(errno, errval)
pymysql.err.OperationalError: (1045, "Access denied for user 'root'@'localhost' (using password: YES)")

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "unix-test-password.py", line 55, in <module>
    asyncio.run(main())
  File "/Users/user/.asdf/installs/python/3.7.12/lib/python3.7/asyncio/runners.py", line 43, in run
    return loop.run_until_complete(main)
  File "/Users/user/.asdf/installs/python/3.7.12/lib/python3.7/asyncio/base_events.py", line 587, in run_until_complete
    return future.result()
  File "unix-test-password.py", line 32, in main
    db='test_pymysql')
  File "/Users/user/dev/aiomysql/aiomysql/connection.py", line 75, in _connect
    await conn._connect()
  File "/Users/user/dev/aiomysql/aiomysql/connection.py", line 521, in _connect
    self._host) from e
pymysql.err.OperationalError: (2003, "Can't connect to MySQL server on 'localhost'")

Python Version

Python 3.7.12

aiomysql Version

master branch, currently on ecbd675

PyMySQL Version

Installed version:     0.9.3

SQLAlchemy Version

-

OS

macOS

Database type and version

MySQL 8.0.27

Additional context

No response

Code of Conduct

  • I agree to follow the aio-libs Code of Conduct
@Nothing4You
Copy link
Collaborator Author

PyMySQLs implementation: PyMySQL/PyMySQL#696

@Nothing4You Nothing4You added the pymysql-port Awaiting or implementing port of PyMySQL change label Jan 22, 2022
@Nothing4You
Copy link
Collaborator Author

should be fixed by 695

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug pymysql-port Awaiting or implementing port of PyMySQL change
Projects
None yet
1 participant