Commit 9e1923ca authored by Hugo Wen's avatar Hugo Wen Committed by Andrew Hutchings

Extend Unix socket authentication to support authentication_string

Before this change the unix socket auth plugin returned true only when
the OS socket user id matches the MariaDB user name.
The authentication string was ignored.

Now if an authentication string is defined with in `unix_socket`
authentication rule, then the authentication string will be used to
compare with the socket's user name, and the plugin will return a
positive if matching.

Make the plugin to fill in the @@external_user variable.

This change is similar to MySQL commit of
https://github.com/mysql/mysql-server/commit/6ddbc58e.
However there's one difference with above commit:

- For MySQL, both Unix user matches DB user name and Unix user matches the
  authentication string will be allowed to connect.
- For MariaDB, we only allows the Unix user matches the authentication
  string to connect, if the authentication string is defined.
  This is because allowing both Unix user names has risks and couldn't
  handle the case that a customer only wants to allow one single Unix user
  to connect which doesn't matches the DB user name.

If DB user is created with multiple unix_socket options for example:
`create user A identified via unix_socket as 'B' or unix_socket as 'C';`
Then both Unix user of B and C are accepted.

Existing MTR test of `plugins.unix_socket` is not impacted.
Also add a new MTR test to verify authentication with authentication
string. See the MTR test cases for supported/unsupported cases.

