1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package auth
16
17 import (
18 "context"
19 "encoding/base64"
20 "errors"
21 "fmt"
22 "reflect"
23 "strings"
24 "sync"
25 "testing"
26 "time"
27
28 "go.etcd.io/etcd/api/v3/authpb"
29 pb "go.etcd.io/etcd/api/v3/etcdserverpb"
30 "go.etcd.io/etcd/api/v3/v3rpc/rpctypes"
31 "go.etcd.io/etcd/pkg/v3/adt"
32 "go.etcd.io/etcd/server/v3/mvcc/backend"
33 betesting "go.etcd.io/etcd/server/v3/mvcc/backend/testing"
34
35 "go.uber.org/zap"
36 "golang.org/x/crypto/bcrypt"
37 "google.golang.org/grpc/metadata"
38 )
39
40 func dummyIndexWaiter(index uint64) <-chan struct{} {
41 ch := make(chan struct{})
42 go func() {
43 ch <- struct{}{}
44 }()
45 return ch
46 }
47
48
49
50 func TestNewAuthStoreRevision(t *testing.T) {
51 b, tPath := betesting.NewDefaultTmpBackend(t)
52
53 tp, err := NewTokenProvider(zap.NewExample(), tokenTypeSimple, dummyIndexWaiter, simpleTokenTTLDefault)
54 if err != nil {
55 t.Fatal(err)
56 }
57 as := NewAuthStore(zap.NewExample(), b, tp, bcrypt.MinCost)
58 err = enableAuthAndCreateRoot(as)
59 if err != nil {
60 t.Fatal(err)
61 }
62 old := as.Revision()
63 as.Close()
64 b.Close()
65
66
67 b2 := backend.NewDefaultBackend(tPath)
68 defer b2.Close()
69 as = NewAuthStore(zap.NewExample(), b2, tp, bcrypt.MinCost)
70 defer as.Close()
71 new := as.Revision()
72
73 if old != new {
74 t.Fatalf("expected revision %d, got %d", old, new)
75 }
76 }
77
78
79 func TestNewAuthStoreBcryptCost(t *testing.T) {
80 b, _ := betesting.NewDefaultTmpBackend(t)
81 defer betesting.Close(t, b)
82
83 tp, err := NewTokenProvider(zap.NewExample(), tokenTypeSimple, dummyIndexWaiter, simpleTokenTTLDefault)
84 if err != nil {
85 t.Fatal(err)
86 }
87
88 invalidCosts := [2]int{bcrypt.MinCost - 1, bcrypt.MaxCost + 1}
89 for _, invalidCost := range invalidCosts {
90 as := NewAuthStore(zap.NewExample(), b, tp, invalidCost)
91 defer as.Close()
92 if as.BcryptCost() != bcrypt.DefaultCost {
93 t.Fatalf("expected DefaultCost when bcryptcost is invalid")
94 }
95 }
96 }
97
98 func encodePassword(s string) string {
99 hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(s), bcrypt.MinCost)
100 return base64.StdEncoding.EncodeToString([]byte(hashedPassword))
101 }
102
103 func setupAuthStore(t *testing.T) (store *authStore, teardownfunc func(t *testing.T)) {
104 b, _ := betesting.NewDefaultTmpBackend(t)
105
106 tp, err := NewTokenProvider(zap.NewExample(), tokenTypeSimple, dummyIndexWaiter, simpleTokenTTLDefault)
107 if err != nil {
108 t.Fatal(err)
109 }
110 as := NewAuthStore(zap.NewExample(), b, tp, bcrypt.MinCost)
111 err = enableAuthAndCreateRoot(as)
112 if err != nil {
113 t.Fatal(err)
114 }
115
116
117 _, err = as.RoleAdd(&pb.AuthRoleAddRequest{Name: "role-test"})
118 if err != nil {
119 t.Fatal(err)
120 }
121
122 ua := &pb.AuthUserAddRequest{Name: "foo", HashedPassword: encodePassword("bar"), Options: &authpb.UserAddOptions{NoPassword: false}}
123 _, err = as.UserAdd(ua)
124 if err != nil {
125 t.Fatal(err)
126 }
127
128
129
130 err = addUserWithNoOption(as)
131 if err != nil {
132 t.Fatal(err)
133 }
134
135 tearDown := func(_ *testing.T) {
136 b.Close()
137 as.Close()
138 }
139 return as, tearDown
140 }
141
142 func addUserWithNoOption(as *authStore) error {
143 _, err := as.UserAdd(&pb.AuthUserAddRequest{Name: "foo-no-user-options", Password: "bar"})
144 if err != nil {
145 return err
146 }
147 return nil
148 }
149
150 func enableAuthAndCreateRoot(as *authStore) error {
151 _, err := as.UserAdd(&pb.AuthUserAddRequest{Name: "root", HashedPassword: encodePassword("root"), Options: &authpb.UserAddOptions{NoPassword: false}})
152 if err != nil {
153 return err
154 }
155
156 _, err = as.RoleAdd(&pb.AuthRoleAddRequest{Name: "root"})
157 if err != nil {
158 return err
159 }
160
161 _, err = as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "root", Role: "root"})
162 if err != nil {
163 return err
164 }
165
166 return as.AuthEnable()
167 }
168
169 func TestUserAdd(t *testing.T) {
170 as, tearDown := setupAuthStore(t)
171 defer tearDown(t)
172
173 const userName = "foo"
174 ua := &pb.AuthUserAddRequest{Name: userName, Options: &authpb.UserAddOptions{NoPassword: false}}
175 _, err := as.UserAdd(ua)
176 if err == nil {
177 t.Fatalf("expected %v, got %v", ErrUserAlreadyExist, err)
178 }
179 if err != ErrUserAlreadyExist {
180 t.Fatalf("expected %v, got %v", ErrUserAlreadyExist, err)
181 }
182
183 ua = &pb.AuthUserAddRequest{Name: "", Options: &authpb.UserAddOptions{NoPassword: false}}
184 _, err = as.UserAdd(ua)
185 if err != ErrUserEmpty {
186 t.Fatal(err)
187 }
188
189 if _, ok := as.rangePermCache[userName]; !ok {
190 t.Fatalf("user %s should be added but it doesn't exist in rangePermCache", userName)
191
192 }
193 }
194
195 func TestRecover(t *testing.T) {
196 as, tearDown := setupAuthStore(t)
197 defer as.Close()
198 defer tearDown(t)
199
200 as.enabled = false
201 as.Recover(as.be)
202
203 if !as.IsAuthEnabled() {
204 t.Fatalf("expected auth enabled got disabled")
205 }
206 }
207
208 func TestRecoverWithEmptyRangePermCache(t *testing.T) {
209 as, tearDown := setupAuthStore(t)
210 defer as.Close()
211 defer tearDown(t)
212
213 as.enabled = false
214 as.rangePermCache = map[string]*unifiedRangePermissions{}
215 as.Recover(as.be)
216
217 if !as.IsAuthEnabled() {
218 t.Fatalf("expected auth enabled got disabled")
219 }
220
221 if len(as.rangePermCache) != 3 {
222 t.Fatalf("rangePermCache should have permission information for 3 users (\"root\" and \"foo\",\"foo-no-user-options\"), but has %d information", len(as.rangePermCache))
223 }
224 if _, ok := as.rangePermCache["root"]; !ok {
225 t.Fatal("user \"root\" should be created by setupAuthStore() but doesn't exist in rangePermCache")
226 }
227 if _, ok := as.rangePermCache["foo"]; !ok {
228 t.Fatal("user \"foo\" should be created by setupAuthStore() but doesn't exist in rangePermCache")
229 }
230 }
231
232 func TestCheckPassword(t *testing.T) {
233 as, tearDown := setupAuthStore(t)
234 defer tearDown(t)
235
236
237 _, err := as.CheckPassword("foo-test", "bar")
238 if err == nil {
239 t.Fatalf("expected %v, got %v", ErrAuthFailed, err)
240 }
241 if err != ErrAuthFailed {
242 t.Fatalf("expected %v, got %v", ErrAuthFailed, err)
243 }
244
245
246 _, err = as.CheckPassword("foo", "bar")
247 if err != nil {
248 t.Fatal(err)
249 }
250
251
252 _, err = as.CheckPassword("foo", "")
253 if err == nil {
254 t.Fatalf("expected %v, got %v", ErrAuthFailed, err)
255 }
256 if err != ErrAuthFailed {
257 t.Fatalf("expected %v, got %v", ErrAuthFailed, err)
258 }
259 }
260
261 func TestUserDelete(t *testing.T) {
262 as, tearDown := setupAuthStore(t)
263 defer tearDown(t)
264
265
266 const userName = "foo"
267 ud := &pb.AuthUserDeleteRequest{Name: userName}
268 _, err := as.UserDelete(ud)
269 if err != nil {
270 t.Fatal(err)
271 }
272
273
274 _, err = as.UserDelete(ud)
275 if err == nil {
276 t.Fatalf("expected %v, got %v", ErrUserNotFound, err)
277 }
278 if err != ErrUserNotFound {
279 t.Fatalf("expected %v, got %v", ErrUserNotFound, err)
280 }
281
282 if _, ok := as.rangePermCache[userName]; ok {
283 t.Fatalf("user %s should be deleted but it exists in rangePermCache", userName)
284
285 }
286 }
287
288 func TestUserDeleteAndPermCache(t *testing.T) {
289 as, tearDown := setupAuthStore(t)
290 defer tearDown(t)
291
292
293 const deletedUserName = "foo"
294 ud := &pb.AuthUserDeleteRequest{Name: deletedUserName}
295 _, err := as.UserDelete(ud)
296 if err != nil {
297 t.Fatal(err)
298 }
299
300
301 _, err = as.UserDelete(ud)
302 if err != ErrUserNotFound {
303 t.Fatalf("expected %v, got %v", ErrUserNotFound, err)
304 }
305
306 if _, ok := as.rangePermCache[deletedUserName]; ok {
307 t.Fatalf("user %s should be deleted but it exists in rangePermCache", deletedUserName)
308 }
309
310
311 const newUser = "bar"
312 ua := &pb.AuthUserAddRequest{Name: newUser, HashedPassword: encodePassword("pwd1"), Options: &authpb.UserAddOptions{NoPassword: false}}
313 _, err = as.UserAdd(ua)
314 if err != nil {
315 t.Fatal(err)
316 }
317
318 if _, ok := as.rangePermCache[newUser]; !ok {
319 t.Fatalf("user %s should exist but it doesn't exist in rangePermCache", deletedUserName)
320
321 }
322 }
323
324 func TestUserChangePassword(t *testing.T) {
325 as, tearDown := setupAuthStore(t)
326 defer tearDown(t)
327
328 ctx1 := context.WithValue(context.WithValue(context.TODO(), AuthenticateParamIndex{}, uint64(1)), AuthenticateParamSimpleTokenPrefix{}, "dummy")
329 _, err := as.Authenticate(ctx1, "foo", "bar")
330 if err != nil {
331 t.Fatal(err)
332 }
333
334 _, err = as.UserChangePassword(&pb.AuthUserChangePasswordRequest{Name: "foo", HashedPassword: encodePassword("baz")})
335 if err != nil {
336 t.Fatal(err)
337 }
338
339 ctx2 := context.WithValue(context.WithValue(context.TODO(), AuthenticateParamIndex{}, uint64(2)), AuthenticateParamSimpleTokenPrefix{}, "dummy")
340 _, err = as.Authenticate(ctx2, "foo", "baz")
341 if err != nil {
342 t.Fatal(err)
343 }
344
345
346 _, err = as.UserChangePassword(&pb.AuthUserChangePasswordRequest{Name: "foo-test", HashedPassword: encodePassword("bar")})
347 if err == nil {
348 t.Fatalf("expected %v, got %v", ErrUserNotFound, err)
349 }
350 if err != ErrUserNotFound {
351 t.Fatalf("expected %v, got %v", ErrUserNotFound, err)
352 }
353
354
355 _, err = as.UserChangePassword(&pb.AuthUserChangePasswordRequest{Name: "foo-no-user-options", HashedPassword: encodePassword("bar")})
356 if err != nil {
357 t.Fatal(err)
358 }
359 }
360
361 func TestRoleAdd(t *testing.T) {
362 as, tearDown := setupAuthStore(t)
363 defer tearDown(t)
364
365
366 _, err := as.RoleAdd(&pb.AuthRoleAddRequest{Name: "role-test-1"})
367 if err != nil {
368 t.Fatal(err)
369 }
370
371
372 _, err = as.RoleAdd(&pb.AuthRoleAddRequest{Name: ""})
373 if err != ErrRoleEmpty {
374 t.Fatal(err)
375 }
376 }
377
378 func TestUserGrant(t *testing.T) {
379 as, tearDown := setupAuthStore(t)
380 defer tearDown(t)
381
382
383 _, err := as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "foo", Role: "role-test"})
384 if err != nil {
385 t.Fatal(err)
386 }
387
388
389 _, err = as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "foo-test", Role: "role-test"})
390 if err == nil {
391 t.Errorf("expected %v, got %v", ErrUserNotFound, err)
392 }
393 if err != ErrUserNotFound {
394 t.Errorf("expected %v, got %v", ErrUserNotFound, err)
395 }
396 }
397
398 func TestHasRole(t *testing.T) {
399 as, tearDown := setupAuthStore(t)
400 defer tearDown(t)
401
402
403 _, err := as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "foo", Role: "role-test"})
404 if err != nil {
405 t.Fatal(err)
406 }
407
408
409 hr := as.HasRole("foo", "role-test")
410 if !hr {
411 t.Fatal("expected role granted, got false")
412 }
413
414
415 hr = as.HasRole("foo", "non-existent-role")
416 if hr {
417 t.Fatal("expected role not found, got true")
418 }
419
420
421 hr = as.HasRole("nouser", "role-test")
422 if hr {
423 t.Fatal("expected user not found got true")
424 }
425 }
426
427 func TestIsOpPermitted(t *testing.T) {
428 as, tearDown := setupAuthStore(t)
429 defer tearDown(t)
430
431
432 _, err := as.RoleAdd(&pb.AuthRoleAddRequest{Name: "role-test-1"})
433 if err != nil {
434 t.Fatal(err)
435 }
436
437 perm := &authpb.Permission{
438 PermType: authpb.WRITE,
439 Key: []byte("Keys"),
440 RangeEnd: []byte("RangeEnd"),
441 }
442
443 _, err = as.RoleGrantPermission(&pb.AuthRoleGrantPermissionRequest{
444 Name: "role-test-1",
445 Perm: perm,
446 })
447 if err != nil {
448 t.Fatal(err)
449 }
450
451
452 _, err = as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "foo", Role: "role-test-1"})
453 if err != nil {
454 t.Fatal(err)
455 }
456
457
458
459 err = as.isOpPermitted("foo", as.Revision(), perm.Key, perm.RangeEnd, perm.PermType)
460 if err != nil {
461 t.Fatal(err)
462 }
463 }
464
465 func TestGetUser(t *testing.T) {
466 as, tearDown := setupAuthStore(t)
467 defer tearDown(t)
468
469 _, err := as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "foo", Role: "role-test"})
470 if err != nil {
471 t.Fatal(err)
472 }
473
474 u, err := as.UserGet(&pb.AuthUserGetRequest{Name: "foo"})
475 if err != nil {
476 t.Fatal(err)
477 }
478 if u == nil {
479 t.Fatal("expect user not nil, got nil")
480 }
481 expected := []string{"role-test"}
482 if !reflect.DeepEqual(expected, u.Roles) {
483 t.Errorf("expected %v, got %v", expected, u.Roles)
484 }
485
486
487 _, err = as.UserGet(&pb.AuthUserGetRequest{Name: "nouser"})
488 if err == nil {
489 t.Errorf("expected %v, got %v", ErrUserNotFound, err)
490 }
491 }
492
493 func TestListUsers(t *testing.T) {
494 as, tearDown := setupAuthStore(t)
495 defer tearDown(t)
496
497 ua := &pb.AuthUserAddRequest{Name: "user1", HashedPassword: encodePassword("pwd1"), Options: &authpb.UserAddOptions{NoPassword: false}}
498 _, err := as.UserAdd(ua)
499 if err != nil {
500 t.Fatal(err)
501 }
502
503 ul, err := as.UserList(&pb.AuthUserListRequest{})
504 if err != nil {
505 t.Fatal(err)
506 }
507 if !contains(ul.Users, "root") {
508 t.Errorf("expected %v in %v", "root", ul.Users)
509 }
510 if !contains(ul.Users, "user1") {
511 t.Errorf("expected %v in %v", "user1", ul.Users)
512 }
513 }
514
515 func TestRoleGrantPermission(t *testing.T) {
516 as, tearDown := setupAuthStore(t)
517 defer tearDown(t)
518
519 _, err := as.RoleAdd(&pb.AuthRoleAddRequest{Name: "role-test-1"})
520 if err != nil {
521 t.Fatal(err)
522 }
523
524 perm := &authpb.Permission{
525 PermType: authpb.WRITE,
526 Key: []byte("Keys"),
527 RangeEnd: []byte("RangeEnd"),
528 }
529 _, err = as.RoleGrantPermission(&pb.AuthRoleGrantPermissionRequest{
530 Name: "role-test-1",
531 Perm: perm,
532 })
533
534 if err != nil {
535 t.Error(err)
536 }
537
538 r, err := as.RoleGet(&pb.AuthRoleGetRequest{Role: "role-test-1"})
539 if err != nil {
540 t.Fatal(err)
541 }
542
543 if !reflect.DeepEqual(perm, r.Perm[0]) {
544 t.Errorf("expected %v, got %v", perm, r.Perm[0])
545 }
546
547
548 _, err = as.RoleGrantPermission(&pb.AuthRoleGrantPermissionRequest{
549 Name: "role-test-1",
550 })
551
552 if err != ErrPermissionNotGiven {
553 t.Error(err)
554 }
555
556 r, err = as.RoleGet(&pb.AuthRoleGetRequest{Role: "role-test-1"})
557 if err != nil {
558 t.Fatal(err)
559 }
560
561 if !reflect.DeepEqual(perm, r.Perm[0]) {
562 t.Errorf("expected %v, got %v", perm, r.Perm[0])
563 }
564 }
565
566 func TestRoleGrantInvalidPermission(t *testing.T) {
567 as, tearDown := setupAuthStore(t)
568 defer tearDown(t)
569
570 _, err := as.RoleAdd(&pb.AuthRoleAddRequest{Name: "role-test-1"})
571 if err != nil {
572 t.Fatal(err)
573 }
574
575 tests := []struct {
576 name string
577 perm *authpb.Permission
578 want error
579 }{
580 {
581 name: "valid range",
582 perm: &authpb.Permission{
583 PermType: authpb.WRITE,
584 Key: []byte("Keys"),
585 RangeEnd: []byte("RangeEnd"),
586 },
587 want: nil,
588 },
589 {
590 name: "invalid range: nil key",
591 perm: &authpb.Permission{
592 PermType: authpb.WRITE,
593 Key: nil,
594 RangeEnd: []byte("RangeEnd"),
595 },
596 want: ErrInvalidAuthMgmt,
597 },
598 {
599 name: "valid range: single key",
600 perm: &authpb.Permission{
601 PermType: authpb.WRITE,
602 Key: []byte("Keys"),
603 RangeEnd: nil,
604 },
605 want: nil,
606 },
607 {
608 name: "valid range: single key",
609 perm: &authpb.Permission{
610 PermType: authpb.WRITE,
611 Key: []byte("Keys"),
612 RangeEnd: []byte{},
613 },
614 want: nil,
615 },
616 {
617 name: "invalid range: empty (Key == RangeEnd)",
618 perm: &authpb.Permission{
619 PermType: authpb.WRITE,
620 Key: []byte("a"),
621 RangeEnd: []byte("a"),
622 },
623 want: ErrInvalidAuthMgmt,
624 },
625 {
626 name: "invalid range: empty (Key > RangeEnd)",
627 perm: &authpb.Permission{
628 PermType: authpb.WRITE,
629 Key: []byte("b"),
630 RangeEnd: []byte("a"),
631 },
632 want: ErrInvalidAuthMgmt,
633 },
634 {
635 name: "invalid range: length of key is 0",
636 perm: &authpb.Permission{
637 PermType: authpb.WRITE,
638 Key: []byte(""),
639 RangeEnd: []byte("a"),
640 },
641 want: ErrInvalidAuthMgmt,
642 },
643 {
644 name: "invalid range: length of key is 0",
645 perm: &authpb.Permission{
646 PermType: authpb.WRITE,
647 Key: []byte(""),
648 RangeEnd: []byte(""),
649 },
650 want: ErrInvalidAuthMgmt,
651 },
652 {
653 name: "invalid range: length of key is 0",
654 perm: &authpb.Permission{
655 PermType: authpb.WRITE,
656 Key: []byte(""),
657 RangeEnd: []byte{0x00},
658 },
659 want: ErrInvalidAuthMgmt,
660 },
661 {
662 name: "valid range: single key permission for []byte{0x00}",
663 perm: &authpb.Permission{
664 PermType: authpb.WRITE,
665 Key: []byte{0x00},
666 RangeEnd: []byte(""),
667 },
668 want: nil,
669 },
670 {
671 name: "valid range: \"a\" or larger keys",
672 perm: &authpb.Permission{
673 PermType: authpb.WRITE,
674 Key: []byte("a"),
675 RangeEnd: []byte{0x00},
676 },
677 want: nil,
678 },
679 {
680 name: "valid range: the entire keys",
681 perm: &authpb.Permission{
682 PermType: authpb.WRITE,
683 Key: []byte{0x00},
684 RangeEnd: []byte{0x00},
685 },
686 want: nil,
687 },
688 }
689
690 for i, tt := range tests {
691 t.Run(tt.name, func(t *testing.T) {
692 _, err = as.RoleGrantPermission(&pb.AuthRoleGrantPermissionRequest{
693 Name: "role-test-1",
694 Perm: tt.perm,
695 })
696
697 if !errors.Is(err, tt.want) {
698 t.Errorf("#%d: result=%t, want=%t", i, err, tt.want)
699 }
700 })
701 }
702 }
703
704 func TestRoleRevokePermission(t *testing.T) {
705 as, tearDown := setupAuthStore(t)
706 defer tearDown(t)
707
708 _, err := as.RoleAdd(&pb.AuthRoleAddRequest{Name: "role-test-1"})
709 if err != nil {
710 t.Fatal(err)
711 }
712
713 perm := &authpb.Permission{
714 PermType: authpb.WRITE,
715 Key: []byte("Keys"),
716 RangeEnd: []byte("RangeEnd"),
717 }
718 _, err = as.RoleGrantPermission(&pb.AuthRoleGrantPermissionRequest{
719 Name: "role-test-1",
720 Perm: perm,
721 })
722
723 if err != nil {
724 t.Fatal(err)
725 }
726
727 _, err = as.RoleGet(&pb.AuthRoleGetRequest{Role: "role-test-1"})
728 if err != nil {
729 t.Fatal(err)
730 }
731
732 _, err = as.RoleRevokePermission(&pb.AuthRoleRevokePermissionRequest{
733 Role: "role-test-1",
734 Key: []byte("Keys"),
735 RangeEnd: []byte("RangeEnd"),
736 })
737 if err != nil {
738 t.Fatal(err)
739 }
740
741 var r *pb.AuthRoleGetResponse
742 r, err = as.RoleGet(&pb.AuthRoleGetRequest{Role: "role-test-1"})
743 if err != nil {
744 t.Fatal(err)
745 }
746 if len(r.Perm) != 0 {
747 t.Errorf("expected %v, got %v", 0, len(r.Perm))
748 }
749 }
750
751 func TestUserRevokePermission(t *testing.T) {
752 as, tearDown := setupAuthStore(t)
753 defer tearDown(t)
754
755 _, err := as.RoleAdd(&pb.AuthRoleAddRequest{Name: "role-test-1"})
756 if err != nil {
757 t.Fatal(err)
758 }
759
760 const userName = "foo"
761 _, err = as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: userName, Role: "role-test"})
762 if err != nil {
763 t.Fatal(err)
764 }
765
766 _, err = as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: userName, Role: "role-test-1"})
767 if err != nil {
768 t.Fatal(err)
769 }
770
771 perm := &authpb.Permission{
772 PermType: authpb.WRITE,
773 Key: []byte("WriteKeyBegin"),
774 RangeEnd: []byte("WriteKeyEnd"),
775 }
776 _, err = as.RoleGrantPermission(&pb.AuthRoleGrantPermissionRequest{
777 Name: "role-test-1",
778 Perm: perm,
779 })
780 if err != nil {
781 t.Fatal(err)
782 }
783
784 if _, ok := as.rangePermCache[userName]; !ok {
785 t.Fatalf("User %s should have its entry in rangePermCache", userName)
786 }
787 unifiedPerm := as.rangePermCache[userName]
788 pt1 := adt.NewBytesAffinePoint([]byte("WriteKeyBegin"))
789 if !unifiedPerm.writePerms.Contains(pt1) {
790 t.Fatal("rangePermCache should contain WriteKeyBegin")
791 }
792 pt2 := adt.NewBytesAffinePoint([]byte("OutOfRange"))
793 if unifiedPerm.writePerms.Contains(pt2) {
794 t.Fatal("rangePermCache should not contain OutOfRange")
795 }
796
797 u, err := as.UserGet(&pb.AuthUserGetRequest{Name: userName})
798 if err != nil {
799 t.Fatal(err)
800 }
801
802 expected := []string{"role-test", "role-test-1"}
803 if !reflect.DeepEqual(expected, u.Roles) {
804 t.Fatalf("expected %v, got %v", expected, u.Roles)
805 }
806
807 _, err = as.UserRevokeRole(&pb.AuthUserRevokeRoleRequest{Name: userName, Role: "role-test-1"})
808 if err != nil {
809 t.Fatal(err)
810 }
811
812 u, err = as.UserGet(&pb.AuthUserGetRequest{Name: userName})
813 if err != nil {
814 t.Fatal(err)
815 }
816
817 expected = []string{"role-test"}
818 if !reflect.DeepEqual(expected, u.Roles) {
819 t.Errorf("expected %v, got %v", expected, u.Roles)
820 }
821 }
822
823 func TestRoleDelete(t *testing.T) {
824 as, tearDown := setupAuthStore(t)
825 defer tearDown(t)
826
827 _, err := as.RoleDelete(&pb.AuthRoleDeleteRequest{Role: "role-test"})
828 if err != nil {
829 t.Fatal(err)
830 }
831 rl, err := as.RoleList(&pb.AuthRoleListRequest{})
832 if err != nil {
833 t.Fatal(err)
834 }
835 expected := []string{"root"}
836 if !reflect.DeepEqual(expected, rl.Roles) {
837 t.Errorf("expected %v, got %v", expected, rl.Roles)
838 }
839 }
840
841 func TestAuthInfoFromCtx(t *testing.T) {
842 as, tearDown := setupAuthStore(t)
843 defer tearDown(t)
844
845 ctx := context.Background()
846 ai, err := as.AuthInfoFromCtx(ctx)
847 if err != nil && ai != nil {
848 t.Errorf("expected (nil, nil), got (%v, %v)", ai, err)
849 }
850
851
852 ctx = metadata.NewIncomingContext(context.Background(), metadata.New(map[string]string{"tokens": "dummy"}))
853 ai, err = as.AuthInfoFromCtx(ctx)
854 if err != nil && ai != nil {
855 t.Errorf("expected (nil, nil), got (%v, %v)", ai, err)
856 }
857
858 ctx = context.WithValue(context.WithValue(context.TODO(), AuthenticateParamIndex{}, uint64(1)), AuthenticateParamSimpleTokenPrefix{}, "dummy")
859 resp, err := as.Authenticate(ctx, "foo", "bar")
860 if err != nil {
861 t.Error(err)
862 }
863
864 ctx = metadata.NewIncomingContext(context.Background(), metadata.New(map[string]string{rpctypes.TokenFieldNameGRPC: "Invalid Token"}))
865 _, err = as.AuthInfoFromCtx(ctx)
866 if err != ErrInvalidAuthToken {
867 t.Errorf("expected %v, got %v", ErrInvalidAuthToken, err)
868 }
869
870 ctx = metadata.NewIncomingContext(context.Background(), metadata.New(map[string]string{rpctypes.TokenFieldNameGRPC: "Invalid.Token"}))
871 _, err = as.AuthInfoFromCtx(ctx)
872 if err != ErrInvalidAuthToken {
873 t.Errorf("expected %v, got %v", ErrInvalidAuthToken, err)
874 }
875
876 ctx = metadata.NewIncomingContext(context.Background(), metadata.New(map[string]string{rpctypes.TokenFieldNameGRPC: resp.Token}))
877 ai, err = as.AuthInfoFromCtx(ctx)
878 if err != nil {
879 t.Error(err)
880 }
881 if ai.Username != "foo" {
882 t.Errorf("expected %v, got %v", "foo", ai.Username)
883 }
884 }
885
886 func TestAuthDisable(t *testing.T) {
887 as, tearDown := setupAuthStore(t)
888 defer tearDown(t)
889
890 as.AuthDisable()
891 ctx := context.WithValue(context.WithValue(context.TODO(), AuthenticateParamIndex{}, uint64(2)), AuthenticateParamSimpleTokenPrefix{}, "dummy")
892 _, err := as.Authenticate(ctx, "foo", "bar")
893 if err != ErrAuthNotEnabled {
894 t.Errorf("expected %v, got %v", ErrAuthNotEnabled, err)
895 }
896
897
898 as.AuthDisable()
899 _, err = as.Authenticate(ctx, "foo", "bar")
900 if err != ErrAuthNotEnabled {
901 t.Errorf("expected %v, got %v", ErrAuthNotEnabled, err)
902 }
903 }
904
905 func TestIsAuthEnabled(t *testing.T) {
906 as, tearDown := setupAuthStore(t)
907 defer tearDown(t)
908
909
910 as.AuthEnable()
911
912 status := as.IsAuthEnabled()
913 ctx := context.WithValue(context.WithValue(context.TODO(), AuthenticateParamIndex{}, uint64(2)), AuthenticateParamSimpleTokenPrefix{}, "dummy")
914 _, _ = as.Authenticate(ctx, "foo", "bar")
915 if status != true {
916 t.Errorf("expected %v, got %v", true, false)
917 }
918
919
920 as.AuthDisable()
921
922 status = as.IsAuthEnabled()
923 _, _ = as.Authenticate(ctx, "foo", "bar")
924 if status != false {
925 t.Errorf("expected %v, got %v", false, true)
926 }
927 }
928
929
930 func TestAuthInfoFromCtxRace(t *testing.T) {
931 b, _ := betesting.NewDefaultTmpBackend(t)
932 defer betesting.Close(t, b)
933
934 tp, err := NewTokenProvider(zap.NewExample(), tokenTypeSimple, dummyIndexWaiter, simpleTokenTTLDefault)
935 if err != nil {
936 t.Fatal(err)
937 }
938 as := NewAuthStore(zap.NewExample(), b, tp, bcrypt.MinCost)
939 defer as.Close()
940
941 donec := make(chan struct{})
942 go func() {
943 defer close(donec)
944 ctx := metadata.NewIncomingContext(context.Background(), metadata.New(map[string]string{rpctypes.TokenFieldNameGRPC: "test"}))
945 as.AuthInfoFromCtx(ctx)
946 }()
947 as.UserAdd(&pb.AuthUserAddRequest{Name: "test", Options: &authpb.UserAddOptions{NoPassword: false}})
948 <-donec
949 }
950
951 func TestIsAdminPermitted(t *testing.T) {
952 as, tearDown := setupAuthStore(t)
953 defer tearDown(t)
954
955 err := as.IsAdminPermitted(&AuthInfo{Username: "root", Revision: 1})
956 if err != nil {
957 t.Errorf("expected nil, got %v", err)
958 }
959
960
961 err = as.IsAdminPermitted(&AuthInfo{Username: "rooti", Revision: 1})
962 if err != ErrUserNotFound {
963 t.Errorf("expected %v, got %v", ErrUserNotFound, err)
964 }
965
966
967 err = as.IsAdminPermitted(&AuthInfo{Username: "", Revision: 1})
968 if err != ErrUserEmpty {
969 t.Errorf("expected %v, got %v", ErrUserEmpty, err)
970 }
971
972
973 err = as.IsAdminPermitted(&AuthInfo{Username: "foo", Revision: 1})
974 if err != ErrPermissionDenied {
975 t.Errorf("expected %v, got %v", ErrPermissionDenied, err)
976 }
977
978
979 as.AuthDisable()
980 err = as.IsAdminPermitted(&AuthInfo{Username: "root", Revision: 1})
981 if err != nil {
982 t.Errorf("expected nil, got %v", err)
983 }
984 }
985
986 func TestRecoverFromSnapshot(t *testing.T) {
987 as, teardown := setupAuthStore(t)
988 defer teardown(t)
989
990 ua := &pb.AuthUserAddRequest{Name: "foo", Options: &authpb.UserAddOptions{NoPassword: false}}
991 _, err := as.UserAdd(ua)
992 if err == nil {
993 t.Fatalf("expected %v, got %v", ErrUserAlreadyExist, err)
994 }
995 if err != ErrUserAlreadyExist {
996 t.Fatalf("expected %v, got %v", ErrUserAlreadyExist, err)
997 }
998
999 ua = &pb.AuthUserAddRequest{Name: "", Options: &authpb.UserAddOptions{NoPassword: false}}
1000 _, err = as.UserAdd(ua)
1001 if err != ErrUserEmpty {
1002 t.Fatal(err)
1003 }
1004
1005 as.Close()
1006
1007 tp, err := NewTokenProvider(zap.NewExample(), tokenTypeSimple, dummyIndexWaiter, simpleTokenTTLDefault)
1008 if err != nil {
1009 t.Fatal(err)
1010 }
1011 as2 := NewAuthStore(zap.NewExample(), as.be, tp, bcrypt.MinCost)
1012 defer as2.Close()
1013
1014 if !as2.IsAuthEnabled() {
1015 t.Fatal("recovering authStore from existing backend failed")
1016 }
1017
1018 ul, err := as.UserList(&pb.AuthUserListRequest{})
1019 if err != nil {
1020 t.Fatal(err)
1021 }
1022 if !contains(ul.Users, "root") {
1023 t.Errorf("expected %v in %v", "root", ul.Users)
1024 }
1025 }
1026
1027 func contains(array []string, str string) bool {
1028 for _, s := range array {
1029 if s == str {
1030 return true
1031 }
1032 }
1033 return false
1034 }
1035
1036 func TestHammerSimpleAuthenticate(t *testing.T) {
1037
1038 oldTTL, oldTTLRes := simpleTokenTTLDefault, simpleTokenTTLResolution
1039 defer func() {
1040 simpleTokenTTLDefault = oldTTL
1041 simpleTokenTTLResolution = oldTTLRes
1042 }()
1043 simpleTokenTTLDefault = 10 * time.Millisecond
1044 simpleTokenTTLResolution = simpleTokenTTLDefault
1045 users := make(map[string]struct{})
1046
1047 as, tearDown := setupAuthStore(t)
1048 defer tearDown(t)
1049
1050
1051 for i := 0; i < 50; i++ {
1052 u := fmt.Sprintf("user-%d", i)
1053 ua := &pb.AuthUserAddRequest{Name: u, HashedPassword: encodePassword("123"), Options: &authpb.UserAddOptions{NoPassword: false}}
1054 if _, err := as.UserAdd(ua); err != nil {
1055 t.Fatal(err)
1056 }
1057 users[u] = struct{}{}
1058 }
1059
1060
1061 for i := 0; i < 10; i++ {
1062 var wg sync.WaitGroup
1063 wg.Add(len(users))
1064 for u := range users {
1065 go func(user string) {
1066 defer wg.Done()
1067 token := fmt.Sprintf("%s(%d)", user, i)
1068 ctx := context.WithValue(context.WithValue(context.TODO(), AuthenticateParamIndex{}, uint64(1)), AuthenticateParamSimpleTokenPrefix{}, token)
1069 if _, err := as.Authenticate(ctx, user, "123"); err != nil {
1070 t.Error(err)
1071 }
1072 if _, err := as.AuthInfoFromCtx(ctx); err != nil {
1073 t.Error(err)
1074 }
1075 }(u)
1076 }
1077 time.Sleep(time.Millisecond)
1078 wg.Wait()
1079 }
1080 }
1081
1082
1083 func TestRolesOrder(t *testing.T) {
1084 b, _ := betesting.NewDefaultTmpBackend(t)
1085 defer betesting.Close(t, b)
1086
1087 tp, err := NewTokenProvider(zap.NewExample(), tokenTypeSimple, dummyIndexWaiter, simpleTokenTTLDefault)
1088 defer tp.disable()
1089 if err != nil {
1090 t.Fatal(err)
1091 }
1092 as := NewAuthStore(zap.NewExample(), b, tp, bcrypt.MinCost)
1093 defer as.Close()
1094 err = enableAuthAndCreateRoot(as)
1095 if err != nil {
1096 t.Fatal(err)
1097 }
1098
1099 username := "user"
1100 _, err = as.UserAdd(&pb.AuthUserAddRequest{Name: username, HashedPassword: encodePassword("pass"), Options: &authpb.UserAddOptions{NoPassword: false}})
1101 if err != nil {
1102 t.Fatal(err)
1103 }
1104
1105 roles := []string{"role1", "role2", "abc", "xyz", "role3"}
1106 for _, role := range roles {
1107 _, err = as.RoleAdd(&pb.AuthRoleAddRequest{Name: role})
1108 if err != nil {
1109 t.Fatal(err)
1110 }
1111
1112 _, err = as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: username, Role: role})
1113 if err != nil {
1114 t.Fatal(err)
1115 }
1116 }
1117
1118 user, err := as.UserGet(&pb.AuthUserGetRequest{Name: username})
1119 if err != nil {
1120 t.Fatal(err)
1121 }
1122
1123 for i := 1; i < len(user.Roles); i++ {
1124 if strings.Compare(user.Roles[i-1], user.Roles[i]) != -1 {
1125 t.Errorf("User.Roles isn't sorted (%s vs %s)", user.Roles[i-1], user.Roles[i])
1126 }
1127 }
1128 }
1129
1130 func TestAuthInfoFromCtxWithRootSimple(t *testing.T) {
1131 testAuthInfoFromCtxWithRoot(t, tokenTypeSimple)
1132 }
1133
1134 func TestAuthInfoFromCtxWithRootJWT(t *testing.T) {
1135 opts := testJWTOpts()
1136 testAuthInfoFromCtxWithRoot(t, opts)
1137 }
1138
1139
1140 func testAuthInfoFromCtxWithRoot(t *testing.T, opts string) {
1141 b, _ := betesting.NewDefaultTmpBackend(t)
1142 defer betesting.Close(t, b)
1143
1144 tp, err := NewTokenProvider(zap.NewExample(), opts, dummyIndexWaiter, simpleTokenTTLDefault)
1145 if err != nil {
1146 t.Fatal(err)
1147 }
1148 as := NewAuthStore(zap.NewExample(), b, tp, bcrypt.MinCost)
1149 defer as.Close()
1150
1151 if err = enableAuthAndCreateRoot(as); err != nil {
1152 t.Fatal(err)
1153 }
1154
1155 ctx := context.Background()
1156 ctx = as.WithRoot(ctx)
1157
1158 ai, aerr := as.AuthInfoFromCtx(ctx)
1159 if aerr != nil {
1160 t.Error(err)
1161 }
1162 if ai == nil {
1163 t.Error("expected non-nil *AuthInfo")
1164 }
1165 if ai.Username != "root" {
1166 t.Errorf("expected user name 'root', got %+v", ai)
1167 }
1168 }
1169
1170 func TestUserNoPasswordAdd(t *testing.T) {
1171 as, tearDown := setupAuthStore(t)
1172 defer tearDown(t)
1173
1174 username := "usernopass"
1175 ua := &pb.AuthUserAddRequest{Name: username, Options: &authpb.UserAddOptions{NoPassword: true}}
1176 _, err := as.UserAdd(ua)
1177 if err != nil {
1178 t.Fatal(err)
1179 }
1180
1181 ctx := context.WithValue(context.WithValue(context.TODO(), AuthenticateParamIndex{}, uint64(1)), AuthenticateParamSimpleTokenPrefix{}, "dummy")
1182 _, err = as.Authenticate(ctx, username, "")
1183 if err != ErrAuthFailed {
1184 t.Fatalf("expected %v, got %v", ErrAuthFailed, err)
1185 }
1186 }
1187
1188 func TestUserAddWithOldLog(t *testing.T) {
1189 as, tearDown := setupAuthStore(t)
1190 defer tearDown(t)
1191
1192 ua := &pb.AuthUserAddRequest{Name: "bar", Password: "baz", Options: &authpb.UserAddOptions{NoPassword: false}}
1193 _, err := as.UserAdd(ua)
1194 if err != nil {
1195 t.Fatal(err)
1196 }
1197 }
1198
1199 func TestUserChangePasswordWithOldLog(t *testing.T) {
1200 as, tearDown := setupAuthStore(t)
1201 defer tearDown(t)
1202
1203 ctx1 := context.WithValue(context.WithValue(context.TODO(), AuthenticateParamIndex{}, uint64(1)), AuthenticateParamSimpleTokenPrefix{}, "dummy")
1204 _, err := as.Authenticate(ctx1, "foo", "bar")
1205 if err != nil {
1206 t.Fatal(err)
1207 }
1208
1209 _, err = as.UserChangePassword(&pb.AuthUserChangePasswordRequest{Name: "foo", Password: "baz"})
1210 if err != nil {
1211 t.Fatal(err)
1212 }
1213
1214 ctx2 := context.WithValue(context.WithValue(context.TODO(), AuthenticateParamIndex{}, uint64(2)), AuthenticateParamSimpleTokenPrefix{}, "dummy")
1215 _, err = as.Authenticate(ctx2, "foo", "baz")
1216 if err != nil {
1217 t.Fatal(err)
1218 }
1219
1220
1221 _, err = as.UserChangePassword(&pb.AuthUserChangePasswordRequest{Name: "foo-test", HashedPassword: encodePassword("bar")})
1222 if err == nil {
1223 t.Fatalf("expected %v, got %v", ErrUserNotFound, err)
1224 }
1225 if err != ErrUserNotFound {
1226 t.Fatalf("expected %v, got %v", ErrUserNotFound, err)
1227 }
1228 }
1229
View as plain text