Skip to content
/ server Public

Commit 0152e99

Browse files
committed
MDEV-14443 DENY statement
Implements DENY/REVOKE DENY and associated tasks.
1 parent d755574 commit 0152e99

Some content is hidden

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

70 files changed

+6503
-541
lines changed

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: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
#
2+
# MDEV-XXXXX: Column-level DENY privilege implementation
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+
# Test 1: 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 'id' 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+
# Test 2: DENY on one column, access to others allowed
41+
#
42+
GRANT SELECT ON deny_col_db.sensitive_data TO col_user2@localhost;
43+
DENY SELECT (ssn) ON deny_col_db.sensitive_data TO col_user2@localhost;
44+
connect con2, localhost, col_user2,,deny_col_db;
45+
SELECT id, public_info, salary, address FROM sensitive_data;
46+
id public_info salary address
47+
1 John Doe 75000.00 123 Main St
48+
2 Jane Smith 85000.00 456 Oak Ave
49+
SELECT ssn FROM sensitive_data;
50+
ERROR 42000: SELECT command denied to user 'col_user2'@'localhost' for column 'ssn' in table 'sensitive_data'
51+
SELECT id, ssn FROM sensitive_data;
52+
ERROR 42000: SELECT command denied to user 'col_user2'@'localhost' for column 'ssn' in table 'sensitive_data'
53+
SELECT * FROM sensitive_data;
54+
ERROR 42000: SELECT command denied to user 'col_user2'@'localhost' for column 'id' in table 'sensitive_data'
55+
disconnect con2;
56+
connection default;
57+
REVOKE SELECT ON deny_col_db.sensitive_data FROM col_user2@localhost;
58+
REVOKE DENY SELECT (ssn) ON deny_col_db.sensitive_data FROM col_user2@localhost;
59+
#
60+
# Test 3: Column DENY takes precedence over explicit column GRANT
61+
#
62+
GRANT SELECT (salary,id,public_info) ON deny_col_db.sensitive_data TO col_user1@localhost;
63+
DENY SELECT (salary) ON deny_col_db.sensitive_data TO col_user1@localhost;
64+
connect con3, localhost, col_user1,,deny_col_db;
65+
SELECT id, public_info FROM sensitive_data;
66+
id public_info
67+
1 John Doe
68+
2 Jane Smith
69+
SELECT salary FROM sensitive_data;
70+
ERROR 42000: SELECT command denied to user 'col_user1'@'localhost' for column 'salary' in table 'sensitive_data'
71+
disconnect con3;
72+
connection default;
73+
REVOKE SELECT (salary,id,public_info) ON deny_col_db.sensitive_data FROM col_user1@localhost;
74+
REVOKE DENY SELECT (salary) ON deny_col_db.sensitive_data FROM col_user1@localhost;
75+
#
76+
# Test 4: REVOKE DENY on a column
77+
#
78+
GRANT SELECT (salary) ON deny_col_db.sensitive_data TO col_user1@localhost;
79+
DENY SELECT (salary,ssn) ON deny_col_db.sensitive_data TO col_user1@localhost;
80+
REVOKE DENY SELECT (salary) ON deny_col_db.sensitive_data FROM col_user1@localhost;
81+
connect con4, localhost, col_user1,,deny_col_db;
82+
SELECT salary FROM sensitive_data;
83+
salary
84+
75000.00
85+
85000.00
86+
SELECT ssn FROM sensitive_data;
87+
ERROR 42000: SELECT command denied to user 'col_user1'@'localhost' for column 'ssn' in table 'sensitive_data'
88+
disconnect con4;
89+
connection default;
90+
REVOKE DENY SELECT (ssn) ON deny_col_db.sensitive_data FROM col_user1@localhost;
91+
#
92+
# Test 5: Multiple column DENYs
93+
#
94+
GRANT SELECT ON deny_col_db.sensitive_data TO col_user2@localhost;
95+
DENY SELECT (salary, ssn, address) ON deny_col_db.sensitive_data TO col_user2@localhost;
96+
connect con5, localhost, col_user2,,deny_col_db;
97+
SELECT id, public_info FROM sensitive_data;
98+
id public_info
99+
1 John Doe
100+
2 Jane Smith
101+
SELECT salary FROM sensitive_data;
102+
ERROR 42000: SELECT command denied to user 'col_user2'@'localhost' for column 'salary' in table 'sensitive_data'
103+
SELECT address FROM sensitive_data;
104+
ERROR 42000: SELECT command denied to user 'col_user2'@'localhost' for column 'address' in table 'sensitive_data'
105+
SELECT * FROM sensitive_data;
106+
ERROR 42000: SELECT command denied to user 'col_user2'@'localhost' for column 'id' in table 'sensitive_data'
107+
disconnect con5;
108+
connection default;
109+
#
110+
# Test 6: DENY one column, then DENY another
111+
#
112+
REVOKE DENY SELECT (salary, ssn, address) ON deny_col_db.sensitive_data FROM col_user2@localhost;
113+
DENY SELECT (salary) ON deny_col_db.sensitive_data TO col_user2@localhost;
114+
DENY SELECT (ssn) ON deny_col_db.sensitive_data TO col_user2@localhost;
115+
connect con6, localhost, col_user2,,deny_col_db;
116+
SELECT id, public_info, address FROM sensitive_data;
117+
id public_info address
118+
1 John Doe 123 Main St
119+
2 Jane Smith 456 Oak Ave
120+
SELECT salary FROM sensitive_data;
121+
ERROR 42000: SELECT command denied to user 'col_user2'@'localhost' for column 'salary' in table 'sensitive_data'
122+
SELECT ssn FROM sensitive_data;
123+
ERROR 42000: SELECT command denied to user 'col_user2'@'localhost' for column 'ssn' in table 'sensitive_data'
124+
disconnect con6;
125+
connection default;
126+
#
127+
# Test 7: SHOW GRANTS displays column-level DENY
128+
#
129+
SHOW GRANTS FOR col_user1@localhost;
130+
Grants for col_user1@localhost
131+
GRANT USAGE ON *.* TO `col_user1`@`localhost`
132+
GRANT SELECT (`salary`) ON `deny_col_db`.`sensitive_data` TO `col_user1`@`localhost`
133+
SHOW GRANTS FOR col_user2@localhost;
134+
Grants for col_user2@localhost
135+
GRANT USAGE ON *.* TO `col_user2`@`localhost`
136+
GRANT SELECT ON `deny_col_db`.`sensitive_data` TO `col_user2`@`localhost`
137+
DENY SELECT (`ssn`, `salary`) ON `deny_col_db`.`sensitive_data` TO `col_user2`@`localhost`
138+
#
139+
# Test 8: Column DENY with INSERT/UPDATE operations
140+
#
141+
CREATE TABLE deny_col_db.audit_log (
142+
id INT AUTO_INCREMENT PRIMARY KEY,
143+
action VARCHAR(50),
144+
modified_by VARCHAR(50),
145+
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
146+
);
147+
GRANT SELECT, INSERT ON deny_col_db.audit_log TO col_user1@localhost;
148+
DENY INSERT (modified_by) ON deny_col_db.audit_log TO col_user1@localhost;
149+
connect con8, localhost, col_user1,,deny_col_db;
150+
INSERT INTO audit_log (action) VALUES ('test_action');
151+
INSERT INTO audit_log (action, modified_by) VALUES ('test', 'hacker');
152+
ERROR 42000: INSERT command denied to user 'col_user1'@'localhost' for column 'modified_by' in table 'audit_log'
153+
SELECT * FROM audit_log;
154+
id action modified_by timestamp
155+
1 test_action NULL TIMESTAMP
156+
disconnect con8;
157+
connection default;
158+
#
159+
# Test 9: Column DENY with UPDATE
160+
#
161+
GRANT UPDATE ON deny_col_db.sensitive_data TO col_user1@localhost;
162+
DENY UPDATE (salary) ON deny_col_db.sensitive_data TO col_user1@localhost;
163+
GRANT SELECT(id,public_info) on deny_col_db.sensitive_data TO col_user1@localhost;
164+
connect con9, localhost, col_user1,,deny_col_db;
165+
UPDATE sensitive_data SET public_info = 'Updated' WHERE id = 1;
166+
UPDATE sensitive_data SET salary = 100000 WHERE id = 1;
167+
ERROR 42000: UPDATE command denied to user 'col_user1'@'localhost' for column 'salary' in table 'sensitive_data'
168+
UPDATE sensitive_data SET public_info = 'X', salary = 90000 WHERE id = 2;
169+
ERROR 42000: UPDATE command denied to user 'col_user1'@'localhost' for column 'salary' in table 'sensitive_data'
170+
disconnect con9;
171+
connection default;
172+
#
173+
# Test 10: REVOKE all column DENYs
174+
#
175+
GRANT SELECT(ssn) on deny_col_db.sensitive_data to col_user1@localhost;
176+
connect con10, localhost, col_user1,,deny_col_db;
177+
SELECT ssn FROM sensitive_data;
178+
ssn
179+
123-45-6789
180+
987-65-4321
181+
disconnect con10;
182+
connection default;
183+
#
184+
# Cleanup
185+
#
186+
DROP USER col_user1@localhost;
187+
DROP USER col_user2@localhost;
188+
DROP DATABASE deny_col_db;
189+
#
190+
# End of column-level DENY tests
191+
#

0 commit comments

Comments
 (0)