From 57423436ce2e6f3374308ad3976403ab346fb02b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Sun, 10 Dec 2023 00:36:29 +0100 Subject: [PATCH] Added options to use MySQL connection via SSL --- .docker/symfony.conf | 2 +- .env | 9 ++++ composer.json | 1 + composer.lock | 2 +- config/services.yaml | 4 ++ docs/configuration.md | 3 ++ .../MySQLSSLConnectionMiddlewareDriver.php | 52 +++++++++++++++++++ .../MySQLSSLConnectionMiddlewareWrapper.php | 39 ++++++++++++++ 8 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 src/Doctrine/Middleware/MySQLSSLConnectionMiddlewareDriver.php create mode 100644 src/Doctrine/Middleware/MySQLSSLConnectionMiddlewareWrapper.php diff --git a/.docker/symfony.conf b/.docker/symfony.conf index 9569f80c..31b608fb 100644 --- a/.docker/symfony.conf +++ b/.docker/symfony.conf @@ -27,7 +27,7 @@ # Pass the configuration from the docker env to the PHP environment (here you should list all .env options) PassEnv APP_ENV APP_DEBUG APP_SECRET PassEnv TRUSTED_PROXIES TRUSTED_HOSTS LOCK_DSN - PassEnv DATABASE_URL ENFORCE_CHANGE_COMMENTS_FOR + PassEnv DATABASE_URL ENFORCE_CHANGE_COMMENTS_FOR DATABASE_MYSQL_USE_SSL_CA DATABASE_MYSQL_SSL_VERIFY_CERT PassEnv DEFAULT_LANG DEFAULT_TIMEZONE BASE_CURRENCY INSTANCE_NAME ALLOW_ATTACHMENT_DOWNLOADS USE_GRAVATAR MAX_ATTACHMENT_FILE_SIZE DEFAULT_URI CHECK_FOR_UPDATES ATTACHMENT_DOWNLOAD_BY_DEFAULT PassEnv MAILER_DSN ALLOW_EMAIL_PW_RESET EMAIL_SENDER_EMAIL EMAIL_SENDER_NAME PassEnv HISTORY_SAVE_CHANGED_FIELDS HISTORY_SAVE_CHANGED_DATA HISTORY_SAVE_REMOVED_DATA HISTORY_SAVE_NEW_DATA diff --git a/.env b/.env index 47919cb7..cd79e581 100644 --- a/.env +++ b/.env @@ -14,6 +14,15 @@ DATABASE_URL="sqlite:///%kernel.project_dir%/var/app.db" # Uncomment this line (and comment the line above to use a MySQL database #DATABASE_URL=mysql://root:@127.0.0.1:3306/part-db?serverVersion=5.7 +# Set this value to 1, if you want to use SSL to connect to the MySQL server. It will be tried to use the CA certificate +# otherwise a CA bundle shipped with PHP will be used. +# Leave it at 0, if you do not want to use SSL or if your server does not support it +DATABASE_MYSQL_USE_SSL_CA=0 + +# Set this value to 0, if you don't want to verify the CA certificate of the MySQL server +# Only do this, if you know what you are doing! +DATABASE_MYSQL_SSL_VERIFY_CERT=1 + ################################################################################### # General settings ################################################################################### diff --git a/composer.json b/composer.json index 3296f037..eb4f0103 100644 --- a/composer.json +++ b/composer.json @@ -13,6 +13,7 @@ "api-platform/core": "^3.1", "beberlei/doctrineextensions": "^1.2", "brick/math": "0.12.1 as 0.11.0", + "composer/ca-bundle": "^1.3", "composer/package-versions-deprecated": "^1.11.99.5", "doctrine/annotations": "1.14.3", "doctrine/data-fixtures": "^1.6.6", diff --git a/composer.lock b/composer.lock index fb00fec2..bed3a72e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "2379491b49e2abf92312a1623292b620", + "content-hash": "efc5a8e6492668498f5e357bc9d9fd2f", "packages": [ { "name": "api-platform/core", diff --git a/config/services.yaml b/config/services.yaml index 88f13415..e31356c5 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -370,6 +370,10 @@ services: $partdb_banner: '%partdb.banner%' $project_dir: '%kernel.project_dir%' + App\Doctrine\Middleware\MySQLSSLConnectionMiddlewareWrapper: + arguments: + $enabled: '%env(bool:DATABASE_MYSQL_USE_SSL_CA)%' + $verify: '%env(bool:DATABASE_MYSQL_SSL_VERIFY_CERT)%' #################################################################################################################### # Monolog diff --git a/docs/configuration.md b/docs/configuration.md index 1796b7df..32472901 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -37,6 +37,9 @@ options listed, see `.env` file for full list of possible env variables. (e.g. `DATABASE_URL=mysql://user:password@127.0.0.1:3306/part-db`). For sqlite use the following format to specify the absolute path where it should be located `sqlite:///path/part/app.db`. You can use `%kernel.project_dir%` as placeholder for the Part-DB root folder (e.g. `sqlite:///%kernel.project_dir%/var/app.db`) +* `DATABASE_MYSQL_USE_SSL_CA`: If this value is set to `1` or `true` and a MySQL connection is used, then the connection + is encrypted by SSL/TLS and the server certificate is verified against the system CA certificates or the CA certificate +bundled with Part-DB. Set `DATABASE_MYSQL_SSL_VERIFY_CERT` if you want to accept all certificates. * `DEFAULT_LANG`: The default language to use server wide (when no language is explicitly specified by a user or via language chooser). Must be something like `en`, `de`, `fr`, etc. * `DEFAULT_TIMEZONE`: The default timezone to use globally, when a user has no timezone specified. Must be something diff --git a/src/Doctrine/Middleware/MySQLSSLConnectionMiddlewareDriver.php b/src/Doctrine/Middleware/MySQLSSLConnectionMiddlewareDriver.php new file mode 100644 index 00000000..2f6d39dd --- /dev/null +++ b/src/Doctrine/Middleware/MySQLSSLConnectionMiddlewareDriver.php @@ -0,0 +1,52 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Doctrine\Middleware; + +use Composer\CaBundle\CaBundle; +use Doctrine\DBAL\Driver; +use Doctrine\DBAL\Driver\Connection; +use Doctrine\DBAL\Driver\Middleware\AbstractDriverMiddleware; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; + +/** + * This middleware sets SSL options for MySQL connections + */ +class MySQLSSLConnectionMiddlewareDriver extends AbstractDriverMiddleware +{ + public function __construct(Driver $wrappedDriver, private readonly bool $enabled, private readonly bool $verify = true) + { + parent::__construct($wrappedDriver); + } + + public function connect(array $params): Connection + { + //Only set this on MySQL connections, as other databases don't support this parameter + if($this->enabled && $this->getDatabasePlatform() instanceof AbstractMySQLPlatform) { + $params['driverOptions'][\PDO::MYSQL_ATTR_SSL_CA] = CaBundle::getSystemCaRootBundlePath(); + $params['driverOptions'][\PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = $this->verify; + } + + return parent::connect($params); + } +} \ No newline at end of file diff --git a/src/Doctrine/Middleware/MySQLSSLConnectionMiddlewareWrapper.php b/src/Doctrine/Middleware/MySQLSSLConnectionMiddlewareWrapper.php new file mode 100644 index 00000000..8bd25971 --- /dev/null +++ b/src/Doctrine/Middleware/MySQLSSLConnectionMiddlewareWrapper.php @@ -0,0 +1,39 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Doctrine\Middleware; + +use Doctrine\DBAL\Driver; +use Doctrine\DBAL\Driver\Middleware; + +class MySQLSSLConnectionMiddlewareWrapper implements Middleware +{ + public function __construct(private readonly bool $enabled, private readonly bool $verify = true) + { + } + + public function wrap(Driver $driver): Driver + { + return new MySQLSSLConnectionMiddlewareDriver($driver, $this->enabled, $this->verify); + } +} \ No newline at end of file