github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/cmd/authn/unit_test.go (about) 1 // Package authn is authentication server for AIStore. 2 /* 3 * Copyright (c) 2018-2022, NVIDIA CORPORATION. All rights reserved. 4 */ 5 package main 6 7 import ( 8 "testing" 9 "time" 10 11 "github.com/NVIDIA/aistore/api/authn" 12 "github.com/NVIDIA/aistore/cmd/authn/tok" 13 "github.com/NVIDIA/aistore/cmn" 14 "github.com/NVIDIA/aistore/cmn/cos" 15 "github.com/NVIDIA/aistore/core/mock" 16 "github.com/NVIDIA/aistore/tools/tassert" 17 ) 18 19 var ( 20 users = []string{"user1", "user2", "user3"} 21 passs = []string{"pass2", "pass1", "passs"} 22 ) 23 24 func init() { 25 // Set default expiration time to 30 minutes 26 if Conf.Server.ExpirePeriod == 0 { 27 Conf.Server.ExpirePeriod = cos.Duration(time.Minute * 30) 28 } 29 } 30 31 func createUsers(mgr *mgr, t *testing.T) { 32 for idx := range users { 33 user := &authn.User{ID: users[idx], Password: passs[idx], Roles: []string{GuestRole}} 34 err := mgr.addUser(user) 35 if err != nil { 36 t.Errorf("Failed to create a user %s: %v", users[idx], err) 37 } 38 } 39 40 srvUsers, err := mgr.userList() 41 tassert.CheckFatal(t, err) 42 if len(srvUsers) != len(users)+1 { 43 t.Errorf("User count mismatch. Found %d users instead of %d", len(srvUsers), len(users)+1) 44 } 45 for _, username := range users { 46 _, ok := srvUsers[username] 47 if !ok { 48 t.Errorf("User %q not found", username) 49 } 50 } 51 } 52 53 func deleteUsers(mgr *mgr, skipNotExist bool, t *testing.T) { 54 var err error 55 for _, username := range users { 56 err = mgr.delUser(username) 57 if err != nil { 58 if !cos.IsErrNotFound(err) || !skipNotExist { 59 t.Errorf("Failed to delete user %s: %v", username, err) 60 } 61 } 62 } 63 } 64 65 func testInvalidUser(mgr *mgr, t *testing.T) { 66 user := &authn.User{ID: users[0], Password: passs[1], Roles: []string{GuestRole}} 67 err := mgr.addUser(user) 68 if err == nil { 69 t.Errorf("User with the existing name %s was created: %v", users[0], err) 70 } 71 72 nonexisting := "someuser" 73 err = mgr.delUser(nonexisting) 74 if err == nil { 75 t.Errorf("Non-existing user %s was deleted: %v", nonexisting, err) 76 } 77 } 78 79 func testUserDelete(mgr *mgr, t *testing.T) { 80 const ( 81 username = "newuser" 82 userpass = "newpass" 83 ) 84 user := &authn.User{ID: username, Password: userpass, Roles: []string{GuestRole}} 85 err := mgr.addUser(user) 86 if err != nil { 87 t.Errorf("Failed to create a user %s: %v", username, err) 88 } 89 srvUsers, err := mgr.userList() 90 tassert.CheckFatal(t, err) 91 if len(srvUsers) != len(users)+2 { 92 t.Errorf("Expected %d users but found %d", len(users)+2, len(srvUsers)) 93 } 94 95 clu := authn.CluACL{ 96 ID: "ABCD", 97 Alias: "cluster-test", 98 URLs: []string{"http://localhost:8080"}, 99 } 100 if err := mgr.db.Set(clustersCollection, clu.ID, clu); err != nil { 101 t.Error(err) 102 } 103 defer mgr.delCluster(clu.ID) 104 105 loginMsg := &authn.LoginMsg{ClusterID: clu.Alias} 106 token, err := mgr.issueToken(username, userpass, loginMsg) 107 if err != nil || token == "" { 108 t.Errorf("Failed to generate token for %s: %v", username, err) 109 } 110 111 err = mgr.delUser(username) 112 if err != nil { 113 t.Errorf("Failed to delete user %s: %v", username, err) 114 } 115 srvUsers, err = mgr.userList() 116 tassert.CheckFatal(t, err) 117 if len(srvUsers) != len(users)+1 { 118 t.Errorf("Expected %d users but found %d", len(users)+1, len(srvUsers)) 119 } 120 token, err = mgr.issueToken(username, userpass, loginMsg) 121 if err == nil { 122 t.Errorf("Token issued for deleted user %s: %v", username, token) 123 } else if err != errInvalidCredentials { 124 t.Errorf("Invalid error: %v", err) 125 } 126 } 127 128 func TestManager(t *testing.T) { 129 driver := mock.NewDBDriver() 130 // NOTE: new manager initailizes users DB and adds a default user as a Guest 131 mgr, err := newMgr(driver) 132 tassert.CheckError(t, err) 133 createUsers(mgr, t) 134 testInvalidUser(mgr, t) 135 testUserDelete(mgr, t) 136 deleteUsers(mgr, false, t) 137 } 138 139 func TestToken(t *testing.T) { 140 if testing.Short() { 141 t.Skipf("skipping %s in short mode", t.Name()) 142 } 143 var ( 144 err error 145 token string 146 secret = Conf.Server.Secret 147 ) 148 149 driver := mock.NewDBDriver() 150 mgr, err := newMgr(driver) 151 tassert.CheckFatal(t, err) 152 createUsers(mgr, t) 153 defer deleteUsers(mgr, false, t) 154 155 clu := authn.CluACL{ 156 ID: "ABCD", 157 Alias: "cluster-test", 158 URLs: []string{"http://localhost:8080"}, 159 } 160 if err := mgr.db.Set(clustersCollection, clu.ID, clu); err != nil { 161 t.Error(err) 162 } 163 defer mgr.delCluster(clu.ID) 164 165 // correct user creds 166 shortExpiration := 2 * time.Second 167 loginMsg := &authn.LoginMsg{ClusterID: clu.Alias, ExpiresIn: &shortExpiration} 168 token, err = mgr.issueToken(users[1], passs[1], loginMsg) 169 if err != nil || token == "" { 170 t.Errorf("Failed to generate token for %s: %v", users[1], err) 171 } 172 info, err := tok.DecryptToken(token, secret) 173 if err != nil { 174 t.Fatalf("Failed to decript token %v: %v", token, err) 175 } 176 if info.UserID != users[1] { 177 t.Errorf("Invalid user %s returned for token of %s", info.UserID, users[1]) 178 } 179 180 // incorrect user creds 181 loginMsg = &authn.LoginMsg{} 182 tokenInval, err := mgr.issueToken(users[1], passs[0], loginMsg) 183 if tokenInval != "" || err == nil { 184 t.Errorf("Some token generated for incorrect user creds: %v", tokenInval) 185 } 186 187 // expired token test 188 time.Sleep(shortExpiration) 189 tk, err := tok.DecryptToken(token, secret) 190 tassert.CheckFatal(t, err) 191 if tk.Expires.After(time.Now()) { 192 t.Fatalf("Token must be expired: %s", token) 193 } 194 } 195 196 func TestMergeCluACLS(t *testing.T) { 197 tests := []struct { 198 title string 199 cluFlt string 200 toACLs cluACLList 201 fromACLs cluACLList 202 resACLs cluACLList 203 }{ 204 { 205 title: "The same lists", 206 toACLs: []*authn.CluACL{ 207 { 208 ID: "1234", 209 Alias: "one", 210 Access: 20, 211 }, 212 { 213 ID: "5678", 214 Alias: "second", 215 Access: 20, 216 }, 217 }, 218 fromACLs: []*authn.CluACL{ 219 { 220 ID: "1234", 221 Alias: "one", 222 Access: 20, 223 }, 224 }, 225 resACLs: []*authn.CluACL{ 226 { 227 ID: "1234", 228 Alias: "one", 229 Access: 20, 230 }, 231 { 232 ID: "5678", 233 Alias: "second", 234 Access: 20, 235 }, 236 }, 237 }, 238 { 239 title: "Update permissions only", 240 toACLs: []*authn.CluACL{ 241 { 242 ID: "1234", 243 Alias: "one", 244 Access: 20, 245 }, 246 { 247 ID: "5678", 248 Alias: "second", 249 Access: 20, 250 }, 251 }, 252 fromACLs: []*authn.CluACL{ 253 { 254 ID: "1234", 255 Alias: "one", 256 Access: 40, 257 }, 258 }, 259 resACLs: []*authn.CluACL{ 260 { 261 ID: "1234", 262 Alias: "one", 263 Access: 40, 264 }, 265 { 266 ID: "5678", 267 Alias: "second", 268 Access: 20, 269 }, 270 }, 271 }, 272 { 273 title: "Append new cluster", 274 toACLs: []*authn.CluACL{ 275 { 276 ID: "1234", 277 Alias: "one", 278 Access: 20, 279 }, 280 { 281 ID: "5678", 282 Alias: "second", 283 Access: 20, 284 }, 285 }, 286 fromACLs: []*authn.CluACL{ 287 { 288 ID: "abcde", 289 Alias: "third", 290 Access: 40, 291 }, 292 { 293 ID: "hijk", 294 Alias: "fourth", 295 Access: 40, 296 }, 297 }, 298 resACLs: []*authn.CluACL{ 299 { 300 ID: "1234", 301 Alias: "one", 302 Access: 20, 303 }, 304 { 305 ID: "5678", 306 Alias: "second", 307 Access: 20, 308 }, 309 { 310 ID: "abcde", 311 Alias: "third", 312 Access: 40, 313 }, 314 { 315 ID: "hijk", 316 Alias: "fourth", 317 Access: 40, 318 }, 319 }, 320 }, 321 { 322 title: "Update permissions for existing cluster and apend new ones", 323 toACLs: []*authn.CluACL{ 324 { 325 ID: "1234", 326 Alias: "one", 327 Access: 20, 328 }, 329 { 330 ID: "5678", 331 Alias: "second", 332 Access: 20, 333 }, 334 }, 335 fromACLs: []*authn.CluACL{ 336 { 337 ID: "1234", 338 Alias: "one", 339 Access: 40, 340 }, 341 { 342 ID: "abcde", 343 Alias: "third", 344 Access: 60, 345 }, 346 }, 347 resACLs: []*authn.CluACL{ 348 { 349 ID: "1234", 350 Alias: "one", 351 Access: 40, 352 }, 353 { 354 ID: "5678", 355 Alias: "second", 356 Access: 20, 357 }, 358 { 359 ID: "abcde", 360 Alias: "third", 361 Access: 60, 362 }, 363 }, 364 }, 365 { 366 title: "Append only 'abcde' cluster", 367 cluFlt: "abcde", 368 toACLs: []*authn.CluACL{ 369 { 370 ID: "1234", 371 Alias: "one", 372 Access: 20, 373 }, 374 { 375 ID: "5678", 376 Alias: "second", 377 Access: 20, 378 }, 379 }, 380 fromACLs: []*authn.CluACL{ 381 { 382 ID: "abcde", 383 Alias: "third", 384 Access: 40, 385 }, 386 { 387 ID: "hijk", 388 Alias: "fourth", 389 Access: 40, 390 }, 391 }, 392 resACLs: []*authn.CluACL{ 393 { 394 ID: "1234", 395 Alias: "one", 396 Access: 20, 397 }, 398 { 399 ID: "5678", 400 Alias: "second", 401 Access: 20, 402 }, 403 { 404 ID: "abcde", 405 Alias: "third", 406 Access: 40, 407 }, 408 }, 409 }, 410 } 411 for _, test := range tests { 412 res := mergeClusterACLs(test.toACLs, test.fromACLs, test.cluFlt) 413 for i, r := range res { 414 if r.String() != test.resACLs[i].String() || r.Access != test.resACLs[i].Access { 415 t.Errorf("%s[filter: %s]: %v[%v] != %v[%v]", test.title, test.cluFlt, r, r.Access, test.resACLs[i], test.resACLs[i].Access) 416 } 417 } 418 } 419 } 420 421 func newBck(name, provider, uuid string) cmn.Bck { 422 return cmn.Bck{ 423 Name: name, 424 Provider: provider, 425 Ns: cmn.Ns{UUID: uuid}, 426 } 427 } 428 429 func TestMergeBckACLS(t *testing.T) { 430 tests := []struct { 431 title string 432 cluFlt string 433 toACLs bckACLList 434 fromACLs bckACLList 435 resACLs bckACLList 436 }{ 437 { 438 title: "Nothing to update", 439 toACLs: []*authn.BckACL{ 440 { 441 Bck: newBck("bck", "ais", "1234"), 442 Access: 20, 443 }, 444 { 445 Bck: newBck("bck", "ais", "5678"), 446 Access: 20, 447 }, 448 }, 449 fromACLs: []*authn.BckACL{ 450 { 451 Bck: newBck("bck", "ais", "1234"), 452 Access: 20, 453 }, 454 }, 455 resACLs: []*authn.BckACL{ 456 { 457 Bck: newBck("bck", "ais", "1234"), 458 Access: 20, 459 }, 460 { 461 Bck: newBck("bck", "ais", "5678"), 462 Access: 20, 463 }, 464 }, 465 }, 466 { 467 title: "Update permissions only", 468 toACLs: []*authn.BckACL{ 469 { 470 Bck: newBck("bck", "ais", "1234"), 471 Access: 20, 472 }, 473 { 474 Bck: newBck("bck", "ais", "5678"), 475 Access: 20, 476 }, 477 }, 478 fromACLs: []*authn.BckACL{ 479 { 480 Bck: newBck("bck", "ais", "5678"), 481 Access: 40, 482 }, 483 }, 484 resACLs: []*authn.BckACL{ 485 { 486 Bck: newBck("bck", "ais", "1234"), 487 Access: 20, 488 }, 489 { 490 Bck: newBck("bck", "ais", "5678"), 491 Access: 40, 492 }, 493 }, 494 }, 495 { 496 title: "Append new buckets", 497 toACLs: []*authn.BckACL{ 498 { 499 Bck: newBck("bck", "ais", "1234"), 500 Access: 20, 501 }, 502 { 503 Bck: newBck("bck", "ais", "5678"), 504 Access: 20, 505 }, 506 }, 507 fromACLs: []*authn.BckACL{ 508 { 509 Bck: newBck("bck", "ais", "5678"), 510 Access: 30, 511 }, 512 { 513 Bck: newBck("bck", "aws", "5678"), 514 Access: 40, 515 }, 516 { 517 Bck: newBck("bck1", "ais", "1234"), 518 Access: 50, 519 }, 520 }, 521 resACLs: []*authn.BckACL{ 522 { 523 Bck: newBck("bck", "ais", "1234"), 524 Access: 20, 525 }, 526 { 527 Bck: newBck("bck", "ais", "5678"), 528 Access: 30, 529 }, 530 { 531 Bck: newBck("bck", "aws", "5678"), 532 Access: 40, 533 }, 534 { 535 Bck: newBck("bck1", "ais", "1234"), 536 Access: 50, 537 }, 538 }, 539 }, 540 { 541 title: "Update permissions for existing buckets and apend new ones", 542 toACLs: []*authn.BckACL{ 543 { 544 Bck: newBck("bck", "ais", "1234"), 545 Access: 20, 546 }, 547 { 548 Bck: newBck("bck", "ais", "5678"), 549 Access: 20, 550 }, 551 }, 552 fromACLs: []*authn.BckACL{ 553 { 554 Bck: newBck("bck2", "ais", "1234"), 555 Access: 20, 556 }, 557 { 558 Bck: newBck("bck", "ais", "1234"), 559 Access: 70, 560 }, 561 }, 562 resACLs: []*authn.BckACL{ 563 { 564 Bck: newBck("bck", "ais", "1234"), 565 Access: 70, 566 }, 567 { 568 Bck: newBck("bck", "ais", "5678"), 569 Access: 20, 570 }, 571 { 572 Bck: newBck("bck2", "ais", "1234"), 573 Access: 20, 574 }, 575 }, 576 }, 577 { 578 title: "Append and update buckets of '5678' cluster only", 579 cluFlt: "5678", 580 toACLs: []*authn.BckACL{ 581 { 582 Bck: newBck("bck", "ais", "1234"), 583 Access: 20, 584 }, 585 { 586 Bck: newBck("bck", "ais", "5678"), 587 Access: 20, 588 }, 589 }, 590 fromACLs: []*authn.BckACL{ 591 { 592 Bck: newBck("bck2", "ais", "5678"), 593 Access: 60, 594 }, 595 { 596 Bck: newBck("bck2", "ais", "1234"), 597 Access: 70, 598 }, 599 { 600 Bck: newBck("bck", "ais", "5678"), 601 Access: 90, 602 }, 603 }, 604 resACLs: []*authn.BckACL{ 605 { 606 Bck: newBck("bck", "ais", "1234"), 607 Access: 20, 608 }, 609 { 610 Bck: newBck("bck", "ais", "5678"), 611 Access: 90, 612 }, 613 { 614 Bck: newBck("bck2", "ais", "5678"), 615 Access: 60, 616 }, 617 }, 618 }, 619 } 620 for _, test := range tests { 621 res := mergeBckACLs(test.toACLs, test.fromACLs, test.cluFlt) 622 for i, r := range res { 623 if !r.Bck.Equal(&test.resACLs[i].Bck) || r.Access != test.resACLs[i].Access { 624 t.Errorf("%s[filter: %s]: %v[%v] != %v[%v]", test.title, test.cluFlt, r.Bck, r.Access, test.resACLs[i], test.resACLs[i].Access) 625 } 626 } 627 } 628 }