Skip to content

Commit be81b12

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

65 files changed

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

mysql-test/main/deny_column.result

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
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+
#
126+
# Column DENY is case-insensitive
127+
#
128+
GRANT SELECT ON deny_col_db.sensitive_data TO col_user1@localhost;
129+
DENY SELECT (SaLaRy) ON deny_col_db.sensitive_data TO col_user1@localhost;
130+
connect con10, localhost, col_user1,,deny_col_db;
131+
SELECT salary FROM sensitive_data;
132+
ERROR 42000: SELECT command denied to user 'col_user1'@'localhost' for column 'salary' in table 'sensitive_data'
133+
disconnect con10;
134+
connection default;
135+
REVOKE DENY SELECT (SaLaRy) ON deny_col_db.sensitive_data FROM col_user1@localhost;
136+
REVOKE SELECT ON deny_col_db.sensitive_data FROM col_user1@localhost;
137+
#
138+
# Cleanup
139+
#
140+
DROP USER col_user1@localhost;
141+
DROP USER col_user2@localhost;
142+
DROP DATABASE deny_col_db;
143+
#
144+
# End of column-level DENY tests
145+
#

0 commit comments

Comments
 (0)