From 5bbe2ea73ed7bd928fb515708c65290774379e65 Mon Sep 17 00:00:00 2001 From: Jaap Eldering Date: Sun, 25 Aug 2024 15:44:23 +0200 Subject: [PATCH 1/4] URL encode variables that go into a MySQL credentials URI See for reference: - https://dev.mysql.com/doc/refman/8.0/en/connecting-using-uri-or-key-value-pairs.html#connecting-using-uri - https://symfony.com/doc/current/doctrine.html but note that we must use `rawurlencode` instead of `urlencode` which differ in how they encode a space (as tested). Fixes: #2651 Closes: #2502 as this is likely fixed but I couldn't reproduce it --- webapp/config/load_db_secrets.php | 6 +++++- webapp/config/packages/doctrine.yaml | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/webapp/config/load_db_secrets.php b/webapp/config/load_db_secrets.php index ea4ca11b83..c3a8b3dfb5 100644 --- a/webapp/config/load_db_secrets.php +++ b/webapp/config/load_db_secrets.php @@ -36,7 +36,11 @@ function get_db_url(): string break; } - return sprintf('mysql://%s:%s@%s:%d/%s?serverVersion=5.7.0', $user, $pass, $host, $port ?? 3306, $db); + return sprintf( + 'mysql://%s:%s@%s:%d/%s?serverVersion=5.7.0', + rawurlencode($user), rawurlencode($pass), rawurlencode($host), + $port ?? 3306, rawurlencode($db) + ); } function get_app_secret(): string diff --git a/webapp/config/packages/doctrine.yaml b/webapp/config/packages/doctrine.yaml index d04de47c52..d4ba6543f6 100644 --- a/webapp/config/packages/doctrine.yaml +++ b/webapp/config/packages/doctrine.yaml @@ -7,7 +7,7 @@ doctrine: charset: utf8mb4 collate: utf8mb4_unicode_ci - url: '%env(resolve:DATABASE_URL)%' + url: '%env(DATABASE_URL)%' profiling_collect_backtrace: '%kernel.debug%' types: tinyint: App\Doctrine\DBAL\Types\TinyIntType From e5fd474bf1a2132646789fe8f381f667952604f5 Mon Sep 17 00:00:00 2001 From: Jaap Eldering Date: Sun, 25 Aug 2024 17:41:09 +0200 Subject: [PATCH 2/4] Add command to update DB user password to current from file There was no easy way to do this, besides also completely dropping and recreating an empty database. --- sql/dj_setup_database.in | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sql/dj_setup_database.in b/sql/dj_setup_database.in index 03742fc161..eb829417d1 100755 --- a/sql/dj_setup_database.in +++ b/sql/dj_setup_database.in @@ -29,6 +29,7 @@ Commands: status check database installation status genpass generate DB,API,Symfony,admin password files create-db-users create (empty) database and users + update-password update DB user database to that in 'etc/dbpasswords.secret' install create database, example contest and users if not existing bare-install create database, setup defaults if not existing uninstall remove database users and database, INCLUDING ALL DATA! @@ -235,6 +236,17 @@ remove_db_users() verbose "DOMjudge database and user(s) removed." } +update_password() +{ + read_dbpasswords + ( + echo "ALTER USER '$domjudge_DBUSER'@'localhost' IDENTIFIED BY '$domjudge_PASSWD';" + echo "FLUSH PRIVILEGES;" + ) | mysql + verbose "ALTER USER '$domjudge_DBUSER'@'localhost' IDENTIFIED BY '$domjudge_PASSWD';" + verbose "Database user password updated from credentials file." +} + install_examples() { DBUSER=$domjudge_DBUSER PASSWD=$domjudge_PASSWD symfony_console domjudge:load-example-data @@ -337,6 +349,10 @@ create-db-users) create_db_users_helper ;; +update-password) + update_password + ;; + bare-install|install) read_dbpasswords create_db_users From e371261c2b31e3fe71710ca9ef22891e9c8e3134 Mon Sep 17 00:00:00 2001 From: Jaap Eldering Date: Sun, 25 Aug 2024 17:46:21 +0200 Subject: [PATCH 3/4] Fixes for supporting passwords with weird characters Use URL encoding in DATABASE_URL and return mysql_options as an array (via ugly global variable), so each element in it can be separately added to the command line using `@` for expansion. --- sql/dj_setup_database.in | 44 ++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/sql/dj_setup_database.in b/sql/dj_setup_database.in index eb829417d1..7f719e802f 100755 --- a/sql/dj_setup_database.in +++ b/sql/dj_setup_database.in @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # @configure_input@ # This script allows one to perform DOMjudge database setup actions. @@ -52,32 +52,47 @@ not have to pass any of the options above. EOF } +urlencode() +{ + php -r "echo rawurlencode('$1');" +} + +# This is global variable to be able to return the output from +# mysql_options() below as an array, which is not possible otherwise. +declare -a _mysql_options + mysql_options() { local user pass + _mysql_options=() # shellcheck disable=SC2153 if [ -n "$DBUSER" ]; then - user="-u $DBUSER" - else - user="${DBA_USER:+-u ${DBA_USER}}" + _mysql_options+=('-u' "$DBUSER") + elif [ -n "$DBA_USER" ]; then + _mysql_options+=('-u' "$DBA_USER") fi # shellcheck disable=SC2153 if [ -n "$PASSWD" ]; then - pass="-p$PASSWD" - else - [ -n "$PROMPT_PASSWD" ] && pass="-p" - [ -n "$DBA_PASSWD" ] && pass="-p$DBA_PASSWD" + _mysql_options+=("-p$PASSWD") + elif [ -n "$DBA_PASSWD" ]; then + _mysql_options+=("-p$DBA_PASSWD") + elif [ -n "$PROMPT_PASSWD" ]; then + _mysql_options+=('-p') fi - [ -z "$USE_SOCKET" ] && port="-P$DBPORT" - echo $user ${pass:+"$pass"} -h "$DBHOST" ${port:+"$port"} + _mysql_options+=('-h' "$DBHOST") + + if [ -z "$USE_SOCKET" ]; then + _mysql_options+=("-P$DBPORT") + fi } # Wrapper around mysql command to allow setting options, user, etc. mysql() { - command mysql $(mysql_options) --silent --skip-column-names "$@" + mysql_options + command mysql "${_mysql_options[@]}" --silent --skip-column-names "$@" } # Quick shell hack to get a key from an INI file. @@ -128,10 +143,13 @@ symfony_console() fi if [ -n "$DBA_USER" ]; then + user=$(urlencode "${DBA_USER}") + host=$(urlencode "${domjudge_DBHOST}") + db=$(urlencode "${domjudge_DBNAME}") if [ -n "$DBA_PASSWD" ]; then - DATABASE_URL=mysql://${DBA_USER}:${DBA_PASSWD}@${domjudge_DBHOST}:${domjudge_DBPORT}/${domjudge_DBNAME} + DATABASE_URL="mysql://$user:$(urlencode "${DBA_PASSWD}")@$host:${domjudge_DBPORT}/$db" else - DATABASE_URL=mysql://${DBA_USER}@${domjudge_DBHOST}:${domjudge_DBPORT}/${domjudge_DBNAME} + DATABASE_URL="mysql://$user@$host:${domjudge_DBPORT}/$db" fi fi fi From 8cecda38d230bb9d41ec38c95036ad50f8d00abb Mon Sep 17 00:00:00 2001 From: Jaap Eldering Date: Sun, 25 Aug 2024 22:09:37 +0200 Subject: [PATCH 4/4] Test plenty of weird characters in CI job MySQL password --- gitlab/base.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitlab/base.sh b/gitlab/base.sh index a07f026d5b..9317ce825b 100755 --- a/gitlab/base.sh +++ b/gitlab/base.sh @@ -33,7 +33,7 @@ fi # Generate a dbpasswords file # Note that this does not use ${DATABASE_NAME} since Symfony adds the _test postfix itself -echo "unused:sqlserver:domjudge:domjudge:domjudge:3306" > etc/dbpasswords.secret +echo 'unused:sqlserver:domjudge:domjudge:domjudge_+% #$*)@(!/;,.:3306' > etc/dbpasswords.secret # Generate APP_SECRET for symfony # shellcheck disable=SC2164