Merge branch '2.3' into 2.4
This commit is contained in:
@ -195,6 +195,10 @@ following fields.
|
|||||||
* `data.attributes.account`
|
* `data.attributes.account`
|
||||||
* Set to `admin` for administrative users and `basic` to read-only users
|
* Set to `admin` for administrative users and `basic` to read-only users
|
||||||
|
|
||||||
|
Only admin accounts can perform POST, PUT, DELETE and PATCH requests. If a basic
|
||||||
|
account performs one of the aforementioned request, the REST API will respond
|
||||||
|
with a `401 Unauthorized` error.
|
||||||
|
|
||||||
Here is an example request body defining the network user _my-user_ with the
|
Here is an example request body defining the network user _my-user_ with the
|
||||||
password _my-password_ that is allowed to execute only read-only operations.
|
password _my-password_ that is allowed to execute only read-only operations.
|
||||||
|
|
||||||
|
@ -354,7 +354,8 @@ exports.builder = function(yargs) {
|
|||||||
return yargs.epilog('The created user can be used with the MaxScale REST API as ' +
|
return yargs.epilog('The created user can be used with the MaxScale REST API as ' +
|
||||||
'well as the MaxAdmin network interface. By default the created ' +
|
'well as the MaxAdmin network interface. By default the created ' +
|
||||||
'user will have read-only privileges. To make the user an ' +
|
'user will have read-only privileges. To make the user an ' +
|
||||||
'administrative user, use the `--type=admin` option.')
|
'administrative user, use the `--type=admin` option. ' +
|
||||||
|
'Basic users can only perform `list` and `show` commands.')
|
||||||
.usage('Usage: create user <name> <password>')
|
.usage('Usage: create user <name> <password>')
|
||||||
.group(['type'], 'Create user options:')
|
.group(['type'], 'Create user options:')
|
||||||
.option('type', {
|
.option('type', {
|
||||||
|
@ -872,11 +872,6 @@ DCB* Listener::accept_one_dcb(int fd, const sockaddr_storage* addr, const char*
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (client_dcb)
|
|
||||||
{
|
|
||||||
mxb::atomic::add(&m_service->client_count, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return client_dcb;
|
return client_dcb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,18 +257,7 @@ private:
|
|||||||
static void session_free(MXS_SESSION* session)
|
static void session_free(MXS_SESSION* session)
|
||||||
{
|
{
|
||||||
MXS_INFO("Stopped %s client session [%" PRIu64 "]", session->service->name(), session->ses_id);
|
MXS_INFO("Stopped %s client session [%" PRIu64 "]", session->service->name(), session->ses_id);
|
||||||
Service* service = static_cast<Service*>(session->service);
|
|
||||||
|
|
||||||
session_final_free(session);
|
session_final_free(session);
|
||||||
bool should_destroy = !mxb::atomic::load(&service->active);
|
|
||||||
|
|
||||||
if (mxb::atomic::add(&service->client_count, -1) == 1 && should_destroy)
|
|
||||||
{
|
|
||||||
// Destroy the service in the main routing worker thread
|
|
||||||
mxs::RoutingWorker* main_worker = mxs::RoutingWorker::get(mxs::RoutingWorker::MAIN);
|
|
||||||
main_worker->execute(std::unique_ptr<ServiceDestroyTask>(new ServiceDestroyTask(service)),
|
|
||||||
Worker::EXECUTE_AUTO);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void session_final_free(MXS_SESSION* ses)
|
static void session_final_free(MXS_SESSION* ses)
|
||||||
@ -1162,6 +1151,7 @@ Session::Session(const SListener& listener)
|
|||||||
|
|
||||||
mxb::atomic::add(&service->stats.n_current, 1, mxb::atomic::RELAXED);
|
mxb::atomic::add(&service->stats.n_current, 1, mxb::atomic::RELAXED);
|
||||||
mxb_assert(service->stats.n_current >= 0);
|
mxb_assert(service->stats.n_current >= 0);
|
||||||
|
mxb::atomic::add(&service->client_count, 1, mxb::atomic::RELAXED);
|
||||||
}
|
}
|
||||||
|
|
||||||
Session::~Session()
|
Session::~Session()
|
||||||
@ -1179,6 +1169,17 @@ Session::~Session()
|
|||||||
|
|
||||||
mxb::atomic::add(&service->stats.n_current, -1, mxb::atomic::RELAXED);
|
mxb::atomic::add(&service->stats.n_current, -1, mxb::atomic::RELAXED);
|
||||||
mxb_assert(service->stats.n_current >= 0);
|
mxb_assert(service->stats.n_current >= 0);
|
||||||
|
|
||||||
|
bool should_destroy = !mxb::atomic::load(&service->active);
|
||||||
|
|
||||||
|
if (mxb::atomic::add(&service->client_count, -1) == 1 && should_destroy)
|
||||||
|
{
|
||||||
|
// Destroy the service in the main routing worker thread
|
||||||
|
mxs::RoutingWorker* main_worker = mxs::RoutingWorker::get(mxs::RoutingWorker::MAIN);
|
||||||
|
main_worker->execute(
|
||||||
|
std::unique_ptr<ServiceDestroyTask>(new ServiceDestroyTask(static_cast<Service*>(service))),
|
||||||
|
Worker::EXECUTE_AUTO);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::set_client_dcb(DCB* dcb)
|
void Session::set_client_dcb(DCB* dcb)
|
||||||
|
@ -478,6 +478,10 @@ int validate_mysql_user(MYSQL_AUTH* instance,
|
|||||||
rval = MXS_AUTH_FAILED_DB;
|
rval = MXS_AUTH_FAILED_DB;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rval = MXS_AUTH_FAILED_WRONG_PASSWORD;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rval;
|
return rval;
|
||||||
|
@ -37,6 +37,8 @@
|
|||||||
#include <maxscale/utils.h>
|
#include <maxscale/utils.h>
|
||||||
#include <maxscale/routingworker.hh>
|
#include <maxscale/routingworker.hh>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
static void* mysql_auth_init(char** options);
|
static void* mysql_auth_init(char** options);
|
||||||
static bool mysql_auth_set_protocol_data(DCB* dcb, GWBUF* buf);
|
static bool mysql_auth_set_protocol_data(DCB* dcb, GWBUF* buf);
|
||||||
static bool mysql_auth_is_client_ssl_capable(DCB* dcb);
|
static bool mysql_auth_is_client_ssl_capable(DCB* dcb);
|
||||||
@ -305,6 +307,48 @@ static GWBUF* gen_auth_switch_request_packet(MySQLProtocol* proto, MYSQL_session
|
|||||||
*bufdata = '\0';
|
*bufdata = '\0';
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void log_auth_failure(DCB* dcb, int auth_ret)
|
||||||
|
{
|
||||||
|
MYSQL_session* client_data = (MYSQL_session*)dcb->data;
|
||||||
|
std::ostringstream extra;
|
||||||
|
|
||||||
|
if (auth_ret == MXS_AUTH_FAILED_DB)
|
||||||
|
{
|
||||||
|
extra << "Unknown database: " << client_data->db;
|
||||||
|
}
|
||||||
|
else if (auth_ret == MXS_AUTH_FAILED_WRONG_PASSWORD)
|
||||||
|
{
|
||||||
|
extra << "Wrong password.";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
extra << "User not found.";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostringstream host;
|
||||||
|
host << "[" << dcb->remote << "]:" << dcb_get_port(dcb);
|
||||||
|
|
||||||
|
std::ostringstream db;
|
||||||
|
|
||||||
|
if (*client_data->db)
|
||||||
|
{
|
||||||
|
db << " to database '" << client_data->db << "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
MXS_LOG_EVENT(maxscale::event::AUTHENTICATION_FAILURE,
|
||||||
|
"%s: login attempt for user '%s'@%s%s, authentication failed. %s",
|
||||||
|
dcb->service->name(), client_data->user, host.str().c_str(),
|
||||||
|
db.str().c_str(), extra.str().c_str());
|
||||||
|
|
||||||
|
if (is_localhost_address(&dcb->ip) && !dcb->service->localhost_match_wildcard_host)
|
||||||
|
{
|
||||||
|
MXS_NOTICE("If you have a wildcard grant that covers this address, "
|
||||||
|
"try adding 'localhost_match_wildcard_host=true' for "
|
||||||
|
"service '%s'. ", dcb->service->name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Authenticates a MySQL user who is a client to MaxScale.
|
* @brief Authenticates a MySQL user who is a client to MaxScale.
|
||||||
*
|
*
|
||||||
@ -368,34 +412,7 @@ static int mysql_auth_authenticate(DCB* dcb)
|
|||||||
}
|
}
|
||||||
else if (dcb->service->log_auth_warnings)
|
else if (dcb->service->log_auth_warnings)
|
||||||
{
|
{
|
||||||
// The default failure is a `User not found` one
|
log_auth_failure(dcb, auth_ret);
|
||||||
char extra[256] = "User not found.";
|
|
||||||
|
|
||||||
if (auth_ret == MXS_AUTH_FAILED_DB)
|
|
||||||
{
|
|
||||||
snprintf(extra, sizeof(extra), "Unknown database: %s", client_data->db);
|
|
||||||
}
|
|
||||||
else if (auth_ret == MXS_AUTH_FAILED_WRONG_PASSWORD)
|
|
||||||
{
|
|
||||||
strcpy(extra, "Wrong password.");
|
|
||||||
}
|
|
||||||
|
|
||||||
MXS_LOG_EVENT(maxscale::event::AUTHENTICATION_FAILURE,
|
|
||||||
"%s: login attempt for user '%s'@[%s]:%d, authentication failed. %s",
|
|
||||||
dcb->service->name(),
|
|
||||||
client_data->user,
|
|
||||||
dcb->remote,
|
|
||||||
dcb_get_port(dcb),
|
|
||||||
extra);
|
|
||||||
|
|
||||||
if (is_localhost_address(&dcb->ip)
|
|
||||||
&& !dcb->service->localhost_match_wildcard_host)
|
|
||||||
{
|
|
||||||
MXS_NOTICE("If you have a wildcard grant that covers this address, "
|
|
||||||
"try adding 'localhost_match_wildcard_host=true' for "
|
|
||||||
"service '%s'. ",
|
|
||||||
dcb->service->name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* let's free the auth_token now */
|
/* let's free the auth_token now */
|
||||||
|
Reference in New Issue
Block a user