Skip to content

Commit ed94038

Browse files
Merge pull request #5562 from percona-ysorokin/dev/PS-9024-8.0-audit_log_filter_host_wildcards
PS-9033 and PS-9024 fixes: audit_log_filter_set_user does not allow wildcards in hostname (8.0)
2 parents 815afe0 + 9227a43 commit ed94038

13 files changed

+499
-19
lines changed

plugin/audit_log_filter/audit_log_filter.cc

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -605,24 +605,28 @@ bool AuditLogFilter::get_connection_user(Security_context_handle &ctx,
605605
MYSQL_LEX_CSTRING user{"", 0};
606606
MYSQL_LEX_CSTRING host{"", 0};
607607

608-
if (m_security_context_opts_srv->get(ctx, "user", &user)) {
608+
if (m_security_context_opts_srv->get(ctx, "priv_user", &user)) {
609609
LogPluginErr(ERROR_LEVEL, ER_LOG_PRINTF_MSG,
610610
"Can not get user name from security context");
611611
return false;
612612
}
613613

614-
if (m_security_context_opts_srv->get(ctx, "host", &host)) {
614+
if (m_security_context_opts_srv->get(ctx, "priv_host", &host)) {
615615
LogPluginErr(ERROR_LEVEL, ER_LOG_PRINTF_MSG,
616616
"Can not get user host from security context");
617617
return false;
618618
}
619619

620-
if (user.length == 0 || host.length == 0) {
621-
return false;
620+
if (user.length == 0) {
621+
user_name.clear();
622+
} else {
623+
user_name.assign(user.str, user.length);
624+
}
625+
if (host.length == 0) {
626+
user_host.clear();
627+
} else {
628+
user_host.assign(host.str, host.length);
622629
}
623-
624-
user_name = user.str;
625-
user_host = host.str;
626630

627631
return true;
628632
}

plugin/audit_log_filter/audit_udf.cc

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ std::unique_ptr<UserNameInfo> check_parse_user_name_host(
7373

7474
const std::regex user_name_all_regex("^%$");
7575
const std::regex user_name_regex("(.*)@(.*)");
76-
const std::regex deprecated_symbols_regex("[\\*|\\%]");
76+
const std::regex deprecated_account_name_characters_regex("[*|%]");
77+
const std::regex deprecated_host_name_characters_regex("[*|]");
7778

7879
auto user_info_data = std::make_unique<UserNameInfo>();
7980

@@ -107,13 +108,15 @@ std::unique_ptr<UserNameInfo> check_parse_user_name_host(
107108
return nullptr;
108109
}
109110

110-
if (std::regex_search(user_name_match.str(), deprecated_symbols_regex)) {
111+
if (std::regex_search(user_name_match.str(),
112+
deprecated_account_name_characters_regex)) {
111113
std::snprintf(message, MYSQL_ERRMSG_SIZE,
112114
"Wrong argument: bad user name format");
113115
return nullptr;
114116
}
115117

116-
if (std::regex_search(user_host_match.str(), deprecated_symbols_regex)) {
118+
if (std::regex_search(user_host_match.str(),
119+
deprecated_host_name_characters_regex)) {
117120
std::snprintf(message, MYSQL_ERRMSG_SIZE,
118121
"Wrong argument: bad host name format");
119122
return nullptr;

plugin/audit_log_filter/log_record_formatter/json.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ AuditRecordString LogRecordFormatterJson::apply(
406406
<< "\",\n"
407407
<< R"( "status": )" << audit_record.event->status << ",\n"
408408
<< R"( "db": ")"
409-
<< make_escaped_string(&audit_record.event->database) << "\""
409+
<< make_escaped_string(&audit_record.event->database) << "\"\n"
410410
<< " }" << extra_attrs_to_string(audit_record.extended_info)
411411
<< "\n }";
412412

@@ -921,7 +921,7 @@ std::string LogRecordFormatterJson::extra_attrs_to_string(
921921
is_first_attr = false;
922922
}
923923

924-
result << "}";
924+
result << "\n }";
925925
}
926926

927927
return result.str();
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
CREATE USER ''@'127.0.0.1';
2+
SET @filter = '{
3+
"filter": {
4+
"class": {
5+
"name": "connection",
6+
"event": {
7+
"name": "connect"
8+
}
9+
}
10+
}
11+
}';
12+
SELECT audit_log_filter_set_filter('log_connect', @filter);
13+
audit_log_filter_set_filter('log_connect', @filter)
14+
OK
15+
###
16+
### 1. Connecting as an anonymous user with no rules set
17+
###
18+
SET @audit_filter_log_name = audit_log_rotate();
19+
USER() CURRENT_USER()
20+
foobarbaz@localhost @127.0.0.1
21+
SET @audit_filter_log_name = audit_log_rotate();
22+
SET @content = CAST(CONVERT(LOAD_FILE(CONCAT(@@global.datadir, @audit_filter_log_name)) USING ascii) AS JSON);
23+
###
24+
### 2. Connecting as an anonymous user with default rule set
25+
###
26+
SELECT audit_log_filter_set_user('%', 'log_connect');
27+
audit_log_filter_set_user('%', 'log_connect')
28+
OK
29+
SET @audit_filter_log_name = audit_log_rotate();
30+
USER() CURRENT_USER()
31+
foobarbaz@localhost @127.0.0.1
32+
SET @audit_filter_log_name = audit_log_rotate();
33+
SET @content = CAST(CONVERT(LOAD_FILE(CONCAT(@@global.datadir, @audit_filter_log_name)) USING ascii) AS JSON);
34+
###
35+
### 3. Connecting as an anonymous user with a dedicated rule for this anonymous user
36+
###
37+
SELECT audit_log_filter_remove_user('%');
38+
audit_log_filter_remove_user('%')
39+
OK
40+
SELECT audit_log_filter_set_user('@127.0.0.1', 'log_connect');
41+
audit_log_filter_set_user('@127.0.0.1', 'log_connect')
42+
OK
43+
SET @audit_filter_log_name = audit_log_rotate();
44+
USER() CURRENT_USER()
45+
foobarbaz@localhost @127.0.0.1
46+
SET @audit_filter_log_name = audit_log_rotate();
47+
SET @content = CAST(CONVERT(LOAD_FILE(CONCAT(@@global.datadir, @audit_filter_log_name)) USING ascii) AS JSON);
48+
SELECT audit_log_filter_remove_user('@127.0.0.1');
49+
audit_log_filter_remove_user('@127.0.0.1')
50+
OK
51+
DROP USER ''@'127.0.0.1';
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
SET @filter = '{
2+
"filter": {
3+
"class": {
4+
"name": "connection",
5+
"event": {
6+
"name": "connect"
7+
}
8+
}
9+
}
10+
}';
11+
SELECT audit_log_filter_set_filter('log_connect', @filter);
12+
audit_log_filter_set_filter('log_connect', @filter)
13+
OK
14+
###
15+
### 1.1 IPv4 and IPv6 users, default audit log rule
16+
###
17+
CREATE USER 'usr'@'127.0.0.1' IDENTIFIED BY 'password';
18+
CREATE USER 'usr'@'::1' IDENTIFIED BY 'password';
19+
SELECT audit_log_filter_set_user('%', 'log_connect');
20+
audit_log_filter_set_user('%', 'log_connect')
21+
OK
22+
SET @audit_filter_log_name = audit_log_rotate();
23+
USER() CURRENT_USER()
24+
usr@localhost [email protected]
25+
USER() CURRENT_USER()
26+
usr@localhost usr@::1
27+
SET @audit_filter_log_name = audit_log_rotate();
28+
SET @content = CAST(CONVERT(LOAD_FILE(CONCAT(@@global.datadir, @audit_filter_log_name)) USING ascii) AS JSON);
29+
###
30+
### 1.2 IPv4 and wildcard users, default audit log rule
31+
###
32+
DROP USER 'usr'@'::1';
33+
CREATE USER 'usr'@'%' IDENTIFIED BY 'password';
34+
USER() CURRENT_USER()
35+
usr@localhost [email protected]
36+
USER() CURRENT_USER()
37+
usr@localhost usr@%
38+
SET @audit_filter_log_name = audit_log_rotate();
39+
SET @content = CAST(CONVERT(LOAD_FILE(CONCAT(@@global.datadir, @audit_filter_log_name)) USING ascii) AS JSON);
40+
###
41+
### 1.3 Only wildcard user, default audit log rule
42+
###
43+
DROP USER 'usr'@'127.0.0.1';
44+
USER() CURRENT_USER()
45+
usr@localhost usr@%
46+
USER() CURRENT_USER()
47+
usr@localhost usr@%
48+
SET @audit_filter_log_name = audit_log_rotate();
49+
SET @content = CAST(CONVERT(LOAD_FILE(CONCAT(@@global.datadir, @audit_filter_log_name)) USING ascii) AS JSON);
50+
###
51+
### 2.1 Only wildcard user, IPv4 audit log rule
52+
###
53+
SELECT audit_log_filter_remove_user('%');
54+
audit_log_filter_remove_user('%')
55+
OK
56+
SELECT audit_log_filter_set_user('[email protected]', 'log_connect');
57+
audit_log_filter_set_user('[email protected]', 'log_connect')
58+
OK
59+
USER() CURRENT_USER()
60+
usr@localhost usr@%
61+
USER() CURRENT_USER()
62+
usr@localhost usr@%
63+
SET @audit_filter_log_name = audit_log_rotate();
64+
SET @content = CAST(CONVERT(LOAD_FILE(CONCAT(@@global.datadir, @audit_filter_log_name)) USING ascii) AS JSON);
65+
###
66+
### 2.2 IPv4 and wildcard users, IPv4 audit log rule
67+
###
68+
CREATE USER 'usr'@'127.0.0.1' IDENTIFIED BY 'password';
69+
USER() CURRENT_USER()
70+
usr@localhost [email protected]
71+
USER() CURRENT_USER()
72+
usr@localhost usr@%
73+
SET @audit_filter_log_name = audit_log_rotate();
74+
SET @content = CAST(CONVERT(LOAD_FILE(CONCAT(@@global.datadir, @audit_filter_log_name)) USING ascii) AS JSON);
75+
###
76+
### 2.3 IPv4 and IPv6 users, IPv4 audit log rule
77+
###
78+
DROP USER 'usr'@'%';
79+
CREATE USER 'usr'@'::1' IDENTIFIED BY 'password';
80+
USER() CURRENT_USER()
81+
usr@localhost [email protected]
82+
USER() CURRENT_USER()
83+
usr@localhost usr@::1
84+
SET @audit_filter_log_name = audit_log_rotate();
85+
SET @content = CAST(CONVERT(LOAD_FILE(CONCAT(@@global.datadir, @audit_filter_log_name)) USING ascii) AS JSON);
86+
###
87+
### 3.1 IPv4 and IPv6 users, wildcard audit log rule
88+
###
89+
SELECT audit_log_filter_remove_user('[email protected]');
90+
audit_log_filter_remove_user('[email protected]')
91+
OK
92+
SELECT audit_log_filter_set_user('usr@%', 'log_connect');
93+
audit_log_filter_set_user('usr@%', 'log_connect')
94+
OK
95+
SET @audit_filter_log_name = audit_log_rotate();
96+
USER() CURRENT_USER()
97+
usr@localhost [email protected]
98+
USER() CURRENT_USER()
99+
usr@localhost usr@::1
100+
SET @audit_filter_log_name = audit_log_rotate();
101+
SET @content = CAST(CONVERT(LOAD_FILE(CONCAT(@@global.datadir, @audit_filter_log_name)) USING ascii) AS JSON);
102+
###
103+
### 3.2 IPv4 and wildcard users, wildcard audit log rule
104+
###
105+
DROP USER 'usr'@'::1';
106+
CREATE USER 'usr'@'%' IDENTIFIED BY 'password';
107+
USER() CURRENT_USER()
108+
usr@localhost [email protected]
109+
USER() CURRENT_USER()
110+
usr@localhost usr@%
111+
SET @audit_filter_log_name = audit_log_rotate();
112+
SET @content = CAST(CONVERT(LOAD_FILE(CONCAT(@@global.datadir, @audit_filter_log_name)) USING ascii) AS JSON);
113+
###
114+
### 3.3 Only wildcard user, wildcard audit log rule
115+
###
116+
DROP USER 'usr'@'127.0.0.1';
117+
USER() CURRENT_USER()
118+
usr@localhost usr@%
119+
USER() CURRENT_USER()
120+
usr@localhost usr@%
121+
SET @audit_filter_log_name = audit_log_rotate();
122+
SET @content = CAST(CONVERT(LOAD_FILE(CONCAT(@@global.datadir, @audit_filter_log_name)) USING ascii) AS JSON);
123+
SELECT audit_log_filter_remove_user('usr@%');
124+
audit_log_filter_remove_user('usr@%')
125+
OK
126+
DROP USER 'usr'@'%';

plugin/audit_log_filter/tests/mtr/r/udf_audit_log_filter_set_user.result

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,17 @@ ERROR HY000: Can't initialize function 'audit_log_filter_set_user'; Wrong argume
3535
SELECT audit_log_filter_set_user('aaaaaa', 'filter_1');
3636
ERROR HY000: Can't initialize function 'audit_log_filter_set_user'; Wrong argument: wrong user_name format, it should be in user_name@host_name format, or '%' to represent the default account
3737
#
38-
# Wildcards are not allowed in user or host name
38+
# [*|%] characters are not allowed in user name
39+
# [*|] characters are not allowed in host name
3940
SELECT audit_log_filter_set_user('user%@localhost', 'filter_1');
4041
ERROR HY000: Can't initialize function 'audit_log_filter_set_user'; Wrong argument: bad user name format
4142
SELECT audit_log_filter_set_user('user*@localhost', 'filter_1');
4243
ERROR HY000: Can't initialize function 'audit_log_filter_set_user'; Wrong argument: bad user name format
43-
SELECT audit_log_filter_set_user('user@host%', 'filter_1');
44+
SELECT audit_log_filter_set_user('user@host|', 'filter_1');
4445
ERROR HY000: Can't initialize function 'audit_log_filter_set_user'; Wrong argument: bad host name format
4546
SELECT audit_log_filter_set_user('user@host*', 'filter_1');
4647
ERROR HY000: Can't initialize function 'audit_log_filter_set_user'; Wrong argument: bad host name format
47-
SELECT audit_log_filter_set_user('user@%', 'filter_1');
48+
SELECT audit_log_filter_set_user('user@|', 'filter_1');
4849
ERROR HY000: Can't initialize function 'audit_log_filter_set_user'; Wrong argument: bad host name format
4950
SELECT audit_log_filter_set_user('user@*', 'filter_1');
5051
ERROR HY000: Can't initialize function 'audit_log_filter_set_user'; Wrong argument: bad host name format

plugin/audit_log_filter/tests/mtr/r/writer_buffer_size_overflow.result

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,6 @@ Variable_name Value
2929
Audit_log_filter_events_lost 3
3030
SHOW GLOBAL STATUS LIKE 'Audit_log_filter_event_max_drop_size';
3131
Variable_name Value
32-
Audit_log_filter_event_max_drop_size 4406
32+
Audit_log_filter_event_max_drop_size 4407
3333
#
3434
# Cleanup
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--audit_log_filter_format=JSON
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
--source audit_tables_init.inc
2+
3+
--let $anonymous_user_name = foobarbaz
4+
--let $ipv4_localhost = 127.0.0.1
5+
6+
--let $MYSQL_PORT = `SELECT @@port`
7+
8+
eval CREATE USER ''@'$ipv4_localhost';
9+
10+
SET @filter = '{
11+
"filter": {
12+
"class": {
13+
"name": "connection",
14+
"event": {
15+
"name": "connect"
16+
}
17+
}
18+
}
19+
}';
20+
SELECT audit_log_filter_set_filter('log_connect', @filter);
21+
22+
--echo ###
23+
--echo ### 1. Connecting as an anonymous user with no rules set
24+
--echo ###
25+
SET @audit_filter_log_name = audit_log_rotate();
26+
27+
--source include/count_sessions.inc
28+
--exec $MYSQL -u$anonymous_user_name -h$ipv4_localhost -P$MYSQL_PORT -e "SELECT USER(), CURRENT_USER();" test
29+
--source include/wait_until_count_sessions.inc
30+
SET @audit_filter_log_name = audit_log_rotate();
31+
SET @content = CAST(CONVERT(LOAD_FILE(CONCAT(@@global.datadir, @audit_filter_log_name)) USING ascii) AS JSON);
32+
33+
--assert(`SELECT JSON_LENGTH(@content) = 0 AS no_connection_events_must_be_logged`)
34+
35+
36+
--echo ###
37+
--echo ### 2. Connecting as an anonymous user with default rule set
38+
--echo ###
39+
SELECT audit_log_filter_set_user('%', 'log_connect');
40+
SET @audit_filter_log_name = audit_log_rotate();
41+
42+
--source include/count_sessions.inc
43+
--exec $MYSQL -u$anonymous_user_name -h$ipv4_localhost -P$MYSQL_PORT -e "SELECT USER(), CURRENT_USER();" test
44+
--source include/wait_until_count_sessions.inc
45+
SET @audit_filter_log_name = audit_log_rotate();
46+
SET @content = CAST(CONVERT(LOAD_FILE(CONCAT(@@global.datadir, @audit_filter_log_name)) USING ascii) AS JSON);
47+
48+
--assert(`SELECT JSON_LENGTH(@content) = 1 AS one_connection_event_must_be_logged`)
49+
--assert(`SELECT JSON_EXTRACT(@content, '\$[0].login.user') = '$anonymous_user_name' AS event_must_be_from_fake_user_name`)
50+
--assert(`SELECT JSON_EXTRACT(@content, '\$[0].login.ip') = '$ipv4_localhost' AS event_must_be_from_ipv4_localhost`)
51+
52+
53+
--echo ###
54+
--echo ### 3. Connecting as an anonymous user with a dedicated rule for this anonymous user
55+
--echo ###
56+
SELECT audit_log_filter_remove_user('%');
57+
eval SELECT audit_log_filter_set_user('@$ipv4_localhost', 'log_connect');
58+
SET @audit_filter_log_name = audit_log_rotate();
59+
60+
--source include/count_sessions.inc
61+
--exec $MYSQL -u$anonymous_user_name -h$ipv4_localhost -P$MYSQL_PORT -e "SELECT USER(), CURRENT_USER();" test
62+
--source include/wait_until_count_sessions.inc
63+
SET @audit_filter_log_name = audit_log_rotate();
64+
SET @content = CAST(CONVERT(LOAD_FILE(CONCAT(@@global.datadir, @audit_filter_log_name)) USING ascii) AS JSON);
65+
66+
--assert(`SELECT JSON_LENGTH(@content) = 1 AS one_connection_event_must_be_logged`)
67+
--assert(`SELECT JSON_EXTRACT(@content, '\$[0].login.user') = '$anonymous_user_name' AS event_must_be_from_fake_user_name`)
68+
--assert(`SELECT JSON_EXTRACT(@content, '\$[0].login.ip') = '$ipv4_localhost' AS event_must_be_from_ipv4_localhost`)
69+
70+
71+
eval SELECT audit_log_filter_remove_user('@$ipv4_localhost');
72+
73+
eval DROP USER ''@'$ipv4_localhost';
74+
75+
--source audit_tables_cleanup.inc
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--audit_log_filter_format=JSON

0 commit comments

Comments
 (0)