From 2079bba49c15aa88e2d65b400f693db9b76cbe1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Mon, 25 Sep 2017 14:47:12 +0300 Subject: [PATCH] MXS-1451: Calculate password even with skip_authentication=true The result of the authentication should be ignored but the scramble that is calculated as a side-effect still needs to be stored. This can be done by altering the SQL used to get the matching row to only match on the username, not the network address. Also expanded the test case to cover the use of bad credentials. --- maxscale-system-test/mxs1451_skip_auth.cpp | 5 +++++ server/modules/authenticator/MySQLAuth/dbusers.c | 14 +++++++++++--- .../modules/authenticator/MySQLAuth/mysql_auth.c | 9 ++++----- .../modules/authenticator/MySQLAuth/mysql_auth.h | 12 +++++++++--- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/maxscale-system-test/mxs1451_skip_auth.cpp b/maxscale-system-test/mxs1451_skip_auth.cpp index 55e16dbc0..3a44fa908 100644 --- a/maxscale-system-test/mxs1451_skip_auth.cpp +++ b/maxscale-system-test/mxs1451_skip_auth.cpp @@ -24,6 +24,11 @@ int main(int argc, char *argv[]) test.try_query(conn, "SHOW DATABASES"); mysql_close(conn); + test.tprintf("Trying query with bad credentials"); + conn = open_conn_db(test.rwsplit_port, test.maxscale_ip(), "test", "wrong_user", "wrong_password", false); + test.add_result(execute_query_silent(conn, "SHOW DATABASES") == 0, "Connection with bad credentials should fail"); + mysql_close(conn); + test.set_timeout(60); test.tprintf("Dropping user"); test.repl->connect(); diff --git a/server/modules/authenticator/MySQLAuth/dbusers.c b/server/modules/authenticator/MySQLAuth/dbusers.c index ef72e31fc..a2acf87b2 100644 --- a/server/modules/authenticator/MySQLAuth/dbusers.c +++ b/server/modules/authenticator/MySQLAuth/dbusers.c @@ -182,17 +182,25 @@ static int auth_cb(void *data, int columns, char** rows, char** row_names) return 0; } -int validate_mysql_user(sqlite3 *handle, DCB *dcb, MYSQL_session *session, +int validate_mysql_user(MYSQL_AUTH* instance, DCB *dcb, MYSQL_session *session, uint8_t *scramble, size_t scramble_len) { + sqlite3 *handle = instance->handle; size_t len = sizeof(mysqlauth_validate_user_query) + strlen(session->user) * 2 + strlen(session->db) * 2 + MYSQL_HOST_MAXLEN + session->auth_token_len * 4 + 1; char sql[len + 1]; int rval = MXS_AUTH_FAILED; char *err; - sprintf(sql, mysqlauth_validate_user_query, session->user, dcb->remote, - dcb->remote, session->db, session->db); + if (instance->skip_auth) + { + sprintf(sql, mysqlauth_skip_auth_query, session->user, session->db, session->db); + } + else + { + sprintf(sql, mysqlauth_validate_user_query, session->user, dcb->remote, + dcb->remote, session->db, session->db); + } struct user_query_result res = {}; diff --git a/server/modules/authenticator/MySQLAuth/mysql_auth.c b/server/modules/authenticator/MySQLAuth/mysql_auth.c index e9339c823..1da67f120 100644 --- a/server/modules/authenticator/MySQLAuth/mysql_auth.c +++ b/server/modules/authenticator/MySQLAuth/mysql_auth.c @@ -329,19 +329,18 @@ mysql_auth_authenticate(DCB *dcb) MYSQL_AUTH *instance = (MYSQL_AUTH*)dcb->listener->auth_instance; - auth_ret = validate_mysql_user(instance->handle, dcb, client_data, + auth_ret = validate_mysql_user(instance, dcb, client_data, protocol->scramble, sizeof(protocol->scramble)); if (auth_ret != MXS_AUTH_SUCCEEDED && - !instance->skip_auth && service_refresh_users(dcb->service) == 0) { - auth_ret = validate_mysql_user(instance->handle, dcb, client_data, + auth_ret = validate_mysql_user(instance, dcb, client_data, protocol->scramble, sizeof(protocol->scramble)); } /* on successful authentication, set user into dcb field */ - if (auth_ret == MXS_AUTH_SUCCEEDED || instance->skip_auth) + if (auth_ret == MXS_AUTH_SUCCEEDED) { auth_ret = MXS_AUTH_SUCCEEDED; dcb->user = MXS_STRDUP_A(client_data->user); @@ -667,7 +666,7 @@ int mysql_auth_reauthenticate(DCB *dcb, const char *user, temp.auth_token_len = token_len; MYSQL_AUTH *instance = (MYSQL_AUTH*)dcb->listener->auth_instance; - int rc = validate_mysql_user(instance->handle, dcb, &temp, scramble, scramble_len); + int rc = validate_mysql_user(instance, dcb, &temp, scramble, scramble_len); if (rc == MXS_AUTH_SUCCEEDED) { diff --git a/server/modules/authenticator/MySQLAuth/mysql_auth.h b/server/modules/authenticator/MySQLAuth/mysql_auth.h index ec10c5401..07f66a1e5 100644 --- a/server/modules/authenticator/MySQLAuth/mysql_auth.h +++ b/server/modules/authenticator/MySQLAuth/mysql_auth.h @@ -66,6 +66,12 @@ static const char mysqlauth_validate_user_query[] = " WHERE user = '%s' AND ( '%s' = host OR '%s' LIKE host) AND (anydb = '1' OR '%s' = '' OR '%s' LIKE db)" " LIMIT 1"; +/** Query that only checks if there's a matching user */ +static const char mysqlauth_skip_auth_query[] = + "SELECT password FROM " MYSQLAUTH_USERS_TABLE_NAME + " WHERE user = '%s' AND (anydb = '1' OR '%s' = '' OR '%s' LIKE db)" + " LIMIT 1"; + /** Query that checks that the database exists */ static const char mysqlauth_validate_database_query[] = "SELECT * FROM " MYSQLAUTH_DATABASES_TABLE_NAME " WHERE db = '%s' LIMIT 1"; @@ -181,7 +187,7 @@ int replace_mysql_users(SERV_LISTENER *listener, bool skip_local); /** * @brief Verify the user has access to the database * - * @param handle SQLite handle to MySQLAuth user database + * @param instance MySQLAuth instance * @param dcb Client DCB * @param session Shared MySQL session * @param scramble The scramble sent to the client in the initial handshake @@ -189,7 +195,7 @@ int replace_mysql_users(SERV_LISTENER *listener, bool skip_local); * * @return MXS_AUTH_SUCCEEDED if the user has access to the database */ -int validate_mysql_user(sqlite3 *handle, DCB *dcb, MYSQL_session *session, - uint8_t *scramble, size_t scramble_len); +int validate_mysql_user(MYSQL_AUTH* instance, DCB *dcb, MYSQL_session *session, + uint8_t *scramble, size_t scramble_len); MXS_END_DECLS