Skip to content
Snippets Groups Projects
Unverified Commit b959a1ad authored by Eileen McNaughton's avatar Eileen McNaughton Committed by GitHub
Browse files

Merge pull request #18264 from demeritcowboy/mysql-ssl-guess

#1926 - Try to autodetect mysql ssl settings from the CMS config
parents 57e6566a fc2b5ff8
Branches
Tags
No related merge requests found
......@@ -39,11 +39,13 @@ if (!defined('CIVI_SETUP')) {
// Compute DSN.
global $databases;
$ssl_params = \Civi\Setup\DrupalUtil::guessSslParams($databases['default']['default']);
$model->db = $model->cmsDb = array(
'server' => \Civi\Setup\DbUtil::encodeHostPort($databases['default']['default']['host'], $databases['default']['default']['port'] ?: NULL),
'username' => $databases['default']['default']['username'],
'password' => $databases['default']['default']['password'],
'database' => $databases['default']['default']['database'],
'ssl_params' => empty($ssl_params) ? NULL : $ssl_params,
);
// Compute URLs
......
......@@ -37,11 +37,13 @@ if (!defined('CIVI_SETUP')) {
// Compute DSN.
global $databases;
$ssl_params = \Civi\Setup\DrupalUtil::guessSslParams($databases['default']['default']);
$model->db = $model->cmsDb = array(
'server' => \Civi\Setup\DbUtil::encodeHostPort($databases['default']['default']['host'], $databases['default']['default']['port'] ?: NULL),
'username' => $databases['default']['default']['username'],
'password' => $databases['default']['default']['password'],
'database' => $databases['default']['default']['database'],
'ssl_params' => empty($ssl_params) ? NULL : $ssl_params,
);
// Compute cmsBaseUrl.
......
......@@ -40,11 +40,13 @@ if (!defined('CIVI_SETUP')) {
// Compute DSN.
$connectionOptions = \Drupal::database()->getConnectionOptions();
$ssl_params = \Civi\Setup\DrupalUtil::guessSslParams($connectionOptions);
$model->db = $model->cmsDb = array(
'server' => \Civi\Setup\DbUtil::encodeHostPort($connectionOptions['host'], $connectionOptions['port'] ?: NULL),
'username' => $connectionOptions['username'],
'password' => $connectionOptions['password'],
'database' => $connectionOptions['database'],
'ssl_params' => empty($ssl_params) ? NULL : $ssl_params,
);
// Compute cmsBaseUrl.
......
......@@ -71,6 +71,13 @@ if (!defined('CIVI_SETUP')) {
$params['CMSdbPass'] = addslashes($m->cmsDb['password']);
$params['CMSdbHost'] = addslashes($m->cmsDb['server']);
$params['CMSdbName'] = addslashes($m->cmsDb['database']);
// The '&' prefix is awkward, but we don't know what's already in the file.
// At the time of writing, it has ?new_link=true. If that is removed,
// then need to update this.
// The PHP_QUERY_RFC3986 is important because PEAR::DB will interpret plus
// signs as a reference to its old DSN format and mangle the DSN, so we
// need to use %20 for spaces.
$params['CMSdbSSL'] = empty($m->cmsDb['ssl_params']) ? '' : addslashes('&' . http_build_query($m->cmsDb['ssl_params'], '', '&', PHP_QUERY_RFC3986));
$params['siteKey'] = addslashes($m->siteKey);
$extraSettings = array();
......
......@@ -71,4 +71,58 @@ class DrupalUtil {
*/
}
/**
* Guess if the CMS is using SSL for MySQL and what the corresponding
* parameters should be for PEAR::DB.
*
* Not all combinations will work. See the install docs for a list of known
* configurations that do. We don't enforce that here since we're just
* trying to guess a default based on what they already have.
*
* @param array $cmsDatabaseParams
* The contents of the section from drupal's settings.php where it defines
* the $database array, usually under 'default'.
* @return array
* The corresponding guessed params for PEAR::DB.
*/
public static function guessSslParams(array $cmsDatabaseParams):array {
// If the pdo-mysql extension isn't loaded or they have nothing in drupal
// config for pdo, then we're done. PDO isn't required for Civi, but note
// the references to PDO constants below would fail and they obviously
// wouldn't have them in drupal config then.
if (empty($cmsDatabaseParams['pdo']) || !extension_loaded('pdo_mysql')) {
return [];
}
$pdo = $cmsDatabaseParams['pdo'];
$pdo_map = [
\PDO::MYSQL_ATTR_SSL_CA => 'ca',
\PDO::MYSQL_ATTR_SSL_KEY => 'key',
\PDO::MYSQL_ATTR_SSL_CERT => 'cert',
\PDO::MYSQL_ATTR_SSL_CAPATH => 'capath',
\PDO::MYSQL_ATTR_SSL_CIPHER => 'cipher',
];
$ssl_params = [];
// If they have one set in drupal config and it's a string, then copy
// it over verbatim.
foreach ($pdo_map as $pdo_name => $ssl_name) {
if (!empty($pdo[$pdo_name]) && is_string($pdo[$pdo_name])) {
$ssl_params[$ssl_name] = $pdo[$pdo_name];
}
}
// No client certificate or server verification, but want SSL. Return our
// made-up indicator ssl=1 that isn't a real mysqli option but which we
// recognize. It's possible they have other params set too which we pass
// along from above, but that may not be compatible but it's up to them.
if (($pdo[\PDO::MYSQL_ATTR_SSL_CA] ?? NULL) === TRUE && ($pdo[\PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] ?? NULL) === FALSE) {
$ssl_params['ssl'] = 1;
}
return $ssl_params;
}
}
......@@ -73,7 +73,7 @@ if (!defined('CIVICRM_UF')) {
* define( 'CIVICRM_UF_DSN', 'mysql://cms_db_username:cms_db_password@db_server/cms_database?new_link=true');
*/
if (!defined('CIVICRM_UF_DSN') && CIVICRM_UF !== 'UnitTests') {
define( 'CIVICRM_UF_DSN' , 'mysql://%%CMSdbUser%%:%%CMSdbPass%%@%%CMSdbHost%%/%%CMSdbName%%?new_link=true');
define( 'CIVICRM_UF_DSN' , 'mysql://%%CMSdbUser%%:%%CMSdbPass%%@%%CMSdbHost%%/%%CMSdbName%%?new_link=true%%CMSdbSSL%%');
}
// %%extraSettings%%
......
<?php
namespace Civi\Setup;
/**
* Class DrupalUtilTest
* @package Civi\Setup
* @group headless
*/
class DrupalUtilTest extends \CiviUnitTestCase {
/**
* Test guessSslParams
* @dataProvider pdoParamsProvider
* @param array $input
* @param array $expected
*/
public function testGuessSslParams(array $input, array $expected) {
$this->assertSame($expected, \Civi\Setup\DrupalUtil::guessSslParams($input));
}
/**
* Data provider for testGuessSslParams
* @return array
*/
public function pdoParamsProvider():array {
return [
'empty' => [[], []],
'empty2' => [['pdo' => []], []],
'no client certificate, no server verification' => [
[
'pdo' => [
\PDO::MYSQL_ATTR_SSL_CA => TRUE,
\PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => FALSE,
],
],
['ssl' => 1],
],
'typical client certificate with server verification' => [
[
'pdo' => [
\PDO::MYSQL_ATTR_SSL_CA => '/tmp/cacert.crt',
\PDO::MYSQL_ATTR_SSL_KEY => '/tmp/my.key',
\PDO::MYSQL_ATTR_SSL_CERT => '/tmp/cert.crt',
],
],
[
'ca' => '/tmp/cacert.crt',
'key' => '/tmp/my.key',
'cert' => '/tmp/cert.crt',
],
],
'client certificate, no server verification' => [
[
'pdo' => [
\PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => FALSE,
\PDO::MYSQL_ATTR_SSL_KEY => '/tmp/my.key',
\PDO::MYSQL_ATTR_SSL_CERT => '/tmp/cert.crt',
],
],
[
'key' => '/tmp/my.key',
'cert' => '/tmp/cert.crt',
],
],
'self-signed client certificate with server verification' => [
[
'pdo' => [
\PDO::MYSQL_ATTR_SSL_CA => '/tmp/cert.crt',
\PDO::MYSQL_ATTR_SSL_KEY => '/tmp/my.key',
\PDO::MYSQL_ATTR_SSL_CERT => '/tmp/cert.crt',
],
],
[
'ca' => '/tmp/cert.crt',
'key' => '/tmp/my.key',
'cert' => '/tmp/cert.crt',
],
],
'Not sure what would happen in practice but is all the string params' => [
[
'pdo' => [
\PDO::MYSQL_ATTR_SSL_CA => '/tmp/cacert.crt',
\PDO::MYSQL_ATTR_SSL_KEY => '/tmp/my.key',
\PDO::MYSQL_ATTR_SSL_CERT => '/tmp/cert.crt',
\PDO::MYSQL_ATTR_SSL_CAPATH => '/tmp/cacert_folder',
\PDO::MYSQL_ATTR_SSL_CIPHER => 'aes',
],
],
[
'ca' => '/tmp/cacert.crt',
'key' => '/tmp/my.key',
'cert' => '/tmp/cert.crt',
'capath' => '/tmp/cacert_folder',
'cipher' => 'aes',
],
],
'Ditto, but showing extra ones should get ignored' => [
[
'pdo' => [
\PDO::MYSQL_ATTR_SSL_CA => '/tmp/cacert.crt',
\PDO::MYSQL_ATTR_SSL_KEY => '/tmp/my.key',
\PDO::MYSQL_ATTR_SSL_CERT => '/tmp/cert.crt',
\PDO::MYSQL_ATTR_SSL_CAPATH => '/tmp/cacert_folder',
\PDO::MYSQL_ATTR_SSL_CIPHER => 'aes',
'fourteen' => 'the number fourteen',
],
],
[
'ca' => '/tmp/cacert.crt',
'key' => '/tmp/my.key',
'cert' => '/tmp/cert.crt',
'capath' => '/tmp/cacert_folder',
'cipher' => 'aes',
],
],
"some windows paths shouldn't get mangled" => [
[
'pdo' => [
\PDO::MYSQL_ATTR_SSL_CA => 'C:/Program Files/MariaDB 10.3/data/cacert.crt',
\PDO::MYSQL_ATTR_SSL_KEY => 'C:/Program Files/MariaDB 10.3/data/my.key',
\PDO::MYSQL_ATTR_SSL_CERT => 'C:\\Program Files\\MariaDB 10.3\\data\\cert.crt',
],
],
[
'ca' => 'C:/Program Files/MariaDB 10.3/data/cacert.crt',
'key' => 'C:/Program Files/MariaDB 10.3/data/my.key',
'cert' => 'C:\\Program Files\\MariaDB 10.3\\data\\cert.crt',
],
],
];
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment