vitess.io/vitess@v0.16.2/go/vt/wrangler/testlib/permissions_test.go (about) 1 /* 2 Copyright 2019 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package testlib 18 19 import ( 20 "context" 21 "strings" 22 "testing" 23 "time" 24 25 "vitess.io/vitess/go/vt/discovery" 26 "vitess.io/vitess/go/vt/topo/topoproto" 27 28 "vitess.io/vitess/go/sqltypes" 29 "vitess.io/vitess/go/vt/logutil" 30 "vitess.io/vitess/go/vt/topo" 31 "vitess.io/vitess/go/vt/topo/memorytopo" 32 "vitess.io/vitess/go/vt/vttablet/tmclient" 33 "vitess.io/vitess/go/vt/wrangler" 34 35 querypb "vitess.io/vitess/go/vt/proto/query" 36 topodatapb "vitess.io/vitess/go/vt/proto/topodata" 37 ) 38 39 func TestPermissions(t *testing.T) { 40 delay := discovery.GetTabletPickerRetryDelay() 41 defer func() { 42 discovery.SetTabletPickerRetryDelay(delay) 43 }() 44 discovery.SetTabletPickerRetryDelay(5 * time.Millisecond) 45 46 // Initialize our environment 47 ctx := context.Background() 48 ts := memorytopo.NewServer("cell1", "cell2") 49 wr := wrangler.New(logutil.NewConsoleLogger(), ts, tmclient.NewTabletManagerClient()) 50 vp := NewVtctlPipe(t, ts) 51 defer vp.Close() 52 53 primary := NewFakeTablet(t, wr, "cell1", 0, topodatapb.TabletType_PRIMARY, nil) 54 replica := NewFakeTablet(t, wr, "cell1", 1, topodatapb.TabletType_REPLICA, nil) 55 56 // mark the primary inside the shard 57 _, err := ts.UpdateShardFields(ctx, primary.Tablet.Keyspace, primary.Tablet.Shard, func(si *topo.ShardInfo) error { 58 si.PrimaryAlias = primary.Tablet.Alias 59 return nil 60 }) 61 if err != nil { 62 t.Fatalf("UpdateShardFields failed: %v", err) 63 } 64 65 // primary will be asked for permissions 66 primary.FakeMysqlDaemon.FetchSuperQueryMap = map[string]*sqltypes.Result{ 67 "SELECT * FROM mysql.user ORDER BY host, user": { 68 Fields: []*querypb.Field{ 69 { 70 Name: "Host", 71 Type: sqltypes.Char, 72 }, 73 { 74 Name: "User", 75 Type: sqltypes.Char, 76 }, 77 { 78 Name: "Password", 79 Type: sqltypes.Char, 80 }, 81 { 82 Name: "Select_priv", 83 Type: sqltypes.Char, 84 }, 85 { 86 Name: "Insert_priv", 87 Type: sqltypes.Char, 88 }, 89 { 90 Name: "Update_priv", 91 Type: sqltypes.Char, 92 }, 93 { 94 Name: "Delete_priv", 95 Type: sqltypes.Char, 96 }, 97 { 98 Name: "Create_priv", 99 Type: sqltypes.Char, 100 }, 101 { 102 Name: "Drop_priv", 103 Type: sqltypes.Char, 104 }, 105 { 106 Name: "Reload_priv", 107 Type: sqltypes.Char, 108 }, 109 { 110 Name: "Shutdown_priv", 111 Type: sqltypes.Char, 112 }, 113 { 114 Name: "Process_priv", 115 Type: sqltypes.Char, 116 }, 117 { 118 Name: "File_priv", 119 Type: sqltypes.Char, 120 }, 121 { 122 Name: "Grant_priv", 123 Type: sqltypes.Char, 124 }, 125 { 126 Name: "References_priv", 127 Type: sqltypes.Char, 128 }, 129 { 130 Name: "Index_priv", 131 Type: sqltypes.Char, 132 }, 133 { 134 Name: "Alter_priv", 135 Type: sqltypes.Char, 136 }, 137 { 138 Name: "Show_db_priv", 139 Type: sqltypes.Char, 140 }, 141 { 142 Name: "Super_priv", 143 Type: sqltypes.Char, 144 }, 145 { 146 Name: "Create_tmp_table_priv", 147 Type: sqltypes.Char, 148 }, 149 { 150 Name: "Lock_tables_priv", 151 Type: sqltypes.Char, 152 }, 153 { 154 Name: "Execute_priv", 155 Type: sqltypes.Char, 156 }, 157 { 158 Name: "Repl_slave_priv", 159 Type: sqltypes.Char, 160 }, 161 { 162 Name: "Repl_client_priv", 163 Type: sqltypes.Char, 164 }, 165 { 166 Name: "Create_view_priv", 167 Type: sqltypes.Char, 168 }, 169 { 170 Name: "Show_view_priv", 171 Type: sqltypes.Char, 172 }, 173 { 174 Name: "Create_routine_priv", 175 Type: sqltypes.Char, 176 }, 177 { 178 Name: "Alter_routine_priv", 179 Type: sqltypes.Char, 180 }, 181 { 182 Name: "Create_user_priv", 183 Type: sqltypes.Char, 184 }, 185 { 186 Name: "Event_priv", 187 Type: sqltypes.Char, 188 }, 189 { 190 Name: "Trigger_priv", 191 Type: sqltypes.Char, 192 }, 193 { 194 Name: "Create_tablespace_priv", 195 Type: sqltypes.Char, 196 }, 197 { 198 Name: "ssl_type", 199 Type: sqltypes.Char, 200 }, 201 { 202 Name: "ssl_cipher", 203 Type: 252, 204 }, 205 { 206 Name: "x509_issuer", 207 Type: 252, 208 }, 209 { 210 Name: "x509_subject", 211 Type: 252, 212 }, 213 { 214 Name: "max_questions", 215 Type: 3, 216 }, 217 { 218 Name: "max_updates", 219 Type: 3, 220 }, 221 { 222 Name: "max_connections", 223 Type: 3, 224 }, 225 { 226 Name: "max_user_connections", 227 Type: 3, 228 }, 229 { 230 Name: "plugin", 231 Type: sqltypes.Char, 232 }, 233 { 234 Name: "authentication_string", 235 Type: 252, 236 }, 237 { 238 Name: "password_expired", 239 Type: sqltypes.Char, 240 }, 241 { 242 Name: "is_role", 243 Type: sqltypes.Char, 244 }}, 245 RowsAffected: 0x6, 246 InsertID: 0x0, 247 Rows: [][]sqltypes.Value{ 248 { 249 sqltypes.NewVarBinary("test_host1"), 250 sqltypes.NewVarBinary("test_user1"), 251 sqltypes.NewVarBinary("test_password1"), 252 sqltypes.NewVarBinary("Y"), 253 sqltypes.NewVarBinary("Y"), 254 sqltypes.NewVarBinary("Y"), 255 sqltypes.NewVarBinary("Y"), 256 sqltypes.NewVarBinary("Y"), 257 sqltypes.NewVarBinary("Y"), 258 sqltypes.NewVarBinary("Y"), 259 sqltypes.NewVarBinary("Y"), 260 sqltypes.NewVarBinary("Y"), 261 sqltypes.NewVarBinary("Y"), 262 sqltypes.NewVarBinary("Y"), 263 sqltypes.NewVarBinary("Y"), 264 sqltypes.NewVarBinary("Y"), 265 sqltypes.NewVarBinary("Y"), 266 sqltypes.NewVarBinary("Y"), 267 sqltypes.NewVarBinary("Y"), 268 sqltypes.NewVarBinary("Y"), 269 sqltypes.NewVarBinary("Y"), 270 sqltypes.NewVarBinary("Y"), 271 sqltypes.NewVarBinary("Y"), 272 sqltypes.NewVarBinary("Y"), 273 sqltypes.NewVarBinary("Y"), 274 sqltypes.NewVarBinary("Y"), 275 sqltypes.NewVarBinary("Y"), 276 sqltypes.NewVarBinary("Y"), 277 sqltypes.NewVarBinary("Y"), 278 sqltypes.NewVarBinary("Y"), 279 sqltypes.NewVarBinary("Y"), 280 sqltypes.NewVarBinary("Y"), 281 sqltypes.NewVarBinary(""), 282 sqltypes.NewVarBinary(""), 283 sqltypes.NewVarBinary(""), 284 sqltypes.NewVarBinary(""), 285 sqltypes.NewVarBinary("0"), 286 sqltypes.NewVarBinary("0"), 287 sqltypes.NewVarBinary("0"), 288 sqltypes.NewVarBinary("0"), 289 sqltypes.NewVarBinary(""), 290 sqltypes.NewVarBinary(""), 291 sqltypes.NewVarBinary("N"), 292 sqltypes.NewVarBinary("N")}, 293 { 294 sqltypes.NewVarBinary("test_host2"), 295 sqltypes.NewVarBinary("test_user2"), 296 sqltypes.NewVarBinary("test_password2"), 297 sqltypes.NewVarBinary("Y"), 298 sqltypes.NewVarBinary("Y"), 299 sqltypes.NewVarBinary("Y"), 300 sqltypes.NewVarBinary("Y"), 301 sqltypes.NewVarBinary("Y"), 302 sqltypes.NewVarBinary("Y"), 303 sqltypes.NewVarBinary("Y"), 304 sqltypes.NewVarBinary("Y"), 305 sqltypes.NewVarBinary("Y"), 306 sqltypes.NewVarBinary("Y"), 307 sqltypes.NewVarBinary("Y"), 308 sqltypes.NewVarBinary("Y"), 309 sqltypes.NewVarBinary("Y"), 310 sqltypes.NewVarBinary("Y"), 311 sqltypes.NewVarBinary("Y"), 312 sqltypes.NewVarBinary("Y"), 313 sqltypes.NewVarBinary("Y"), 314 sqltypes.NewVarBinary("Y"), 315 sqltypes.NewVarBinary("Y"), 316 sqltypes.NewVarBinary("Y"), 317 sqltypes.NewVarBinary("Y"), 318 sqltypes.NewVarBinary("Y"), 319 sqltypes.NewVarBinary("Y"), 320 sqltypes.NewVarBinary("Y"), 321 sqltypes.NewVarBinary("Y"), 322 sqltypes.NewVarBinary("Y"), 323 sqltypes.NewVarBinary("Y"), 324 sqltypes.NewVarBinary("Y"), 325 sqltypes.NewVarBinary("Y"), 326 sqltypes.NewVarBinary(""), 327 sqltypes.NewVarBinary(""), 328 sqltypes.NewVarBinary(""), 329 sqltypes.NewVarBinary(""), 330 sqltypes.NewVarBinary("0"), 331 sqltypes.NewVarBinary("0"), 332 sqltypes.NewVarBinary("0"), 333 sqltypes.NewVarBinary("0"), 334 sqltypes.NewVarBinary(""), 335 sqltypes.NewVarBinary(""), 336 sqltypes.NewVarBinary("N"), 337 sqltypes.NewVarBinary("N")}, 338 { 339 sqltypes.NewVarBinary("test_host3"), 340 sqltypes.NewVarBinary("test_user3"), 341 sqltypes.NewVarBinary("test_password3"), 342 sqltypes.NewVarBinary("Y"), 343 sqltypes.NewVarBinary("Y"), 344 sqltypes.NewVarBinary("Y"), 345 sqltypes.NewVarBinary("Y"), 346 sqltypes.NewVarBinary("Y"), 347 sqltypes.NewVarBinary("Y"), 348 sqltypes.NewVarBinary("Y"), 349 sqltypes.NewVarBinary("N"), 350 sqltypes.NewVarBinary("Y"), 351 sqltypes.NewVarBinary("Y"), 352 sqltypes.NewVarBinary("N"), 353 sqltypes.NewVarBinary("Y"), 354 sqltypes.NewVarBinary("Y"), 355 sqltypes.NewVarBinary("Y"), 356 sqltypes.NewVarBinary("Y"), 357 sqltypes.NewVarBinary("N"), 358 sqltypes.NewVarBinary("Y"), 359 sqltypes.NewVarBinary("Y"), 360 sqltypes.NewVarBinary("Y"), 361 sqltypes.NewVarBinary("Y"), 362 sqltypes.NewVarBinary("Y"), 363 sqltypes.NewVarBinary("Y"), 364 sqltypes.NewVarBinary("Y"), 365 sqltypes.NewVarBinary("Y"), 366 sqltypes.NewVarBinary("Y"), 367 sqltypes.NewVarBinary("Y"), 368 sqltypes.NewVarBinary("Y"), 369 sqltypes.NewVarBinary("Y"), 370 sqltypes.NewVarBinary("N"), 371 sqltypes.NewVarBinary(""), 372 sqltypes.NewVarBinary(""), 373 sqltypes.NewVarBinary(""), 374 sqltypes.NewVarBinary(""), 375 sqltypes.NewVarBinary("0"), 376 sqltypes.NewVarBinary("0"), 377 sqltypes.NewVarBinary("0"), 378 sqltypes.NewVarBinary("0"), 379 sqltypes.NewVarBinary(""), 380 sqltypes.NewVarBinary(""), 381 sqltypes.NewVarBinary("N"), 382 sqltypes.NewVarBinary("N")}, 383 { 384 sqltypes.NewVarBinary("test_host4"), 385 sqltypes.NewVarBinary("test_user4"), 386 sqltypes.NewVarBinary("test_password4"), 387 sqltypes.NewVarBinary("N"), 388 sqltypes.NewVarBinary("N"), 389 sqltypes.NewVarBinary("N"), 390 sqltypes.NewVarBinary("N"), 391 sqltypes.NewVarBinary("N"), 392 sqltypes.NewVarBinary("N"), 393 sqltypes.NewVarBinary("N"), 394 sqltypes.NewVarBinary("N"), 395 sqltypes.NewVarBinary("N"), 396 sqltypes.NewVarBinary("N"), 397 sqltypes.NewVarBinary("N"), 398 sqltypes.NewVarBinary("N"), 399 sqltypes.NewVarBinary("N"), 400 sqltypes.NewVarBinary("N"), 401 sqltypes.NewVarBinary("N"), 402 sqltypes.NewVarBinary("N"), 403 sqltypes.NewVarBinary("N"), 404 sqltypes.NewVarBinary("N"), 405 sqltypes.NewVarBinary("N"), 406 sqltypes.NewVarBinary("Y"), 407 sqltypes.NewVarBinary("N"), 408 sqltypes.NewVarBinary("N"), 409 sqltypes.NewVarBinary("N"), 410 sqltypes.NewVarBinary("N"), 411 sqltypes.NewVarBinary("N"), 412 sqltypes.NewVarBinary("N"), 413 sqltypes.NewVarBinary("N"), 414 sqltypes.NewVarBinary("N"), 415 sqltypes.NewVarBinary("N"), 416 sqltypes.NewVarBinary(""), 417 sqltypes.NewVarBinary(""), 418 sqltypes.NewVarBinary(""), 419 sqltypes.NewVarBinary(""), 420 sqltypes.NewVarBinary("0"), 421 sqltypes.NewVarBinary("0"), 422 sqltypes.NewVarBinary("0"), 423 sqltypes.NewVarBinary("0"), 424 sqltypes.NewVarBinary(""), 425 sqltypes.NewVarBinary(""), 426 sqltypes.NewVarBinary("N"), 427 sqltypes.NewVarBinary("N"), 428 }, 429 }, 430 }, 431 "SELECT * FROM mysql.db ORDER BY host, db, user": { 432 Fields: []*querypb.Field{ 433 { 434 Name: "Host", 435 Type: sqltypes.Char, 436 }, 437 { 438 Name: "Db", 439 Type: sqltypes.Char, 440 }, 441 { 442 Name: "User", 443 Type: sqltypes.Char, 444 }, 445 { 446 Name: "Select_priv", 447 Type: sqltypes.Char, 448 }, 449 { 450 Name: "Insert_priv", 451 Type: sqltypes.Char, 452 }, 453 { 454 Name: "Update_priv", 455 Type: sqltypes.Char, 456 }, 457 { 458 Name: "Delete_priv", 459 Type: sqltypes.Char, 460 }, 461 { 462 Name: "Create_priv", 463 Type: sqltypes.Char, 464 }, 465 { 466 Name: "Drop_priv", 467 Type: sqltypes.Char, 468 }, 469 { 470 Name: "Grant_priv", 471 Type: sqltypes.Char, 472 }, 473 { 474 Name: "References_priv", 475 Type: sqltypes.Char, 476 }, 477 { 478 Name: "Index_priv", 479 Type: sqltypes.Char, 480 }, 481 { 482 Name: "Alter_priv", 483 Type: sqltypes.Char, 484 }, 485 { 486 Name: "Create_tmp_table_priv", 487 Type: sqltypes.Char, 488 }, 489 { 490 Name: "Lock_tables_priv", 491 Type: sqltypes.Char, 492 }, 493 { 494 Name: "Create_view_priv", 495 Type: sqltypes.Char, 496 }, 497 { 498 Name: "Show_view_priv", 499 Type: sqltypes.Char, 500 }, 501 { 502 Name: "Create_routine_priv", 503 Type: sqltypes.Char, 504 }, 505 { 506 Name: "Alter_routine_priv", 507 Type: sqltypes.Char, 508 }, 509 { 510 Name: "Execute_priv", 511 Type: sqltypes.Char, 512 }, 513 { 514 Name: "Event_priv", 515 Type: sqltypes.Char, 516 }, 517 { 518 Name: "Trigger_priv", 519 Type: sqltypes.Char, 520 }, 521 }, 522 RowsAffected: 0, 523 InsertID: 0, 524 Rows: [][]sqltypes.Value{ 525 { 526 sqltypes.NewVarBinary("test_host"), 527 sqltypes.NewVarBinary("test_db"), 528 sqltypes.NewVarBinary("test_user"), 529 sqltypes.NewVarBinary("Y"), 530 sqltypes.NewVarBinary("Y"), 531 sqltypes.NewVarBinary("Y"), 532 sqltypes.NewVarBinary("Y"), 533 sqltypes.NewVarBinary("Y"), 534 sqltypes.NewVarBinary("Y"), 535 sqltypes.NewVarBinary("N"), 536 sqltypes.NewVarBinary("Y"), 537 sqltypes.NewVarBinary("Y"), 538 sqltypes.NewVarBinary("Y"), 539 sqltypes.NewVarBinary("Y"), 540 sqltypes.NewVarBinary("Y"), 541 sqltypes.NewVarBinary("N"), 542 sqltypes.NewVarBinary("Y"), 543 sqltypes.NewVarBinary("Y"), 544 sqltypes.NewVarBinary("Y"), 545 sqltypes.NewVarBinary("Y"), 546 sqltypes.NewVarBinary("Y"), 547 sqltypes.NewVarBinary("Y"), 548 }, 549 }, 550 }, 551 } 552 primary.StartActionLoop(t, wr) 553 defer primary.StopActionLoop(t) 554 555 // Make a two-level-deep copy, so we can make them diverge later. 556 user := *primary.FakeMysqlDaemon.FetchSuperQueryMap["SELECT * FROM mysql.user ORDER BY host, user"] 557 user.Fields = append([]*querypb.Field{}, user.Fields...) 558 559 // replica will be asked for permissions 560 replica.FakeMysqlDaemon.FetchSuperQueryMap = map[string]*sqltypes.Result{ 561 "SELECT * FROM mysql.user ORDER BY host, user": &user, 562 "SELECT * FROM mysql.db ORDER BY host, db, user": primary.FakeMysqlDaemon.FetchSuperQueryMap["SELECT * FROM mysql.db ORDER BY host, db, user"], 563 } 564 replica.FakeMysqlDaemon.SetReplicationSourceInputs = append(replica.FakeMysqlDaemon.SetReplicationSourceInputs, topoproto.MysqlAddr(primary.Tablet)) 565 replica.FakeMysqlDaemon.ExpectedExecuteSuperQueryList = []string{ 566 // These 4 statements come from tablet startup 567 "STOP SLAVE", 568 "RESET SLAVE ALL", 569 "FAKE SET MASTER", 570 "START SLAVE", 571 } 572 replica.StartActionLoop(t, wr) 573 defer replica.StopActionLoop(t) 574 575 // Overwrite with the correct value to make sure it passes. 576 replica.FakeMysqlDaemon.FetchSuperQueryMap["SELECT * FROM mysql.user ORDER BY host, user"].Fields[0] = &querypb.Field{ 577 Name: "Host", 578 Type: sqltypes.Char, 579 } 580 581 // run ValidatePermissionsKeyspace, this should work 582 if err := vp.Run([]string{"ValidatePermissionsKeyspace", primary.Tablet.Keyspace}); err != nil { 583 t.Fatalf("ValidatePermissionsKeyspace failed: %v", err) 584 } 585 586 // modify one field, this should fail 587 replica.FakeMysqlDaemon.FetchSuperQueryMap["SELECT * FROM mysql.user ORDER BY host, user"].Fields[0] = &querypb.Field{ 588 Name: "Wrong", 589 Type: sqltypes.Char, 590 } 591 592 // run ValidatePermissionsKeyspace again, this should now fail 593 if err := vp.Run([]string{"ValidatePermissionsKeyspace", primary.Tablet.Keyspace}); err == nil || !strings.Contains(err.Error(), "has an extra user") { 594 t.Fatalf("ValidatePermissionsKeyspace has unexpected err: %v", err) 595 } 596 597 }