From 93b9ed744fd885e8fab14991cc107aed140705f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Fri, 26 Oct 2018 15:12:54 +0300 Subject: [PATCH] MXS-2111: Use authentication_string when password is empty If the password field in mysql.user is empty, it is possible that the actual password is stored in the authentication_string field. Most of the time this happens due to MDEV-16774 which causes the password to be stored in the authentication_string field. Also added a test case that verifies the problem and that it is fixed by this commit. --- maxscale-system-test/CMakeLists.txt | 3 ++ maxscale-system-test/mxs2111_auth_string.cpp | 32 +++++++++++++++++++ .../modules/authenticator/MySQLAuth/dbusers.c | 8 +++-- 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 maxscale-system-test/mxs2111_auth_string.cpp diff --git a/maxscale-system-test/CMakeLists.txt b/maxscale-system-test/CMakeLists.txt index 0ddff7c5b..2feaa1a80 100644 --- a/maxscale-system-test/CMakeLists.txt +++ b/maxscale-system-test/CMakeLists.txt @@ -981,6 +981,9 @@ add_test_executable(mxs2043_select_for_update.cpp mxs2043_select_for_update repl # MXS-2054: Hybrid clusters add_test_executable(mxs2054_hybrid_cluster.cpp mxs2054_hybrid_cluster mxs2054_hybrid_cluster LABELS REPL_BACKEND) +# MXS-2111: mysql.user sometimes has SHA1 in authentication_string instead of password +add_test_executable(mxs2111_auth_string.cpp mxs2111_auth_string replication LABELS REPL_BACKEND) + # MXS-2115: Automatic version_string detection add_test_executable(mxs2115_version_string.cpp mxs2115_version_string replication LABELS REPL_BACKEND) diff --git a/maxscale-system-test/mxs2111_auth_string.cpp b/maxscale-system-test/mxs2111_auth_string.cpp new file mode 100644 index 000000000..50d008ee8 --- /dev/null +++ b/maxscale-system-test/mxs2111_auth_string.cpp @@ -0,0 +1,32 @@ +/** + * MXS-2111: The password is stored in `authentication_string` instead of `password` due to MDEV-16774 + */ + +#include "testconnections.h" + +int main(int argc, char **argv) +{ + TestConnections::require_repl_version("10.2.0"); + TestConnections test(argc, argv); + + auto batch = [&](std::vector queries){ + test.maxscales->connect(); + for (const auto& a: queries) + { + test.try_query(test.maxscales->conn_rwsplit[0], "%s", a.c_str()); + } + test.maxscales->disconnect(); + }; + + batch({"CREATE USER 'test' IDENTIFIED BY 'test'", + "GRANT SELECT ON *.* TO test", + "SET PASSWORD FOR 'test' = PASSWORD('test')"}); + + MYSQL* conn = open_conn(test.maxscales->rwsplit_port[0], test.maxscales->IP[0], "test", "test"); + test.try_query(conn, "SELECT 1"); + mysql_close(conn); + + batch({"DROP USER 'test'"}); + + return test.global_result; +} diff --git a/server/modules/authenticator/MySQLAuth/dbusers.c b/server/modules/authenticator/MySQLAuth/dbusers.c index 9e601b49f..0dc0c1ed2 100644 --- a/server/modules/authenticator/MySQLAuth/dbusers.c +++ b/server/modules/authenticator/MySQLAuth/dbusers.c @@ -56,11 +56,15 @@ const char* mariadb_102_users_query = // `t` is users that are not roles "WITH RECURSIVE t AS ( " - " SELECT u.user, u.host, d.db, u.select_priv, u.password AS password, u.is_role, u.default_role" + " SELECT u.user, u.host, d.db, u.select_priv, " + " IF(u.password <> '', u.password, u.authentication_string) AS password, " + " u.is_role, u.default_role" " FROM mysql.user AS u LEFT JOIN mysql.db AS d " " ON (u.user = d.user AND u.host = d.host) " " UNION " - " SELECT u.user, u.host, t.db, u.select_priv, u.password AS password, u.is_role, u.default_role " + " SELECT u.user, u.host, t.db, u.select_priv, " + " IF(u.password <> '', u.password, u.authentication_string), " + " u.is_role, u.default_role " " FROM mysql.user AS u LEFT JOIN mysql.tables_priv AS t " " ON (u.user = t.user AND u.host = t.host)" "), users AS ("