From fe689504b0f0344cbcb0d0299e9ecf5eeefaeb64 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Tue, 18 Oct 2016 14:06:32 +0300 Subject: [PATCH] Move service user injection into MySQL authenticator The MySQL authenticator now injects the service user into the list of allowed users if loading of database users fails. This allows the removal of common code in the binlogrouter and maxinfo modules. --- .../Authenticators/MySQL-Authenticator.md | 18 ++++++ include/maxscale/router.h | 4 +- server/core/service.c | 1 - server/modules/authenticator/mysql_auth.c | 60 ++++++++++++++++++- server/modules/routing/binlog/blr.c | 2 +- 5 files changed, 79 insertions(+), 6 deletions(-) diff --git a/Documentation/Authenticators/MySQL-Authenticator.md b/Documentation/Authenticators/MySQL-Authenticator.md index aee19d778..85a1adaca 100644 --- a/Documentation/Authenticators/MySQL-Authenticator.md +++ b/Documentation/Authenticators/MySQL-Authenticator.md @@ -32,3 +32,21 @@ port=4006 authenticator=MySQLAuth authenticator_options=cache_dir=/tmp ``` + +### `inject_service_user` + +Inject service credentials into the list of database users if loading of +users fails. This option takes a boolean value and it is enabled by +default. + +When a connection to the backend database cannot be made, the service user +can be injected into the list of allowed users. This allows administrative +operations to be done via the SQL interface with modules that support it +e.g. the Binlogrouter and Maxinfo modules. + +If users are loaded successfully, the service user credentials are _not_ +injected into the list of users. + +``` +authenticator_options=inject_service_user=false +``` diff --git a/include/maxscale/router.h b/include/maxscale/router.h index 91c363b9b..40b27038a 100644 --- a/include/maxscale/router.h +++ b/include/maxscale/router.h @@ -100,9 +100,7 @@ typedef enum router_capability_t RCAP_TYPE_UNDEFINED = 0x00, RCAP_TYPE_STMT_INPUT = 0x01, /**< Statement per buffer */ RCAP_TYPE_PACKET_INPUT = 0x02, /**< Data as it was read from DCB */ - RCAP_TYPE_NO_RSESSION = 0x04, /**< Router does not use router sessions */ - RCAP_TYPE_NO_USERS_INIT = 0x08 /**< Prevent the loading of authenticator - users when the service is started */ + RCAP_TYPE_NO_RSESSION = 0x04 /**< Router does not use router sessions */ } router_capability_t; MXS_END_DECLS diff --git a/server/core/service.c b/server/core/service.c index c6d7b871d..a6a5e167c 100644 --- a/server/core/service.c +++ b/server/core/service.c @@ -303,7 +303,6 @@ serviceStartPort(SERVICE *service, SERV_LISTENER *port) /** Load the authentication users before before starting the listener */ if (port->listener->authfunc.loadusers && - (service->router->getCapabilities() & RCAP_TYPE_NO_USERS_INIT) == 0 && port->listener->authfunc.loadusers(port) != MXS_AUTH_LOADUSERS_OK) { MXS_ERROR("[%s] Failed to load users for listener '%s', authentication might not work.", diff --git a/server/modules/authenticator/mysql_auth.c b/server/modules/authenticator/mysql_auth.c index 9e0cb9214..4c002ae53 100644 --- a/server/modules/authenticator/mysql_auth.c +++ b/server/modules/authenticator/mysql_auth.c @@ -37,7 +37,8 @@ typedef struct mysql_auth { - char *cache_dir; /**< Custom cache directory location */ + char *cache_dir; /**< Custom cache directory location */ + bool inject_service_user; /**< Inject the service user into the list of users */ } MYSQL_AUTH; @@ -142,6 +143,7 @@ static void* mysql_auth_init(char **options) { bool error = false; instance->cache_dir = NULL; + instance->inject_service_user = true; for (int i = 0; options[i]; i++) { @@ -158,6 +160,10 @@ static void* mysql_auth_init(char **options) error = true; } } + else if (strcmp(options[i], "inject_service_user") == 0) + { + instance->inject_service_user = config_truth_value(value); + } else { MXS_ERROR("Unknown authenticator option: %s", options[i]); @@ -830,6 +836,48 @@ mysql_auth_free_client_data(DCB *dcb) MXS_FREE(dcb->data); } +/** + * @brief Inject the service user into the cache + * + * @param port Service listener + * @return True on success, false on error + */ +static bool add_service_user(SERV_LISTENER *port) +{ + char *user = NULL; + char *pw = NULL; + bool rval = false; + + if (serviceGetUser(port->service, &user, &pw)) + { + pw = decryptPassword(pw); + + if (pw) + { + char *newpw = create_hex_sha1_sha1_passwd(pw); + + if (newpw) + { + add_mysql_users_with_host_ipv4(port->users, user, "%", newpw, "Y", ""); + add_mysql_users_with_host_ipv4(port->users, user, "localhost", newpw, "Y", ""); + MXS_FREE(newpw); + rval = true; + } + MXS_FREE(pw); + } + else + { + MXS_ERROR("[%s] Failed to decrypt service user password.", port->service->name); + } + } + else + { + MXS_ERROR("[%s] Failed to retrieve service credentials.", port->service->name); + } + + return rval; +} + /** * @brief Load MySQL authentication users * @@ -871,6 +919,16 @@ static int mysql_auth_load_users(SERV_LISTENER *port) { MXS_WARNING("Using cached credential information."); } + + if (instance->inject_service_user) + { + /** Inject the service user as a 'backup' user that's available + * if loading of the users fails */ + if (!add_service_user(port)) + { + MXS_ERROR("[%s] Failed to inject service user.", port->service->name); + } + } } else { diff --git a/server/modules/routing/binlog/blr.c b/server/modules/routing/binlog/blr.c index 47909e625..213b9eb87 100644 --- a/server/modules/routing/binlog/blr.c +++ b/server/modules/routing/binlog/blr.c @@ -1790,7 +1790,7 @@ static void rses_end_locked_router_action(ROUTER_SLAVE *rses) static uint64_t getCapabilities() { - return (RCAP_TYPE_NO_RSESSION | RCAP_TYPE_NO_USERS_INIT); + return RCAP_TYPE_NO_RSESSION; } /**