Skip to content

Commit df02867

Browse files
committed
MDEV-14443 DENY statement
Implements DENY/REVOKE DENY and associated tasks.
1 parent ef4be39 commit df02867

65 files changed

Lines changed: 6601 additions & 628 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

libmysqld/lib_sql.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -787,7 +787,7 @@ int check_embedded_connection(MYSQL *mysql, const char *db)
787787
strmake_buf(sctx->priv_user, mysql->user);
788788
sctx->user= my_strdup(PSI_NOT_INSTRUMENTED, mysql->user, MYF(0));
789789
sctx->proxy_user[0]= 0;
790-
sctx->master_access= GLOBAL_ACLS; // Full rights
790+
sctx->master_access= access_t(GLOBAL_ACLS); // Full rights
791791
emb_transfer_connect_attrs(mysql);
792792

793793
/* Change database if necessary */

mysql-test/main/deny_admin.result

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#
2+
# Test DENY for global administrative privileges
3+
#
4+
CREATE USER user1@localhost;
5+
CREATE USER user2@localhost;
6+
# Test RELOAD privilege
7+
GRANT ALL PRIVILEGES ON *.* TO user1@localhost;
8+
DENY RELOAD ON *.* TO user1@localhost;
9+
connect con1, localhost, user1,,;
10+
FLUSH TABLES;
11+
ERROR 42000: Access denied; you need (at least one of) the RELOAD privilege(s) for this operation
12+
FLUSH LOGS;
13+
ERROR 42000: Access denied; you need (at least one of) the RELOAD privilege(s) for this operation
14+
connection default;
15+
disconnect con1;
16+
# Test SHUTDOWN privilege
17+
GRANT ALL PRIVILEGES ON *.* TO user1@localhost;
18+
DENY SHUTDOWN ON *.* TO user1@localhost;
19+
connect con1, localhost, user1,,;
20+
SHUTDOWN;
21+
ERROR 42000: Access denied; you need (at least one of) the SHUTDOWN privilege(s) for this operation
22+
connection default;
23+
disconnect con1;
24+
# Test PROCESS privilege
25+
GRANT ALL PRIVILEGES ON *.* TO user1@localhost;
26+
DENY PROCESS ON *.* TO user1@localhost;
27+
connect con1, localhost, user1,,;
28+
SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER <> 'user1';
29+
COUNT(*)
30+
0
31+
connection default;
32+
disconnect con1;
33+
# Test FILE privilege
34+
GRANT ALL PRIVILEGES ON *.* TO user1@localhost;
35+
DENY FILE ON *.* TO user1@localhost;
36+
connect con1, localhost, user1,,;
37+
SELECT 'test' INTO OUTFILE '/tmp/test.txt';
38+
ERROR 28000: Access denied for user 'user1'@'localhost' (using password: NO)
39+
connection default;
40+
disconnect con1;
41+
# Test combination of DENY on multiple global privileges
42+
GRANT ALL PRIVILEGES ON *.* TO user2@localhost;
43+
DENY RELOAD, SHUTDOWN ON *.* TO user2@localhost;
44+
connect con2, localhost, user2,,;
45+
FLUSH TABLES;
46+
ERROR 42000: Access denied; you need (at least one of) the RELOAD privilege(s) for this operation
47+
SHUTDOWN;
48+
ERROR 42000: Access denied; you need (at least one of) the SHUTDOWN privilege(s) for this operation
49+
connection default;
50+
disconnect con2;
51+
# Cleanup
52+
DROP USER user1@localhost;
53+
DROP USER user2@localhost;
54+
#
55+
# Test CONNECTION ADMIN privilege behaviors with DENY
56+
#
57+
CREATE USER user_super@localhost;
58+
GRANT ALL PRIVILEGES ON *.* TO user_super@localhost;
59+
DENY CONNECTION ADMIN ON *.* TO user_super@localhost;
60+
connect con_super, localhost, user_super,,;
61+
# Should not be able to kill other connections
62+
connection default;
63+
connection con_super;
64+
KILL ID;
65+
ERROR HY000: You are not owner of thread ID
66+
# Should not be able to set global variables
67+
SET GLOBAL max_connections = 200;
68+
ERROR 42000: Access denied; you need (at least one of) the CONNECTION ADMIN privilege(s) for this operation
69+
connection default;
70+
disconnect con_super;
71+
DROP USER user_super@localhost;

