github.com/DerekStrickland/consul@v1.4.5/agent/acl_endpoint_test.go (about) 1 package agent 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "io" 7 "net/http" 8 "net/http/httptest" 9 "testing" 10 11 "github.com/hashicorp/consul/agent/structs" 12 "github.com/hashicorp/consul/testrpc" 13 "github.com/stretchr/testify/require" 14 ) 15 16 // NOTE: The tests contained herein are designed to test the HTTP API 17 // They are not intended to thoroughly test the backing RPC 18 // functionality as that will be done with other tests. 19 20 func TestACL_Disabled_Response(t *testing.T) { 21 t.Parallel() 22 a := NewTestAgent(t, t.Name(), "") 23 defer a.Shutdown() 24 25 type testCase struct { 26 name string 27 fn func(resp http.ResponseWriter, req *http.Request) (interface{}, error) 28 } 29 30 tests := []testCase{ 31 {"ACLBootstrap", a.srv.ACLBootstrap}, 32 {"ACLReplicationStatus", a.srv.ACLReplicationStatus}, 33 {"AgentToken", a.srv.AgentToken}, // See TestAgent_Token 34 {"ACLRulesTranslate", a.srv.ACLRulesTranslate}, 35 {"ACLRulesTranslateLegacyToken", a.srv.ACLRulesTranslateLegacyToken}, 36 {"ACLPolicyList", a.srv.ACLPolicyList}, 37 {"ACLPolicyCRUD", a.srv.ACLPolicyCRUD}, 38 {"ACLPolicyCreate", a.srv.ACLPolicyCreate}, 39 {"ACLTokenList", a.srv.ACLTokenList}, 40 {"ACLTokenCreate", a.srv.ACLTokenCreate}, 41 {"ACLTokenSelf", a.srv.ACLTokenSelf}, 42 {"ACLTokenCRUD", a.srv.ACLTokenCRUD}, 43 } 44 testrpc.WaitForLeader(t, a.RPC, "dc1") 45 for _, tt := range tests { 46 t.Run(tt.name, func(t *testing.T) { 47 req, _ := http.NewRequest("PUT", "/should/not/care", nil) 48 resp := httptest.NewRecorder() 49 obj, err := tt.fn(resp, req) 50 require.NoError(t, err) 51 require.Nil(t, obj) 52 require.Equal(t, http.StatusUnauthorized, resp.Code) 53 require.Contains(t, resp.Body.String(), "ACL support disabled") 54 }) 55 } 56 } 57 58 func jsonBody(v interface{}) io.Reader { 59 body := bytes.NewBuffer(nil) 60 enc := json.NewEncoder(body) 61 enc.Encode(v) 62 return body 63 } 64 65 func TestACL_Bootstrap(t *testing.T) { 66 t.Parallel() 67 a := NewTestAgent(t, t.Name(), TestACLConfig()+` 68 acl_master_token = "" 69 `) 70 defer a.Shutdown() 71 72 tests := []struct { 73 name string 74 method string 75 code int 76 token bool 77 }{ 78 {"bootstrap", "PUT", http.StatusOK, true}, 79 {"not again", "PUT", http.StatusForbidden, false}, 80 } 81 testrpc.WaitForLeader(t, a.RPC, "dc1") 82 for _, tt := range tests { 83 t.Run(tt.name, func(t *testing.T) { 84 resp := httptest.NewRecorder() 85 req, _ := http.NewRequest(tt.method, "/v1/acl/bootstrap", nil) 86 out, err := a.srv.ACLBootstrap(resp, req) 87 if tt.token && err != nil { 88 t.Fatalf("err: %v", err) 89 } 90 if got, want := resp.Code, tt.code; got != want { 91 t.Fatalf("got %d want %d", got, want) 92 } 93 if tt.token { 94 wrap, ok := out.(*aclBootstrapResponse) 95 if !ok { 96 t.Fatalf("bad: %T", out) 97 } 98 if len(wrap.ID) != len("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx") { 99 t.Fatalf("bad: %v", wrap) 100 } 101 if wrap.ID != wrap.SecretID { 102 t.Fatalf("bad: %v", wrap) 103 } 104 } else { 105 if out != nil { 106 t.Fatalf("bad: %T", out) 107 } 108 } 109 }) 110 } 111 } 112 113 func TestACL_HTTP(t *testing.T) { 114 t.Parallel() 115 a := NewTestAgent(t, t.Name(), TestACLConfig()) 116 defer a.Shutdown() 117 118 testrpc.WaitForLeader(t, a.RPC, "dc1") 119 120 idMap := make(map[string]string) 121 policyMap := make(map[string]*structs.ACLPolicy) 122 tokenMap := make(map[string]*structs.ACLToken) 123 124 // This is all done as a subtest for a couple reasons 125 // 1. It uses only 1 test agent and these are 126 // somewhat expensive to bring up and tear down often 127 // 2. Instead of having to bring up a new agent and prime 128 // the ACL system with some data before running the test 129 // we can intelligently order these tests so we can still 130 // test everything with less actual operations and do 131 // so in a manner that is less prone to being flaky 132 // 3. While this test will be large it should 133 t.Run("Policy", func(t *testing.T) { 134 t.Run("Create", func(t *testing.T) { 135 policyInput := &structs.ACLPolicy{ 136 Name: "test", 137 Description: "test", 138 Rules: `acl = "read"`, 139 Datacenters: []string{"dc1"}, 140 } 141 142 req, _ := http.NewRequest("PUT", "/v1/acl/policy?token=root", jsonBody(policyInput)) 143 resp := httptest.NewRecorder() 144 obj, err := a.srv.ACLPolicyCreate(resp, req) 145 require.NoError(t, err) 146 147 policy, ok := obj.(*structs.ACLPolicy) 148 require.True(t, ok) 149 150 // 36 = length of the string form of uuids 151 require.Len(t, policy.ID, 36) 152 require.Equal(t, policyInput.Name, policy.Name) 153 require.Equal(t, policyInput.Description, policy.Description) 154 require.Equal(t, policyInput.Rules, policy.Rules) 155 require.Equal(t, policyInput.Datacenters, policy.Datacenters) 156 require.True(t, policy.CreateIndex > 0) 157 require.Equal(t, policy.CreateIndex, policy.ModifyIndex) 158 require.NotNil(t, policy.Hash) 159 require.NotEqual(t, policy.Hash, []byte{}) 160 161 idMap["policy-test"] = policy.ID 162 policyMap[policy.ID] = policy 163 }) 164 165 t.Run("Minimal", func(t *testing.T) { 166 policyInput := &structs.ACLPolicy{ 167 Name: "minimal", 168 Rules: `key_prefix "" { policy = "read" }`, 169 } 170 171 req, _ := http.NewRequest("PUT", "/v1/acl/policy?token=root", jsonBody(policyInput)) 172 resp := httptest.NewRecorder() 173 obj, err := a.srv.ACLPolicyCreate(resp, req) 174 require.NoError(t, err) 175 176 policy, ok := obj.(*structs.ACLPolicy) 177 require.True(t, ok) 178 179 // 36 = length of the string form of uuids 180 require.Len(t, policy.ID, 36) 181 require.Equal(t, policyInput.Name, policy.Name) 182 require.Equal(t, policyInput.Description, policy.Description) 183 require.Equal(t, policyInput.Rules, policy.Rules) 184 require.Equal(t, policyInput.Datacenters, policy.Datacenters) 185 require.True(t, policy.CreateIndex > 0) 186 require.Equal(t, policy.CreateIndex, policy.ModifyIndex) 187 require.NotNil(t, policy.Hash) 188 require.NotEqual(t, policy.Hash, []byte{}) 189 190 idMap["policy-minimal"] = policy.ID 191 policyMap[policy.ID] = policy 192 }) 193 194 t.Run("Name Chars", func(t *testing.T) { 195 policyInput := &structs.ACLPolicy{ 196 Name: "read-all_nodes-012", 197 Rules: `node_prefix "" { policy = "read" }`, 198 } 199 200 req, _ := http.NewRequest("PUT", "/v1/acl/policy?token=root", jsonBody(policyInput)) 201 resp := httptest.NewRecorder() 202 obj, err := a.srv.ACLPolicyCreate(resp, req) 203 require.NoError(t, err) 204 205 policy, ok := obj.(*structs.ACLPolicy) 206 require.True(t, ok) 207 208 // 36 = length of the string form of uuids 209 require.Len(t, policy.ID, 36) 210 require.Equal(t, policyInput.Name, policy.Name) 211 require.Equal(t, policyInput.Description, policy.Description) 212 require.Equal(t, policyInput.Rules, policy.Rules) 213 require.Equal(t, policyInput.Datacenters, policy.Datacenters) 214 require.True(t, policy.CreateIndex > 0) 215 require.Equal(t, policy.CreateIndex, policy.ModifyIndex) 216 require.NotNil(t, policy.Hash) 217 require.NotEqual(t, policy.Hash, []byte{}) 218 219 idMap["policy-read-all-nodes"] = policy.ID 220 policyMap[policy.ID] = policy 221 }) 222 223 t.Run("Update Name ID Mistmatch", func(t *testing.T) { 224 policyInput := &structs.ACLPolicy{ 225 ID: "ac7560be-7f11-4d6d-bfcf-15633c2090fd", 226 Name: "read-all-nodes", 227 Description: "Can read all node information", 228 Rules: `node_prefix "" { policy = "read" }`, 229 Datacenters: []string{"dc1"}, 230 } 231 232 req, _ := http.NewRequest("PUT", "/v1/acl/policy/"+idMap["policy-read-all-nodes"]+"?token=root", jsonBody(policyInput)) 233 resp := httptest.NewRecorder() 234 _, err := a.srv.ACLPolicyCRUD(resp, req) 235 require.Error(t, err) 236 _, ok := err.(BadRequestError) 237 require.True(t, ok) 238 }) 239 240 t.Run("Policy CRUD Missing ID in URL", func(t *testing.T) { 241 req, _ := http.NewRequest("GET", "/v1/acl/policy/?token=root", nil) 242 resp := httptest.NewRecorder() 243 _, err := a.srv.ACLPolicyCRUD(resp, req) 244 require.Error(t, err) 245 _, ok := err.(BadRequestError) 246 require.True(t, ok) 247 }) 248 249 t.Run("Update", func(t *testing.T) { 250 policyInput := &structs.ACLPolicy{ 251 Name: "read-all-nodes", 252 Description: "Can read all node information", 253 Rules: `node_prefix "" { policy = "read" }`, 254 Datacenters: []string{"dc1"}, 255 } 256 257 req, _ := http.NewRequest("PUT", "/v1/acl/policy/"+idMap["policy-read-all-nodes"]+"?token=root", jsonBody(policyInput)) 258 resp := httptest.NewRecorder() 259 obj, err := a.srv.ACLPolicyCRUD(resp, req) 260 require.NoError(t, err) 261 262 policy, ok := obj.(*structs.ACLPolicy) 263 require.True(t, ok) 264 265 // 36 = length of the string form of uuids 266 require.Len(t, policy.ID, 36) 267 require.Equal(t, policyInput.Name, policy.Name) 268 require.Equal(t, policyInput.Description, policy.Description) 269 require.Equal(t, policyInput.Rules, policy.Rules) 270 require.Equal(t, policyInput.Datacenters, policy.Datacenters) 271 require.True(t, policy.CreateIndex > 0) 272 require.True(t, policy.CreateIndex < policy.ModifyIndex) 273 require.NotNil(t, policy.Hash) 274 require.NotEqual(t, policy.Hash, []byte{}) 275 276 idMap["policy-read-all-nodes"] = policy.ID 277 policyMap[policy.ID] = policy 278 }) 279 280 t.Run("ID Supplied", func(t *testing.T) { 281 policyInput := &structs.ACLPolicy{ 282 ID: "12123d01-37f1-47e6-b55b-32328652bd38", 283 Name: "with-id", 284 Description: "test", 285 Rules: `acl = "read"`, 286 Datacenters: []string{"dc1"}, 287 } 288 289 req, _ := http.NewRequest("PUT", "/v1/acl/policy?token=root", jsonBody(policyInput)) 290 resp := httptest.NewRecorder() 291 _, err := a.srv.ACLPolicyCreate(resp, req) 292 require.Error(t, err) 293 _, ok := err.(BadRequestError) 294 require.True(t, ok) 295 }) 296 297 t.Run("Invalid payload", func(t *testing.T) { 298 body := bytes.NewBuffer(nil) 299 body.Write([]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) 300 301 req, _ := http.NewRequest("PUT", "/v1/acl/policy?token=root", body) 302 resp := httptest.NewRecorder() 303 _, err := a.srv.ACLPolicyCreate(resp, req) 304 require.Error(t, err) 305 _, ok := err.(BadRequestError) 306 require.True(t, ok) 307 }) 308 309 t.Run("Delete", func(t *testing.T) { 310 req, _ := http.NewRequest("DELETE", "/v1/acl/policy/"+idMap["policy-minimal"]+"?token=root", nil) 311 resp := httptest.NewRecorder() 312 _, err := a.srv.ACLPolicyCRUD(resp, req) 313 require.NoError(t, err) 314 delete(policyMap, idMap["policy-minimal"]) 315 delete(idMap, "policy-minimal") 316 }) 317 318 t.Run("List", func(t *testing.T) { 319 req, _ := http.NewRequest("GET", "/v1/acl/policies?token=root", nil) 320 resp := httptest.NewRecorder() 321 raw, err := a.srv.ACLPolicyList(resp, req) 322 require.NoError(t, err) 323 policies, ok := raw.(structs.ACLPolicyListStubs) 324 require.True(t, ok) 325 326 // 2 we just created + global management 327 require.Len(t, policies, 3) 328 329 for policyID, expected := range policyMap { 330 found := false 331 for _, actual := range policies { 332 if actual.ID == policyID { 333 require.Equal(t, expected.Name, actual.Name) 334 require.Equal(t, expected.Datacenters, actual.Datacenters) 335 require.Equal(t, expected.Hash, actual.Hash) 336 require.Equal(t, expected.CreateIndex, actual.CreateIndex) 337 require.Equal(t, expected.ModifyIndex, actual.ModifyIndex) 338 found = true 339 break 340 } 341 } 342 343 require.True(t, found) 344 } 345 }) 346 347 t.Run("Read", func(t *testing.T) { 348 req, _ := http.NewRequest("GET", "/v1/acl/policy/"+idMap["policy-read-all-nodes"]+"?token=root", nil) 349 resp := httptest.NewRecorder() 350 raw, err := a.srv.ACLPolicyCRUD(resp, req) 351 require.NoError(t, err) 352 policy, ok := raw.(*structs.ACLPolicy) 353 require.True(t, ok) 354 require.Equal(t, policyMap[idMap["policy-read-all-nodes"]], policy) 355 }) 356 }) 357 358 t.Run("Token", func(t *testing.T) { 359 t.Run("Create", func(t *testing.T) { 360 tokenInput := &structs.ACLToken{ 361 Description: "test", 362 Policies: []structs.ACLTokenPolicyLink{ 363 structs.ACLTokenPolicyLink{ 364 ID: idMap["policy-test"], 365 Name: policyMap[idMap["policy-test"]].Name, 366 }, 367 structs.ACLTokenPolicyLink{ 368 ID: idMap["policy-read-all-nodes"], 369 Name: policyMap[idMap["policy-read-all-nodes"]].Name, 370 }, 371 }, 372 } 373 374 req, _ := http.NewRequest("PUT", "/v1/acl/token?token=root", jsonBody(tokenInput)) 375 resp := httptest.NewRecorder() 376 obj, err := a.srv.ACLTokenCreate(resp, req) 377 require.NoError(t, err) 378 379 token, ok := obj.(*structs.ACLToken) 380 require.True(t, ok) 381 382 // 36 = length of the string form of uuids 383 require.Len(t, token.AccessorID, 36) 384 require.Len(t, token.SecretID, 36) 385 require.Equal(t, tokenInput.Description, token.Description) 386 require.Equal(t, tokenInput.Policies, token.Policies) 387 require.True(t, token.CreateIndex > 0) 388 require.Equal(t, token.CreateIndex, token.ModifyIndex) 389 require.NotNil(t, token.Hash) 390 require.NotEqual(t, token.Hash, []byte{}) 391 392 idMap["token-test"] = token.AccessorID 393 tokenMap[token.AccessorID] = token 394 }) 395 t.Run("Create Local", func(t *testing.T) { 396 tokenInput := &structs.ACLToken{ 397 Description: "local", 398 Policies: []structs.ACLTokenPolicyLink{ 399 structs.ACLTokenPolicyLink{ 400 ID: idMap["policy-test"], 401 Name: policyMap[idMap["policy-test"]].Name, 402 }, 403 structs.ACLTokenPolicyLink{ 404 ID: idMap["policy-read-all-nodes"], 405 Name: policyMap[idMap["policy-read-all-nodes"]].Name, 406 }, 407 }, 408 Local: true, 409 } 410 411 req, _ := http.NewRequest("PUT", "/v1/acl/token?token=root", jsonBody(tokenInput)) 412 resp := httptest.NewRecorder() 413 obj, err := a.srv.ACLTokenCreate(resp, req) 414 require.NoError(t, err) 415 416 token, ok := obj.(*structs.ACLToken) 417 require.True(t, ok) 418 419 // 36 = length of the string form of uuids 420 require.Len(t, token.AccessorID, 36) 421 require.Len(t, token.SecretID, 36) 422 require.Equal(t, tokenInput.Description, token.Description) 423 require.Equal(t, tokenInput.Policies, token.Policies) 424 require.True(t, token.CreateIndex > 0) 425 require.Equal(t, token.CreateIndex, token.ModifyIndex) 426 require.NotNil(t, token.Hash) 427 require.NotEqual(t, token.Hash, []byte{}) 428 429 idMap["token-local"] = token.AccessorID 430 tokenMap[token.AccessorID] = token 431 }) 432 t.Run("Read", func(t *testing.T) { 433 expected := tokenMap[idMap["token-test"]] 434 req, _ := http.NewRequest("GET", "/v1/acl/token/"+expected.AccessorID+"?token=root", nil) 435 resp := httptest.NewRecorder() 436 obj, err := a.srv.ACLTokenCRUD(resp, req) 437 require.NoError(t, err) 438 token, ok := obj.(*structs.ACLToken) 439 require.True(t, ok) 440 require.Equal(t, expected, token) 441 }) 442 t.Run("Self", func(t *testing.T) { 443 expected := tokenMap[idMap["token-test"]] 444 req, _ := http.NewRequest("GET", "/v1/acl/token/self?token="+expected.SecretID, nil) 445 resp := httptest.NewRecorder() 446 obj, err := a.srv.ACLTokenSelf(resp, req) 447 require.NoError(t, err) 448 token, ok := obj.(*structs.ACLToken) 449 require.True(t, ok) 450 require.Equal(t, expected, token) 451 }) 452 t.Run("Clone", func(t *testing.T) { 453 tokenInput := &structs.ACLToken{ 454 Description: "cloned token", 455 } 456 457 baseToken := tokenMap[idMap["token-test"]] 458 459 req, _ := http.NewRequest("PUT", "/v1/acl/token/"+baseToken.AccessorID+"/clone?token=root", jsonBody(tokenInput)) 460 resp := httptest.NewRecorder() 461 obj, err := a.srv.ACLTokenCRUD(resp, req) 462 require.NoError(t, err) 463 token, ok := obj.(*structs.ACLToken) 464 require.True(t, ok) 465 466 require.NotEqual(t, baseToken.AccessorID, token.AccessorID) 467 require.NotEqual(t, baseToken.SecretID, token.SecretID) 468 require.Equal(t, tokenInput.Description, token.Description) 469 require.Equal(t, baseToken.Policies, token.Policies) 470 require.True(t, token.CreateIndex > 0) 471 require.Equal(t, token.CreateIndex, token.ModifyIndex) 472 require.NotNil(t, token.Hash) 473 require.NotEqual(t, token.Hash, []byte{}) 474 475 idMap["token-cloned"] = token.AccessorID 476 tokenMap[token.AccessorID] = token 477 }) 478 t.Run("Update", func(t *testing.T) { 479 originalToken := tokenMap[idMap["token-cloned"]] 480 481 // Accessor and Secret will be filled in 482 tokenInput := &structs.ACLToken{ 483 Description: "Better description for this cloned token", 484 Policies: []structs.ACLTokenPolicyLink{ 485 structs.ACLTokenPolicyLink{ 486 ID: idMap["policy-read-all-nodes"], 487 Name: policyMap[idMap["policy-read-all-nodes"]].Name, 488 }, 489 }, 490 } 491 492 req, _ := http.NewRequest("PUT", "/v1/acl/token/"+originalToken.AccessorID+"?token=root", jsonBody(tokenInput)) 493 resp := httptest.NewRecorder() 494 obj, err := a.srv.ACLTokenCRUD(resp, req) 495 require.NoError(t, err) 496 token, ok := obj.(*structs.ACLToken) 497 require.True(t, ok) 498 499 require.Equal(t, originalToken.AccessorID, token.AccessorID) 500 require.Equal(t, originalToken.SecretID, token.SecretID) 501 require.Equal(t, tokenInput.Description, token.Description) 502 require.Equal(t, tokenInput.Policies, token.Policies) 503 require.True(t, token.CreateIndex > 0) 504 require.True(t, token.CreateIndex < token.ModifyIndex) 505 require.NotNil(t, token.Hash) 506 require.NotEqual(t, token.Hash, []byte{}) 507 require.NotEqual(t, token.Hash, originalToken.Hash) 508 509 tokenMap[token.AccessorID] = token 510 }) 511 512 t.Run("CRUD Missing Token Accessor ID", func(t *testing.T) { 513 req, _ := http.NewRequest("GET", "/v1/acl/token/?token=root", nil) 514 resp := httptest.NewRecorder() 515 obj, err := a.srv.ACLTokenCRUD(resp, req) 516 require.Error(t, err) 517 require.Nil(t, obj) 518 _, ok := err.(BadRequestError) 519 require.True(t, ok) 520 }) 521 t.Run("Update Accessor Mismatch", func(t *testing.T) { 522 originalToken := tokenMap[idMap["token-cloned"]] 523 524 // Accessor and Secret will be filled in 525 tokenInput := &structs.ACLToken{ 526 AccessorID: "e8aeb69a-0ace-42b9-b95f-d1d9eafe1561", 527 Description: "Better description for this cloned token", 528 Policies: []structs.ACLTokenPolicyLink{ 529 structs.ACLTokenPolicyLink{ 530 ID: idMap["policy-read-all-nodes"], 531 Name: policyMap[idMap["policy-read-all-nodes"]].Name, 532 }, 533 }, 534 } 535 536 req, _ := http.NewRequest("PUT", "/v1/acl/token/"+originalToken.AccessorID+"?token=root", jsonBody(tokenInput)) 537 resp := httptest.NewRecorder() 538 obj, err := a.srv.ACLTokenCRUD(resp, req) 539 require.Error(t, err) 540 require.Nil(t, obj) 541 _, ok := err.(BadRequestError) 542 require.True(t, ok) 543 }) 544 t.Run("Delete", func(t *testing.T) { 545 req, _ := http.NewRequest("DELETE", "/v1/acl/token/"+idMap["token-cloned"]+"?token=root", nil) 546 resp := httptest.NewRecorder() 547 _, err := a.srv.ACLTokenCRUD(resp, req) 548 require.NoError(t, err) 549 delete(tokenMap, idMap["token-cloned"]) 550 delete(idMap, "token-cloned") 551 }) 552 t.Run("List", func(t *testing.T) { 553 req, _ := http.NewRequest("GET", "/v1/acl/tokens?token=root", nil) 554 resp := httptest.NewRecorder() 555 raw, err := a.srv.ACLTokenList(resp, req) 556 require.NoError(t, err) 557 tokens, ok := raw.(structs.ACLTokenListStubs) 558 require.True(t, ok) 559 560 // 3 tokens created but 1 was deleted + master token + anon token 561 require.Len(t, tokens, 4) 562 563 // this loop doesn't verify anything about the master token 564 for tokenID, expected := range tokenMap { 565 found := false 566 for _, actual := range tokens { 567 if actual.AccessorID == tokenID { 568 require.Equal(t, expected.Description, actual.Description) 569 require.Equal(t, expected.Policies, actual.Policies) 570 require.Equal(t, expected.Local, actual.Local) 571 require.Equal(t, expected.CreateTime, actual.CreateTime) 572 require.Equal(t, expected.Hash, actual.Hash) 573 require.Equal(t, expected.CreateIndex, actual.CreateIndex) 574 require.Equal(t, expected.ModifyIndex, actual.ModifyIndex) 575 found = true 576 break 577 } 578 } 579 require.True(t, found) 580 } 581 }) 582 t.Run("List by Policy", func(t *testing.T) { 583 req, _ := http.NewRequest("GET", "/v1/acl/tokens?token=root&policy="+structs.ACLPolicyGlobalManagementID, nil) 584 resp := httptest.NewRecorder() 585 raw, err := a.srv.ACLTokenList(resp, req) 586 require.NoError(t, err) 587 tokens, ok := raw.(structs.ACLTokenListStubs) 588 require.True(t, ok) 589 require.Len(t, tokens, 1) 590 token := tokens[0] 591 require.Equal(t, "Master Token", token.Description) 592 require.Len(t, token.Policies, 1) 593 require.Equal(t, structs.ACLPolicyGlobalManagementID, token.Policies[0].ID) 594 }) 595 }) 596 }