1// Copyright 2016 The etcd Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package auth 16 17import ( 18 "context" 19 "fmt" 20 "os" 21 "reflect" 22 "strings" 23 "sync" 24 "testing" 25 "time" 26 27 "go.etcd.io/etcd/auth/authpb" 28 "go.etcd.io/etcd/etcdserver/api/v3rpc/rpctypes" 29 pb "go.etcd.io/etcd/etcdserver/etcdserverpb" 30 "go.etcd.io/etcd/mvcc/backend" 31 32 "go.uber.org/zap" 33 "golang.org/x/crypto/bcrypt" 34 "google.golang.org/grpc/metadata" 35) 36 37func dummyIndexWaiter(index uint64) <-chan struct{} { 38 ch := make(chan struct{}) 39 go func() { 40 ch <- struct{}{} 41 }() 42 return ch 43} 44 45// TestNewAuthStoreRevision ensures newly auth store 46// keeps the old revision when there are no changes. 47func TestNewAuthStoreRevision(t *testing.T) { 48 b, tPath := backend.NewDefaultTmpBackend() 49 defer os.Remove(tPath) 50 51 tp, err := NewTokenProvider(zap.NewExample(), tokenTypeSimple, dummyIndexWaiter) 52 if err != nil { 53 t.Fatal(err) 54 } 55 as := NewAuthStore(zap.NewExample(), b, nil, tp, bcrypt.MinCost) 56 err = enableAuthAndCreateRoot(as) 57 if err != nil { 58 t.Fatal(err) 59 } 60 old := as.Revision() 61 as.Close() 62 b.Close() 63 64 // no changes to commit 65 b2 := backend.NewDefaultBackend(tPath) 66 as = NewAuthStore(zap.NewExample(), b2, nil, tp, bcrypt.MinCost) 67 new := as.Revision() 68 as.Close() 69 b2.Close() 70 71 if old != new { 72 t.Fatalf("expected revision %d, got %d", old, new) 73 } 74} 75 76// TestNewAuthStoreBryptCost ensures that NewAuthStore uses default when given bcrypt-cost is invalid 77func TestNewAuthStoreBcryptCost(t *testing.T) { 78 b, tPath := backend.NewDefaultTmpBackend() 79 defer os.Remove(tPath) 80 81 tp, err := NewTokenProvider(zap.NewExample(), tokenTypeSimple, dummyIndexWaiter) 82 if err != nil { 83 t.Fatal(err) 84 } 85 86 invalidCosts := [2]int{bcrypt.MinCost - 1, bcrypt.MaxCost + 1} 87 for _, invalidCost := range invalidCosts { 88 as := NewAuthStore(zap.NewExample(), b, nil, tp, invalidCost) 89 if as.BcryptCost() != bcrypt.DefaultCost { 90 t.Fatalf("expected DefaultCost when bcryptcost is invalid") 91 } 92 as.Close() 93 } 94 95 b.Close() 96} 97 98func setupAuthStore(t *testing.T) (store *authStore, teardownfunc func(t *testing.T)) { 99 b, tPath := backend.NewDefaultTmpBackend() 100 101 tp, err := NewTokenProvider(zap.NewExample(), tokenTypeSimple, dummyIndexWaiter) 102 if err != nil { 103 t.Fatal(err) 104 } 105 as := NewAuthStore(zap.NewExample(), b, nil, tp, bcrypt.MinCost) 106 err = enableAuthAndCreateRoot(as) 107 if err != nil { 108 t.Fatal(err) 109 } 110 111 // adds a new role 112 _, err = as.RoleAdd(&pb.AuthRoleAddRequest{Name: "role-test"}) 113 if err != nil { 114 t.Fatal(err) 115 } 116 117 ua := &pb.AuthUserAddRequest{Name: "foo", Password: "bar", Options: &authpb.UserAddOptions{NoPassword: false}} 118 _, err = as.UserAdd(ua) // add a non-existing user 119 if err != nil { 120 t.Fatal(err) 121 } 122 123 tearDown := func(_ *testing.T) { 124 b.Close() 125 os.Remove(tPath) 126 as.Close() 127 } 128 return as, tearDown 129} 130 131func enableAuthAndCreateRoot(as *authStore) error { 132 _, err := as.UserAdd(&pb.AuthUserAddRequest{Name: "root", Password: "root", Options: &authpb.UserAddOptions{NoPassword: false}}) 133 if err != nil { 134 return err 135 } 136 137 _, err = as.RoleAdd(&pb.AuthRoleAddRequest{Name: "root"}) 138 if err != nil { 139 return err 140 } 141 142 _, err = as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "root", Role: "root"}) 143 if err != nil { 144 return err 145 } 146 147 return as.AuthEnable() 148} 149 150func TestUserAdd(t *testing.T) { 151 as, tearDown := setupAuthStore(t) 152 defer tearDown(t) 153 154 ua := &pb.AuthUserAddRequest{Name: "foo", Options: &authpb.UserAddOptions{NoPassword: false}} 155 _, err := as.UserAdd(ua) // add an existing user 156 if err == nil { 157 t.Fatalf("expected %v, got %v", ErrUserAlreadyExist, err) 158 } 159 if err != ErrUserAlreadyExist { 160 t.Fatalf("expected %v, got %v", ErrUserAlreadyExist, err) 161 } 162 163 ua = &pb.AuthUserAddRequest{Name: "", Options: &authpb.UserAddOptions{NoPassword: false}} 164 _, err = as.UserAdd(ua) // add a user with empty name 165 if err != ErrUserEmpty { 166 t.Fatal(err) 167 } 168} 169 170func TestRecover(t *testing.T) { 171 as, tearDown := setupAuthStore(t) 172 defer tearDown(t) 173 174 as.enabled = false 175 as.Recover(as.be) 176 177 if !as.IsAuthEnabled() { 178 t.Fatalf("expected auth enabled got disabled") 179 } 180} 181 182func TestCheckPassword(t *testing.T) { 183 as, tearDown := setupAuthStore(t) 184 defer tearDown(t) 185 186 // auth a non-existing user 187 _, err := as.CheckPassword("foo-test", "bar") 188 if err == nil { 189 t.Fatalf("expected %v, got %v", ErrAuthFailed, err) 190 } 191 if err != ErrAuthFailed { 192 t.Fatalf("expected %v, got %v", ErrAuthFailed, err) 193 } 194 195 // auth an existing user with correct password 196 _, err = as.CheckPassword("foo", "bar") 197 if err != nil { 198 t.Fatal(err) 199 } 200 201 // auth an existing user but with wrong password 202 _, err = as.CheckPassword("foo", "") 203 if err == nil { 204 t.Fatalf("expected %v, got %v", ErrAuthFailed, err) 205 } 206 if err != ErrAuthFailed { 207 t.Fatalf("expected %v, got %v", ErrAuthFailed, err) 208 } 209} 210 211func TestUserDelete(t *testing.T) { 212 as, tearDown := setupAuthStore(t) 213 defer tearDown(t) 214 215 // delete an existing user 216 ud := &pb.AuthUserDeleteRequest{Name: "foo"} 217 _, err := as.UserDelete(ud) 218 if err != nil { 219 t.Fatal(err) 220 } 221 222 // delete a non-existing user 223 _, err = as.UserDelete(ud) 224 if err == nil { 225 t.Fatalf("expected %v, got %v", ErrUserNotFound, err) 226 } 227 if err != ErrUserNotFound { 228 t.Fatalf("expected %v, got %v", ErrUserNotFound, err) 229 } 230} 231 232func TestUserChangePassword(t *testing.T) { 233 as, tearDown := setupAuthStore(t) 234 defer tearDown(t) 235 236 ctx1 := context.WithValue(context.WithValue(context.TODO(), AuthenticateParamIndex{}, uint64(1)), AuthenticateParamSimpleTokenPrefix{}, "dummy") 237 _, err := as.Authenticate(ctx1, "foo", "bar") 238 if err != nil { 239 t.Fatal(err) 240 } 241 242 _, err = as.UserChangePassword(&pb.AuthUserChangePasswordRequest{Name: "foo", Password: "baz"}) 243 if err != nil { 244 t.Fatal(err) 245 } 246 247 ctx2 := context.WithValue(context.WithValue(context.TODO(), AuthenticateParamIndex{}, uint64(2)), AuthenticateParamSimpleTokenPrefix{}, "dummy") 248 _, err = as.Authenticate(ctx2, "foo", "baz") 249 if err != nil { 250 t.Fatal(err) 251 } 252 253 // change a non-existing user 254 _, err = as.UserChangePassword(&pb.AuthUserChangePasswordRequest{Name: "foo-test", Password: "bar"}) 255 if err == nil { 256 t.Fatalf("expected %v, got %v", ErrUserNotFound, err) 257 } 258 if err != ErrUserNotFound { 259 t.Fatalf("expected %v, got %v", ErrUserNotFound, err) 260 } 261} 262 263func TestRoleAdd(t *testing.T) { 264 as, tearDown := setupAuthStore(t) 265 defer tearDown(t) 266 267 // adds a new role 268 _, err := as.RoleAdd(&pb.AuthRoleAddRequest{Name: "role-test-1"}) 269 if err != nil { 270 t.Fatal(err) 271 } 272 273 // add a role with empty name 274 _, err = as.RoleAdd(&pb.AuthRoleAddRequest{Name: ""}) 275 if err != ErrRoleEmpty { 276 t.Fatal(err) 277 } 278} 279 280func TestUserGrant(t *testing.T) { 281 as, tearDown := setupAuthStore(t) 282 defer tearDown(t) 283 284 // grants a role to the user 285 _, err := as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "foo", Role: "role-test"}) 286 if err != nil { 287 t.Fatal(err) 288 } 289 290 // grants a role to a non-existing user 291 _, err = as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "foo-test", Role: "role-test"}) 292 if err == nil { 293 t.Errorf("expected %v, got %v", ErrUserNotFound, err) 294 } 295 if err != ErrUserNotFound { 296 t.Errorf("expected %v, got %v", ErrUserNotFound, err) 297 } 298} 299 300func TestHasRole(t *testing.T) { 301 as, tearDown := setupAuthStore(t) 302 defer tearDown(t) 303 304 // grants a role to the user 305 _, err := as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "foo", Role: "role-test"}) 306 if err != nil { 307 t.Fatal(err) 308 } 309 310 // checks role reflects correctly 311 hr := as.HasRole("foo", "role-test") 312 if !hr { 313 t.Fatal("expected role granted, got false") 314 } 315 316 // checks non existent role 317 hr = as.HasRole("foo", "non-existent-role") 318 if hr { 319 t.Fatal("expected role not found, got true") 320 } 321 322 // checks non existent user 323 hr = as.HasRole("nouser", "role-test") 324 if hr { 325 t.Fatal("expected user not found got true") 326 } 327} 328 329func TestIsOpPermitted(t *testing.T) { 330 as, tearDown := setupAuthStore(t) 331 defer tearDown(t) 332 333 // add new role 334 _, err := as.RoleAdd(&pb.AuthRoleAddRequest{Name: "role-test-1"}) 335 if err != nil { 336 t.Fatal(err) 337 } 338 339 perm := &authpb.Permission{ 340 PermType: authpb.WRITE, 341 Key: []byte("Keys"), 342 RangeEnd: []byte("RangeEnd"), 343 } 344 345 _, err = as.RoleGrantPermission(&pb.AuthRoleGrantPermissionRequest{ 346 Name: "role-test-1", 347 Perm: perm, 348 }) 349 if err != nil { 350 t.Fatal(err) 351 } 352 353 // grants a role to the user 354 _, err = as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "foo", Role: "role-test-1"}) 355 if err != nil { 356 t.Fatal(err) 357 } 358 359 // check permission reflected to user 360 361 err = as.isOpPermitted("foo", as.Revision(), perm.Key, perm.RangeEnd, perm.PermType) 362 if err != nil { 363 t.Fatal(err) 364 } 365} 366 367func TestGetUser(t *testing.T) { 368 as, tearDown := setupAuthStore(t) 369 defer tearDown(t) 370 371 _, err := as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "foo", Role: "role-test"}) 372 if err != nil { 373 t.Fatal(err) 374 } 375 376 u, err := as.UserGet(&pb.AuthUserGetRequest{Name: "foo"}) 377 if err != nil { 378 t.Fatal(err) 379 } 380 if u == nil { 381 t.Fatal("expect user not nil, got nil") 382 } 383 expected := []string{"role-test"} 384 if !reflect.DeepEqual(expected, u.Roles) { 385 t.Errorf("expected %v, got %v", expected, u.Roles) 386 } 387 388 // check non existent user 389 _, err = as.UserGet(&pb.AuthUserGetRequest{Name: "nouser"}) 390 if err == nil { 391 t.Errorf("expected %v, got %v", ErrUserNotFound, err) 392 } 393} 394 395func TestListUsers(t *testing.T) { 396 as, tearDown := setupAuthStore(t) 397 defer tearDown(t) 398 399 ua := &pb.AuthUserAddRequest{Name: "user1", Password: "pwd1", Options: &authpb.UserAddOptions{NoPassword: false}} 400 _, err := as.UserAdd(ua) // add a non-existing user 401 if err != nil { 402 t.Fatal(err) 403 } 404 405 ul, err := as.UserList(&pb.AuthUserListRequest{}) 406 if err != nil { 407 t.Fatal(err) 408 } 409 if !contains(ul.Users, "root") { 410 t.Errorf("expected %v in %v", "root", ul.Users) 411 } 412 if !contains(ul.Users, "user1") { 413 t.Errorf("expected %v in %v", "user1", ul.Users) 414 } 415} 416 417func TestRoleGrantPermission(t *testing.T) { 418 as, tearDown := setupAuthStore(t) 419 defer tearDown(t) 420 421 _, err := as.RoleAdd(&pb.AuthRoleAddRequest{Name: "role-test-1"}) 422 if err != nil { 423 t.Fatal(err) 424 } 425 426 perm := &authpb.Permission{ 427 PermType: authpb.WRITE, 428 Key: []byte("Keys"), 429 RangeEnd: []byte("RangeEnd"), 430 } 431 _, err = as.RoleGrantPermission(&pb.AuthRoleGrantPermissionRequest{ 432 Name: "role-test-1", 433 Perm: perm, 434 }) 435 436 if err != nil { 437 t.Error(err) 438 } 439 440 r, err := as.RoleGet(&pb.AuthRoleGetRequest{Role: "role-test-1"}) 441 if err != nil { 442 t.Fatal(err) 443 } 444 445 if !reflect.DeepEqual(perm, r.Perm[0]) { 446 t.Errorf("expected %v, got %v", perm, r.Perm[0]) 447 } 448} 449 450func TestRoleRevokePermission(t *testing.T) { 451 as, tearDown := setupAuthStore(t) 452 defer tearDown(t) 453 454 _, err := as.RoleAdd(&pb.AuthRoleAddRequest{Name: "role-test-1"}) 455 if err != nil { 456 t.Fatal(err) 457 } 458 459 perm := &authpb.Permission{ 460 PermType: authpb.WRITE, 461 Key: []byte("Keys"), 462 RangeEnd: []byte("RangeEnd"), 463 } 464 _, err = as.RoleGrantPermission(&pb.AuthRoleGrantPermissionRequest{ 465 Name: "role-test-1", 466 Perm: perm, 467 }) 468 469 if err != nil { 470 t.Fatal(err) 471 } 472 473 _, err = as.RoleGet(&pb.AuthRoleGetRequest{Role: "role-test-1"}) 474 if err != nil { 475 t.Fatal(err) 476 } 477 478 _, err = as.RoleRevokePermission(&pb.AuthRoleRevokePermissionRequest{ 479 Role: "role-test-1", 480 Key: []byte("Keys"), 481 RangeEnd: []byte("RangeEnd"), 482 }) 483 if err != nil { 484 t.Fatal(err) 485 } 486 487 var r *pb.AuthRoleGetResponse 488 r, err = as.RoleGet(&pb.AuthRoleGetRequest{Role: "role-test-1"}) 489 if err != nil { 490 t.Fatal(err) 491 } 492 if len(r.Perm) != 0 { 493 t.Errorf("expected %v, got %v", 0, len(r.Perm)) 494 } 495} 496 497func TestUserRevokePermission(t *testing.T) { 498 as, tearDown := setupAuthStore(t) 499 defer tearDown(t) 500 501 _, err := as.RoleAdd(&pb.AuthRoleAddRequest{Name: "role-test-1"}) 502 if err != nil { 503 t.Fatal(err) 504 } 505 506 _, err = as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "foo", Role: "role-test"}) 507 if err != nil { 508 t.Fatal(err) 509 } 510 511 _, err = as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "foo", Role: "role-test-1"}) 512 if err != nil { 513 t.Fatal(err) 514 } 515 516 u, err := as.UserGet(&pb.AuthUserGetRequest{Name: "foo"}) 517 if err != nil { 518 t.Fatal(err) 519 } 520 521 expected := []string{"role-test", "role-test-1"} 522 if !reflect.DeepEqual(expected, u.Roles) { 523 t.Fatalf("expected %v, got %v", expected, u.Roles) 524 } 525 526 _, err = as.UserRevokeRole(&pb.AuthUserRevokeRoleRequest{Name: "foo", Role: "role-test-1"}) 527 if err != nil { 528 t.Fatal(err) 529 } 530 531 u, err = as.UserGet(&pb.AuthUserGetRequest{Name: "foo"}) 532 if err != nil { 533 t.Fatal(err) 534 } 535 536 expected = []string{"role-test"} 537 if !reflect.DeepEqual(expected, u.Roles) { 538 t.Errorf("expected %v, got %v", expected, u.Roles) 539 } 540} 541 542func TestRoleDelete(t *testing.T) { 543 as, tearDown := setupAuthStore(t) 544 defer tearDown(t) 545 546 _, err := as.RoleDelete(&pb.AuthRoleDeleteRequest{Role: "role-test"}) 547 if err != nil { 548 t.Fatal(err) 549 } 550 rl, err := as.RoleList(&pb.AuthRoleListRequest{}) 551 if err != nil { 552 t.Fatal(err) 553 } 554 expected := []string{"root"} 555 if !reflect.DeepEqual(expected, rl.Roles) { 556 t.Errorf("expected %v, got %v", expected, rl.Roles) 557 } 558} 559 560func TestAuthInfoFromCtx(t *testing.T) { 561 as, tearDown := setupAuthStore(t) 562 defer tearDown(t) 563 564 ctx := context.Background() 565 ai, err := as.AuthInfoFromCtx(ctx) 566 if err != nil && ai != nil { 567 t.Errorf("expected (nil, nil), got (%v, %v)", ai, err) 568 } 569 570 // as if it came from RPC 571 ctx = metadata.NewIncomingContext(context.Background(), metadata.New(map[string]string{"tokens": "dummy"})) 572 ai, err = as.AuthInfoFromCtx(ctx) 573 if err != nil && ai != nil { 574 t.Errorf("expected (nil, nil), got (%v, %v)", ai, err) 575 } 576 577 ctx = context.WithValue(context.WithValue(context.TODO(), AuthenticateParamIndex{}, uint64(1)), AuthenticateParamSimpleTokenPrefix{}, "dummy") 578 resp, err := as.Authenticate(ctx, "foo", "bar") 579 if err != nil { 580 t.Error(err) 581 } 582 583 ctx = metadata.NewIncomingContext(context.Background(), metadata.New(map[string]string{rpctypes.TokenFieldNameGRPC: "Invalid Token"})) 584 _, err = as.AuthInfoFromCtx(ctx) 585 if err != ErrInvalidAuthToken { 586 t.Errorf("expected %v, got %v", ErrInvalidAuthToken, err) 587 } 588 589 ctx = metadata.NewIncomingContext(context.Background(), metadata.New(map[string]string{rpctypes.TokenFieldNameGRPC: "Invalid.Token"})) 590 _, err = as.AuthInfoFromCtx(ctx) 591 if err != ErrInvalidAuthToken { 592 t.Errorf("expected %v, got %v", ErrInvalidAuthToken, err) 593 } 594 595 ctx = metadata.NewIncomingContext(context.Background(), metadata.New(map[string]string{rpctypes.TokenFieldNameGRPC: resp.Token})) 596 ai, err = as.AuthInfoFromCtx(ctx) 597 if err != nil { 598 t.Error(err) 599 } 600 if ai.Username != "foo" { 601 t.Errorf("expected %v, got %v", "foo", ai.Username) 602 } 603} 604 605func TestAuthDisable(t *testing.T) { 606 as, tearDown := setupAuthStore(t) 607 defer tearDown(t) 608 609 as.AuthDisable() 610 ctx := context.WithValue(context.WithValue(context.TODO(), AuthenticateParamIndex{}, uint64(2)), AuthenticateParamSimpleTokenPrefix{}, "dummy") 611 _, err := as.Authenticate(ctx, "foo", "bar") 612 if err != ErrAuthNotEnabled { 613 t.Errorf("expected %v, got %v", ErrAuthNotEnabled, err) 614 } 615 616 // Disabling disabled auth to make sure it can return safely if store is already disabled. 617 as.AuthDisable() 618 _, err = as.Authenticate(ctx, "foo", "bar") 619 if err != ErrAuthNotEnabled { 620 t.Errorf("expected %v, got %v", ErrAuthNotEnabled, err) 621 } 622} 623 624func TestIsAuthEnabled(t *testing.T) { 625 as, tearDown := setupAuthStore(t) 626 defer tearDown(t) 627 628 // enable authentication to test the first possible condition 629 as.AuthEnable() 630 631 status := as.IsAuthEnabled() 632 ctx := context.WithValue(context.WithValue(context.TODO(), AuthenticateParamIndex{}, uint64(2)), AuthenticateParamSimpleTokenPrefix{}, "dummy") 633 _, _ = as.Authenticate(ctx, "foo", "bar") 634 if status != true { 635 t.Errorf("expected %v, got %v", true, false) 636 } 637 638 // Disabling disabled auth to test the other condition that can be return 639 as.AuthDisable() 640 641 status = as.IsAuthEnabled() 642 _, _ = as.Authenticate(ctx, "foo", "bar") 643 if status != false { 644 t.Errorf("expected %v, got %v", false, true) 645 } 646} 647 648// TestAuthRevisionRace ensures that access to authStore.revision is thread-safe. 649func TestAuthInfoFromCtxRace(t *testing.T) { 650 b, tPath := backend.NewDefaultTmpBackend() 651 defer os.Remove(tPath) 652 653 tp, err := NewTokenProvider(zap.NewExample(), tokenTypeSimple, dummyIndexWaiter) 654 if err != nil { 655 t.Fatal(err) 656 } 657 as := NewAuthStore(zap.NewExample(), b, nil, tp, bcrypt.MinCost) 658 defer as.Close() 659 660 donec := make(chan struct{}) 661 go func() { 662 defer close(donec) 663 ctx := metadata.NewIncomingContext(context.Background(), metadata.New(map[string]string{rpctypes.TokenFieldNameGRPC: "test"})) 664 as.AuthInfoFromCtx(ctx) 665 }() 666 as.UserAdd(&pb.AuthUserAddRequest{Name: "test", Options: &authpb.UserAddOptions{NoPassword: false}}) 667 <-donec 668} 669 670func TestIsAdminPermitted(t *testing.T) { 671 as, tearDown := setupAuthStore(t) 672 defer tearDown(t) 673 674 err := as.IsAdminPermitted(&AuthInfo{Username: "root", Revision: 1}) 675 if err != nil { 676 t.Errorf("expected nil, got %v", err) 677 } 678 679 // invalid user 680 err = as.IsAdminPermitted(&AuthInfo{Username: "rooti", Revision: 1}) 681 if err != ErrUserNotFound { 682 t.Errorf("expected %v, got %v", ErrUserNotFound, err) 683 } 684 685 // non-admin user 686 err = as.IsAdminPermitted(&AuthInfo{Username: "foo", Revision: 1}) 687 if err != ErrPermissionDenied { 688 t.Errorf("expected %v, got %v", ErrPermissionDenied, err) 689 } 690 691 // disabled auth should return nil 692 as.AuthDisable() 693 err = as.IsAdminPermitted(&AuthInfo{Username: "root", Revision: 1}) 694 if err != nil { 695 t.Errorf("expected nil, got %v", err) 696 } 697} 698 699func TestRecoverFromSnapshot(t *testing.T) { 700 as, _ := setupAuthStore(t) 701 702 ua := &pb.AuthUserAddRequest{Name: "foo", Options: &authpb.UserAddOptions{NoPassword: false}} 703 _, err := as.UserAdd(ua) // add an existing user 704 if err == nil { 705 t.Fatalf("expected %v, got %v", ErrUserAlreadyExist, err) 706 } 707 if err != ErrUserAlreadyExist { 708 t.Fatalf("expected %v, got %v", ErrUserAlreadyExist, err) 709 } 710 711 ua = &pb.AuthUserAddRequest{Name: "", Options: &authpb.UserAddOptions{NoPassword: false}} 712 _, err = as.UserAdd(ua) // add a user with empty name 713 if err != ErrUserEmpty { 714 t.Fatal(err) 715 } 716 717 as.Close() 718 719 tp, err := NewTokenProvider(zap.NewExample(), tokenTypeSimple, dummyIndexWaiter) 720 if err != nil { 721 t.Fatal(err) 722 } 723 as2 := NewAuthStore(zap.NewExample(), as.be, nil, tp, bcrypt.MinCost) 724 defer func(a *authStore) { 725 a.Close() 726 }(as2) 727 728 if !as2.IsAuthEnabled() { 729 t.Fatal("recovering authStore from existing backend failed") 730 } 731 732 ul, err := as.UserList(&pb.AuthUserListRequest{}) 733 if err != nil { 734 t.Fatal(err) 735 } 736 if !contains(ul.Users, "root") { 737 t.Errorf("expected %v in %v", "root", ul.Users) 738 } 739} 740 741func contains(array []string, str string) bool { 742 for _, s := range array { 743 if s == str { 744 return true 745 } 746 } 747 return false 748} 749 750func TestHammerSimpleAuthenticate(t *testing.T) { 751 // set TTL values low to try to trigger races 752 oldTTL, oldTTLRes := simpleTokenTTL, simpleTokenTTLResolution 753 defer func() { 754 simpleTokenTTL = oldTTL 755 simpleTokenTTLResolution = oldTTLRes 756 }() 757 simpleTokenTTL = 10 * time.Millisecond 758 simpleTokenTTLResolution = simpleTokenTTL 759 users := make(map[string]struct{}) 760 761 as, tearDown := setupAuthStore(t) 762 defer tearDown(t) 763 764 // create lots of users 765 for i := 0; i < 50; i++ { 766 u := fmt.Sprintf("user-%d", i) 767 ua := &pb.AuthUserAddRequest{Name: u, Password: "123", Options: &authpb.UserAddOptions{NoPassword: false}} 768 if _, err := as.UserAdd(ua); err != nil { 769 t.Fatal(err) 770 } 771 users[u] = struct{}{} 772 } 773 774 // hammer on authenticate with lots of users 775 for i := 0; i < 10; i++ { 776 var wg sync.WaitGroup 777 wg.Add(len(users)) 778 for u := range users { 779 go func(user string) { 780 defer wg.Done() 781 token := fmt.Sprintf("%s(%d)", user, i) 782 ctx := context.WithValue(context.WithValue(context.TODO(), AuthenticateParamIndex{}, uint64(1)), AuthenticateParamSimpleTokenPrefix{}, token) 783 if _, err := as.Authenticate(ctx, user, "123"); err != nil { 784 t.Error(err) 785 } 786 if _, err := as.AuthInfoFromCtx(ctx); err != nil { 787 t.Error(err) 788 } 789 }(u) 790 } 791 time.Sleep(time.Millisecond) 792 wg.Wait() 793 } 794} 795 796// TestRolesOrder tests authpb.User.Roles is sorted 797func TestRolesOrder(t *testing.T) { 798 b, tPath := backend.NewDefaultTmpBackend() 799 defer os.Remove(tPath) 800 801 tp, err := NewTokenProvider(zap.NewExample(), tokenTypeSimple, dummyIndexWaiter) 802 if err != nil { 803 t.Fatal(err) 804 } 805 as := NewAuthStore(zap.NewExample(), b, nil, tp, bcrypt.MinCost) 806 err = enableAuthAndCreateRoot(as) 807 if err != nil { 808 t.Fatal(err) 809 } 810 811 username := "user" 812 _, err = as.UserAdd(&pb.AuthUserAddRequest{Name: username, Password: "pass", Options: &authpb.UserAddOptions{NoPassword: false}}) 813 if err != nil { 814 t.Fatal(err) 815 } 816 817 roles := []string{"role1", "role2", "abc", "xyz", "role3"} 818 for _, role := range roles { 819 _, err = as.RoleAdd(&pb.AuthRoleAddRequest{Name: role}) 820 if err != nil { 821 t.Fatal(err) 822 } 823 824 _, err = as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: username, Role: role}) 825 if err != nil { 826 t.Fatal(err) 827 } 828 } 829 830 user, err := as.UserGet(&pb.AuthUserGetRequest{Name: username}) 831 if err != nil { 832 t.Fatal(err) 833 } 834 835 for i := 1; i < len(user.Roles); i++ { 836 if strings.Compare(user.Roles[i-1], user.Roles[i]) != -1 { 837 t.Errorf("User.Roles isn't sorted (%s vs %s)", user.Roles[i-1], user.Roles[i]) 838 } 839 } 840} 841 842func TestAuthInfoFromCtxWithRootSimple(t *testing.T) { 843 testAuthInfoFromCtxWithRoot(t, tokenTypeSimple) 844} 845 846func TestAuthInfoFromCtxWithRootJWT(t *testing.T) { 847 opts := testJWTOpts() 848 testAuthInfoFromCtxWithRoot(t, opts) 849} 850 851// testAuthInfoFromCtxWithRoot ensures "WithRoot" properly embeds token in the context. 852func testAuthInfoFromCtxWithRoot(t *testing.T, opts string) { 853 b, tPath := backend.NewDefaultTmpBackend() 854 defer os.Remove(tPath) 855 856 tp, err := NewTokenProvider(zap.NewExample(), opts, dummyIndexWaiter) 857 if err != nil { 858 t.Fatal(err) 859 } 860 as := NewAuthStore(zap.NewExample(), b, nil, tp, bcrypt.MinCost) 861 defer as.Close() 862 863 if err = enableAuthAndCreateRoot(as); err != nil { 864 t.Fatal(err) 865 } 866 867 ctx := context.Background() 868 ctx = as.WithRoot(ctx) 869 870 ai, aerr := as.AuthInfoFromCtx(ctx) 871 if aerr != nil { 872 t.Error(err) 873 } 874 if ai == nil { 875 t.Error("expected non-nil *AuthInfo") 876 } 877 if ai.Username != "root" { 878 t.Errorf("expected user name 'root', got %+v", ai) 879 } 880} 881 882func TestUserNoPasswordAdd(t *testing.T) { 883 as, tearDown := setupAuthStore(t) 884 defer tearDown(t) 885 886 username := "usernopass" 887 ua := &pb.AuthUserAddRequest{Name: username, Options: &authpb.UserAddOptions{NoPassword: true}} 888 _, err := as.UserAdd(ua) 889 if err != nil { 890 t.Fatal(err) 891 } 892 893 ctx := context.WithValue(context.WithValue(context.TODO(), AuthenticateParamIndex{}, uint64(1)), AuthenticateParamSimpleTokenPrefix{}, "dummy") 894 _, err = as.Authenticate(ctx, username, "") 895 if err != ErrAuthFailed { 896 t.Fatalf("expected %v, got %v", ErrAuthFailed, err) 897 } 898} 899