mysql-test/main/deny_admin.test

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
--source include/not_embedded.inc
2+
--source include/no_protocol.inc
3+
4+
--echo #
5+
--echo # Test DENY for global administrative privileges
6+
--echo #
7+
8+
CREATE USER user1@localhost;
9+
CREATE USER user2@localhost;
10+
11+
--echo # Test RELOAD privilege
12+
GRANT ALL PRIVILEGES ON *.* TO user1@localhost;
13+
DENY RELOAD ON *.* TO user1@localhost;
14+
15+
connect (con1, localhost, user1,,);
16+
--error ER_SPECIFIC_ACCESS_DENIED_ERROR
17+
FLUSH TABLES;
18+
19+
--error ER_SPECIFIC_ACCESS_DENIED_ERROR
20+
FLUSH LOGS;
21+
22+
connection default;
23+
disconnect con1;
24+
25+
--echo # Test SHUTDOWN privilege
26+
GRANT ALL PRIVILEGES ON *.* TO user1@localhost;
27+
DENY SHUTDOWN ON *.* TO user1@localhost;
28+
29+
connect (con1, localhost, user1,,);
30+
--error ER_SPECIFIC_ACCESS_DENIED_ERROR
31+
SHUTDOWN;
32+
33+
connection default;
34+
disconnect con1;
35+
36+
--echo # Test PROCESS privilege
37+
GRANT ALL PRIVILEGES ON *.* TO user1@localhost;
38+
DENY PROCESS ON *.* TO user1@localhost;
39+
40+
let $count_sessions= 1;
41+
--source include/wait_until_count_sessions.inc
42+
43+
connect (con1, localhost, user1,,);
44+
SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER <> 'user1';
45+
46+
connection default;
47+
disconnect con1;
48+
49+
50+
--echo # Test FILE privilege
51+
GRANT ALL PRIVILEGES ON *.* TO user1@localhost;
52+
DENY FILE ON *.* TO user1@localhost;
53+
54+
connect (con1, localhost, user1,,);
55+
56+
--error ER_ACCESS_DENIED_ERROR
57+
SELECT 'test' INTO OUTFILE '/tmp/test.txt';
58+
59+
connection default;
60+
disconnect con1;
61+
62+
--echo # Test combination of DENY on multiple global privileges
63+
GRANT ALL PRIVILEGES ON *.* TO user2@localhost;
64+
DENY RELOAD, SHUTDOWN ON *.* TO user2@localhost;
65+
66+
connect (con2, localhost, user2,,);
67+
--error ER_SPECIFIC_ACCESS_DENIED_ERROR
68+
FLUSH TABLES;
69+
70+
--error ER_SPECIFIC_ACCESS_DENIED_ERROR
71+
SHUTDOWN;
72+
73+
connection default;
74+
disconnect con2;
75+
76+
--echo # Cleanup
77+
DROP USER user1@localhost;
78+
DROP USER user2@localhost;
79+
80+
--echo #
81+
--echo # Test CONNECTION ADMIN privilege behaviors with DENY
82+
--echo #
83+
CREATE USER user_super@localhost;
84+
GRANT ALL PRIVILEGES ON *.* TO user_super@localhost;
85+
DENY CONNECTION ADMIN ON *.* TO user_super@localhost;
86+
87+
connect (con_super, localhost, user_super,,);
88+
89+
--echo # Should not be able to kill other connections
90+
connection default;
91+
let $default_id = `SELECT CONNECTION_ID()`;
92+
93+
connection con_super;
94+
--replace_result $default_id ID
95+
--error ER_KILL_DENIED_ERROR
96+
eval KILL $default_id;
97+
98+
--echo # Should not be able to set global variables
99+
--error ER_SPECIFIC_ACCESS_DENIED_ERROR
100+
SET GLOBAL max_connections = 200;
101+
102+
103+
connection default;
104+
disconnect con_super;
105+
DROP USER user_super@localhost;

