Bug 36026: Use only configured TLS options for database connection

Database connections with TLS require client private keys
and certificates for authentication but MariaDB also supports
authentication by user and password.

This patch allows omitting the TLS options for certificate based
client authentication.

This is not easily testable within a development environment like ktd.
But the patch has been verified by different parties on
production and testing systems installed with Debian packages.

0) Apply patch.
1) Configure the database to support TLS connections.
2) Set "<tls>yes</tls>" in the config section in koha-conf.xml.
3) Run "koha-plack --reload <koha_instance>".
4) Open Koha's staff interface in the browser.
5) Observe an internal server error.
6) Apply patch.
7) Repeat step 3 and 4.
8) Observe the error is gone.
9) Run "prove -v t/db_dependent/Koha/Database.t"

Sponsored-by: Karlsruhe Institute of Technology (KIT)
Signed-off-by: Cornelius Amzar <cornelius.amzar@bsz-bw.de>
Signed-off-by: Markus John <markus.john@bsz-bw.de>
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Thomas Klausner <domm@plix.at>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
This commit is contained in:
Lukas Koszyk 2024-10-10 13:35:54 +00:00 committed by Katrin Fischer
parent 8e2b493d67
commit 6d884baf99
No known key found for this signature in database
GPG Key ID: 0EF6E2C03357A834
2 changed files with 107 additions and 18 deletions

View File

@ -61,13 +61,7 @@ sub dbh {
my $driver = db_scheme2dbi($config->get('db_scheme'));
my $user = $config->get("user"),
my $pass = $config->get("pass"),
my $dsn = sprintf(
'dbi:%s:database=%s;host=%s;port=%s',
$driver,
$config->get("database_test") || $config->get("database"),
$config->get("hostname"),
$config->get("port") || '',
);
my $dsn = generate_dsn($config);
my $attr = {
RaiseError => 1,
@ -75,16 +69,6 @@ sub dbh {
};
if ($driver eq 'mysql') {
my $tls = $config->get("tls");
if ($tls && $tls eq 'yes') {
$dsn .= sprintf(
';mysql_ssl=1;mysql_ssl_client_key=%s;mysql_ssl_client_cert=%s;mysql_ssl_ca_file=%s',
$config->get('key'),
$config->get('cert'),
$config->get('ca'),
);
}
$attr->{mysql_enable_utf8} = 1;
}
@ -197,6 +181,55 @@ sub db_scheme2dbi {
return $scheme eq 'Pg' ? $scheme : 'mysql';
}
=head2 generate_dsn
my $dsn = Koha::Database::generate_dsn($config);
Returns a data source name (DSN) for a database connection
from the config instance.
=cut
sub generate_dsn {
my ($config) = @_;
my $driver = db_scheme2dbi( $config->get('db_scheme') );
my $dsn = sprintf(
'dbi:%s:database=%s;host=%s;port=%s',
$driver,
$config->get("database_test") || $config->get("database"),
$config->get("hostname"),
$config->get("port") || '',
);
if ( $driver eq 'mysql' ) {
my $tls = $config->get("tls");
if ( $tls && $tls eq 'yes' ) {
$dsn .= ';mysql_ssl=1';
my $mysql_ssl_client_key = $config->get('key');
my $mysql_ssl_client_cert = $config->get('cert');
my $mysql_ssl_ca_file = $config->get('ca');
if ( $mysql_ssl_client_key && $mysql_ssl_client_key ne '__DB_TLS_CLIENT_KEY__' ) {
$dsn .= sprintf( ';mysql_ssl_client_key=%s', $mysql_ssl_client_key );
}
if ( $mysql_ssl_client_cert && $mysql_ssl_client_cert ne '__DB_TLS_CLIENT_CERTIFICATE__' ) {
$dsn .= sprintf( ';mysql_ssl_client_cert=%s', $mysql_ssl_client_cert );
}
if ( $mysql_ssl_ca_file && $mysql_ssl_ca_file ne '__DB_TLS_CA_CERTIFICATE__' ) {
$dsn .= sprintf( ';mysql_ssl_ca_file=%s', $mysql_ssl_ca_file );
}
}
}
return $dsn;
}
=head2 EXPORT
None by default.

View File

@ -16,8 +16,9 @@
# along with Koha; if not, see <http://www.gnu.org/licenses>.
use Modern::Perl;
use Test::More tests => 3;
use Test::More tests => 4;
use C4::Context;
use t::lib::Mocks;
my $dbh = C4::Context->dbh;
my $sql_mode = $dbh->selectrow_array(q|SELECT @@SQL_MODE|);
@ -33,3 +34,58 @@ subtest 'db_scheme2dbi' => sub {
is(Koha::Database::db_scheme2dbi('xxx'), 'mysql', 'ask for unsupported DBMS, get mysql');
is(Koha::Database::db_scheme2dbi(), 'mysql', 'ask for nothing, get mysql');
};
subtest 'generate_dsn' => sub {
plan tests => 6;
my $config = Koha::Config->get_instance;
t::lib::Mocks::mock_config( 'database', 'koha' );
t::lib::Mocks::mock_config( 'hostname', 'localhost' );
t::lib::Mocks::mock_config( 'port', '3306' );
t::lib::Mocks::mock_config( 'db_scheme', 'mysql' );
t::lib::Mocks::mock_config( 'tls', 'no' );
is(
Koha::Database::generate_dsn($config),
'dbi:mysql:database=koha;host=localhost;port=3306',
'DSN string for MySQL configuration without TLS.'
);
t::lib::Mocks::mock_config( 'tls', 'yes' );
is(
Koha::Database::generate_dsn($config),
'dbi:mysql:database=koha;host=localhost;port=3306;mysql_ssl=1',
'DSN string for MySQL configuration with TLS without client key, client cert and ca file.'
);
t::lib::Mocks::mock_config( 'key', '/path/to/client-key.pem' );
is(
Koha::Database::generate_dsn($config),
'dbi:mysql:database=koha;host=localhost;port=3306;mysql_ssl=1;mysql_ssl_client_key=/path/to/client-key.pem',
'DSN string for MySQL configuration with TLS and client key.'
);
t::lib::Mocks::mock_config( 'cert', '/path/to/client-cert.pem' );
is(
Koha::Database::generate_dsn($config),
'dbi:mysql:database=koha;host=localhost;port=3306;mysql_ssl=1;mysql_ssl_client_key=/path/to/client-key.pem;mysql_ssl_client_cert=/path/to/client-cert.pem',
'DSN string for MySQL configuration with TLS, client key and client cert.'
);
t::lib::Mocks::mock_config( 'ca', '/path/to/ca.pem' );
is(
Koha::Database::generate_dsn($config),
'dbi:mysql:database=koha;host=localhost;port=3306;mysql_ssl=1;mysql_ssl_client_key=/path/to/client-key.pem;mysql_ssl_client_cert=/path/to/client-cert.pem;mysql_ssl_ca_file=/path/to/ca.pem',
'DSN string for MySQL configuration with TLS with client key, client cert and ca file.'
);
t::lib::Mocks::mock_config( 'key', '__DB_TLS_CLIENT_KEY__' );
t::lib::Mocks::mock_config( 'cert', '__DB_TLS_CLIENT_CERTIFICATE__' );
is(
Koha::Database::generate_dsn($config),
'dbi:mysql:database=koha;host=localhost;port=3306;mysql_ssl=1;mysql_ssl_ca_file=/path/to/ca.pem',
'DSN string for MySQL configuration with TLS with ca file.'
);
};