# MySQL-Mimic
[![Tests](https://github.com/kelsin/mysql-mimic/actions/workflows/tests.yml/badge.svg)](https://github.com/kelsin/mysql-mimic/actions/workflows/tests.yml)
Pure-python implementation of the MySQL server [wire protocol](https://dev.mysql.com/doc/internals/en/client-server-protocol.html).
This can be used to create applications that act as a MySQL server.
## Installation
```shell
pip install mysql-mimic
```
## Usage
A minimal use case might look like this:
```python
import asyncio
from mysql_mimic import MysqlServer, Session
class MySession(Session):
async def query(self, expression, sql, attrs):
print(f"Parsed abstract syntax tree: {expression}")
print(f"Original SQL string: {sql}")
print(f"Query attributes: {sql}")
print(f"Currently authenticated user: {self.username}")
print(f"Currently selected database: {self.database}")
return [("a", 1), ("b", 2)], ["col1", "col2"]
async def schema(self):
# Optionally provide the database schema.
# This is used to serve INFORMATION_SCHEMA and SHOW queries.
return {
"table": {
"col1": "TEXT",
"col2": "INT",
}
}
if __name__ == "__main__":
server = MysqlServer(session_factory=MySession)
asyncio.run(server.serve_forever())
```
Using [sqlglot](https://github.com/tobymao/sqlglot), the abstract `Session` class handles queries to metadata, variables, etc. that many MySQL clients expect.
To bypass this default behavior, you can implement the [`mysql_mimic.session.BaseSession`](mysql_mimic/session.py) interface.
See [examples](./examples) for more examples.
## Authentication
MySQL-mimic has built in support for several standard MySQL authentication plugins:
- [mysql_native_password](https://dev.mysql.com/doc/refman/8.0/en/native-pluggable-authentication.html)
- The client sends hashed passwords to the server, and the server stores hashed passwords. See the documentation for more details on how this works.
- [example](examples/auth_native_password.py)
- [mysql_clear_password](https://dev.mysql.com/doc/refman/8.0/en/cleartext-pluggable-authentication.html)
- The client sends passwords to the server as clear text, without hashing or encryption.
- This is typically used as the client plugin for a custom server plugin. As such, MySQL-mimic provides an abstract class, [`mysql_mimic.auth.AbstractClearPasswordAuthPlugin`](mysql_mimic/auth.py), which can be extended.
- [example](examples/auth_clear_password.py)
- [mysql_no_login](https://dev.mysql.com/doc/refman/8.0/en/no-login-pluggable-authentication.html)
- The server prevents clients from directly authenticating as an account. See the documentation for relevant use cases.
- [authentication_kerberos](https://dev.mysql.com/doc/mysql-security-excerpt/8.0/en/kerberos-pluggable-authentication.html)
- Kerberos uses tickets together with symmetric-key cryptography, enabling authentication without sending passwords over the network. Kerberos authentication supports userless and passwordless scenarios.
By default, a session naively accepts whatever username the client provides.
Plugins are provided to the server by implementing [`mysql_mimic.IdentityProvider`](mysql_mimic/auth.py), which configures all available plugins and a callback for fetching users.
Custom plugins can be created by extending [`mysql_mimic.auth.AuthPlugin`](mysql_mimic/auth.py).
## Development
You can install dependencies with `make deps`.
You can format your code with `make format`.
You can lint with `make lint`.
You can check type annotations with `make types`.
You can run tests with `make test`. This will build a coverage report in `./htmlcov/index.html`.
You can run all the checks with `make check`.
You can build a pip package with `make build`.
Raw data
{
"_id": null,
"home_page": "https://github.com/kelsin/mysql-mimic",
"name": "mysql-mimic",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.6",
"maintainer_email": null,
"keywords": null,
"author": "Christopher Giroir",
"author_email": "kelsin@valefor.com",
"download_url": "https://files.pythonhosted.org/packages/da/1d/f216617d6f042698a51e9377ca94ffdb9c7485c12cbee317257f0124c343/mysql-mimic-2.5.7.tar.gz",
"platform": null,
"description": "# MySQL-Mimic\n\n[![Tests](https://github.com/kelsin/mysql-mimic/actions/workflows/tests.yml/badge.svg)](https://github.com/kelsin/mysql-mimic/actions/workflows/tests.yml)\n\nPure-python implementation of the MySQL server [wire protocol](https://dev.mysql.com/doc/internals/en/client-server-protocol.html).\n\nThis can be used to create applications that act as a MySQL server.\n\n## Installation\n\n```shell\npip install mysql-mimic\n```\n\n## Usage\n\nA minimal use case might look like this:\n\n```python\nimport asyncio\n\nfrom mysql_mimic import MysqlServer, Session\n\n\nclass MySession(Session):\n async def query(self, expression, sql, attrs):\n print(f\"Parsed abstract syntax tree: {expression}\")\n print(f\"Original SQL string: {sql}\")\n print(f\"Query attributes: {sql}\")\n print(f\"Currently authenticated user: {self.username}\")\n print(f\"Currently selected database: {self.database}\")\n return [(\"a\", 1), (\"b\", 2)], [\"col1\", \"col2\"]\n\n async def schema(self):\n # Optionally provide the database schema.\n # This is used to serve INFORMATION_SCHEMA and SHOW queries.\n return {\n \"table\": {\n \"col1\": \"TEXT\",\n \"col2\": \"INT\",\n }\n }\n\nif __name__ == \"__main__\":\n server = MysqlServer(session_factory=MySession)\n asyncio.run(server.serve_forever())\n```\n\nUsing [sqlglot](https://github.com/tobymao/sqlglot), the abstract `Session` class handles queries to metadata, variables, etc. that many MySQL clients expect.\n\nTo bypass this default behavior, you can implement the [`mysql_mimic.session.BaseSession`](mysql_mimic/session.py) interface.\n\nSee [examples](./examples) for more examples.\n\n## Authentication\n\nMySQL-mimic has built in support for several standard MySQL authentication plugins:\n- [mysql_native_password](https://dev.mysql.com/doc/refman/8.0/en/native-pluggable-authentication.html)\n - The client sends hashed passwords to the server, and the server stores hashed passwords. See the documentation for more details on how this works.\n - [example](examples/auth_native_password.py)\n- [mysql_clear_password](https://dev.mysql.com/doc/refman/8.0/en/cleartext-pluggable-authentication.html)\n - The client sends passwords to the server as clear text, without hashing or encryption.\n - This is typically used as the client plugin for a custom server plugin. As such, MySQL-mimic provides an abstract class, [`mysql_mimic.auth.AbstractClearPasswordAuthPlugin`](mysql_mimic/auth.py), which can be extended.\n - [example](examples/auth_clear_password.py)\n- [mysql_no_login](https://dev.mysql.com/doc/refman/8.0/en/no-login-pluggable-authentication.html)\n - The server prevents clients from directly authenticating as an account. See the documentation for relevant use cases.\n- [authentication_kerberos](https://dev.mysql.com/doc/mysql-security-excerpt/8.0/en/kerberos-pluggable-authentication.html)\n - Kerberos uses tickets together with symmetric-key cryptography, enabling authentication without sending passwords over the network. Kerberos authentication supports userless and passwordless scenarios.\n\n\nBy default, a session naively accepts whatever username the client provides.\n\nPlugins are provided to the server by implementing [`mysql_mimic.IdentityProvider`](mysql_mimic/auth.py), which configures all available plugins and a callback for fetching users.\n\nCustom plugins can be created by extending [`mysql_mimic.auth.AuthPlugin`](mysql_mimic/auth.py).\n\n## Development\n\nYou can install dependencies with `make deps`.\n\nYou can format your code with `make format`.\n\nYou can lint with `make lint`.\n\nYou can check type annotations with `make types`.\n\nYou can run tests with `make test`. This will build a coverage report in `./htmlcov/index.html`.\n\nYou can run all the checks with `make check`.\n\nYou can build a pip package with `make build`.\n\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "A python implementation of the mysql server protocol",
"version": "2.5.7",
"project_urls": {
"Homepage": "https://github.com/kelsin/mysql-mimic"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "2040dc111963785614d1fcdcbe8ed1bd25345a0ea12100aeaa731504756ffd56",
"md5": "3a626e2a2bc174f1a5a34a14d200a36d",
"sha256": "f4b88cd48109428a2cc221f935725a5ff25fc23651c7ebb670ba4c14b35590a1"
},
"downloads": -1,
"filename": "mysql_mimic-2.5.7-py3-none-any.whl",
"has_sig": false,
"md5_digest": "3a626e2a2bc174f1a5a34a14d200a36d",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.6",
"size": 46159,
"upload_time": "2024-09-09T19:23:53",
"upload_time_iso_8601": "2024-09-09T19:23:53.109669Z",
"url": "https://files.pythonhosted.org/packages/20/40/dc111963785614d1fcdcbe8ed1bd25345a0ea12100aeaa731504756ffd56/mysql_mimic-2.5.7-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "da1df216617d6f042698a51e9377ca94ffdb9c7485c12cbee317257f0124c343",
"md5": "054d9899fc6605ac4a45a2565d65861b",
"sha256": "11c1cc387dce6c6ee72759ed048bf249bf3d51af9b20fbfa1e79208807583e0f"
},
"downloads": -1,
"filename": "mysql-mimic-2.5.7.tar.gz",
"has_sig": false,
"md5_digest": "054d9899fc6605ac4a45a2565d65861b",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.6",
"size": 52374,
"upload_time": "2024-09-09T19:23:54",
"upload_time_iso_8601": "2024-09-09T19:23:54.276890Z",
"url": "https://files.pythonhosted.org/packages/da/1d/f216617d6f042698a51e9377ca94ffdb9c7485c12cbee317257f0124c343/mysql-mimic-2.5.7.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-09-09 19:23:54",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "kelsin",
"github_project": "mysql-mimic",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [],
"lcname": "mysql-mimic"
}