Extract auth testing utils from 'test_auth_methods-t.cpp'

pull/4941/head
Javier Jaramago Fernández 1 year ago
parent 128fa60003
commit ea8211618e

@ -0,0 +1,603 @@
#ifndef UTILS_AUTH_H
#define UTILS_AUTH_H
#include <utility>
#include <vector>
#include "proxysql_utils.h"
#include "mysql.h"
#include "utils.h"
#include "tap.h"
using std::pair;
using std::string;
using std::vector;
#define MYSQL_QUERY_T__(mysql, query) \
do { \
if (mysql_query_t(mysql, query)) { \
fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(mysql)); \
return { EXIT_FAILURE, vector<user_creds_t> {} }; \
} \
} while(0)
#define MYSQL_QUERY_T_(mysql, query) \
do { \
if (mysql_query_t(mysql, query)) { \
fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(mysql)); \
return { EXIT_FAILURE, user_def_t {} }; \
} \
} while(0)
mf_unique_ptr<char> MF_CHAR_(const char* s) {
return mf_unique_ptr<char> { s ? strdup(s) : nullptr };
}
struct user_def_t {
string name {};
mf_unique_ptr<char> prim_pass { nullptr };
mf_unique_ptr<char> addl_pass { nullptr };
string auth {};
string def_db {};
uint32_t def_hg { 0 };
bool rand_pass {};
user_def_t() {}
user_def_t(const string& name_) : name(name_) {}
user_def_t(
const string& name_,
mf_unique_ptr<char> prim_pass_,
mf_unique_ptr<char> addl_pass_,
const string& auth_,
const uint32_t def_hg_ = 0,
const string def_db_ = {},
bool rand_pass_ = false
) :
name(name_),
prim_pass(std::move(prim_pass_)),
addl_pass(std::move(addl_pass_)),
auth(auth_),
def_hg(def_hg_),
def_db(def_db_),
rand_pass(rand_pass_)
{}
user_def_t(const user_def_t& other) :
name(other.name),
auth(other.auth),
rand_pass(other.rand_pass),
def_hg(other.def_hg),
def_db(other.def_db)
{
if (other.prim_pass) {
this->prim_pass = mf_unique_ptr<char>(strdup(other.prim_pass.get()));
} else {
this->prim_pass = nullptr;
}
if (other.addl_pass) {
this->addl_pass = mf_unique_ptr<char>(strdup(other.addl_pass.get()));
} else {
this->addl_pass = nullptr;
}
}
void operator=(const user_def_t& other) {
this->name = other.name;
this->auth = other.auth;
this->rand_pass = other.rand_pass;
this->def_hg = other.def_hg;
this->def_db = other.def_db;
if (other.prim_pass) {
this->prim_pass = mf_unique_ptr<char>(strdup(other.prim_pass.get()));
} else {
this->prim_pass = nullptr;
}
if (other.addl_pass) {
this->addl_pass = mf_unique_ptr<char>(strdup(other.addl_pass.get()));
} else {
this->addl_pass = nullptr;
}
}
user_def_t(user_def_t&& other) :
name(other.name),
auth(other.auth),
rand_pass(other.rand_pass),
prim_pass(std::move(other.prim_pass)),
addl_pass(std::move(other.addl_pass)),
def_hg(other.def_hg),
def_db(other.def_db)
{}
void operator=(user_def_t&& other) {
this->name = other.name;
this->auth = other.auth;
this->rand_pass = other.rand_pass;
this->prim_pass = std::move(other.prim_pass);
this->addl_pass = std::move(other.addl_pass);
this->def_hg = other.def_hg;
this->def_db = other.def_db;
}
};
struct user_creds_t {
user_def_t user_def;
mf_unique_ptr<char> hashed_prim_pass_bin { nullptr };
mf_unique_ptr<char> hashed_addl_pass_bin { nullptr };
user_creds_t(const user_creds_t&) = delete;
user_creds_t(user_creds_t&&) noexcept(false) = default;
void operator=(user_creds_t&& other) {
this->user_def = std::move(other.user_def);
this->hashed_prim_pass_bin = std::move(other.hashed_prim_pass_bin);
this->hashed_addl_pass_bin = std::move(other.hashed_addl_pass_bin);
}
};
bool is_empty_pass(const char* pass) {
return pass == nullptr || (pass && strlen(pass) == 0);
}
std::string unhex(const std::string& hex) {
if (hex.size() % 2) { return {}; };
string result {};
for (size_t i = 0; i < hex.size() - 1; i += 2) {
string hex_char { string { hex[i] } + hex[i+1] };
uint64_t char_val { 0 };
std::istringstream stream { hex_char };
stream >> std::hex >> char_val;
result += string { static_cast<char>(char_val) };
}
return result;
}
std::string hex(const std::string& str) {
std::ostringstream hex_stream;
for (unsigned char c : str) {
hex_stream << std::hex << std::setfill('0') << std::setw(2) <<
std::uppercase << static_cast<uint64_t>(c);
}
return hex_stream.str();
}
/**
* @brief TODO: Limitation ProxySQL doesn't allow a clear-text pass to start with '*'. See #1762.
* @param pass Password to check.
* @return 'true' if password is an invalid clear-text pass for ProxySQL.
*/
bool chk_inv_pass(const char* pass) {
if (is_empty_pass(pass)) {
return true;
} else {
if (strlen(pass)) {
return pass[0] == '*';
} else {
return false;
}
}
}
pair<int,user_def_t> create_mysql_user_exp_creds(MYSQL* mysql, const user_def_t& user_def) {
const char* addl_pass { user_def.addl_pass.get() };
const char* prim_pass { user_def.prim_pass.get() };
if (addl_pass && strlen(addl_pass)) {
const string CREATE_USER {
"CREATE USER '" + user_def.name + "'@'%' IDENTIFIED WITH"
" '" + user_def.auth + "' BY '" + user_def.addl_pass.get() + "'"
};
const string GRANT_USER_PRIVS { "GRANT ALL on *.* to '" + user_def.name + "'@'%'" };
MYSQL_QUERY_T_(mysql, CREATE_USER.c_str());
MYSQL_QUERY_T_(mysql, GRANT_USER_PRIVS.c_str());
if (prim_pass && strlen(prim_pass)) {
const string ALTER_USER_RETAIN {
"ALTER USER '" + user_def.name + "'@'%' IDENTIFIED BY '" + prim_pass + "'"
" RETAIN CURRENT PASSWORD"
};
MYSQL_QUERY_T_(mysql, ALTER_USER_RETAIN.c_str());
} else {
const string ALTER_USER_NO_RETAIN {
"ALTER USER '" + user_def.name + "'@'%' IDENTIFIED BY ''"
};
// When new password is empty; retaining the previous one isn't possible
MYSQL_QUERY_T_(mysql, ALTER_USER_NO_RETAIN.c_str());
}
} else {
string CREATE_USER { "CREATE USER '" + user_def.name + "'@'%'" };
string GRANT_USER_PRIVS { "GRANT ALL on *.* to '" + user_def.name + "'@'%'" };
if (prim_pass) {
CREATE_USER += " IDENTIFIED WITH '" + user_def.auth + "' BY '" + prim_pass + "'";
}
MYSQL_QUERY_T_(mysql, CREATE_USER.c_str());
MYSQL_QUERY_T_(mysql, GRANT_USER_PRIVS.c_str());
}
// If user has a 'default_schema' create the target schema and grant perms
if (!user_def.def_db.empty()) {
const string& u_db { user_def.def_db };
const string& u_name { user_def.name };
MYSQL_QUERY_T_(mysql, ("CREATE DATABASE IF NOT EXISTS " + u_db).c_str());
MYSQL_QUERY_T_(mysql, ("GRANT ALL ON " + u_db + ".* TO '" + u_name + "'@'%'").c_str());
}
return { EXIT_SUCCESS, user_def };
}
pair<int,user_def_t> create_mysql_user_rnd_creds(MYSQL* mysql, const user_def_t& user_def) {
const string CREATE_USER {
"CREATE USER '" + user_def.name + "'@'%' IDENTIFIED WITH"
" '" + user_def.auth + "' BY RANDOM PASSWORD"
};
const string DROP_USER { "DROP USER IF EXISTS '" + user_def.name + "'"};
mf_unique_ptr<char> addl_text_pass { nullptr };
{
// NOTE: Required due to potential pass recreation
MYSQL_QUERY_T_(mysql, DROP_USER.c_str());
MYSQL_QUERY_T_(mysql, CREATE_USER.c_str());
MYSQL_RES* myres = mysql_store_result(mysql);
MYSQL_ROW myrow = mysql_fetch_row(myres);
if (myrow && myrow[2]) {
addl_text_pass = mf_unique_ptr<char>(strdup(myrow[2]));
}
mysql_free_result(myres);
}
const string ALTER_USER {
"ALTER USER '" + user_def.name + "'@'%' IDENTIFIED WITH"
" '" + user_def.auth + "' BY RANDOM PASSWORD RETAIN CURRENT PASSWORD"
};
mf_unique_ptr<char> prim_text_pass {};
{
MYSQL_QUERY_T_(mysql, ALTER_USER.c_str());
MYSQL_RES* myres = mysql_store_result(mysql);
MYSQL_ROW myrow = mysql_fetch_row(myres);
if (myrow && myrow[2]) {
prim_text_pass = mf_unique_ptr<char>(strdup(myrow[2]));
}
mysql_free_result(myres);
}
return {
EXIT_SUCCESS,
user_def_t {
user_def.name,
std::move(prim_text_pass),
std::move(addl_text_pass),
user_def.auth,
user_def.def_hg,
user_def.def_db,
user_def.rand_pass
}
};
}
pair<int,user_def_t> create_mysql_user(MYSQL* mysql, const user_def_t& user_def) {
if (user_def.rand_pass) {
pair<int,user_def_t> rnd_user_def {};
while (
rnd_user_def.first == EXIT_SUCCESS &&
(chk_inv_pass(rnd_user_def.second.prim_pass.get())
|| chk_inv_pass(rnd_user_def.second.addl_pass.get()))
) {
rnd_user_def = create_mysql_user_rnd_creds(mysql, user_def);
}
return rnd_user_def;
} else {
return create_mysql_user_exp_creds(mysql, user_def);
}
}
/**
* @brief Extract the auth strings (prim/addl) pass from an existing user.
* @param mysql Opened MySQL conn in which to perform the queries.
* @param user_def User definition; used to match by username.
* @return A pair of kind `{err_code, user_creds}`.
*/
pair<int,user_creds_t> ext_user_auth_strs(MYSQL* mysql, const user_def_t& user_def) {
const char* addl_pass { user_def.addl_pass.get() };
const char* prim_pass { user_def.prim_pass.get() };
pair<int,user_creds_t> p_creds_res { EXIT_SUCCESS, user_creds_t {} };
const string ext_auths_query {
"SELECT HEX(authentication_string),json_value(user_attributes, '$.additional_password') "
"FROM mysql.user WHERE user='" + user_def.name + "'"
};
if (mysql_query_t(mysql, ext_auths_query.c_str())) {
fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(mysql));
return { EXIT_FAILURE, user_creds_t {} };
}
MYSQL_RES* myres = mysql_store_result(mysql);
MYSQL_ROW myrow = mysql_fetch_row(myres);
if (myrow && myrow[0]) {
const char* p_addl_pass { myrow[1] };
if (p_addl_pass) {
p_creds_res = {
EXIT_SUCCESS,
user_creds_t {
user_def,
mf_unique_ptr<char> { strdup(myrow[0]) },
mf_unique_ptr<char> { strdup(p_addl_pass) }
}
};
} else {
// MySQL wont allow that 'aditional' pass for a backend user; we don't verify user attributes
// right now when loading to runtime; but we wont allow user to connect with empty
// 'additional' passwords either;
if (addl_pass && strlen(addl_pass) == 0) {
p_creds_res = {
EXIT_SUCCESS,
user_creds_t {
user_def,
mf_unique_ptr<char> { strdup(myrow[0]) },
mf_unique_ptr<char> { strdup("") },
}
};
} else {
p_creds_res = {
EXIT_SUCCESS,
user_creds_t {
user_def,
mf_unique_ptr<char> { strdup(myrow[0]) },
mf_unique_ptr<char> { nullptr },
}
};
}
}
} else {
diag("Empty result; no auth_string found for user user:'%s'", user_def.name.c_str());
}
mysql_free_result(myres);
return p_creds_res;
}
pair<int,user_creds_t> create_backend_user(MYSQL* mysql, const user_def_t& user_def) {
const pair<int,user_def_t> c_user_def { create_mysql_user(mysql, user_def) };
if (c_user_def.first == EXIT_SUCCESS) {
pair<int,user_creds_t> p_creds_res { ext_user_auth_strs(mysql, c_user_def.second) };
return p_creds_res;
} else {
return { EXIT_FAILURE, user_creds_t {} };
}
}
/**
* @brief Configure the backend MySQL 8 users for frontend-backend connection creation.
* @param mysql Already opened MySQL connection.
* @param backend_users The users to be created in the MySQL server.
* @return A pair of kind `{err_code, user_creds}`.
*/
pair<int,vector<user_creds_t>> config_mysql_backend_users(
MYSQL* mysql, const vector<user_def_t>& users_defs
) {
for (const auto& u : users_defs) {
MYSQL_QUERY_T__(mysql, ("DROP USER IF EXISTS '" + u.name + "'").c_str());
}
vector<user_creds_t> f_users_creds {};
for (const auto& user_def : users_defs) {
pair<int,user_creds_t> creds_res { create_backend_user(mysql, user_def) };
if (creds_res.first == EXIT_SUCCESS) {
f_users_creds.push_back(std::move(creds_res.second));
} else {
return { EXIT_FAILURE, vector<user_creds_t> {} };
}
}
return { EXIT_SUCCESS, std::move(f_users_creds) };
}
struct test_conf_t {
/* @brief Default auth method announced by ProxySQL */
string def_auth;
/* @brief Auth method requested by client */
string req_auth;
/* @brief Wether to use hashed or 'clear_text' passwords. Implies a reload of 'mysql_users'. */
bool hashed_pass;
/* @brief Wether to attempt auth under SSL conn or not. */
bool use_ssl;
/* @brief Wether to attempt auth with compression enabled or not. */
bool use_comp;
};
string to_string(const test_conf_t& conf) {
return "{ "
"\"req_auth\":'" + conf.req_auth + "', "
"\"def_auth\":'" + conf.def_auth + "', "
"\"hashed_pass\":'" + std::to_string(conf.hashed_pass) + "', "
"\"use_ssl\":'" + std::to_string(conf.use_ssl) + "'"
" }";
}
/**
* @brief Gen all combinations of tests configs.
* @param def_auths Defaults auths to set for ProxySQL.
* @param req_auths Auth methods for client to request.
* @param hash_pass If passwords should be hashed or not.
* @param use_ssl If connection is started with SSL or not.
* @return Vector with the combinations.
*/
vector<test_conf_t> get_auth_conf_combs(
const vector<string>& def_auths,
const vector<string>& req_auths,
const vector<bool>& hash_pass,
const vector<bool>& use_ssl,
const vector<bool>& use_comp
) {
vector<test_conf_t> confs {};
for (const auto& def_auth : def_auths) {
for (const auto& req_auth : req_auths) {
for (const auto& hashed : hash_pass) {
for (const auto& ssl : use_ssl) {
for (const auto& comp : use_comp) {
confs.push_back({def_auth, req_auth, hashed, ssl, comp});
}
}
}
}
}
return confs;
}
struct PASS_TYPE {
enum E {
UNKNOWN = 0,
PRIMARY,
ADDITIONAL,
};
};
string to_string(const PASS_TYPE::E type) {
if (type == PASS_TYPE::PRIMARY) {
return "PRIM";
} else if (type == PASS_TYPE::ADDITIONAL) {
return "ADDL";
} else {
return "UNKN";
}
}
/**
* @brief Info from user defs (user_def_t), extracted for building 'test_creds_t'.
*/
struct creds_info_t {
PASS_TYPE::E type;
string auth;
};
/**
* @brief Info about user creds used in a particular test case.
* @details Multiple 'test_creds_t' are used while testing a single 'test_conf_t'.
*/
struct test_creds_t {
string name {};
mf_unique_ptr<char> pass { nullptr };
creds_info_t info {};
test_creds_t(const string& name_, mf_unique_ptr<char> pass_) : name(name_), pass(std::move(pass_)) {}
test_creds_t(const string& name_, mf_unique_ptr<char> pass_, const creds_info_t& info_) :
name(name_), pass(std::move(pass_)), info(info_) {}
test_creds_t(const test_creds_t& other) : name(other.name), info(other.info) {
this->pass = other.pass ? MF_CHAR_(other.pass.get()) : nullptr;
}
};
string to_string(const test_creds_t& creds) {
return "{ "
"\"name\":'" + creds.name + "', "
"\"pass\":'" + (creds.pass ? creds.pass.get() : "NULL") + "', "
"\"type\":'" + to_string(creds.info.type) + "'"
" }";
}
int config_proxysql_users(MYSQL* admin, const test_conf_t& test_conf, const vector<user_creds_t>& users) {
for (const auto& u : users) {
MYSQL_QUERY_T(admin, ("DELETE FROM mysql_users WHERE username='" + u.user_def.name + "'").c_str());
}
// Ensure cleanup of previously cached clear_text 'caching_sha2' passwords
MYSQL_QUERY_T(admin, "LOAD MYSQL USERS TO RUNTIME");
MYSQL_QUERY_T(admin, "LOAD MYSQL USERS TO RUNTIME");
for (const auto& u : users) {
const string def_hg { _TO_S(u.user_def.def_hg) };
string attrs {};
// A user may not have an additional_password configured
if (u.user_def.addl_pass) {
string addl_pass {};
// NOTE: If the primary pass is empty, addl pass must be empty **by spec**
if (is_empty_pass(u.user_def.prim_pass.get())) {
addl_pass = {};
} else if (test_conf.hashed_pass) {
const char* c_addl_pass { u.hashed_addl_pass_bin.get() };
if (c_addl_pass) {
addl_pass = c_addl_pass;
}
} else {
addl_pass = u.user_def.addl_pass.get();
}
const string hex_addl_pass { hex(addl_pass) };
attrs = "{\"additional_password\": \"" + hex_addl_pass + "\"}";
}
string insert_query {};
if (u.user_def.prim_pass) {
const string prim_pass {
test_conf.hashed_pass && strlen(u.hashed_prim_pass_bin.get()) > 0 ?
"UNHEX('" + string { u.hashed_prim_pass_bin.get() } + "')" :
"'" + string { u.user_def.prim_pass.get() } + "'"
};
if (u.user_def.addl_pass) {
insert_query = {
"INSERT INTO mysql_users (username,password,default_hostgroup,attributes) "
"VALUES ('" + u.user_def.name + "'," + prim_pass + "," + def_hg + ",'" + attrs + "')"
};
} else {
insert_query = {
"INSERT INTO mysql_users (username,password,default_hostgroup) "
"VALUES ('" + u.user_def.name + "'," + prim_pass + "," + def_hg + ")"
};
}
} else {
insert_query = {
"INSERT INTO mysql_users (username,default_hostgroup,attributes) "
"VALUES ('" + u.user_def.name + "'," + def_hg + ",'" + attrs + "')"
};
}
MYSQL_QUERY_T(admin, insert_query.c_str());
}
MYSQL_QUERY_T(admin, "LOAD MYSQL USERS TO RUNTIME");
return EXIT_SUCCESS;
}
#endif