All new code of the whole pull request, including one or several files
that are either new files or modified ones, are contributed under the
BSD-new license. I am contributing on behalf of my employer Amazon Web
Services, Inc.
parent 25b5c639
########################################################################
# Test for case:
# - create user A identified via unix_socket as 'B' or unix_socket as 'C';
# - connect as database user A using unix user of B
# Expected result:
# - connection succeed
########################################################################
create user 'DB_USER1' identified via unix_socket as 'OS_USER' or unix_socket as '-Cannot-Match-Any-Legal-Unix-User-Name';
grant select on test.* to 'DB_USER1';
#
# Auth succeed with OS user matches the first authentication string.
# @@external_user is set to OS_USER name.
#
select user(), current_user(), database();
user() current_user() database()
DB_USER1@localhost DB_USER1@% test
select @@external_user;
@@external_user
OS_USER
select host, user, json_value(priv, '$.authentication_string') as authentication_string,
json_value(priv, '$.auth_or[0].authentication_string') as optional_authentication_string from mysql.global_priv where user='DB_USER1';
host user authentication_string optional_authentication_string
% DB_USER1 -Cannot-Match-Any-Legal-Unix-User-Name OS_USER
########################################################################
# Test for case:
# - create user A identified via unix_socket as 'B' or unix_socket as 'C';
# - connect as database user A using unix user of C
# Expected result:
# - connection succeed
########################################################################
create user 'DB_USER2' identified via unix_socket as '-Cannot-Match-Any-Legal-Unix-User-Name' or unix_socket as 'OS_USER';
grant select on test.* to 'DB_USER2';
#
# Auth succeed with OS user matches the optional authentication string.
# @@external_user is set to OS_USER name.
#
select user(), current_user(), database();
user() current_user() database()
DB_USER2@localhost DB_USER2@% test
select @@external_user;
@@external_user
OS_USER
select host, user, json_value(priv, '$.authentication_string') as authentication_string,
json_value(priv, '$.auth_or[0].authentication_string') as optional_authentication_string from mysql.global_priv where user='DB_USER1';
host user authentication_string optional_authentication_string
% DB_USER1 -Cannot-Match-Any-Legal-Unix-User-Name OS_USER
########################################################################
# Test for case:
# - create user A identified via unix_socket as 'B';
# - connect as database user A using unix user of D
# Expected result:
# - connection is refused
########################################################################
create user 'DB_USER3' identified via unix_socket as '-Cannot-Match-Any-Legal-Unix-User-Name';
grant select on test.* to 'DB_USER3';
#
# Auth fail with OS user that does not match the authentication string.
#
#
########################################################################
# Test for case:
# - create user A identified via unix_socket as 'B' or unix_socket as 'C';
# - connect as database user A using unix user of D
# Expected result:
# - connection is refused
########################################################################
create user 'DB_USER4' identified via unix_socket as '-Cannot-Match-Any-Legal-Unix-User-Name-1'
or unix_socket as '-Cannot-Match-Any-Legal-Unix-User-Name-2';
grant select on test.* to 'DB_USER4';
#
# Auth fail with OS user that does not match the authentication string.
#
select host, user, json_value(priv, '$.authentication_string') as authentication_string,
json_value(priv, '$.auth_or[0].authentication_string') as optional_authentication_string from mysql.global_priv where user='DB_USER1';
host user authentication_string optional_authentication_string
% DB_USER1 -Cannot-Match-Any-Legal-Unix-User-Name OS_USER
########################################################################
# Test for case:
# - create user A identified via unix_socket as 'B' or unix_socket as 'C' or unix_socket as 'D' or unix_socket as 'E' or unix_socket as 'F';
# - connect as database user A using unix user of 'D'
# Expected result:
# - connection succeed
########################################################################
create user 'DB_USER5' identified via unix_socket as '-Cannot-Match-Any-Legal-Unix-User-Name-B'
or unix_socket as '-Cannot-Match-Any-Legal-Unix-User-Name-C'
or unix_socket as 'OS_USER'
or unix_socket as '-Cannot-Match-Any-Legal-Unix-User-Name-E'
or unix_socket as '-Cannot-Match-Any-Legal-Unix-User-Name-F';
grant select on test.* to 'DB_USER5';
#
# Auth succeed with OS user matches the first authentication string.
# @@external_user is set to OS_USER name.
#
select user(), current_user(), database();
user() current_user() database()
DB_USER5@localhost DB_USER5@% test
select @@external_user;
@@external_user
OS_USER
select host, user, json_value(priv, '$.authentication_string') as authentication_string,
json_value(priv, '$.auth_or[0].authentication_string') as optional_authentication_string_0,
json_value(priv, '$.auth_or[1].authentication_string') as optional_authentication_string_1,
json_value(priv, '$.auth_or[2].authentication_string') as optional_authentication_string_2,
json_value(priv, '$.auth_or[3].authentication_string') as optional_authentication_string_3
from mysql.global_priv where user='DB_USER5';
host user authentication_string optional_authentication_string_0 optional_authentication_string_1 optional_authentication_string_2 optional_authentication_string_3
% DB_USER5 -Cannot-Match-Any-Legal-Unix-User-Name-F -Cannot-Match-Any-Legal-Unix-User-Name-B -Cannot-Match-Any-Legal-Unix-User-Name-C OS_USER -Cannot-Match-Any-Legal-Unix-User-Name-E
########################################################################
# Test for case:
# - create user A identified via unix_socket as 'B';
# - connect as database user A using unix user of A
# Expected result:
# - connection is rejected
########################################################################
#
# Create DB user different with the OS user name, but using OS user name as the authentication string.
#
create user 'OS_USER' identified via unix_socket as '-Cannot-Match-Any-Legal-Unix-User-Name';
grant select on test.* to 'OS_USER';
#
# Auth fail with OS user that does not match the authentication string.
#
########################################################################
# Removing the test user.
########################################################################
drop user 'DB_USER1';
drop user 'DB_USER2';
drop user 'DB_USER3';
drop user 'DB_USER4';
drop user 'DB_USER5';
drop user 'OS_USER';
FLUSH PRIVILEGES;
########################################################################
# Removing the test file.
########################################################################
--source include/have_unix_socket.inc
--let $OS_USER=$USER
--write_file $MYSQLTEST_VARDIR/tmp/peercred_test.txt
select user(), current_user(), database();
select @@external_user;
EOF
--echo ########################################################################
--echo # Test for case:
--echo # - create user A identified via unix_socket as 'B' or unix_socket as 'C';
--echo # - connect as database user A using unix user of B
--echo # Expected result:
--echo # - connection succeed
--echo ########################################################################
--replace_result $OS_USER "OS_USER"
eval create user 'DB_USER1' identified via unix_socket as '$OS_USER' or unix_socket as '-Cannot-Match-Any-Legal-Unix-User-Name';
--replace_result $OS_USER "OS_USER"
eval grant select on test.* to 'DB_USER1';
--echo #
--echo # Auth succeed with OS user matches the first authentication string.
--echo # @@external_user is set to OS_USER name.
--echo #
--replace_result $OS_USER "OS_USER"
--exec $MYSQL_TEST -u DB_USER1 < $MYSQLTEST_VARDIR/tmp/peercred_test.txt
--replace_result $OS_USER "OS_USER"
select host, user, json_value(priv, '$.authentication_string') as authentication_string,
json_value(priv, '$.auth_or[0].authentication_string') as optional_authentication_string from mysql.global_priv where user='DB_USER1';
--echo
--echo ########################################################################
--echo # Test for case:
--echo # - create user A identified via unix_socket as 'B' or unix_socket as 'C';
--echo # - connect as database user A using unix user of C
--echo # Expected result:
--echo # - connection succeed
--echo ########################################################################
--replace_result $OS_USER "OS_USER"
eval create user 'DB_USER2' identified via unix_socket as '-Cannot-Match-Any-Legal-Unix-User-Name' or unix_socket as '$OS_USER';
--replace_result $OS_USER "OS_USER"
eval grant select on test.* to 'DB_USER2';
--echo #
--echo # Auth succeed with OS user matches the optional authentication string.
--echo # @@external_user is set to OS_USER name.
--echo #
--replace_result $OS_USER "OS_USER"
--exec $MYSQL_TEST -u DB_USER2 < $MYSQLTEST_VARDIR/tmp/peercred_test.txt
--replace_result $OS_USER "OS_USER"
select host, user, json_value(priv, '$.authentication_string') as authentication_string,
json_value(priv, '$.auth_or[0].authentication_string') as optional_authentication_string from mysql.global_priv where user='DB_USER1';
--echo
--echo ########################################################################
--echo # Test for case:
--echo # - create user A identified via unix_socket as 'B';
--echo # - connect as database user A using unix user of D
--echo # Expected result:
--echo # - connection is refused
--echo ########################################################################
eval create user 'DB_USER3' identified via unix_socket as '-Cannot-Match-Any-Legal-Unix-User-Name';
eval grant select on test.* to 'DB_USER3';
--echo #
--echo # Auth fail with OS user that does not match the authentication string.
--echo #
--error 1
--exec $MYSQL_TEST -u DB_USER3 < $MYSQLTEST_VARDIR/tmp/peercred_test.txt
--echo #
--echo ########################################################################
--echo # Test for case:
--echo # - create user A identified via unix_socket as 'B' or unix_socket as 'C';
--echo # - connect as database user A using unix user of D
--echo # Expected result:
--echo # - connection is refused
--echo ########################################################################
eval create user 'DB_USER4' identified via unix_socket as '-Cannot-Match-Any-Legal-Unix-User-Name-1'
or unix_socket as '-Cannot-Match-Any-Legal-Unix-User-Name-2';
eval grant select on test.* to 'DB_USER4';
--echo #
--echo # Auth fail with OS user that does not match the authentication string.
--echo #
--error 1
--exec $MYSQL_TEST -u DB_USER4 < $MYSQLTEST_VARDIR/tmp/peercred_test.txt
--replace_result $OS_USER "OS_USER"
select host, user, json_value(priv, '$.authentication_string') as authentication_string,
json_value(priv, '$.auth_or[0].authentication_string') as optional_authentication_string from mysql.global_priv where user='DB_USER1';
--echo ########################################################################
--echo # Test for case:
--echo # - create user A identified via unix_socket as 'B' or unix_socket as 'C' or unix_socket as 'D' or unix_socket as 'E' or unix_socket as 'F';
--echo # - connect as database user A using unix user of 'D'
--echo # Expected result:
--echo # - connection succeed
--echo ########################################################################
--replace_result $OS_USER "OS_USER"
eval create user 'DB_USER5' identified via unix_socket as '-Cannot-Match-Any-Legal-Unix-User-Name-B'
or unix_socket as '-Cannot-Match-Any-Legal-Unix-User-Name-C'
or unix_socket as '$OS_USER'
or unix_socket as '-Cannot-Match-Any-Legal-Unix-User-Name-E'
or unix_socket as '-Cannot-Match-Any-Legal-Unix-User-Name-F';
--replace_result $OS_USER "OS_USER"
eval grant select on test.* to 'DB_USER5';
--echo #
--echo # Auth succeed with OS user matches the first authentication string.
--echo # @@external_user is set to OS_USER name.
--echo #
--replace_result $OS_USER "OS_USER"
--exec $MYSQL_TEST -u DB_USER5 < $MYSQLTEST_VARDIR/tmp/peercred_test.txt
--replace_result $OS_USER "OS_USER"
select host, user, json_value(priv, '$.authentication_string') as authentication_string,
json_value(priv, '$.auth_or[0].authentication_string') as optional_authentication_string_0,
json_value(priv, '$.auth_or[1].authentication_string') as optional_authentication_string_1,
json_value(priv, '$.auth_or[2].authentication_string') as optional_authentication_string_2,
json_value(priv, '$.auth_or[3].authentication_string') as optional_authentication_string_3
from mysql.global_priv where user='DB_USER5';
--echo
--echo ########################################################################
--echo # Test for case:
--echo # - create user A identified via unix_socket as 'B';
--echo # - connect as database user A using unix user of A
--echo # Expected result:
--echo # - connection is rejected
--echo ########################################################################
--echo #
--echo # Create DB user different with the OS user name, but using OS user name as the authentication string.
--echo #
--replace_result $OS_USER "OS_USER"
eval create user '$OS_USER' identified via unix_socket as '-Cannot-Match-Any-Legal-Unix-User-Name';
--replace_result $OS_USER "OS_USER"
eval grant select on test.* to '$OS_USER';
--echo #
--echo # Auth fail with OS user that does not match the authentication string.
--echo #
--error 1
--exec $MYSQL_TEST -u $OS_USER < $MYSQLTEST_VARDIR/tmp/peercred_test.txt
--echo
--echo ########################################################################
--echo # Removing the test user.
--echo ########################################################################
eval drop user 'DB_USER1';
eval drop user 'DB_USER2';
eval drop user 'DB_USER3';
eval drop user 'DB_USER4';
eval drop user 'DB_USER5';
--replace_result $OS_USER "OS_USER"
eval drop user '$OS_USER';
FLUSH PRIVILEGES;
--echo ########################################################################
--echo # Removing the test file.
--echo ########################################################################
--remove_file $MYSQLTEST_VARDIR/tmp/peercred_test.txt
......@@ -119,13 +119,20 @@ static int socket_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
u = cred.uid;
#endif
/* and find the username for this uid */
/* and find the socket user name for this uid */
getpwuid_r(u, &pwd_buf, buf, sizeof(buf), &pwd);
if (pwd == NULL)
return CR_ERROR;
/* now it's simple as that */
return strcmp(pwd->pw_name, info->user_name) ? CR_ERROR : CR_OK;
/* fill in the external user name used */
strncpy(info->external_user, pwd->pw_name, sizeof(info->external_user) - 1);
info->external_user[sizeof(info->external_user) - 1]= '\0';
/* compare with auth_string if it's defined, otherwise compare with DB user name*/
if (info->auth_string && info->auth_string[0])
return !strcmp(pwd->pw_name, info->auth_string) ? CR_OK : CR_ERROR;
else
return !strcmp(pwd->pw_name, info->user_name) ? CR_OK : CR_ERROR;
}
static struct st_mysql_auth socket_auth_handler=
......@@ -146,10 +153,10 @@ maria_declare_plugin(auth_socket)
PLUGIN_LICENSE_GPL,
NULL,
NULL,
0x0100,
0x0101,
NULL,
NULL,
"1.0",
"1.1",
MariaDB_PLUGIN_MATURITY_STABLE
}
maria_declare_plugin_end;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment