MXS-1600: Add case-insensitive matching to MySQLAuth
The authenticator now supports similar identifier matching as the MariaDB server. The lower_case_table_names parameter explains its intended use (case-insensitive identifier matching): https://mariadb.com/kb/en/library/server-system-variables/#lower_case_table_names
This commit is contained in:
@ -67,3 +67,16 @@ injected into the list of users.
|
|||||||
```
|
```
|
||||||
authenticator_options=inject_service_user=false
|
authenticator_options=inject_service_user=false
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `lower_case_table_names`
|
||||||
|
|
||||||
|
Enable case-insensitive identifier matching for authentication. This parameter
|
||||||
|
is disabled by default.
|
||||||
|
|
||||||
|
The parameter functions exactly as the MariaDB Server system variable
|
||||||
|
[lower_case_table_names](https://mariadb.com/kb/en/library/server-system-variables/#lower_case_table_names).
|
||||||
|
This makes the matching done by the authenticator on database names to be
|
||||||
|
case-insensitive by converting all names into their lowercase form.
|
||||||
|
|
||||||
|
**Note:** The identifier names are converted using an ASCII-only function. This
|
||||||
|
means that non-ASCII characters will retain their case-sensitivity.
|
||||||
|
|||||||
@ -186,7 +186,10 @@ int validate_mysql_user(MYSQL_AUTH* instance, DCB *dcb, MYSQL_session *session,
|
|||||||
uint8_t *scramble, size_t scramble_len)
|
uint8_t *scramble, size_t scramble_len)
|
||||||
{
|
{
|
||||||
sqlite3 *handle = instance->handle;
|
sqlite3 *handle = instance->handle;
|
||||||
size_t len = sizeof(mysqlauth_validate_user_query) + strlen(session->user) * 2 +
|
const char* validate_query = instance->lower_case_table_names ?
|
||||||
|
mysqlauth_validate_user_query_lower :
|
||||||
|
mysqlauth_validate_user_query;
|
||||||
|
size_t len = strlen(validate_query) + 1 + strlen(session->user) * 2 +
|
||||||
strlen(session->db) * 2 + MYSQL_HOST_MAXLEN + session->auth_token_len * 4 + 1;
|
strlen(session->db) * 2 + MYSQL_HOST_MAXLEN + session->auth_token_len * 4 + 1;
|
||||||
char sql[len + 1];
|
char sql[len + 1];
|
||||||
int rval = MXS_AUTH_FAILED;
|
int rval = MXS_AUTH_FAILED;
|
||||||
@ -198,7 +201,7 @@ int validate_mysql_user(MYSQL_AUTH* instance, DCB *dcb, MYSQL_session *session,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sprintf(sql, mysqlauth_validate_user_query, session->user, dcb->remote,
|
sprintf(sql, validate_query, session->user, dcb->remote,
|
||||||
dcb->remote, session->db, session->db);
|
dcb->remote, session->db, session->db);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,7 +217,7 @@ int validate_mysql_user(MYSQL_AUTH* instance, DCB *dcb, MYSQL_session *session,
|
|||||||
if (!res.ok && strchr(dcb->remote, ':') && strchr(dcb->remote, '.'))
|
if (!res.ok && strchr(dcb->remote, ':') && strchr(dcb->remote, '.'))
|
||||||
{
|
{
|
||||||
const char *ipv4 = strrchr(dcb->remote, ':') + 1;
|
const char *ipv4 = strrchr(dcb->remote, ':') + 1;
|
||||||
sprintf(sql, mysqlauth_validate_user_query, session->user, ipv4, ipv4,
|
sprintf(sql, validate_query, session->user, ipv4, ipv4,
|
||||||
session->db, session->db);
|
session->db, session->db);
|
||||||
|
|
||||||
if (sqlite3_exec(handle, sql, auth_cb, &res, &err) != SQLITE_OK)
|
if (sqlite3_exec(handle, sql, auth_cb, &res, &err) != SQLITE_OK)
|
||||||
@ -233,7 +236,7 @@ int validate_mysql_user(MYSQL_AUTH* instance, DCB *dcb, MYSQL_session *session,
|
|||||||
char client_hostname[MYSQL_HOST_MAXLEN] = "";
|
char client_hostname[MYSQL_HOST_MAXLEN] = "";
|
||||||
get_hostname(dcb, client_hostname, sizeof(client_hostname) - 1);
|
get_hostname(dcb, client_hostname, sizeof(client_hostname) - 1);
|
||||||
|
|
||||||
sprintf(sql, mysqlauth_validate_user_query, session->user, client_hostname,
|
sprintf(sql, validate_query, session->user, client_hostname,
|
||||||
client_hostname, session->db, session->db);
|
client_hostname, session->db, session->db);
|
||||||
|
|
||||||
if (sqlite3_exec(handle, sql, auth_cb, &res, &err) != SQLITE_OK)
|
if (sqlite3_exec(handle, sql, auth_cb, &res, &err) != SQLITE_OK)
|
||||||
|
|||||||
@ -183,6 +183,7 @@ static void* mysql_auth_init(char **options)
|
|||||||
instance->cache_dir = NULL;
|
instance->cache_dir = NULL;
|
||||||
instance->inject_service_user = true;
|
instance->inject_service_user = true;
|
||||||
instance->skip_auth = false;
|
instance->skip_auth = false;
|
||||||
|
instance->lower_case_table_names = false;
|
||||||
instance->handle = NULL;
|
instance->handle = NULL;
|
||||||
|
|
||||||
for (int i = 0; options[i]; i++)
|
for (int i = 0; options[i]; i++)
|
||||||
@ -209,6 +210,10 @@ static void* mysql_auth_init(char **options)
|
|||||||
{
|
{
|
||||||
instance->skip_auth = config_truth_value(value);
|
instance->skip_auth = config_truth_value(value);
|
||||||
}
|
}
|
||||||
|
else if (strcmp(options[i], "lower_case_table_names") == 0)
|
||||||
|
{
|
||||||
|
instance->lower_case_table_names = config_truth_value(value);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MXS_ERROR("Unknown authenticator option: %s", options[i]);
|
MXS_ERROR("Unknown authenticator option: %s", options[i]);
|
||||||
|
|||||||
@ -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)"
|
" WHERE user = '%s' AND ( '%s' = host OR '%s' LIKE host) AND (anydb = '1' OR '%s' = '' OR '%s' LIKE db)"
|
||||||
" LIMIT 1";
|
" LIMIT 1";
|
||||||
|
|
||||||
|
/** Query that checks if there's a grant for the user being authenticated */
|
||||||
|
static const char mysqlauth_validate_user_query_lower[] =
|
||||||
|
"SELECT password FROM " MYSQLAUTH_USERS_TABLE_NAME
|
||||||
|
" WHERE user = '%s' AND ( '%s' = host OR '%s' LIKE host) AND (anydb = '1' OR '%s' = '' OR LOWER('%s') LIKE LOWER(db))"
|
||||||
|
" LIMIT 1";
|
||||||
|
|
||||||
/** Query that only checks if there's a matching user */
|
/** Query that only checks if there's a matching user */
|
||||||
static const char mysqlauth_skip_auth_query[] =
|
static const char mysqlauth_skip_auth_query[] =
|
||||||
"SELECT password FROM " MYSQLAUTH_USERS_TABLE_NAME
|
"SELECT password FROM " MYSQLAUTH_USERS_TABLE_NAME
|
||||||
@ -106,10 +112,11 @@ static int db_flags = SQLITE_OPEN_READWRITE |
|
|||||||
|
|
||||||
typedef struct mysql_auth
|
typedef struct mysql_auth
|
||||||
{
|
{
|
||||||
sqlite3 *handle; /**< SQLite3 database handle */
|
sqlite3 *handle; /**< SQLite3 database handle */
|
||||||
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 */
|
bool inject_service_user; /**< Inject the service user into the list of users */
|
||||||
bool skip_auth; /**< Authentication will always be successful */
|
bool skip_auth; /**< Authentication will always be successful */
|
||||||
|
bool lower_case_table_names; /**< Disable database case-sensitivity */
|
||||||
} MYSQL_AUTH;
|
} MYSQL_AUTH;
|
||||||
|
|
||||||
/** Common structure for both backend and client authenticators */
|
/** Common structure for both backend and client authenticators */
|
||||||
|
|||||||
Reference in New Issue
Block a user