@ -31,17 +31,18 @@
#include <thread>
#include <unistd.h>
#include "openssl/ssl.h"
#include "openssl/types.h"
#include "json.hpp"
#include "mysql.h"
#include "tap.h"
#include "command_line.h"
#include "utils.h"
#include "utils_auth.h"
// Additional env variables
uint32_t TAP_MYSQL8_BACKEND_HG = 30;
uint32_t TAP_NUM_CLIENT_THREADS = 4;
uint32_t MYSQL8_HG = get_env_int("TAP_MYSQL8_BACKEND_HG", 30);
uint32_t NUM_CLIENT_THREADS = get_env_int("TAP_NUM_CLIENT_THREADS", 4);
using std::pair;
using std::string;
@ -80,134 +81,6 @@ string my_escape_string(MYSQL* mysql, const string& q) {
}
}
bool is_empty_pass(const char* pass) {
return pass == nullptr || (pass && strlen(pass) == 0);
}
bool match_pass(const char* p1, const char* p2) {
if (is_empty_pass(p1) && is_empty_pass(p2)) {
return true;
} else if (!is_empty_pass(p1) && !is_empty_pass(p2)) {
return strcmp(p1, p2) == 0;
} else {
return false;
}
}
std::string unhex(const std::string& hex) {
if (hex.size() % 2) { return {}; };
string result {};
for (size_t i = 0; i < hex.size() - 1; i += 2) {
string hex_char { string { hex[i] } + hex[i+1] };
uint64_t char_val { 0 };
std::istringstream stream { hex_char };
stream >> std::hex >> char_val;
result += string { static_cast<char>(char_val) };
}
return result;
}
std::string hex(const std::string& str) {
std::ostringstream hex_stream;
for (unsigned char c : str) {
hex_stream << std::hex << std::setfill('0') << std::setw(2) <<
std::uppercase << static_cast<uint64_t>(c);
}
return hex_stream.str();
}
struct free_deleter {
void operator()(void* x) { free(x); }
void operator()(const void* x) { free(const_cast<void*>(x)); }
};
template <typename T>
using mf_unique_ptr = std::unique_ptr<T, free_deleter>;
mf_unique_ptr<char> MF_CHAR_(const char* s) {
return mf_unique_ptr<char> { s ? strdup(s) : nullptr };
}
struct user_def_t {
string name {};
mf_unique_ptr<char> prim_pass { nullptr };
mf_unique_ptr<char> addl_pass { nullptr };
string auth {};
bool rand_pass {};
user_def_t() {}
user_def_t(const string& name_) : name(name_) {}
user_def_t(
const string& name_,
mf_unique_ptr<char> prim_pass_,
mf_unique_ptr<char> addl_pass_,
const string& auth_,
bool rand_pass_ = false
) :
name(name_),
prim_pass(std::move(prim_pass_)),
addl_pass(std::move(addl_pass_)),
auth(auth_),
rand_pass(rand_pass_)
{}
user_def_t(const user_def_t& other) :
name(other.name), auth(other.auth), rand_pass(other.rand_pass)
{
if (other.prim_pass) {
this->prim_pass = mf_unique_ptr<char>(strdup(other.prim_pass.get()));
} else {
this->prim_pass = nullptr;
}
if (other.addl_pass) {
this->addl_pass = mf_unique_ptr<char>(strdup(other.addl_pass.get()));
} else {
this->addl_pass = nullptr;
}
}
void operator=(const user_def_t& other) {
this->name = other.name;
this->auth = other.auth;
this->rand_pass = other.rand_pass;
if (other.prim_pass) {
this->prim_pass = mf_unique_ptr<char>(strdup(other.prim_pass.get()));
} else {
this->prim_pass = nullptr;
}
if (other.addl_pass) {
this->addl_pass = mf_unique_ptr<char>(strdup(other.addl_pass.get()));
} else {
this->addl_pass = nullptr;
}
}
user_def_t(user_def_t&& other) :
name(other.name),
auth(other.auth),
rand_pass(other.rand_pass),
prim_pass(std::move(other.prim_pass)),
addl_pass(std::move(other.addl_pass))
{}
void operator=(user_def_t&& other) {
this->name = other.name;
this->auth = other.auth;
this->rand_pass = other.rand_pass;
this->prim_pass = std::move(other.prim_pass);
this->addl_pass = std::move(other.addl_pass);
}
};
struct user_auth_stats_t {
user_def_t user_def;
uint64_t prim_pass_auths;
@ -217,21 +90,6 @@ struct user_auth_stats_t {
using auth_reg_t = std::unordered_map<string, user_auth_stats_t>;
struct user_creds_t {
user_def_t user_def;
mf_unique_ptr<char> hashed_prim_pass_bin { nullptr };
mf_unique_ptr<char> hashed_addl_pass_bin { nullptr };
user_creds_t(const user_creds_t&) = delete;
user_creds_t(user_creds_t&&) noexcept(false) = default;
void operator=(user_creds_t&& other) {
this->user_def = std::move(other.user_def);
this->hashed_prim_pass_bin = std::move(other.hashed_prim_pass_bin);
this->hashed_addl_pass_bin = std::move(other.hashed_addl_pass_bin);
}
};
/**
* @brief Extracts a nested JSON element from the supplied path.
* @param j The JSON from which to extract the element.
@ -254,34 +112,6 @@ const nlohmann::json* get_nested_elem(const nlohmann::json& j, const vector<stri
return next_step;
}
template <typename T>
T get_nested_elem_val(const nlohmann::json& j, const std::vector<std::string>& p, const T def_val) {
const nlohmann::json* next_step = get_nested_elem(j, p);
try {
if (next_step != nullptr && !next_step->is_null()) {
return next_step->get<T>();
} else {
return def_val;
}
} catch (std::exception&) {
return def_val;
}
}
struct test_conf_t {
/* @brief Default auth method announced by ProxySQL */
string def_auth;
/* @brief Auth method requested by client */
string req_auth;
/* @brief Wether to use hashed or 'clear_text' passwords. Implies a reload of 'mysql_users'. */
bool hashed_pass;
/* @brief Wether to attempt auth under SSL conn or not. */
bool use_ssl;
/* @brief Wether to attempt auth with compression enabled or not. */
bool use_comp;
};
struct sess_info_t {
int sent_pkts;
int recv_pkts;
@ -289,37 +119,6 @@ struct sess_info_t {
int full_sha2_auth;
};
struct PASS_TYPE {
enum E {
UNKNOWN = 0,
PRIMARY,
ADDITIONAL,
};
};
/**
* @brief Info from user defs (user_def_t), extracted for building 'test_creds_t'.
*/
struct creds_info_t {
PASS_TYPE::E type;
string auth;
};
/**
* @brief Info about user creds used in a particular test case.
* @details Multiple 'test_creds_t' are used while testing a single 'test_conf_t'.
*/
struct test_creds_t {
string name {};
mf_unique_ptr<char> pass { nullptr };
creds_info_t info {};
test_creds_t(const string& name_, mf_unique_ptr<char> pass_) : name(name_), pass(std::move(pass_)) {}
test_creds_t(const test_creds_t& other) : name(other.name), info(other.info) {
this->pass = other.pass ? MF_CHAR_(other.pass.get()) : nullptr;
}
};
sess_info_t ext_sess_info(MYSQL* proxy) {
sess_info_t sess_info { -3, -3, -3 };
nlohmann::json session { fetch_internal_session(proxy) };
@ -348,319 +147,6 @@ auth_reg_t create_auth_reg(const vector<user_creds_t>& users_creds) {
using chk_exp_scs_t = function<bool(const test_conf_t&, const test_creds_t&)>;
using chk_exp_seq_scs_t = function<bool(const test_conf_t&, const test_creds_t&, const user_auth_stats_t&)>;
/**
* @brief Extract the auth strings (prim/addl) pass from an existing user.
* @param mysql Opened MySQL conn in which to perform the queries.
* @param user_def User definition; used to match by username.
* @return A pair of kind `{err_code, user_creds}`.
*/
pair<int,user_creds_t> ext_user_auth_strs(MYSQL* mysql, const user_def_t& user_def) {
const char* addl_pass { user_def.addl_pass.get() };
const char* prim_pass { user_def.prim_pass.get() };
pair<int,user_creds_t> p_creds_res { EXIT_SUCCESS, user_creds_t {} };
const string ext_auths_query {
"SELECT HEX(authentication_string),json_value(user_attributes, '$.additional_password') "
"FROM mysql.user WHERE user='" + user_def.name + "'"
};
if (mysql_query_t(mysql, ext_auths_query.c_str())) {
fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(mysql));
return { EXIT_FAILURE, user_creds_t {} };
}
MYSQL_RES* myres = mysql_store_result(mysql);
MYSQL_ROW myrow = mysql_fetch_row(myres);
if (myrow && myrow[0]) {
const char* p_addl_pass { myrow[1] };
if (p_addl_pass) {
p_creds_res = {
EXIT_SUCCESS,
user_creds_t {
user_def,
mf_unique_ptr<char> { strdup(myrow[0]) },
mf_unique_ptr<char> { strdup(p_addl_pass) }
}
};
} else {
// MySQL wont allow that 'aditional' pass for a backend user; we don't verify user attributes
// right now when loading to runtime; but we wont allow user to connect with empty
// 'additional' passwords either;
if (addl_pass && strlen(addl_pass) == 0) {
p_creds_res = {
EXIT_SUCCESS,
user_creds_t {
user_def,
mf_unique_ptr<char> { strdup(myrow[0]) },
mf_unique_ptr<char> { strdup("") },
}
};
} else {
p_creds_res = {
EXIT_SUCCESS,
user_creds_t {
user_def,
mf_unique_ptr<char> { strdup(myrow[0]) },
mf_unique_ptr<char> { nullptr },
}
};
}
}
} else {
diag("Empty result; no auth_string found for user user:'%s'", user_def.name.c_str());
}
mysql_free_result(myres);
return p_creds_res;
}
/**
* @brief TODO: Limitation ProxySQL doesn't allow a clear-text pass to start with '*'. See #1762.
* @param pass Password to check.
* @return 'true' if password is an invalid clear-text pass for ProxySQL.
*/
bool chk_inv_pass(const char* pass) {
if (is_empty_pass(pass)) {
return true;
} else {
if (strlen(pass)) {
return pass[0] == '*';
} else {
return false;
}
}
}
pair<int,user_def_t> create_mysql_user_rnd_creds(MYSQL* mysql, const user_def_t& user_def) {
const string CREATE_USER {
"CREATE USER '" + user_def.name + "'@'%' IDENTIFIED WITH"
" '" + user_def.auth + "' BY RANDOM PASSWORD"
};
const string DROP_USER { "DROP USER IF EXISTS '" + user_def.name + "'"};
mf_unique_ptr<char> addl_text_pass { nullptr };
{
// NOTE: Required due to potential pass recreation
MYSQL_QUERY_T_(mysql, DROP_USER.c_str());
MYSQL_QUERY_T_(mysql, CREATE_USER.c_str());
MYSQL_RES* myres = mysql_store_result(mysql);
MYSQL_ROW myrow = mysql_fetch_row(myres);
if (myrow && myrow[2]) {
addl_text_pass = mf_unique_ptr<char>(strdup(myrow[2]));
}
mysql_free_result(myres);
}
const string ALTER_USER {
"ALTER USER '" + user_def.name + "'@'%' IDENTIFIED WITH"
" '" + user_def.auth + "' BY RANDOM PASSWORD RETAIN CURRENT PASSWORD"
};
mf_unique_ptr<char> prim_text_pass {};
{
MYSQL_QUERY_T_(mysql, ALTER_USER.c_str());
MYSQL_RES* myres = mysql_store_result(mysql);
MYSQL_ROW myrow = mysql_fetch_row(myres);
if (myrow && myrow[2]) {
prim_text_pass = mf_unique_ptr<char>(strdup(myrow[2]));
}
mysql_free_result(myres);
}
return {
EXIT_SUCCESS,
user_def_t {
user_def.name,
std::move(prim_text_pass),
std::move(addl_text_pass),
user_def.auth,
user_def.rand_pass
}
};
}
pair<int,user_def_t> create_mysql_user_exp_creds(MYSQL* mysql, const user_def_t& user_def) {
const char* addl_pass { user_def.addl_pass.get() };
const char* prim_pass { user_def.prim_pass.get() };
if (addl_pass && strlen(addl_pass)) {
const string CREATE_USER {
"CREATE USER '" + user_def.name + "'@'%' IDENTIFIED WITH"
" '" + user_def.auth + "' BY '" + user_def.addl_pass.get() + "'"
};
const string GRANT_USER_PRIVS { "GRANT ALL on *.* to '" + user_def.name + "'@'%'" };
MYSQL_QUERY_T_(mysql, CREATE_USER.c_str());
MYSQL_QUERY_T_(mysql, GRANT_USER_PRIVS.c_str());
if (prim_pass && strlen(prim_pass)) {
const string ALTER_USER_RETAIN {
"ALTER USER '" + user_def.name + "'@'%' IDENTIFIED BY '" + prim_pass + "'"
" RETAIN CURRENT PASSWORD"
};
MYSQL_QUERY_T_(mysql, ALTER_USER_RETAIN.c_str());
} else {
const string ALTER_USER_NO_RETAIN {
"ALTER USER '" + user_def.name + "'@'%' IDENTIFIED BY ''"
};
// When new password is empty; retaining the previous one isn't possible
MYSQL_QUERY_T_(mysql, ALTER_USER_NO_RETAIN.c_str());
}
} else {
string CREATE_USER { "CREATE USER '" + user_def.name + "'@'%'" };
string GRANT_USER_PRIVS { "GRANT ALL on *.* to '" + user_def.name + "'@'%'" };
if (prim_pass) {
CREATE_USER += " IDENTIFIED WITH '" + user_def.auth + "' BY '" + prim_pass + "'";
}
MYSQL_QUERY_T_(mysql, CREATE_USER.c_str());
MYSQL_QUERY_T_(mysql, GRANT_USER_PRIVS.c_str());
}
return { EXIT_SUCCESS, user_def };
}
pair<int,user_def_t> create_mysql_user(MYSQL* mysql, const user_def_t& user_def) {
if (user_def.rand_pass) {
pair<int,user_def_t> rnd_user_def {};
while (
rnd_user_def.first == EXIT_SUCCESS &&
(chk_inv_pass(rnd_user_def.second.prim_pass.get())
|| chk_inv_pass(rnd_user_def.second.addl_pass.get()))
) {
rnd_user_def = create_mysql_user_rnd_creds(mysql, user_def);
}
return rnd_user_def;
} else {
return create_mysql_user_exp_creds(mysql, user_def);
}
}
pair<int,user_creds_t> create_backend_user(MYSQL* mysql, const user_def_t& user_def) {
const pair<int,user_def_t> c_user_def { create_mysql_user(mysql, user_def) };
if (c_user_def.first == EXIT_SUCCESS) {
pair<int,user_creds_t> p_creds_res { ext_user_auth_strs(mysql, c_user_def.second) };
return p_creds_res;
} else {
return { EXIT_FAILURE, user_creds_t {} };
}
}
/**
* @brief Configure the backend MySQL 8 users for frontend-backend connection creation.
* @param mysql Already opened MySQL connection.
* @param backend_users The users to be created in the MySQL server.
* @return A pair of kind `{err_code, user_creds}`.
*/
pair<int,vector<user_creds_t>> config_mysql_backend_users(
MYSQL* mysql, const vector<user_def_t>& users_defs
) {
for (const auto& u : users_defs) {
MYSQL_QUERY_T__(mysql, ("DROP USER IF EXISTS '" + u.name + "'").c_str());
}
vector<user_creds_t> f_users_creds {};
for (const auto& user_def : users_defs) {
pair<int,user_creds_t> creds_res { create_backend_user(mysql, user_def) };
if (creds_res.first == EXIT_SUCCESS) {
f_users_creds.push_back(std::move(creds_res.second));
} else {
return { EXIT_FAILURE, vector<user_creds_t> {} };
}
}
return { EXIT_SUCCESS, std::move(f_users_creds) };
}
int config_proxysql_users(MYSQL* admin, const test_conf_t& test_conf, const vector<user_creds_t>& users) {
const string DEF_HG { std::to_string(TAP_MYSQL8_BACKEND_HG) };
for (const auto& u : users) {
MYSQL_QUERY_T(admin, ("DELETE FROM mysql_users WHERE username='" + u.user_def.name + "'").c_str());
}
// Ensure cleanup of previously cached clear_text 'caching_sha2' passwords
MYSQL_QUERY_T(admin, "LOAD MYSQL USERS TO RUNTIME");
MYSQL_QUERY_T(admin, "LOAD MYSQL USERS TO RUNTIME");
for (const auto& u : users) {
string attrs {};
// A user may not have an additional_password configured
if (u.user_def.addl_pass) {
string addl_pass {};
// NOTE: If the primary pass is empty, addl pass must be empty **by spec**
if (is_empty_pass(u.user_def.prim_pass.get())) {
addl_pass = {};
} else if (test_conf.hashed_pass) {
const char* c_addl_pass { u.hashed_addl_pass_bin.get() };
if (c_addl_pass) {
addl_pass = c_addl_pass;
}
} else {
addl_pass = u.user_def.addl_pass.get();
}
const string hex_addl_pass { hex(addl_pass) };
attrs = "{\"additional_password\": \"" + hex_addl_pass + "\"}";
}
string insert_query {};
if (u.user_def.prim_pass) {
const string prim_pass {
test_conf.hashed_pass && strlen(u.hashed_prim_pass_bin.get()) > 0 ?
"UNHEX('" + string { u.hashed_prim_pass_bin.get() } + "')" :
"'" + string { u.user_def.prim_pass.get() } + "'"
};
if (u.user_def.addl_pass) {
insert_query = {
"INSERT INTO mysql_users (username,password,default_hostgroup,attributes) "
"VALUES ('" + u.user_def.name + "'," + prim_pass + "," + DEF_HG + ",'" + attrs + "')"
};
} else {
insert_query = {
"INSERT INTO mysql_users (username,password,default_hostgroup) "
"VALUES ('" + u.user_def.name + "'," + prim_pass + "," + DEF_HG + ")"
};
}
} else {
insert_query = {
"INSERT INTO mysql_users (username,default_hostgroup,attributes) "
"VALUES ('" + u.user_def.name + "'," + DEF_HG + ",'" + attrs + "')"
};
}
MYSQL_QUERY_T(admin, insert_query.c_str());
}
MYSQL_QUERY_T(admin, "LOAD MYSQL USERS TO RUNTIME");
return EXIT_SUCCESS;
}
FILE* F_SSLKEYLOGFILE = nullptr;
void ssl_keylog_callback(SSL*, const char* line) {
@ -671,33 +157,6 @@ void ssl_keylog_callback(SSL*, const char* line) {
}
}
string to_string(const test_conf_t& conf) {
return "{ "
"\"req_auth\":'" + conf.req_auth + "', "
"\"def_auth\":'" + conf.def_auth + "', "
"\"hashed_pass\":'" + std::to_string(conf.hashed_pass) + "', "
"\"use_ssl\":'" + std::to_string(conf.use_ssl) + "'"
" }";
}
string to_string(const PASS_TYPE::E type) {
if (type == PASS_TYPE::PRIMARY) {
return "PRIM";
} else if (type == PASS_TYPE::ADDITIONAL) {
return "ADDL";
} else {
return "UNKN";
}
}
string to_string(const test_creds_t& creds) {
return "{ "
"\"name\":'" + creds.name + "', "
"\"pass\":'" + (creds.pass ? creds.pass.get() : "NULL") + "', "
"\"type\":'" + to_string(creds.info.type) + "'"
" }";
}
string to_string(const sess_info_t& sess) {
return "{ "
"\"recv_pkts\":'" + std::to_string(sess.recv_pkts) + "', "
@ -714,6 +173,16 @@ string to_string(const user_auth_stats_t& stats) {
" }";
}
bool match_pass(const char* p1, const char* p2) {
if (is_empty_pass(p1) && is_empty_pass(p2)) {
return true;
} else if (!is_empty_pass(p1) && !is_empty_pass(p2)) {
return strcmp(p1, p2) == 0;
} else {
return false;
}
}
PASS_TYPE::E get_matching_pass(const user_creds_t& creds, const char* p) {
const char* prim_pass { creds.user_def.prim_pass.get() };
const char* addl_pass { creds.user_def.addl_pass.get() };
@ -990,38 +459,6 @@ bool chk_exp_scs_no_warmup(const test_conf_t& conf, const test_creds_t& creds) {
return chk_exp_scs_basic(conf, creds) && !chk_exp_fail_except_no_warmup(conf, creds);
}
/**
* @brief Gen all combinations of tests configs.
* @param def_auths Defaults auths to set for ProxySQL.
* @param req_auths Auth methods for client to request.
* @param hash_pass If passwords should be hashed or not.
* @param use_ssl If connection is started with SSL or not.
* @return Vector with the combinations.
*/
vector<test_conf_t> get_conf_combs(
const vector<string>& def_auths,
const vector<string>& req_auths,
const vector<bool>& hash_pass,
const vector<bool>& use_ssl,
const vector<bool>& use_comp
) {
vector<test_conf_t> confs {};
for (const auto& def_auth : def_auths) {
for (const auto& req_auth : req_auths) {
for (const auto& hashed : hash_pass) {
for (const auto& ssl : use_ssl) {
for (const auto& comp : use_comp) {
confs.push_back({def_auth, req_auth, hashed, ssl, comp});
}
}
}
}
}
return confs;
}
user_auth_stats_t update_auth_reg(MYSQL* mysql, const string& user, const char* pass, auth_reg_t& auth_reg) {
user_auth_stats_t auth_info {};
@ -1274,25 +711,25 @@ user_auth_stats_t check_auth_creds(
}
const vector<user_def_t> backend_users {
{ "dualpass1", MF_CHAR_(nullptr), MF_CHAR_(nullptr), "mysql_native_password" },
{ "dualpass2", MF_CHAR_(""), MF_CHAR_(nullptr), "mysql_native_password" },
{ "dualpass3", MF_CHAR_("newpass3"), MF_CHAR_(nullptr), "mysql_native_password" },
{ "dualpass4", MF_CHAR_(nullptr), MF_CHAR_(""), "mysql_native_password" },
{ "dualpass5", MF_CHAR_(""), MF_CHAR_(""), "mysql_native_password" },
{ "dualpass6", MF_CHAR_("newpass6"), MF_CHAR_(""), "mysql_native_password" },
{ "dualpass7", MF_CHAR_(""), MF_CHAR_("oldpass7"), "mysql_native_password" },
{ "dualpass8", MF_CHAR_(""), MF_CHAR_("oldpass8"), "mysql_native_password" },
{ "dualpass9", MF_CHAR_("newpass9"), MF_CHAR_("oldpass9"), "mysql_native_password" },
{ "dualpass11", MF_CHAR_(nullptr), MF_CHAR_(nullptr), "caching_sha2_password" },
{ "dualpass12", MF_CHAR_(""), MF_CHAR_(nullptr), "caching_sha2_password" },
{ "dualpass13", MF_CHAR_("newpass13"), MF_CHAR_(nullptr), "caching_sha2_password" },
{ "dualpass14", MF_CHAR_(nullptr), MF_CHAR_(""), "caching_sha2_password" },
{ "dualpass15", MF_CHAR_(""), MF_CHAR_(""), "caching_sha2_password" },
{ "dualpass16", MF_CHAR_("newpass16"), MF_CHAR_(""), "caching_sha2_password" },
{ "dualpass17", MF_CHAR_(""), MF_CHAR_("oldpass17"), "caching_sha2_password" },
{ "dualpass18", MF_CHAR_(""), MF_CHAR_("oldpass18"), "caching_sha2_password" },
{ "dualpass19", MF_CHAR_("newpass19"), MF_CHAR_("oldpass19"), "caching_sha2_password" },
{ "dualpass1", MF_CHAR_(nullptr), MF_CHAR_(nullptr), "mysql_native_password", MYSQL8_HG },
{ "dualpass2", MF_CHAR_(""), MF_CHAR_(nullptr), "mysql_native_password", MYSQL8_HG },
{ "dualpass3", MF_CHAR_("newpass3"), MF_CHAR_(nullptr), "mysql_native_password", MYSQL8_HG },
{ "dualpass4", MF_CHAR_(nullptr), MF_CHAR_(""), "mysql_native_password", MYSQL8_HG },
{ "dualpass5", MF_CHAR_(""), MF_CHAR_(""), "mysql_native_password", MYSQL8_HG },
{ "dualpass6", MF_CHAR_("newpass6"), MF_CHAR_(""), "mysql_native_password", MYSQL8_HG },
{ "dualpass7", MF_CHAR_(""), MF_CHAR_("oldpass7"), "mysql_native_password", MYSQL8_HG },
{ "dualpass8", MF_CHAR_(""), MF_CHAR_("oldpass8"), "mysql_native_password", MYSQL8_HG },
{ "dualpass9", MF_CHAR_("newpass9"), MF_CHAR_("oldpass9"), "mysql_native_password", MYSQL8_HG },
{ "dualpass11", MF_CHAR_(nullptr), MF_CHAR_(nullptr), "caching_sha2_password", MYSQL8_HG },
{ "dualpass12", MF_CHAR_(""), MF_CHAR_(nullptr), "caching_sha2_password", MYSQL8_HG },
{ "dualpass13", MF_CHAR_("newpass13"), MF_CHAR_(nullptr), "caching_sha2_password", MYSQL8_HG },
{ "dualpass14", MF_CHAR_(nullptr), MF_CHAR_(""), "caching_sha2_password", MYSQL8_HG },
{ "dualpass15", MF_CHAR_(""), MF_CHAR_(""), "caching_sha2_password", MYSQL8_HG },
{ "dualpass16", MF_CHAR_("newpass16"), MF_CHAR_(""), "caching_sha2_password", MYSQL8_HG },
{ "dualpass17", MF_CHAR_(""), MF_CHAR_("oldpass17"), "caching_sha2_password", MYSQL8_HG },
{ "dualpass18", MF_CHAR_(""), MF_CHAR_("oldpass18"), "caching_sha2_password", MYSQL8_HG },
{ "dualpass19", MF_CHAR_("newpass19"), MF_CHAR_("oldpass19"), "caching_sha2_password", MYSQL8_HG },
};
/**
@ -1423,14 +860,14 @@ int backend_conns_cleanup(MYSQL* admin) {
diag("Cleaning up previous backend connections...");
MYSQL_QUERY(admin,
("UPDATE mysql_servers SET max_connections=0 "
"WHERE hostgroup_id=" + std::to_string(TAP_MYSQL8_BACKEND_HG)).c_str()
"WHERE hostgroup_id=" + std::to_string(MYSQL8_HG)).c_str()
);
MYSQL_QUERY(admin, "LOAD MYSQL SERVERS TO RUNTIME");
// Wait for backend connection cleanup
const string check_conn_cleanup {
"SELECT IIF((SELECT SUM(ConnUsed + ConnFree) FROM stats.stats_mysql_connection_pool"
" WHERE hostgroup=" + std::to_string(TAP_MYSQL8_BACKEND_HG) + ")=0, 'TRUE', 'FALSE')"
" WHERE hostgroup=" + std::to_string(MYSQL8_HG) + ")=0, 'TRUE', 'FALSE')"
};
int w_res = wait_for_cond(admin, check_conn_cleanup, 10);
if (w_res != EXIT_SUCCESS) {
@ -1441,7 +878,7 @@ int backend_conns_cleanup(MYSQL* admin) {
diag("Setup new connection limit max_connections='2000'");
MYSQL_QUERY(admin,
("UPDATE mysql_servers SET max_connections=2000 "
"WHERE hostgroup_id=" + std::to_string(TAP_MYSQL8_BACKEND_HG)).c_str()
"WHERE hostgroup_id=" + std::to_string(MYSQL8_HG)).c_str()
);
MYSQL_QUERY(admin, "LOAD MYSQL SERVERS TO RUNTIME");
@ -1522,7 +959,7 @@ int test_confs_creds_combs_frontend(
std::vector<std::thread> client_threads {};
// Perform parallel fronted logging tests
for (uint32_t i = 0; i < TAP_NUM_CLIENT_THREADS; i++) {
for (uint32_t i = 0; i < NUM_CLIENT_THREADS; i++) {
client_threads.push_back(std::thread([&cl, &p_conf_creds, &chk_exp_scs] () {
for (const auto& creds : p_conf_creds.second) {
test_creds_frontend(cl, p_conf_creds.first, creds, chk_exp_scs);
@ -1566,14 +1003,14 @@ int test_all_confs_creds(
MYSQL_QUERY_T(admin, "LOAD MYSQL USERS TO RUNTIME");
std::vector<std::thread> client_thds {};
std::vector<uint64_t> thds_exp_sha2_auths(TAP_NUM_CLIENT_THREADS);
std::vector<uint64_t> thds_exp_sha2_auths(NUM_CLIENT_THREADS);
std::vector<auth_reg_t> thds_auth_regs {};
for (uint32_t i = 0; i < TAP_NUM_CLIENT_THREADS; i++) {
for (uint32_t i = 0; i < NUM_CLIENT_THREADS; i++) {
thds_auth_regs.push_back(create_auth_reg(users_creds));
}
for (uint32_t i = 0; i < TAP_NUM_CLIENT_THREADS; i++) {
for (uint32_t i = 0; i < NUM_CLIENT_THREADS; i++) {
client_thds.push_back(
std::thread(
[&cl, &conf, &thds_auth_regs, &thds_exp_sha2_auths, i, &users_creds, &tests_creds] () {
@ -1609,7 +1046,7 @@ int test_all_confs_creds(
cthread.join();
}
for (uint32_t i = 0; i < TAP_NUM_CLIENT_THREADS; i++) {
for (uint32_t i = 0; i < NUM_CLIENT_THREADS; i++) {
auth_reg_t& auth_reg { thds_auth_regs[i] };
for (const auto& auth_stats : auth_reg) {
@ -1622,7 +1059,7 @@ int test_all_confs_creds(
}
}
uint64_t exp_scs_total = non_warmup_tests_scs_count * TAP_NUM_CLIENT_THREADS;
uint64_t exp_scs_total = non_warmup_tests_scs_count * NUM_CLIENT_THREADS;
uint64_t exp_full_sha2_total = exp_sha2_auths;
ok(
@ -1648,9 +1085,6 @@ int main(int argc, char** argv) {
return EXIT_FAILURE;
}
TAP_MYSQL8_BACKEND_HG = get_env_int("TAP_MYSQL8_BACKEND_HG", 30);
TAP_NUM_CLIENT_THREADS = get_env_int("TAP_NUM_CLIENT_THREADS", 4);
MYSQL* mysql = mysql_init(NULL);
if (!mysql_real_connect(mysql, cl.host, cl.mysql_username, cl.mysql_password, NULL, cl.mysql_port, NULL, 0)) {
@ -1734,7 +1168,7 @@ int main(int argc, char** argv) {
// Sequential access tests; exercising full logic
const vector<test_conf_t> all_conf_combs {
get_conf_combs(def_auths, req_auhts, hash_pass, use_ssl, use_comp)
get_auth_conf_combs(def_auths, req_auhts, hash_pass, use_ssl, use_comp)
};
const auto scs_stats { count_exp_scs(all_conf_combs, cbres.second, tests_creds) };

Loading…
Cancel
Save