store_test.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  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. package auth
  15. import (
  16. "fmt"
  17. "os"
  18. "reflect"
  19. "sync"
  20. "testing"
  21. "time"
  22. "github.com/coreos/etcd/auth/authpb"
  23. pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
  24. "github.com/coreos/etcd/mvcc/backend"
  25. "golang.org/x/crypto/bcrypt"
  26. "golang.org/x/net/context"
  27. "google.golang.org/grpc/metadata"
  28. )
  29. func init() { BcryptCost = bcrypt.MinCost }
  30. func dummyIndexWaiter(index uint64) <-chan struct{} {
  31. ch := make(chan struct{})
  32. go func() {
  33. ch <- struct{}{}
  34. }()
  35. return ch
  36. }
  37. // TestNewAuthStoreRevision ensures newly auth store
  38. // keeps the old revision when there are no changes.
  39. func TestNewAuthStoreRevision(t *testing.T) {
  40. b, tPath := backend.NewDefaultTmpBackend()
  41. defer os.Remove(tPath)
  42. tp, err := NewTokenProvider("simple", dummyIndexWaiter)
  43. if err != nil {
  44. t.Fatal(err)
  45. }
  46. as := NewAuthStore(b, tp)
  47. err = enableAuthAndCreateRoot(as)
  48. if err != nil {
  49. t.Fatal(err)
  50. }
  51. old := as.Revision()
  52. b.Close()
  53. as.Close()
  54. // no changes to commit
  55. b2 := backend.NewDefaultBackend(tPath)
  56. as = NewAuthStore(b2, tp)
  57. new := as.Revision()
  58. b2.Close()
  59. as.Close()
  60. if old != new {
  61. t.Fatalf("expected revision %d, got %d", old, new)
  62. }
  63. }
  64. func setupAuthStore(t *testing.T) (store *authStore, teardownfunc func(t *testing.T)) {
  65. b, tPath := backend.NewDefaultTmpBackend()
  66. tp, err := NewTokenProvider("simple", dummyIndexWaiter)
  67. if err != nil {
  68. t.Fatal(err)
  69. }
  70. as := NewAuthStore(b, tp)
  71. err = enableAuthAndCreateRoot(as)
  72. if err != nil {
  73. t.Fatal(err)
  74. }
  75. // adds a new role
  76. _, err = as.RoleAdd(&pb.AuthRoleAddRequest{Name: "role-test"})
  77. if err != nil {
  78. t.Fatal(err)
  79. }
  80. ua := &pb.AuthUserAddRequest{Name: "foo", Password: "bar"}
  81. _, err = as.UserAdd(ua) // add a non-existing user
  82. if err != nil {
  83. t.Fatal(err)
  84. }
  85. tearDown := func(t *testing.T) {
  86. b.Close()
  87. os.Remove(tPath)
  88. as.Close()
  89. }
  90. return as, tearDown
  91. }
  92. func enableAuthAndCreateRoot(as *authStore) error {
  93. _, err := as.UserAdd(&pb.AuthUserAddRequest{Name: "root", Password: "root"})
  94. if err != nil {
  95. return err
  96. }
  97. _, err = as.RoleAdd(&pb.AuthRoleAddRequest{Name: "root"})
  98. if err != nil {
  99. return err
  100. }
  101. _, err = as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "root", Role: "root"})
  102. if err != nil {
  103. return err
  104. }
  105. return as.AuthEnable()
  106. }
  107. func TestUserAdd(t *testing.T) {
  108. as, tearDown := setupAuthStore(t)
  109. defer tearDown(t)
  110. ua := &pb.AuthUserAddRequest{Name: "foo"}
  111. _, err := as.UserAdd(ua) // add an existing user
  112. if err == nil {
  113. t.Fatalf("expected %v, got %v", ErrUserAlreadyExist, err)
  114. }
  115. if err != ErrUserAlreadyExist {
  116. t.Fatalf("expected %v, got %v", ErrUserAlreadyExist, err)
  117. }
  118. ua = &pb.AuthUserAddRequest{Name: ""}
  119. _, err = as.UserAdd(ua) // add a user with empty name
  120. if err != ErrUserEmpty {
  121. t.Fatal(err)
  122. }
  123. }
  124. func TestCheckPassword(t *testing.T) {
  125. as, tearDown := setupAuthStore(t)
  126. defer tearDown(t)
  127. // auth a non-existing user
  128. _, err := as.CheckPassword("foo-test", "bar")
  129. if err == nil {
  130. t.Fatalf("expected %v, got %v", ErrAuthFailed, err)
  131. }
  132. if err != ErrAuthFailed {
  133. t.Fatalf("expected %v, got %v", ErrAuthFailed, err)
  134. }
  135. // auth an existing user with correct password
  136. _, err = as.CheckPassword("foo", "bar")
  137. if err != nil {
  138. t.Fatal(err)
  139. }
  140. // auth an existing user but with wrong password
  141. _, err = as.CheckPassword("foo", "")
  142. if err == nil {
  143. t.Fatalf("expected %v, got %v", ErrAuthFailed, err)
  144. }
  145. if err != ErrAuthFailed {
  146. t.Fatalf("expected %v, got %v", ErrAuthFailed, err)
  147. }
  148. }
  149. func TestUserDelete(t *testing.T) {
  150. as, tearDown := setupAuthStore(t)
  151. defer tearDown(t)
  152. // delete an existing user
  153. ud := &pb.AuthUserDeleteRequest{Name: "foo"}
  154. _, err := as.UserDelete(ud)
  155. if err != nil {
  156. t.Fatal(err)
  157. }
  158. // delete a non-existing user
  159. _, err = as.UserDelete(ud)
  160. if err == nil {
  161. t.Fatalf("expected %v, got %v", ErrUserNotFound, err)
  162. }
  163. if err != ErrUserNotFound {
  164. t.Fatalf("expected %v, got %v", ErrUserNotFound, err)
  165. }
  166. }
  167. func TestUserChangePassword(t *testing.T) {
  168. as, tearDown := setupAuthStore(t)
  169. defer tearDown(t)
  170. ctx1 := context.WithValue(context.WithValue(context.TODO(), "index", uint64(1)), "simpleToken", "dummy")
  171. _, err := as.Authenticate(ctx1, "foo", "bar")
  172. if err != nil {
  173. t.Fatal(err)
  174. }
  175. _, err = as.UserChangePassword(&pb.AuthUserChangePasswordRequest{Name: "foo", Password: "baz"})
  176. if err != nil {
  177. t.Fatal(err)
  178. }
  179. ctx2 := context.WithValue(context.WithValue(context.TODO(), "index", uint64(2)), "simpleToken", "dummy")
  180. _, err = as.Authenticate(ctx2, "foo", "baz")
  181. if err != nil {
  182. t.Fatal(err)
  183. }
  184. // change a non-existing user
  185. _, err = as.UserChangePassword(&pb.AuthUserChangePasswordRequest{Name: "foo-test", Password: "bar"})
  186. if err == nil {
  187. t.Fatalf("expected %v, got %v", ErrUserNotFound, err)
  188. }
  189. if err != ErrUserNotFound {
  190. t.Fatalf("expected %v, got %v", ErrUserNotFound, err)
  191. }
  192. }
  193. func TestRoleAdd(t *testing.T) {
  194. as, tearDown := setupAuthStore(t)
  195. defer tearDown(t)
  196. // adds a new role
  197. _, err := as.RoleAdd(&pb.AuthRoleAddRequest{Name: "role-test-1"})
  198. if err != nil {
  199. t.Fatal(err)
  200. }
  201. }
  202. func TestUserGrant(t *testing.T) {
  203. as, tearDown := setupAuthStore(t)
  204. defer tearDown(t)
  205. // grants a role to the user
  206. _, err := as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "foo", Role: "role-test"})
  207. if err != nil {
  208. t.Fatal(err)
  209. }
  210. // grants a role to a non-existing user
  211. _, err = as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "foo-test", Role: "role-test"})
  212. if err == nil {
  213. t.Errorf("expected %v, got %v", ErrUserNotFound, err)
  214. }
  215. if err != ErrUserNotFound {
  216. t.Errorf("expected %v, got %v", ErrUserNotFound, err)
  217. }
  218. }
  219. func TestGetUser(t *testing.T) {
  220. as, tearDown := setupAuthStore(t)
  221. defer tearDown(t)
  222. _, err := as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "foo", Role: "role-test"})
  223. if err != nil {
  224. t.Fatal(err)
  225. }
  226. u, err := as.UserGet(&pb.AuthUserGetRequest{Name: "foo"})
  227. if err != nil {
  228. t.Fatal(err)
  229. }
  230. if u == nil {
  231. t.Fatal("expect user not nil, got nil")
  232. }
  233. expected := []string{"role-test"}
  234. if !reflect.DeepEqual(expected, u.Roles) {
  235. t.Errorf("expected %v, got %v", expected, u.Roles)
  236. }
  237. }
  238. func TestListUsers(t *testing.T) {
  239. as, tearDown := setupAuthStore(t)
  240. defer tearDown(t)
  241. ua := &pb.AuthUserAddRequest{Name: "user1", Password: "pwd1"}
  242. _, err := as.UserAdd(ua) // add a non-existing user
  243. if err != nil {
  244. t.Fatal(err)
  245. }
  246. ul, err := as.UserList(&pb.AuthUserListRequest{})
  247. if err != nil {
  248. t.Fatal(err)
  249. }
  250. if !contains(ul.Users, "root") {
  251. t.Errorf("expected %v in %v", "root", ul.Users)
  252. }
  253. if !contains(ul.Users, "user1") {
  254. t.Errorf("expected %v in %v", "user1", ul.Users)
  255. }
  256. }
  257. func TestRoleGrantPermission(t *testing.T) {
  258. as, tearDown := setupAuthStore(t)
  259. defer tearDown(t)
  260. _, err := as.RoleAdd(&pb.AuthRoleAddRequest{Name: "role-test-1"})
  261. if err != nil {
  262. t.Fatal(err)
  263. }
  264. perm := &authpb.Permission{
  265. PermType: authpb.WRITE,
  266. Key: []byte("Keys"),
  267. RangeEnd: []byte("RangeEnd"),
  268. }
  269. _, err = as.RoleGrantPermission(&pb.AuthRoleGrantPermissionRequest{
  270. Name: "role-test-1",
  271. Perm: perm,
  272. })
  273. if err != nil {
  274. t.Error(err)
  275. }
  276. r, err := as.RoleGet(&pb.AuthRoleGetRequest{Role: "role-test-1"})
  277. if err != nil {
  278. t.Fatal(err)
  279. }
  280. if !reflect.DeepEqual(perm, r.Perm[0]) {
  281. t.Errorf("expected %v, got %v", perm, r.Perm[0])
  282. }
  283. }
  284. func TestRoleRevokePermission(t *testing.T) {
  285. as, tearDown := setupAuthStore(t)
  286. defer tearDown(t)
  287. _, err := as.RoleAdd(&pb.AuthRoleAddRequest{Name: "role-test-1"})
  288. if err != nil {
  289. t.Fatal(err)
  290. }
  291. perm := &authpb.Permission{
  292. PermType: authpb.WRITE,
  293. Key: []byte("Keys"),
  294. RangeEnd: []byte("RangeEnd"),
  295. }
  296. _, err = as.RoleGrantPermission(&pb.AuthRoleGrantPermissionRequest{
  297. Name: "role-test-1",
  298. Perm: perm,
  299. })
  300. if err != nil {
  301. t.Fatal(err)
  302. }
  303. _, err = as.RoleGet(&pb.AuthRoleGetRequest{Role: "role-test-1"})
  304. if err != nil {
  305. t.Fatal(err)
  306. }
  307. _, err = as.RoleRevokePermission(&pb.AuthRoleRevokePermissionRequest{
  308. Role: "role-test-1",
  309. Key: "Keys",
  310. RangeEnd: "RangeEnd",
  311. })
  312. if err != nil {
  313. t.Fatal(err)
  314. }
  315. var r *pb.AuthRoleGetResponse
  316. r, err = as.RoleGet(&pb.AuthRoleGetRequest{Role: "role-test-1"})
  317. if err != nil {
  318. t.Fatal(err)
  319. }
  320. if len(r.Perm) != 0 {
  321. t.Errorf("expected %v, got %v", 0, len(r.Perm))
  322. }
  323. }
  324. func TestUserRevokePermission(t *testing.T) {
  325. as, tearDown := setupAuthStore(t)
  326. defer tearDown(t)
  327. _, err := as.RoleAdd(&pb.AuthRoleAddRequest{Name: "role-test-1"})
  328. if err != nil {
  329. t.Fatal(err)
  330. }
  331. _, err = as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "foo", Role: "role-test"})
  332. if err != nil {
  333. t.Fatal(err)
  334. }
  335. _, err = as.UserGrantRole(&pb.AuthUserGrantRoleRequest{User: "foo", Role: "role-test-1"})
  336. if err != nil {
  337. t.Fatal(err)
  338. }
  339. u, err := as.UserGet(&pb.AuthUserGetRequest{Name: "foo"})
  340. if err != nil {
  341. t.Fatal(err)
  342. }
  343. expected := []string{"role-test", "role-test-1"}
  344. if !reflect.DeepEqual(expected, u.Roles) {
  345. t.Fatalf("expected %v, got %v", expected, u.Roles)
  346. }
  347. _, err = as.UserRevokeRole(&pb.AuthUserRevokeRoleRequest{Name: "foo", Role: "role-test-1"})
  348. if err != nil {
  349. t.Fatal(err)
  350. }
  351. u, err = as.UserGet(&pb.AuthUserGetRequest{Name: "foo"})
  352. if err != nil {
  353. t.Fatal(err)
  354. }
  355. expected = []string{"role-test"}
  356. if !reflect.DeepEqual(expected, u.Roles) {
  357. t.Errorf("expected %v, got %v", expected, u.Roles)
  358. }
  359. }
  360. func TestRoleDelete(t *testing.T) {
  361. as, tearDown := setupAuthStore(t)
  362. defer tearDown(t)
  363. _, err := as.RoleDelete(&pb.AuthRoleDeleteRequest{Role: "role-test"})
  364. if err != nil {
  365. t.Fatal(err)
  366. }
  367. rl, err := as.RoleList(&pb.AuthRoleListRequest{})
  368. if err != nil {
  369. t.Fatal(err)
  370. }
  371. expected := []string{"root"}
  372. if !reflect.DeepEqual(expected, rl.Roles) {
  373. t.Errorf("expected %v, got %v", expected, rl.Roles)
  374. }
  375. }
  376. func TestAuthInfoFromCtx(t *testing.T) {
  377. as, tearDown := setupAuthStore(t)
  378. defer tearDown(t)
  379. ctx := context.Background()
  380. ai, err := as.AuthInfoFromCtx(ctx)
  381. if err != nil && ai != nil {
  382. t.Errorf("expected (nil, nil), got (%v, %v)", ai, err)
  383. }
  384. // as if it came from RPC
  385. ctx = metadata.NewIncomingContext(context.Background(), metadata.New(map[string]string{"tokens": "dummy"}))
  386. ai, err = as.AuthInfoFromCtx(ctx)
  387. if err != nil && ai != nil {
  388. t.Errorf("expected (nil, nil), got (%v, %v)", ai, err)
  389. }
  390. ctx = context.WithValue(context.WithValue(context.TODO(), "index", uint64(1)), "simpleToken", "dummy")
  391. resp, err := as.Authenticate(ctx, "foo", "bar")
  392. if err != nil {
  393. t.Error(err)
  394. }
  395. ctx = metadata.NewIncomingContext(context.Background(), metadata.New(map[string]string{"token": "Invalid Token"}))
  396. _, err = as.AuthInfoFromCtx(ctx)
  397. if err != ErrInvalidAuthToken {
  398. t.Errorf("expected %v, got %v", ErrInvalidAuthToken, err)
  399. }
  400. ctx = metadata.NewIncomingContext(context.Background(), metadata.New(map[string]string{"token": "Invalid.Token"}))
  401. _, err = as.AuthInfoFromCtx(ctx)
  402. if err != ErrInvalidAuthToken {
  403. t.Errorf("expected %v, got %v", ErrInvalidAuthToken, err)
  404. }
  405. ctx = metadata.NewIncomingContext(context.Background(), metadata.New(map[string]string{"token": resp.Token}))
  406. ai, err = as.AuthInfoFromCtx(ctx)
  407. if err != nil {
  408. t.Error(err)
  409. }
  410. if ai.Username != "foo" {
  411. t.Errorf("expected %v, got %v", "foo", ai.Username)
  412. }
  413. }
  414. func TestAuthDisable(t *testing.T) {
  415. as, tearDown := setupAuthStore(t)
  416. defer tearDown(t)
  417. as.AuthDisable()
  418. ctx := context.WithValue(context.WithValue(context.TODO(), "index", uint64(2)), "simpleToken", "dummy")
  419. _, err := as.Authenticate(ctx, "foo", "bar")
  420. if err != ErrAuthNotEnabled {
  421. t.Errorf("expected %v, got %v", ErrAuthNotEnabled, err)
  422. }
  423. // Disabling disabled auth to make sure it can return safely if store is already disabled.
  424. as.AuthDisable()
  425. _, err = as.Authenticate(ctx, "foo", "bar")
  426. if err != ErrAuthNotEnabled {
  427. t.Errorf("expected %v, got %v", ErrAuthNotEnabled, err)
  428. }
  429. }
  430. // TestAuthRevisionRace ensures that access to authStore.revision is thread-safe.
  431. func TestAuthInfoFromCtxRace(t *testing.T) {
  432. b, tPath := backend.NewDefaultTmpBackend()
  433. defer os.Remove(tPath)
  434. tp, err := NewTokenProvider("simple", dummyIndexWaiter)
  435. if err != nil {
  436. t.Fatal(err)
  437. }
  438. as := NewAuthStore(b, tp)
  439. defer as.Close()
  440. donec := make(chan struct{})
  441. go func() {
  442. defer close(donec)
  443. ctx := metadata.NewIncomingContext(context.Background(), metadata.New(map[string]string{"token": "test"}))
  444. as.AuthInfoFromCtx(ctx)
  445. }()
  446. as.UserAdd(&pb.AuthUserAddRequest{Name: "test"})
  447. <-donec
  448. }
  449. func TestIsAdminPermitted(t *testing.T) {
  450. as, tearDown := setupAuthStore(t)
  451. defer tearDown(t)
  452. err := as.IsAdminPermitted(&AuthInfo{Username: "root", Revision: 1})
  453. if err != nil {
  454. t.Errorf("expected nil, got %v", err)
  455. }
  456. // invalid user
  457. err = as.IsAdminPermitted(&AuthInfo{Username: "rooti", Revision: 1})
  458. if err != ErrUserNotFound {
  459. t.Errorf("expected %v, got %v", ErrUserNotFound, err)
  460. }
  461. // non-admin user
  462. err = as.IsAdminPermitted(&AuthInfo{Username: "foo", Revision: 1})
  463. if err != ErrPermissionDenied {
  464. t.Errorf("expected %v, got %v", ErrPermissionDenied, err)
  465. }
  466. // disabled auth should return nil
  467. as.AuthDisable()
  468. err = as.IsAdminPermitted(&AuthInfo{Username: "root", Revision: 1})
  469. if err != nil {
  470. t.Errorf("expected nil, got %v", err)
  471. }
  472. }
  473. func TestRecoverFromSnapshot(t *testing.T) {
  474. as, _ := setupAuthStore(t)
  475. ua := &pb.AuthUserAddRequest{Name: "foo"}
  476. _, err := as.UserAdd(ua) // add an existing user
  477. if err == nil {
  478. t.Fatalf("expected %v, got %v", ErrUserAlreadyExist, err)
  479. }
  480. if err != ErrUserAlreadyExist {
  481. t.Fatalf("expected %v, got %v", ErrUserAlreadyExist, err)
  482. }
  483. ua = &pb.AuthUserAddRequest{Name: ""}
  484. _, err = as.UserAdd(ua) // add a user with empty name
  485. if err != ErrUserEmpty {
  486. t.Fatal(err)
  487. }
  488. as.Close()
  489. tp, err := NewTokenProvider("simple", dummyIndexWaiter)
  490. if err != nil {
  491. t.Fatal(err)
  492. }
  493. as2 := NewAuthStore(as.be, tp)
  494. defer func(a *authStore) {
  495. a.Close()
  496. }(as2)
  497. if !as2.isAuthEnabled() {
  498. t.Fatal("recovering authStore from existing backend failed")
  499. }
  500. ul, err := as.UserList(&pb.AuthUserListRequest{})
  501. if err != nil {
  502. t.Fatal(err)
  503. }
  504. if !contains(ul.Users, "root") {
  505. t.Errorf("expected %v in %v", "root", ul.Users)
  506. }
  507. }
  508. func contains(array []string, str string) bool {
  509. for _, s := range array {
  510. if s == str {
  511. return true
  512. }
  513. }
  514. return false
  515. }
  516. func TestHammerSimpleAuthenticate(t *testing.T) {
  517. // set TTL values low to try to trigger races
  518. oldTTL, oldTTLRes := simpleTokenTTL, simpleTokenTTLResolution
  519. defer func() {
  520. simpleTokenTTL = oldTTL
  521. simpleTokenTTLResolution = oldTTLRes
  522. }()
  523. simpleTokenTTL = 10 * time.Millisecond
  524. simpleTokenTTLResolution = simpleTokenTTL
  525. users := make(map[string]struct{})
  526. as, tearDown := setupAuthStore(t)
  527. defer tearDown(t)
  528. // create lots of users
  529. for i := 0; i < 50; i++ {
  530. u := fmt.Sprintf("user-%d", i)
  531. ua := &pb.AuthUserAddRequest{Name: u, Password: "123"}
  532. if _, err := as.UserAdd(ua); err != nil {
  533. t.Fatal(err)
  534. }
  535. users[u] = struct{}{}
  536. }
  537. // hammer on authenticate with lots of users
  538. for i := 0; i < 10; i++ {
  539. var wg sync.WaitGroup
  540. wg.Add(len(users))
  541. for u := range users {
  542. go func(user string) {
  543. defer wg.Done()
  544. token := fmt.Sprintf("%s(%d)", user, i)
  545. ctx := context.WithValue(context.WithValue(context.TODO(), "index", uint64(1)), "simpleToken", token)
  546. if _, err := as.Authenticate(ctx, user, "123"); err != nil {
  547. t.Fatal(err)
  548. }
  549. if _, err := as.AuthInfoFromCtx(ctx); err != nil {
  550. t.Fatal(err)
  551. }
  552. }(u)
  553. }
  554. time.Sleep(time.Millisecond)
  555. wg.Wait()
  556. }
  557. }