mysql-test/main/deny_column.result

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
#
2+
# Column-level DENY privilege test
3+
#
4+
CREATE DATABASE deny_col_db;
5+
CREATE TABLE deny_col_db.sensitive_data (
6+
id INT,
7+
public_info VARCHAR(50),
8+
salary DECIMAL(10,2),
9+
ssn VARCHAR(11),
10+
address VARCHAR(100)
11+
);
12+
INSERT INTO deny_col_db.sensitive_data VALUES
13+
(1, 'John Doe', 75000.00, '123-45-6789', '123 Main St'),
14+
(2, 'Jane Smith', 85000.00, '987-65-4321', '456 Oak Ave');
15+
CREATE USER col_user1@localhost;
16+
CREATE USER col_user2@localhost;
17+
#
18+
# Basic column-level DENY
19+
#
20+
GRANT SELECT ON deny_col_db.sensitive_data TO col_user1@localhost;
21+
DENY SELECT (salary, ssn) ON deny_col_db.sensitive_data TO col_user1@localhost;
22+
connect con1, localhost, col_user1,,deny_col_db;
23+
SELECT id, public_info FROM sensitive_data;
24+
id public_info
25+
1 John Doe
26+
2 Jane Smith
27+
SELECT salary FROM sensitive_data;
28+
ERROR 42000: SELECT command denied to user 'col_user1'@'localhost' for column 'salary' in table 'sensitive_data'
29+
SELECT ssn FROM sensitive_data;
30+
ERROR 42000: SELECT command denied to user 'col_user1'@'localhost' for column 'ssn' in table 'sensitive_data'
31+
SELECT * FROM sensitive_data;
32+
ERROR 42000: SELECT command denied to user 'col_user1'@'localhost' for column 'salary' in table 'sensitive_data'
33+
SELECT id, salary FROM sensitive_data;
34+
ERROR 42000: SELECT command denied to user 'col_user1'@'localhost' for column 'salary' in table 'sensitive_data'
35+
disconnect con1;
36+
connection default;
37+
REVOKE SELECT ON deny_col_db.sensitive_data FROM col_user1@localhost;
38+
REVOKE DENY SELECT (salary, ssn) ON deny_col_db.sensitive_data FROM col_user1@localhost;
39+
#
40+
# Column DENY takes precedence over explicit column GRANT
41+
#
42+
GRANT SELECT (salary,id,public_info) ON deny_col_db.sensitive_data TO col_user1@localhost;
43+
DENY SELECT (salary) ON deny_col_db.sensitive_data TO col_user1@localhost;
44+
connect con3, localhost, col_user1,,deny_col_db;
45+
SELECT id, public_info FROM sensitive_data;
46+
id public_info
47+
1 John Doe
48+
2 Jane Smith
49+
SELECT salary FROM sensitive_data;
50+
ERROR 42000: SELECT command denied to user 'col_user1'@'localhost' for column 'salary' in table 'sensitive_data'
51+
disconnect con3;
52+
connection default;
53+
REVOKE SELECT (salary,id,public_info) ON deny_col_db.sensitive_data FROM col_user1@localhost;
54+
REVOKE DENY SELECT (salary) ON deny_col_db.sensitive_data FROM col_user1@localhost;
55+
#
56+
# REVOKE DENY on a column
57+
#
58+
GRANT SELECT (salary) ON deny_col_db.sensitive_data TO col_user1@localhost;
59+
DENY SELECT (salary,ssn) ON deny_col_db.sensitive_data TO col_user1@localhost;
60+
REVOKE DENY SELECT (salary) ON deny_col_db.sensitive_data FROM col_user1@localhost;
61+
connect con4, localhost, col_user1,,deny_col_db;
62+
SELECT salary FROM sensitive_data;
63+
salary
64+
75000.00
65+
85000.00
66+
SELECT ssn FROM sensitive_data;
67+
ERROR 42000: SELECT command denied to user 'col_user1'@'localhost' for column 'ssn' in table 'sensitive_data'
68+
disconnect con4;
69+
connection default;
70+
REVOKE DENY SELECT (ssn) ON deny_col_db.sensitive_data FROM col_user1@localhost;
71+
#
72+
# Multiple column DENYs
73+
#
74+
GRANT SELECT ON deny_col_db.sensitive_data TO col_user2@localhost;
75+
DENY SELECT (salary, ssn, address) ON deny_col_db.sensitive_data TO col_user2@localhost;
76+
connect con5, localhost, col_user2,,deny_col_db;
77+
SELECT id, public_info FROM sensitive_data;
78+
id public_info
79+
1 John Doe
80+
2 Jane Smith
81+
SELECT salary FROM sensitive_data;
82+
ERROR 42000: SELECT command denied to user 'col_user2'@'localhost' for column 'salary' in table 'sensitive_data'
83+
SELECT address FROM sensitive_data;
84+
ERROR 42000: SELECT command denied to user 'col_user2'@'localhost' for column 'address' in table 'sensitive_data'
85+
SELECT * FROM sensitive_data;
86+
ERROR 42000: SELECT command denied to user 'col_user2'@'localhost' for column 'salary' in table 'sensitive_data'
87+
disconnect con5;
88+
connection default;
89+
REVOKE DENY SELECT (salary, ssn, address) ON deny_col_db.sensitive_data FROM col_user2@localhost;
90+
REVOKE SELECT ON deny_col_db.sensitive_data FROM col_user2@localhost;
91+
#
92+
# Column DENY with INSERT/UPDATE operations
93+
#
94+
CREATE TABLE deny_col_db.audit_log (
95+
id INT AUTO_INCREMENT PRIMARY KEY,
96+
action VARCHAR(50),
97+
modified_by VARCHAR(50),
98+
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
99+
);
100+
GRANT SELECT, INSERT ON deny_col_db.audit_log TO col_user1@localhost;
101+
DENY INSERT (modified_by) ON deny_col_db.audit_log TO col_user1@localhost;
102+
connect con8, localhost, col_user1,,deny_col_db;
103+
INSERT INTO audit_log (action) VALUES ('test_action');
104+
INSERT INTO audit_log (action, modified_by) VALUES ('test', 'hacker');
105+
ERROR 42000: INSERT command denied to user 'col_user1'@'localhost' for column 'modified_by' in table 'audit_log'
106+
SELECT * FROM audit_log;
107+
id action modified_by timestamp
108+
1 test_action NULL TIMESTAMP
109+
disconnect con8;
110+
connection default;
111+
#
112+
# Column DENY with UPDATE
113+
#
114+
GRANT UPDATE ON deny_col_db.sensitive_data TO col_user1@localhost;
115+
DENY UPDATE (salary) ON deny_col_db.sensitive_data TO col_user1@localhost;
116+
GRANT SELECT(id,public_info) on deny_col_db.sensitive_data TO col_user1@localhost;
117+
connect con9, localhost, col_user1,,deny_col_db;
118+
UPDATE sensitive_data SET public_info = 'Updated' WHERE id = 1;
119+
UPDATE sensitive_data SET salary = 100000 WHERE id = 1;
120+
ERROR 42000: UPDATE command denied to user 'col_user1'@'localhost' for column 'salary' in table 'sensitive_data'
121+
UPDATE sensitive_data SET public_info = 'X', salary = 90000 WHERE id = 2;
122+
ERROR 42000: UPDATE command denied to user 'col_user1'@'localhost' for column 'salary' in table 'sensitive_data'
123+
disconnect con9;
124+
connection default;
125+
REVOKE SELECT (id,public_info) ON deny_col_db.sensitive_data FROM col_user1@localhost;
126+
#
127+
# Table-level DENY SELECT: UPDATE without WHERE must succeed (no read needed)
128+
#
129+
DENY SELECT ON deny_col_db.sensitive_data TO col_user1@localhost;
130+
connect con9b, localhost, col_user1,,deny_col_db;
131+
# UPDATE with WHERE reads id -> SELECT needed -> DENY fires
132+
UPDATE sensitive_data SET public_info = 'ps_test' WHERE id = 1;
133+
ERROR 42000: SELECT command denied to user 'col_user1'@'localhost' for column 'id' in table 'sensitive_data'
134+
# UPDATE without WHERE: no SELECT needed, must succeed
135+
UPDATE sensitive_data SET public_info = 'ps_test';
136+
disconnect con9b;
137+
connection default;
138+
REVOKE DENY SELECT ON deny_col_db.sensitive_data FROM col_user1@localhost;
139+
REVOKE UPDATE ON deny_col_db.sensitive_data FROM col_user1@localhost;
140+
#
141+
# Column DENY is case-insensitive
142+
#
143+
GRANT SELECT ON deny_col_db.sensitive_data TO col_user1@localhost;
144+
DENY SELECT (SaLaRy) ON deny_col_db.sensitive_data TO col_user1@localhost;
145+
connect con10, localhost, col_user1,,deny_col_db;
146+
SELECT salary FROM sensitive_data;
147+
ERROR 42000: SELECT command denied to user 'col_user1'@'localhost' for column 'salary' in table 'sensitive_data'
148+
disconnect con10;
149+
connection default;
150+
REVOKE DENY SELECT (SaLaRy) ON deny_col_db.sensitive_data FROM col_user1@localhost;
151+
REVOKE SELECT ON deny_col_db.sensitive_data FROM col_user1@localhost;
152+
#
153+
# Cleanup
154+
#
155+
DROP USER col_user1@localhost;
156+
DROP USER col_user2@localhost;
157+
DROP DATABASE deny_col_db;
158+
#
159+
# End of column-level DENY tests
160+
#

0 commit comments

Comments
 (0)