forked from pingcap/tidb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrevoke_test.go
273 lines (233 loc) · 11.6 KB
/
revoke_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
// Copyright 2017 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package executor_test
import (
"fmt"
"strings"
"testing"
"github.com/pingcap/tidb/executor"
"github.com/pingcap/tidb/parser/mysql"
"github.com/pingcap/tidb/parser/terror"
"github.com/pingcap/tidb/testkit"
"github.com/stretchr/testify/require"
)
func TestRevokeGlobal(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
_, err := tk.Exec(`REVOKE ALL PRIVILEGES ON *.* FROM 'nonexistuser'@'host'`)
require.Error(t, err)
// Create a new user.
createUserSQL := `CREATE USER 'testGlobalRevoke'@'localhost' IDENTIFIED BY '123';`
tk.MustExec(createUserSQL)
grantPrivSQL := `GRANT ALL PRIVILEGES ON *.* to 'testGlobalRevoke'@'localhost';`
tk.MustExec(grantPrivSQL)
// Make sure all the global privs for new user is "Y".
for _, v := range mysql.AllDBPrivs {
sql := fmt.Sprintf(`SELECT %s FROM mysql.User WHERE User="testGlobalRevoke" and host="localhost";`, mysql.Priv2UserCol[v])
r := tk.MustQuery(sql)
r.Check(testkit.Rows("Y"))
}
// Revoke each priv from the user.
for _, v := range mysql.AllGlobalPrivs {
sql := fmt.Sprintf("REVOKE %s ON *.* FROM 'testGlobalRevoke'@'localhost';", mysql.Priv2Str[v])
tk.MustExec(sql)
sql = fmt.Sprintf(`SELECT %s FROM mysql.User WHERE User="testGlobalRevoke" and host="localhost"`, mysql.Priv2UserCol[v])
tk.MustQuery(sql).Check(testkit.Rows("N"))
}
}
func TestRevokeDBScope(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
// Create a new user.
tk.MustExec(`CREATE USER 'testDBRevoke'@'localhost' IDENTIFIED BY '123';`)
tk.MustExec(`GRANT ALL ON test.* TO 'testDBRevoke'@'localhost';`)
_, err := tk.Exec(`REVOKE ALL PRIVILEGES ON nonexistdb.* FROM 'testDBRevoke'@'localhost'`)
require.Error(t, err)
// Revoke each priv from the user.
for _, v := range mysql.AllDBPrivs {
check := fmt.Sprintf(`SELECT %s FROM mysql.DB WHERE User="testDBRevoke" and host="localhost" and db="test"`, mysql.Priv2UserCol[v])
sql := fmt.Sprintf("REVOKE %s ON test.* FROM 'testDBRevoke'@'localhost';", mysql.Priv2Str[v])
tk.MustQuery(check).Check(testkit.Rows("Y"))
tk.MustExec(sql)
if v == mysql.AllDBPrivs[len(mysql.AllDBPrivs)-1] {
// When all privileges are set to 'N', then the record should be removed as well.
// https://github.com/pingcap/tidb/issues/38363
tk.MustQuery(check).Check(testkit.Rows())
} else {
tk.MustQuery(check).Check(testkit.Rows("N"))
}
}
}
func TestRevokeTableScope(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
// Create a new user.
tk.MustExec(`CREATE USER 'testTblRevoke'@'localhost' IDENTIFIED BY '123';`)
tk.MustExec(`CREATE TABLE test.test1(c1 int);`)
tk.MustExec(`GRANT ALL PRIVILEGES ON test.test1 TO 'testTblRevoke'@'localhost';`)
_, err := tk.Exec(`REVOKE ALL PRIVILEGES ON test.nonexisttable FROM 'testTblRevoke'@'localhost'`)
require.Error(t, err)
// Make sure all the table privs for new user is Y.
res := tk.MustQuery(`SELECT Table_priv FROM mysql.tables_priv WHERE User="testTblRevoke" and host="localhost" and db="test" and Table_name="test1"`)
res.Check(testkit.Rows("Select,Insert,Update,Delete,Create,Drop,Index,Alter,Create View,Show View,Trigger,References"))
// Revoke each priv from the user.
for index, v := range mysql.AllTablePrivs {
sql := fmt.Sprintf("REVOKE %s ON test.test1 FROM 'testTblRevoke'@'localhost';", mysql.Priv2Str[v])
tk.MustExec(sql)
rows := tk.MustQuery(`SELECT Table_priv FROM mysql.tables_priv WHERE User="testTblRevoke" and host="localhost" and db="test" and Table_name="test1";`).Rows()
if index < len(mysql.AllTablePrivs)-1 {
require.Len(t, rows, 1)
row := rows[0]
require.Len(t, row, 1)
op := v.SetString()
found := false
for _, p := range executor.SetFromString(fmt.Sprintf("%s", row[0])) {
if op == p {
found = true
break
}
}
require.False(t, found, "%s", mysql.Priv2SetStr[v])
} else {
//delete row when last prv , updated by issue #38421
require.Len(t, rows, 0)
}
}
// Revoke all table scope privs.
tk.MustExec(`GRANT ALL PRIVILEGES ON test.test1 TO 'testTblRevoke'@'localhost';`)
tk.MustExec("REVOKE ALL ON test.test1 FROM 'testTblRevoke'@'localhost';")
//delete row when last prv , updated by issue #38421
rows := tk.MustQuery(`SELECT Table_priv FROM mysql.Tables_priv WHERE User="testTblRevoke" and host="localhost" and db="test" and Table_name="test1"`).Rows()
require.Len(t, rows, 0)
}
func TestRevokeColumnScope(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
// Create a new user.
tk.MustExec(`CREATE USER 'testColRevoke'@'localhost' IDENTIFIED BY '123';`)
tk.MustExec(`CREATE TABLE test.test3(c1 int, c2 int);`)
tk.MustQuery(`SELECT * FROM mysql.Columns_priv WHERE User="testColRevoke" and host="localhost" and db="test" and Table_name="test3" and Column_name="c2"`).Check(testkit.Rows())
// Grant and Revoke each priv on the user.
for _, v := range mysql.AllColumnPrivs {
grantSQL := fmt.Sprintf("GRANT %s(c1) ON test.test3 TO 'testColRevoke'@'localhost';", mysql.Priv2Str[v])
revokeSQL := fmt.Sprintf("REVOKE %s(c1) ON test.test3 FROM 'testColRevoke'@'localhost';", mysql.Priv2Str[v])
checkSQL := `SELECT Column_priv FROM mysql.Columns_priv WHERE User="testColRevoke" and host="localhost" and db="test" and Table_name="test3" and Column_name="c1"`
tk.MustExec(grantSQL)
rows := tk.MustQuery(checkSQL).Rows()
require.Len(t, rows, 1)
row := rows[0]
require.Len(t, row, 1)
p := fmt.Sprintf("%v", row[0])
require.Greater(t, strings.Index(p, mysql.Priv2SetStr[v]), -1)
tk.MustExec(revokeSQL)
//delete row when last prv , updated by issue #38421
rows = tk.MustQuery(checkSQL).Rows()
require.Len(t, rows, 0)
}
// Create a new user.
tk.MustExec("CREATE USER 'testCol1Revoke'@'localhost' IDENTIFIED BY '123';")
tk.MustExec("USE test;")
// Grant all column scope privs.
tk.MustExec("GRANT ALL(c2) ON test3 TO 'testCol1Revoke'@'localhost';")
// Make sure all the column privs for granted user are in the Column_priv set.
for _, v := range mysql.AllColumnPrivs {
rows := tk.MustQuery(`SELECT Column_priv FROM mysql.Columns_priv WHERE User="testCol1Revoke" and host="localhost" and db="test" and Table_name="test3" and Column_name="c2";`).Rows()
require.Len(t, rows, 1)
row := rows[0]
require.Len(t, row, 1)
p := fmt.Sprintf("%v", row[0])
require.Greater(t, strings.Index(p, mysql.Priv2SetStr[v]), -1)
}
tk.MustExec("REVOKE ALL(c2) ON test3 FROM 'testCol1Revoke'@'localhost'")
//delete row when last prv , updated by issue #38421
rows := tk.MustQuery(`SELECT Column_priv FROM mysql.Columns_priv WHERE User="testCol1Revoke" and host="localhost" and db="test" and Table_name="test3"`).Rows()
require.Len(t, rows, 0)
}
// ref issue #38421
func TestRevokeTableSingle(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
// Create a new user.
tk.MustExec(`CREATE USER test;`)
tk.MustExec(`CREATE TABLE test.test1(c1 int);`)
tk.MustExec(`GRANT SELECT ON test.test1 TO test;`)
tk.MustExec(`REVOKE SELECT ON test.test1 from test;`)
rows := tk.MustQuery(`SELECT Column_priv FROM mysql.tables_priv WHERE User="test" `).Rows()
require.Len(t, rows, 0)
}
// ref issue #38421(column fix)
func TestRevokeTableSingleColumn(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
// Create a new user.
tk.MustExec(`CREATE USER test;`)
tk.MustExec(`GRANT SELECT(Host) ON mysql.db TO test`)
tk.MustExec(`GRANT SELECT(DB) ON mysql.db TO test`)
tk.MustExec(`REVOKE SELECT(Host) ON mysql.db FROM test`)
rows := tk.MustQuery(`SELECT Column_priv FROM mysql.columns_priv WHERE User="test" and Column_name ='Host' `).Rows()
require.Len(t, rows, 0)
rows = tk.MustQuery(`SELECT Column_priv FROM mysql.columns_priv WHERE User="test" and Column_name ='DB' `).Rows()
require.Len(t, rows, 1)
}
func TestRevokeDynamicPrivs(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("DROP USER if exists dyn")
tk.MustExec("create user dyn")
tk.MustExec("GRANT BACKUP_Admin ON *.* TO dyn") // grant one priv
tk.MustQuery("SELECT * FROM mysql.global_grants WHERE `Host` = '%' AND `User` = 'dyn' ORDER BY user,host,priv,with_grant_option").Check(testkit.Rows("dyn % BACKUP_ADMIN N"))
// try revoking only on test.* - should fail:
_, err := tk.Exec("REVOKE BACKUP_Admin,system_variables_admin ON test.* FROM dyn")
require.True(t, terror.ErrorEqual(err, executor.ErrIllegalPrivilegeLevel))
// privs should still be intact:
tk.MustQuery("SELECT * FROM mysql.global_grants WHERE `Host` = '%' AND `User` = 'dyn' ORDER BY user,host,priv,with_grant_option").Check(testkit.Rows("dyn % BACKUP_ADMIN N"))
// with correct usage, the privilege is revoked
tk.MustExec("REVOKE BACKUP_Admin ON *.* FROM dyn")
tk.MustQuery("SELECT * FROM mysql.global_grants WHERE `Host` = '%' AND `User` = 'dyn' ORDER BY user,host,priv,with_grant_option").Check(testkit.Rows())
// Revoke bogus is a warning in MySQL
tk.MustExec("REVOKE bogus ON *.* FROM dyn")
tk.MustQuery("SHOW WARNINGS").Check(testkit.Rows("Warning 3929 Dynamic privilege 'BOGUS' is not registered with the server."))
// grant and revoke two dynamic privileges at once.
tk.MustExec("GRANT BACKUP_ADMIN, SYSTEM_VARIABLES_ADMIN ON *.* TO dyn")
tk.MustQuery("SELECT * FROM mysql.global_grants WHERE `Host` = '%' AND `User` = 'dyn' ORDER BY user,host,priv,with_grant_option").Check(testkit.Rows("dyn % BACKUP_ADMIN N", "dyn % SYSTEM_VARIABLES_ADMIN N"))
tk.MustExec("REVOKE BACKUP_ADMIN, SYSTEM_VARIABLES_ADMIN ON *.* FROM dyn")
tk.MustQuery("SELECT * FROM mysql.global_grants WHERE `Host` = '%' AND `User` = 'dyn' ORDER BY user,host,priv,with_grant_option").Check(testkit.Rows())
// revoke a combination of dynamic + non-dynamic
tk.MustExec("GRANT BACKUP_ADMIN, SYSTEM_VARIABLES_ADMIN, SELECT, INSERT ON *.* TO dyn")
tk.MustExec("REVOKE BACKUP_ADMIN, SYSTEM_VARIABLES_ADMIN, SELECT, INSERT ON *.* FROM dyn")
tk.MustQuery("SELECT * FROM mysql.global_grants WHERE `Host` = '%' AND `User` = 'dyn' ORDER BY user,host,priv,with_grant_option").Check(testkit.Rows())
// revoke grant option from privileges
tk.MustExec("GRANT BACKUP_ADMIN, SYSTEM_VARIABLES_ADMIN, SELECT ON *.* TO dyn WITH GRANT OPTION")
tk.MustExec("REVOKE BACKUP_ADMIN, SELECT, GRANT OPTION ON *.* FROM dyn")
tk.MustQuery("SELECT * FROM mysql.global_grants WHERE `Host` = '%' AND `User` = 'dyn' ORDER BY user,host,priv,with_grant_option").Check(testkit.Rows("dyn % SYSTEM_VARIABLES_ADMIN Y"))
}
func TestRevokeOnNonExistTable(t *testing.T) {
// issue #28533
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("CREATE DATABASE d1;")
defer tk.MustExec("DROP DATABASE IF EXISTS d1;")
tk.MustExec("USE d1;")
tk.MustExec("CREATE TABLE t1 (a int)")
defer tk.MustExec("DROP TABLE IF EXISTS t1")
tk.MustExec("CREATE USER issue28533")
defer tk.MustExec("DROP USER issue28533")
// GRANT ON existent table success
tk.MustExec("GRANT ALTER ON d1.t1 TO issue28533;")
// GRANT ON non-existent table success
tk.MustExec("GRANT INSERT, CREATE ON d1.t2 TO issue28533;")
// REVOKE ON non-existent table success
tk.MustExec("DROP TABLE t1;")
tk.MustExec("REVOKE ALTER ON d1.t1 FROM issue28533;")
}