Merge branch '2.3' into 2.4
This commit is contained in:
148
system-test/auth_change_user_loop.cpp
Normal file
148
system-test/auth_change_user_loop.cpp
Normal file
@ -0,0 +1,148 @@
|
||||
/**
|
||||
* @file bug601.cpp regression case for bug 601 ("COM_CHANGE_USER fails with correct user/pwd if executed
|
||||
* during authentication")
|
||||
* - configure Maxscale.cnf to use only one thread
|
||||
* - in 100 parallel threads start to open/close session
|
||||
* - do change_user 2000 times
|
||||
* - check all change_user are ok
|
||||
* - check Mascale is alive
|
||||
*/
|
||||
|
||||
/*
|
||||
* Vilho Raatikka 2014-10-30 14:30:57 UTC
|
||||
* If COM_CHANGE_USER is executed while backend protocol's state is not yet MYSQL_AUTH_RECV it will fail in
|
||||
* the backend.
|
||||
*
|
||||
* If MaxScale uses multiple worked threads this occurs rarely and it would be possible to easily suspend
|
||||
* execution of COM_CHANGE_USER.
|
||||
*
|
||||
* If MaxScale uses one worker thread then there's currently no way to suspend execution. It would require
|
||||
* thread to put current task on hold, complete authentication task and return to COM_CHANGE_USER execution.
|
||||
*
|
||||
* In theory it is possible to add an event to client's DCB and let it become notified in the same way than
|
||||
* events that occur in sockets. It would have to be added first (not last) and ensure that no other command
|
||||
* is executed before it.
|
||||
*
|
||||
* Since this is the only case known where this would be necessary, it could be enough to add a "pending auth
|
||||
* change" pointer in client's protocol object which would be checked before thread returns to epoll_wait
|
||||
* after completing the authentication.
|
||||
* Comment 1 Massimiliano 2014-11-07 17:01:29 UTC
|
||||
* Current code in develop branch let COM_CHANGE_USER work fine.
|
||||
*
|
||||
* I noticed sometime a failed authentication issue using only.
|
||||
* This because backend protocol's state is not yet MYSQL_AUTH_RECV and necessary data for succesfull backend
|
||||
* change user (such as scramble data from handshake) may be not available.
|
||||
*
|
||||
*
|
||||
* I put a query before change_user and the issue doesn't appear: that's another proof.
|
||||
* Comment 2 Vilho Raatikka 2014-11-13 15:54:15 UTC
|
||||
* In gw_change_user->gw_send_change_user_to_backend authentication message was sent to backend server before
|
||||
* backend had its scramble data. That caused authentication to fail.
|
||||
* Comment 3 Vilho Raatikka 2014-11-13 15:58:34 UTC
|
||||
* if (func.auth ==)gw_change_user->gw_send_change_user_to_backend is called before backend has its scramble,
|
||||
* auth packet is set to backend's delauqueue instead of writing it to backend. When backend_write_delayqueue
|
||||
* is called COM_CHANGE_USER packets are rewritten with backend's current data.
|
||||
*/
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <maxtest/testconnections.hh>
|
||||
|
||||
using namespace std;
|
||||
|
||||
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
|
||||
int exit_flag = 0;
|
||||
|
||||
TestConnections* Test;
|
||||
|
||||
void* parall_traffic(void* ptr);
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int iterations = 1000;
|
||||
Test = new TestConnections(argc, argv);
|
||||
if (Test->smoke)
|
||||
{
|
||||
iterations = 100;
|
||||
}
|
||||
|
||||
|
||||
pthread_t parall_traffic1[100];
|
||||
|
||||
Test->set_timeout(60);
|
||||
Test->repl->connect();
|
||||
Test->repl->execute_query_all_nodes((char*) "set global max_connect_errors=1000;");
|
||||
Test->repl->execute_query_all_nodes((char*) "set global max_connections=1000;");
|
||||
|
||||
Test->maxscales->connect_maxscale(0);
|
||||
Test->tprintf("Creating one user 'user@%%'");
|
||||
execute_query_silent(Test->maxscales->conn_rwsplit[0], (char*) "DROP USER user@'%'");
|
||||
Test->try_query(Test->maxscales->conn_rwsplit[0], (char*) "CREATE USER user@'%%' identified by 'pass2'");
|
||||
Test->try_query(Test->maxscales->conn_rwsplit[0], (char*) "GRANT SELECT ON test.* TO user@'%%';");
|
||||
Test->try_query(Test->maxscales->conn_rwsplit[0], (char*) "FLUSH PRIVILEGES;");
|
||||
|
||||
Test->tprintf("Starting parallel thread which opens/closes session in the loop");
|
||||
|
||||
for (int j = 0; j < 25; j++)
|
||||
{
|
||||
pthread_create(¶ll_traffic1[j], NULL, parall_traffic, NULL);
|
||||
}
|
||||
|
||||
Test->tprintf("Doing change_user in the loop");
|
||||
for (int i = 0; i < iterations; i++)
|
||||
{
|
||||
Test->set_timeout(15);
|
||||
Test->add_result(mysql_change_user(Test->maxscales->conn_rwsplit[0], "user", "pass2", (char*) "test"),
|
||||
"change_user failed! %s", mysql_error(Test->maxscales->conn_rwsplit[0]));
|
||||
Test->add_result(mysql_change_user(Test->maxscales->conn_rwsplit[0], Test->maxscales->user_name,
|
||||
Test->maxscales->password,
|
||||
(char*) "test"), "change_user failed! %s",
|
||||
mysql_error(Test->maxscales->conn_rwsplit[0]));
|
||||
}
|
||||
|
||||
Test->tprintf("Waiting for all threads to finish");
|
||||
exit_flag = 1;
|
||||
for (int j = 0; j < 25; j++)
|
||||
{
|
||||
Test->set_timeout(30);
|
||||
pthread_join(parall_traffic1[j], NULL);
|
||||
}
|
||||
Test->tprintf("All threads are finished");
|
||||
Test->repl->flush_hosts();
|
||||
|
||||
Test->tprintf("Change user to '%s' in order to be able to DROP user", Test->maxscales->user_name);
|
||||
Test->set_timeout(30);
|
||||
mysql_change_user(Test->maxscales->conn_rwsplit[0],
|
||||
Test->maxscales->user_name,
|
||||
Test->maxscales->password,
|
||||
NULL);
|
||||
|
||||
Test->tprintf("Dropping user", Test->maxscales->user_name);
|
||||
Test->try_query(Test->maxscales->conn_rwsplit[0], (char*) "DROP USER user@'%%';");
|
||||
|
||||
Test->maxscales->verbose = true;
|
||||
Test->check_maxscale_alive(0);
|
||||
Test->maxscales->verbose = false;
|
||||
|
||||
int rval = Test->global_result;
|
||||
delete Test;
|
||||
return rval;
|
||||
}
|
||||
|
||||
void* parall_traffic(void* ptr)
|
||||
{
|
||||
while (exit_flag == 0)
|
||||
{
|
||||
MYSQL* conn = Test->maxscales->open_rwsplit_connection(0);
|
||||
|
||||
while (exit_flag == 0 && mysql_query(conn, "DO 1") == 0)
|
||||
{
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
mysql_close(conn);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
Reference in New Issue
Block a user