1package agent 2 3import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io" 8 "net/http" 9 "net/http/httptest" 10 "testing" 11 "time" 12 13 "github.com/hashicorp/consul/acl" 14 "github.com/hashicorp/consul/agent/consul/authmethod/testauth" 15 "github.com/hashicorp/consul/agent/structs" 16 "github.com/hashicorp/consul/internal/go-sso/oidcauth/oidcauthtest" 17 "github.com/hashicorp/consul/sdk/freeport" 18 "github.com/hashicorp/consul/sdk/testutil" 19 "github.com/hashicorp/consul/testrpc" 20 "github.com/hashicorp/go-uuid" 21 "github.com/stretchr/testify/require" 22 "gopkg.in/square/go-jose.v2/jwt" 23) 24 25// NOTE: The tests contained herein are designed to test the HTTP API 26// They are not intended to thoroughly test the backing RPC 27// functionality as that will be done with other tests. 28 29func TestACL_Disabled_Response(t *testing.T) { 30 t.Parallel() 31 a := NewTestAgent(t, "") 32 defer a.Shutdown() 33 34 type testCase struct { 35 name string 36 fn func(resp http.ResponseWriter, req *http.Request) (interface{}, error) 37 } 38 39 tests := []testCase{ 40 {"ACLBootstrap", a.srv.ACLBootstrap}, 41 {"ACLReplicationStatus", a.srv.ACLReplicationStatus}, 42 {"AgentToken", a.srv.AgentToken}, // See TestAgent_Token 43 {"ACLRulesTranslate", a.srv.ACLRulesTranslate}, 44 {"ACLRulesTranslateLegacyToken", a.srv.ACLRulesTranslateLegacyToken}, 45 {"ACLPolicyList", a.srv.ACLPolicyList}, 46 {"ACLPolicyCRUD", a.srv.ACLPolicyCRUD}, 47 {"ACLPolicyCreate", a.srv.ACLPolicyCreate}, 48 {"ACLTokenList", a.srv.ACLTokenList}, 49 {"ACLTokenCreate", a.srv.ACLTokenCreate}, 50 {"ACLTokenSelf", a.srv.ACLTokenSelf}, 51 {"ACLTokenCRUD", a.srv.ACLTokenCRUD}, 52 {"ACLRoleList", a.srv.ACLRoleList}, 53 {"ACLRoleCreate", a.srv.ACLRoleCreate}, 54 {"ACLRoleCRUD", a.srv.ACLRoleCRUD}, 55 {"ACLBindingRuleList", a.srv.ACLBindingRuleList}, 56 {"ACLBindingRuleCreate", a.srv.ACLBindingRuleCreate}, 57 {"ACLBindingRuleCRUD", a.srv.ACLBindingRuleCRUD}, 58 {"ACLAuthMethodList", a.srv.ACLAuthMethodList}, 59 {"ACLAuthMethodCreate", a.srv.ACLAuthMethodCreate}, 60 {"ACLAuthMethodCRUD", a.srv.ACLAuthMethodCRUD}, 61 {"ACLLogin", a.srv.ACLLogin}, 62 {"ACLLogout", a.srv.ACLLogout}, 63 {"ACLAuthorize", a.srv.ACLAuthorize}, 64 } 65 testrpc.WaitForLeader(t, a.RPC, "dc1") 66 for _, tt := range tests { 67 t.Run(tt.name, func(t *testing.T) { 68 req, _ := http.NewRequest("PUT", "/should/not/care", nil) 69 resp := httptest.NewRecorder() 70 obj, err := tt.fn(resp, req) 71 require.NoError(t, err) 72 require.Nil(t, obj) 73 require.Equal(t, http.StatusUnauthorized, resp.Code) 74 require.Contains(t, resp.Body.String(), "ACL support disabled") 75 }) 76 } 77} 78 79func jsonBody(v interface{}) io.Reader { 80 body := bytes.NewBuffer(nil) 81 enc := json.NewEncoder(body) 82 enc.Encode(v) 83 return body 84} 85 86func TestACL_Bootstrap(t *testing.T) { 87 t.Parallel() 88 a := NewTestAgent(t, TestACLConfig()+` 89 acl_master_token = "" 90 `) 91 defer a.Shutdown() 92 93 tests := []struct { 94 name string 95 method string 96 code int 97 token bool 98 }{ 99 {"bootstrap", "PUT", http.StatusOK, true}, 100 {"not again", "PUT", http.StatusForbidden, false}, 101 } 102 testrpc.WaitForLeader(t, a.RPC, "dc1") 103 for _, tt := range tests { 104 t.Run(tt.name, func(t *testing.T) { 105 resp := httptest.NewRecorder() 106 req, _ := http.NewRequest(tt.method, "/v1/acl/bootstrap", nil) 107 out, err := a.srv.ACLBootstrap(resp, req) 108 if tt.token && err != nil { 109 t.Fatalf("err: %v", err) 110 } 111 if got, want := resp.Code, tt.code; got != want { 112 t.Fatalf("got %d want %d", got, want) 113 } 114 if tt.token { 115 wrap, ok := out.(*aclBootstrapResponse) 116 if !ok { 117 t.Fatalf("bad: %T", out) 118 } 119 if len(wrap.ID) != len("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx") { 120 t.Fatalf("bad: %v", wrap) 121 } 122 if wrap.ID != wrap.SecretID { 123 t.Fatalf("bad: %v", wrap) 124 } 125 } else { 126 if out != nil { 127 t.Fatalf("bad: %T", out) 128 } 129 } 130 }) 131 } 132} 133 134func TestACL_HTTP(t *testing.T) { 135 t.Parallel() 136 a := NewTestAgent(t, TestACLConfig()) 137 defer a.Shutdown() 138 139 testrpc.WaitForLeader(t, a.RPC, "dc1") 140 141 idMap := make(map[string]string) 142 policyMap := make(map[string]*structs.ACLPolicy) 143 roleMap := make(map[string]*structs.ACLRole) 144 tokenMap := make(map[string]*structs.ACLToken) 145 146 // This is all done as a subtest for a couple reasons 147 // 1. It uses only 1 test agent and these are 148 // somewhat expensive to bring up and tear down often 149 // 2. Instead of having to bring up a new agent and prime 150 // the ACL system with some data before running the test 151 // we can intelligently order these tests so we can still 152 // test everything with less actual operations and do 153 // so in a manner that is less prone to being flaky 154 // 155 // This could be accomplished with just blocks of code but I find 156 // the go test output nicer to pinpoint the error if they are grouped. 157 // 158 // NOTE: None of the subtests should be parallelized in order for 159 // any of it to work properly. 160 t.Run("Policy", func(t *testing.T) { 161 t.Run("Create", func(t *testing.T) { 162 policyInput := &structs.ACLPolicy{ 163 Name: "test", 164 Description: "test", 165 Rules: `acl = "read"`, 166 Datacenters: []string{"dc1"}, 167 } 168 169 req, _ := http.NewRequest("PUT", "/v1/acl/policy?token=root", jsonBody(policyInput)) 170 resp := httptest.NewRecorder() 171 obj, err := a.srv.ACLPolicyCreate(resp, req) 172 require.NoError(t, err) 173 174 policy, ok := obj.(*structs.ACLPolicy) 175 require.True(t, ok) 176 177 // 36 = length of the string form of uuids 178 require.Len(t, policy.ID, 36) 179 require.Equal(t, policyInput.Name, policy.Name) 180 require.Equal(t, policyInput.Description, policy.Description) 181 require.Equal(t, policyInput.Rules, policy.Rules) 182 require.Equal(t, policyInput.Datacenters, policy.Datacenters) 183 require.True(t, policy.CreateIndex > 0) 184 require.Equal(t, policy.CreateIndex, policy.ModifyIndex) 185 require.NotNil(t, policy.Hash) 186 require.NotEqual(t, policy.Hash, []byte{}) 187 188 idMap["policy-test"] = policy.ID 189 policyMap[policy.ID] = policy 190 }) 191 192 t.Run("Minimal", func(t *testing.T) { 193 policyInput := &structs.ACLPolicy{ 194 Name: "minimal", 195 Rules: `key_prefix "" { policy = "read" }`, 196 } 197 198 req, _ := http.NewRequest("PUT", "/v1/acl/policy?token=root", jsonBody(policyInput)) 199 resp := httptest.NewRecorder() 200 obj, err := a.srv.ACLPolicyCreate(resp, req) 201 require.NoError(t, err) 202 203 policy, ok := obj.(*structs.ACLPolicy) 204 require.True(t, ok) 205 206 // 36 = length of the string form of uuids 207 require.Len(t, policy.ID, 36) 208 require.Equal(t, policyInput.Name, policy.Name) 209 require.Equal(t, policyInput.Description, policy.Description) 210 require.Equal(t, policyInput.Rules, policy.Rules) 211 require.Equal(t, policyInput.Datacenters, policy.Datacenters) 212 require.True(t, policy.CreateIndex > 0) 213 require.Equal(t, policy.CreateIndex, policy.ModifyIndex) 214 require.NotNil(t, policy.Hash) 215 require.NotEqual(t, policy.Hash, []byte{}) 216 217 idMap["policy-minimal"] = policy.ID 218 policyMap[policy.ID] = policy 219 }) 220 221 t.Run("Name Chars", func(t *testing.T) { 222 policyInput := &structs.ACLPolicy{ 223 Name: "read-all_nodes-012", 224 Rules: `node_prefix "" { policy = "read" }`, 225 } 226 227 req, _ := http.NewRequest("PUT", "/v1/acl/policy?token=root", jsonBody(policyInput)) 228 resp := httptest.NewRecorder() 229 obj, err := a.srv.ACLPolicyCreate(resp, req) 230 require.NoError(t, err) 231 232 policy, ok := obj.(*structs.ACLPolicy) 233 require.True(t, ok) 234 235 // 36 = length of the string form of uuids 236 require.Len(t, policy.ID, 36) 237 require.Equal(t, policyInput.Name, policy.Name) 238 require.Equal(t, policyInput.Description, policy.Description) 239 require.Equal(t, policyInput.Rules, policy.Rules) 240 require.Equal(t, policyInput.Datacenters, policy.Datacenters) 241 require.True(t, policy.CreateIndex > 0) 242 require.Equal(t, policy.CreateIndex, policy.ModifyIndex) 243 require.NotNil(t, policy.Hash) 244 require.NotEqual(t, policy.Hash, []byte{}) 245 246 idMap["policy-read-all-nodes"] = policy.ID 247 policyMap[policy.ID] = policy 248 }) 249 250 t.Run("Update Name ID Mismatch", func(t *testing.T) { 251 policyInput := &structs.ACLPolicy{ 252 ID: "ac7560be-7f11-4d6d-bfcf-15633c2090fd", 253 Name: "read-all-nodes", 254 Description: "Can read all node information", 255 Rules: `node_prefix "" { policy = "read" }`, 256 Datacenters: []string{"dc1"}, 257 } 258 259 req, _ := http.NewRequest("PUT", "/v1/acl/policy/"+idMap["policy-read-all-nodes"]+"?token=root", jsonBody(policyInput)) 260 resp := httptest.NewRecorder() 261 _, err := a.srv.ACLPolicyCRUD(resp, req) 262 require.Error(t, err) 263 _, ok := err.(BadRequestError) 264 require.True(t, ok) 265 }) 266 267 t.Run("Policy CRUD Missing ID in URL", func(t *testing.T) { 268 req, _ := http.NewRequest("GET", "/v1/acl/policy/?token=root", nil) 269 resp := httptest.NewRecorder() 270 _, err := a.srv.ACLPolicyCRUD(resp, req) 271 require.Error(t, err) 272 _, ok := err.(BadRequestError) 273 require.True(t, ok) 274 }) 275 276 t.Run("Update", func(t *testing.T) { 277 policyInput := &structs.ACLPolicy{ 278 Name: "read-all-nodes", 279 Description: "Can read all node information", 280 Rules: `node_prefix "" { policy = "read" }`, 281 Datacenters: []string{"dc1"}, 282 } 283 284 req, _ := http.NewRequest("PUT", "/v1/acl/policy/"+idMap["policy-read-all-nodes"]+"?token=root", jsonBody(policyInput)) 285 resp := httptest.NewRecorder() 286 obj, err := a.srv.ACLPolicyCRUD(resp, req) 287 require.NoError(t, err) 288 289 policy, ok := obj.(*structs.ACLPolicy) 290 require.True(t, ok) 291 292 // 36 = length of the string form of uuids 293 require.Len(t, policy.ID, 36) 294 require.Equal(t, policyInput.Name, policy.Name) 295 require.Equal(t, policyInput.Description, policy.Description) 296 require.Equal(t, policyInput.Rules, policy.Rules) 297 require.Equal(t, policyInput.Datacenters, policy.Datacenters) 298 require.True(t, policy.CreateIndex > 0) 299 require.True(t, policy.CreateIndex < policy.ModifyIndex) 300 require.NotNil(t, policy.Hash) 301 require.NotEqual(t, policy.Hash, []byte{}) 302 303 idMap["policy-read-all-nodes"] = policy.ID 304 policyMap[policy.ID] = policy 305 }) 306 307 t.Run("ID Supplied", func(t *testing.T) { 308 policyInput := &structs.ACLPolicy{ 309 ID: "12123d01-37f1-47e6-b55b-32328652bd38", 310 Name: "with-id", 311 Description: "test", 312 Rules: `acl = "read"`, 313 Datacenters: []string{"dc1"}, 314 } 315 316 req, _ := http.NewRequest("PUT", "/v1/acl/policy?token=root", jsonBody(policyInput)) 317 resp := httptest.NewRecorder() 318 _, err := a.srv.ACLPolicyCreate(resp, req) 319 require.Error(t, err) 320 _, ok := err.(BadRequestError) 321 require.True(t, ok) 322 }) 323 324 t.Run("Invalid payload", func(t *testing.T) { 325 body := bytes.NewBuffer(nil) 326 body.Write([]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) 327 328 req, _ := http.NewRequest("PUT", "/v1/acl/policy?token=root", body) 329 resp := httptest.NewRecorder() 330 _, err := a.srv.ACLPolicyCreate(resp, req) 331 require.Error(t, err) 332 _, ok := err.(BadRequestError) 333 require.True(t, ok) 334 }) 335 336 t.Run("Delete", func(t *testing.T) { 337 req, _ := http.NewRequest("DELETE", "/v1/acl/policy/"+idMap["policy-minimal"]+"?token=root", nil) 338 resp := httptest.NewRecorder() 339 _, err := a.srv.ACLPolicyCRUD(resp, req) 340 require.NoError(t, err) 341 delete(policyMap, idMap["policy-minimal"]) 342 delete(idMap, "policy-minimal") 343 }) 344 345 t.Run("List", func(t *testing.T) { 346 req, _ := http.NewRequest("GET", "/v1/acl/policies?token=root", nil) 347 resp := httptest.NewRecorder() 348 raw, err := a.srv.ACLPolicyList(resp, req) 349 require.NoError(t, err) 350 policies, ok := raw.(structs.ACLPolicyListStubs) 351 require.True(t, ok) 352 353 // 2 we just created + global management 354 require.Len(t, policies, 3) 355 356 for policyID, expected := range policyMap { 357 found := false 358 for _, actual := range policies { 359 if actual.ID == policyID { 360 require.Equal(t, expected.Name, actual.Name) 361 require.Equal(t, expected.Datacenters, actual.Datacenters) 362 require.Equal(t, expected.Hash, actual.Hash) 363 require.Equal(t, expected.CreateIndex, actual.CreateIndex) 364 require.Equal(t, expected.ModifyIndex, actual.ModifyIndex) 365 found = true 366 break 367 } 368 } 369 370 require.True(t, found) 371 } 372 }) 373 374 t.Run("Read", func(t *testing.T) { 375 req, _ := http.NewRequest("GET", "/v1/acl/policy/"+idMap["policy-read-all-nodes"]+"?token=root", nil) 376 resp := httptest.NewRecorder() 377 raw, err := a.srv.ACLPolicyCRUD(resp, req) 378 require.NoError(t, err) 379 policy, ok := raw.(*structs.ACLPolicy) 380 require.True(t, ok) 381 require.Equal(t, policyMap[idMap["policy-read-all-nodes"]], policy) 382 }) 383 384 t.Run("Read Name", func(t *testing.T) { 385 policyName := "read-all-nodes" 386 req, _ := http.NewRequest("GET", "/v1/acl/policy/name/"+policyName+"?token=root", nil) 387 resp := httptest.NewRecorder() 388 raw, err := a.srv.ACLPolicyReadByName(resp, req) 389 require.NoError(t, err) 390 policy, ok := raw.(*structs.ACLPolicy) 391 require.True(t, ok) 392 require.Equal(t, policyMap[idMap["policy-"+policyName]], policy) 393 }) 394 }) 395 396 t.Run("Role", func(t *testing.T) { 397 t.Run("Create", func(t *testing.T) { 398 roleInput := &structs.ACLRole{ 399 Name: "test", 400 Description: "test", 401 Policies: []structs.ACLRolePolicyLink{ 402 structs.ACLRolePolicyLink{ 403 ID: idMap["policy-test"], 404 Name: policyMap[idMap["policy-test"]].Name, 405 }, 406 structs.ACLRolePolicyLink{ 407 ID: idMap["policy-read-all-nodes"], 408 Name: policyMap[idMap["policy-read-all-nodes"]].Name, 409 }, 410 }, 411 NodeIdentities: []*structs.ACLNodeIdentity{ 412 &structs.ACLNodeIdentity{ 413 NodeName: "web-node", 414 Datacenter: "foo", 415 }, 416 }, 417 } 418 419 req, _ := http.NewRequest("PUT", "/v1/acl/role?token=root", jsonBody(roleInput)) 420 resp := httptest.NewRecorder() 421 obj, err := a.srv.ACLRoleCreate(resp, req) 422 require.NoError(t, err) 423 424 role, ok := obj.(*structs.ACLRole) 425 require.True(t, ok) 426 427 // 36 = length of the string form of uuids 428 require.Len(t, role.ID, 36) 429 require.Equal(t, roleInput.Name, role.Name) 430 require.Equal(t, roleInput.Description, role.Description) 431 require.Equal(t, roleInput.Policies, role.Policies) 432 require.Equal(t, roleInput.NodeIdentities, role.NodeIdentities) 433 require.True(t, role.CreateIndex > 0) 434 require.Equal(t, role.CreateIndex, role.ModifyIndex) 435 require.NotNil(t, role.Hash) 436 require.NotEqual(t, role.Hash, []byte{}) 437 438 idMap["role-test"] = role.ID 439 roleMap[role.ID] = role 440 }) 441 442 t.Run("Name Chars", func(t *testing.T) { 443 roleInput := &structs.ACLRole{ 444 Name: "service-id-web", 445 ServiceIdentities: []*structs.ACLServiceIdentity{ 446 &structs.ACLServiceIdentity{ 447 ServiceName: "web", 448 }, 449 }, 450 } 451 452 req, _ := http.NewRequest("PUT", "/v1/acl/role?token=root", jsonBody(roleInput)) 453 resp := httptest.NewRecorder() 454 obj, err := a.srv.ACLRoleCreate(resp, req) 455 require.NoError(t, err) 456 457 role, ok := obj.(*structs.ACLRole) 458 require.True(t, ok) 459 460 // 36 = length of the string form of uuids 461 require.Len(t, role.ID, 36) 462 require.Equal(t, roleInput.Name, role.Name) 463 require.Equal(t, roleInput.Description, role.Description) 464 require.Equal(t, roleInput.ServiceIdentities, role.ServiceIdentities) 465 require.True(t, role.CreateIndex > 0) 466 require.Equal(t, role.CreateIndex, role.ModifyIndex) 467 require.NotNil(t, role.Hash) 468 require.NotEqual(t, role.Hash, []byte{}) 469 470 idMap["role-service-id-web"] = role.ID 471 roleMap[role.ID] = role 472 }) 473 474 t.Run("Update Name ID Mismatch", func(t *testing.T) { 475 roleInput := &structs.ACLRole{ 476 ID: "ac7560be-7f11-4d6d-bfcf-15633c2090fd", 477 Name: "test", 478 Description: "test", 479 ServiceIdentities: []*structs.ACLServiceIdentity{ 480 &structs.ACLServiceIdentity{ 481 ServiceName: "db", 482 }, 483 }, 484 } 485 486 req, _ := http.NewRequest("PUT", "/v1/acl/role/"+idMap["role-test"]+"?token=root", jsonBody(roleInput)) 487 resp := httptest.NewRecorder() 488 _, err := a.srv.ACLRoleCRUD(resp, req) 489 require.Error(t, err) 490 _, ok := err.(BadRequestError) 491 require.True(t, ok) 492 }) 493 494 t.Run("Role CRUD Missing ID in URL", func(t *testing.T) { 495 req, _ := http.NewRequest("GET", "/v1/acl/role/?token=root", nil) 496 resp := httptest.NewRecorder() 497 _, err := a.srv.ACLRoleCRUD(resp, req) 498 require.Error(t, err) 499 _, ok := err.(BadRequestError) 500 require.True(t, ok) 501 }) 502 503 t.Run("Update", func(t *testing.T) { 504 roleInput := &structs.ACLRole{ 505 Name: "test", 506 Description: "test", 507 ServiceIdentities: []*structs.ACLServiceIdentity{ 508 &structs.ACLServiceIdentity{ 509 ServiceName: "web-indexer", 510 }, 511 }, 512 NodeIdentities: []*structs.ACLNodeIdentity{ 513 &structs.ACLNodeIdentity{ 514 NodeName: "web-node", 515 Datacenter: "foo", 516 }, 517 }, 518 } 519 520 req, _ := http.NewRequest("PUT", "/v1/acl/role/"+idMap["role-test"]+"?token=root", jsonBody(roleInput)) 521 resp := httptest.NewRecorder() 522 obj, err := a.srv.ACLRoleCRUD(resp, req) 523 require.NoError(t, err) 524 525 role, ok := obj.(*structs.ACLRole) 526 require.True(t, ok) 527 528 // 36 = length of the string form of uuids 529 require.Len(t, role.ID, 36) 530 require.Equal(t, roleInput.Name, role.Name) 531 require.Equal(t, roleInput.Description, role.Description) 532 require.Equal(t, roleInput.Policies, role.Policies) 533 require.Equal(t, roleInput.ServiceIdentities, role.ServiceIdentities) 534 require.Equal(t, roleInput.NodeIdentities, role.NodeIdentities) 535 require.True(t, role.CreateIndex > 0) 536 require.True(t, role.CreateIndex < role.ModifyIndex) 537 require.NotNil(t, role.Hash) 538 require.NotEqual(t, role.Hash, []byte{}) 539 540 idMap["role-test"] = role.ID 541 roleMap[role.ID] = role 542 }) 543 544 t.Run("ID Supplied", func(t *testing.T) { 545 roleInput := &structs.ACLRole{ 546 ID: "12123d01-37f1-47e6-b55b-32328652bd38", 547 Name: "with-id", 548 Description: "test", 549 ServiceIdentities: []*structs.ACLServiceIdentity{ 550 &structs.ACLServiceIdentity{ 551 ServiceName: "foobar", 552 }, 553 }, 554 } 555 556 req, _ := http.NewRequest("PUT", "/v1/acl/role?token=root", jsonBody(roleInput)) 557 resp := httptest.NewRecorder() 558 _, err := a.srv.ACLRoleCreate(resp, req) 559 require.Error(t, err) 560 _, ok := err.(BadRequestError) 561 require.True(t, ok) 562 }) 563 564 t.Run("Invalid payload", func(t *testing.T) { 565 body := bytes.NewBuffer(nil) 566 body.Write([]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) 567 568 req, _ := http.NewRequest("PUT", "/v1/acl/role?token=root", body) 569 resp := httptest.NewRecorder() 570 _, err := a.srv.ACLRoleCreate(resp, req) 571 require.Error(t, err) 572 _, ok := err.(BadRequestError) 573 require.True(t, ok) 574 }) 575 576 t.Run("Delete", func(t *testing.T) { 577 req, _ := http.NewRequest("DELETE", "/v1/acl/role/"+idMap["role-service-id-web"]+"?token=root", nil) 578 resp := httptest.NewRecorder() 579 _, err := a.srv.ACLRoleCRUD(resp, req) 580 require.NoError(t, err) 581 delete(roleMap, idMap["role-service-id-web"]) 582 delete(idMap, "role-service-id-web") 583 }) 584 585 t.Run("List", func(t *testing.T) { 586 req, _ := http.NewRequest("GET", "/v1/acl/roles?token=root", nil) 587 resp := httptest.NewRecorder() 588 raw, err := a.srv.ACLRoleList(resp, req) 589 require.NoError(t, err) 590 roles, ok := raw.(structs.ACLRoles) 591 require.True(t, ok) 592 593 // 1 we just created 594 require.Len(t, roles, 1) 595 596 for roleID, expected := range roleMap { 597 found := false 598 for _, actual := range roles { 599 if actual.ID == roleID { 600 require.Equal(t, expected.Name, actual.Name) 601 require.Equal(t, expected.Policies, actual.Policies) 602 require.Equal(t, expected.ServiceIdentities, actual.ServiceIdentities) 603 require.Equal(t, expected.Hash, actual.Hash) 604 require.Equal(t, expected.CreateIndex, actual.CreateIndex) 605 require.Equal(t, expected.ModifyIndex, actual.ModifyIndex) 606 found = true 607 break 608 } 609 } 610 611 require.True(t, found) 612 } 613 }) 614 615 t.Run("Read", func(t *testing.T) { 616 req, _ := http.NewRequest("GET", "/v1/acl/role/"+idMap["role-test"]+"?token=root", nil) 617 resp := httptest.NewRecorder() 618 raw, err := a.srv.ACLRoleCRUD(resp, req) 619 require.NoError(t, err) 620 role, ok := raw.(*structs.ACLRole) 621 require.True(t, ok) 622 require.Equal(t, roleMap[idMap["role-test"]], role) 623 }) 624 }) 625 626 t.Run("Token", func(t *testing.T) { 627 t.Run("Create", func(t *testing.T) { 628 tokenInput := &structs.ACLToken{ 629 Description: "test", 630 Policies: []structs.ACLTokenPolicyLink{ 631 structs.ACLTokenPolicyLink{ 632 ID: idMap["policy-test"], 633 Name: policyMap[idMap["policy-test"]].Name, 634 }, 635 structs.ACLTokenPolicyLink{ 636 ID: idMap["policy-read-all-nodes"], 637 Name: policyMap[idMap["policy-read-all-nodes"]].Name, 638 }, 639 }, 640 NodeIdentities: []*structs.ACLNodeIdentity{ 641 &structs.ACLNodeIdentity{ 642 NodeName: "foo", 643 Datacenter: "bar", 644 }, 645 }, 646 } 647 648 req, _ := http.NewRequest("PUT", "/v1/acl/token?token=root", jsonBody(tokenInput)) 649 resp := httptest.NewRecorder() 650 obj, err := a.srv.ACLTokenCreate(resp, req) 651 require.NoError(t, err) 652 653 token, ok := obj.(*structs.ACLToken) 654 require.True(t, ok) 655 656 // 36 = length of the string form of uuids 657 require.Len(t, token.AccessorID, 36) 658 require.Len(t, token.SecretID, 36) 659 require.Equal(t, tokenInput.Description, token.Description) 660 require.Equal(t, tokenInput.Policies, token.Policies) 661 require.Equal(t, tokenInput.NodeIdentities, token.NodeIdentities) 662 require.True(t, token.CreateIndex > 0) 663 require.Equal(t, token.CreateIndex, token.ModifyIndex) 664 require.NotNil(t, token.Hash) 665 require.NotEqual(t, token.Hash, []byte{}) 666 667 idMap["token-test"] = token.AccessorID 668 tokenMap[token.AccessorID] = token 669 }) 670 t.Run("Create Local", func(t *testing.T) { 671 tokenInput := &structs.ACLToken{ 672 Description: "local", 673 Policies: []structs.ACLTokenPolicyLink{ 674 structs.ACLTokenPolicyLink{ 675 ID: idMap["policy-test"], 676 Name: policyMap[idMap["policy-test"]].Name, 677 }, 678 structs.ACLTokenPolicyLink{ 679 ID: idMap["policy-read-all-nodes"], 680 Name: policyMap[idMap["policy-read-all-nodes"]].Name, 681 }, 682 }, 683 Local: true, 684 } 685 686 req, _ := http.NewRequest("PUT", "/v1/acl/token?token=root", jsonBody(tokenInput)) 687 resp := httptest.NewRecorder() 688 obj, err := a.srv.ACLTokenCreate(resp, req) 689 require.NoError(t, err) 690 691 token, ok := obj.(*structs.ACLToken) 692 require.True(t, ok) 693 694 // 36 = length of the string form of uuids 695 require.Len(t, token.AccessorID, 36) 696 require.Len(t, token.SecretID, 36) 697 require.Equal(t, tokenInput.Description, token.Description) 698 require.Equal(t, tokenInput.Policies, token.Policies) 699 require.True(t, token.CreateIndex > 0) 700 require.Equal(t, token.CreateIndex, token.ModifyIndex) 701 require.NotNil(t, token.Hash) 702 require.NotEqual(t, token.Hash, []byte{}) 703 704 idMap["token-local"] = token.AccessorID 705 tokenMap[token.AccessorID] = token 706 }) 707 t.Run("Read", func(t *testing.T) { 708 expected := tokenMap[idMap["token-test"]] 709 req, _ := http.NewRequest("GET", "/v1/acl/token/"+expected.AccessorID+"?token=root", nil) 710 resp := httptest.NewRecorder() 711 obj, err := a.srv.ACLTokenCRUD(resp, req) 712 require.NoError(t, err) 713 token, ok := obj.(*structs.ACLToken) 714 require.True(t, ok) 715 require.Equal(t, expected, token) 716 }) 717 t.Run("Self", func(t *testing.T) { 718 expected := tokenMap[idMap["token-test"]] 719 req, _ := http.NewRequest("GET", "/v1/acl/token/self?token="+expected.SecretID, nil) 720 resp := httptest.NewRecorder() 721 obj, err := a.srv.ACLTokenSelf(resp, req) 722 require.NoError(t, err) 723 token, ok := obj.(*structs.ACLToken) 724 require.True(t, ok) 725 require.Equal(t, expected, token) 726 }) 727 t.Run("Clone", func(t *testing.T) { 728 tokenInput := &structs.ACLToken{ 729 Description: "cloned token", 730 } 731 732 baseToken := tokenMap[idMap["token-test"]] 733 734 req, _ := http.NewRequest("PUT", "/v1/acl/token/"+baseToken.AccessorID+"/clone?token=root", jsonBody(tokenInput)) 735 resp := httptest.NewRecorder() 736 obj, err := a.srv.ACLTokenCRUD(resp, req) 737 require.NoError(t, err) 738 token, ok := obj.(*structs.ACLToken) 739 require.True(t, ok) 740 741 require.NotEqual(t, baseToken.AccessorID, token.AccessorID) 742 require.NotEqual(t, baseToken.SecretID, token.SecretID) 743 require.Equal(t, tokenInput.Description, token.Description) 744 require.Equal(t, baseToken.Policies, token.Policies) 745 require.True(t, token.CreateIndex > 0) 746 require.Equal(t, token.CreateIndex, token.ModifyIndex) 747 require.NotNil(t, token.Hash) 748 require.NotEqual(t, token.Hash, []byte{}) 749 750 idMap["token-cloned"] = token.AccessorID 751 tokenMap[token.AccessorID] = token 752 }) 753 t.Run("Update", func(t *testing.T) { 754 originalToken := tokenMap[idMap["token-cloned"]] 755 756 // Accessor and Secret will be filled in 757 tokenInput := &structs.ACLToken{ 758 Description: "Better description for this cloned token", 759 Policies: []structs.ACLTokenPolicyLink{ 760 structs.ACLTokenPolicyLink{ 761 ID: idMap["policy-read-all-nodes"], 762 Name: policyMap[idMap["policy-read-all-nodes"]].Name, 763 }, 764 }, 765 NodeIdentities: []*structs.ACLNodeIdentity{ 766 &structs.ACLNodeIdentity{ 767 NodeName: "foo", 768 Datacenter: "bar", 769 }, 770 }, 771 } 772 773 req, _ := http.NewRequest("PUT", "/v1/acl/token/"+originalToken.AccessorID+"?token=root", jsonBody(tokenInput)) 774 resp := httptest.NewRecorder() 775 obj, err := a.srv.ACLTokenCRUD(resp, req) 776 require.NoError(t, err) 777 token, ok := obj.(*structs.ACLToken) 778 require.True(t, ok) 779 780 require.Equal(t, originalToken.AccessorID, token.AccessorID) 781 require.Equal(t, originalToken.SecretID, token.SecretID) 782 require.Equal(t, tokenInput.Description, token.Description) 783 require.Equal(t, tokenInput.Policies, token.Policies) 784 require.Equal(t, tokenInput.NodeIdentities, token.NodeIdentities) 785 require.True(t, token.CreateIndex > 0) 786 require.True(t, token.CreateIndex < token.ModifyIndex) 787 require.NotNil(t, token.Hash) 788 require.NotEqual(t, token.Hash, []byte{}) 789 require.NotEqual(t, token.Hash, originalToken.Hash) 790 791 tokenMap[token.AccessorID] = token 792 }) 793 794 t.Run("CRUD Missing Token Accessor ID", func(t *testing.T) { 795 req, _ := http.NewRequest("GET", "/v1/acl/token/?token=root", nil) 796 resp := httptest.NewRecorder() 797 obj, err := a.srv.ACLTokenCRUD(resp, req) 798 require.Error(t, err) 799 require.Nil(t, obj) 800 _, ok := err.(BadRequestError) 801 require.True(t, ok) 802 }) 803 t.Run("Update Accessor Mismatch", func(t *testing.T) { 804 originalToken := tokenMap[idMap["token-cloned"]] 805 806 // Accessor and Secret will be filled in 807 tokenInput := &structs.ACLToken{ 808 AccessorID: "e8aeb69a-0ace-42b9-b95f-d1d9eafe1561", 809 Description: "Better description for this cloned token", 810 Policies: []structs.ACLTokenPolicyLink{ 811 structs.ACLTokenPolicyLink{ 812 ID: idMap["policy-read-all-nodes"], 813 Name: policyMap[idMap["policy-read-all-nodes"]].Name, 814 }, 815 }, 816 } 817 818 req, _ := http.NewRequest("PUT", "/v1/acl/token/"+originalToken.AccessorID+"?token=root", jsonBody(tokenInput)) 819 resp := httptest.NewRecorder() 820 obj, err := a.srv.ACLTokenCRUD(resp, req) 821 require.Error(t, err) 822 require.Nil(t, obj) 823 _, ok := err.(BadRequestError) 824 require.True(t, ok) 825 }) 826 t.Run("Delete", func(t *testing.T) { 827 req, _ := http.NewRequest("DELETE", "/v1/acl/token/"+idMap["token-cloned"]+"?token=root", nil) 828 resp := httptest.NewRecorder() 829 _, err := a.srv.ACLTokenCRUD(resp, req) 830 require.NoError(t, err) 831 delete(tokenMap, idMap["token-cloned"]) 832 delete(idMap, "token-cloned") 833 }) 834 t.Run("List", func(t *testing.T) { 835 req, _ := http.NewRequest("GET", "/v1/acl/tokens?token=root", nil) 836 resp := httptest.NewRecorder() 837 raw, err := a.srv.ACLTokenList(resp, req) 838 require.NoError(t, err) 839 tokens, ok := raw.(structs.ACLTokenListStubs) 840 require.True(t, ok) 841 842 // 3 tokens created but 1 was deleted + master token + anon token 843 require.Len(t, tokens, 4) 844 845 // this loop doesn't verify anything about the master token 846 for tokenID, expected := range tokenMap { 847 found := false 848 for _, actual := range tokens { 849 if actual.AccessorID == tokenID { 850 require.Equal(t, expected.Description, actual.Description) 851 require.Equal(t, expected.Policies, actual.Policies) 852 require.Equal(t, expected.Local, actual.Local) 853 require.Equal(t, expected.CreateTime, actual.CreateTime) 854 require.Equal(t, expected.Hash, actual.Hash) 855 require.Equal(t, expected.CreateIndex, actual.CreateIndex) 856 require.Equal(t, expected.ModifyIndex, actual.ModifyIndex) 857 found = true 858 break 859 } 860 } 861 require.True(t, found) 862 } 863 }) 864 t.Run("List by Policy", func(t *testing.T) { 865 req, _ := http.NewRequest("GET", "/v1/acl/tokens?token=root&policy="+structs.ACLPolicyGlobalManagementID, nil) 866 resp := httptest.NewRecorder() 867 raw, err := a.srv.ACLTokenList(resp, req) 868 require.NoError(t, err) 869 tokens, ok := raw.(structs.ACLTokenListStubs) 870 require.True(t, ok) 871 require.Len(t, tokens, 1) 872 token := tokens[0] 873 require.Equal(t, "Master Token", token.Description) 874 require.Len(t, token.Policies, 1) 875 require.Equal(t, structs.ACLPolicyGlobalManagementID, token.Policies[0].ID) 876 }) 877 t.Run("Create with Accessor", func(t *testing.T) { 878 tokenInput := &structs.ACLToken{ 879 AccessorID: "56e8e6a3-708b-4a2f-8ab3-b973cce39108", 880 Description: "test", 881 Policies: []structs.ACLTokenPolicyLink{ 882 structs.ACLTokenPolicyLink{ 883 ID: idMap["policy-test"], 884 Name: policyMap[idMap["policy-test"]].Name, 885 }, 886 structs.ACLTokenPolicyLink{ 887 ID: idMap["policy-read-all-nodes"], 888 Name: policyMap[idMap["policy-read-all-nodes"]].Name, 889 }, 890 }, 891 } 892 893 req, _ := http.NewRequest("PUT", "/v1/acl/token?token=root", jsonBody(tokenInput)) 894 resp := httptest.NewRecorder() 895 obj, err := a.srv.ACLTokenCreate(resp, req) 896 require.NoError(t, err) 897 898 token, ok := obj.(*structs.ACLToken) 899 require.True(t, ok) 900 901 // 36 = length of the string form of uuids 902 require.Equal(t, tokenInput.AccessorID, token.AccessorID) 903 require.Len(t, token.SecretID, 36) 904 require.Equal(t, tokenInput.Description, token.Description) 905 require.Equal(t, tokenInput.Policies, token.Policies) 906 require.True(t, token.CreateIndex > 0) 907 require.Equal(t, token.CreateIndex, token.ModifyIndex) 908 require.NotNil(t, token.Hash) 909 require.NotEqual(t, token.Hash, []byte{}) 910 911 idMap["token-test"] = token.AccessorID 912 tokenMap[token.AccessorID] = token 913 }) 914 915 t.Run("Create with Secret", func(t *testing.T) { 916 tokenInput := &structs.ACLToken{ 917 SecretID: "4e3efd15-d06c-442e-a7cc-1744f55c8dea", 918 Description: "test", 919 Policies: []structs.ACLTokenPolicyLink{ 920 structs.ACLTokenPolicyLink{ 921 ID: idMap["policy-test"], 922 Name: policyMap[idMap["policy-test"]].Name, 923 }, 924 structs.ACLTokenPolicyLink{ 925 ID: idMap["policy-read-all-nodes"], 926 Name: policyMap[idMap["policy-read-all-nodes"]].Name, 927 }, 928 }, 929 } 930 931 req, _ := http.NewRequest("PUT", "/v1/acl/token?token=root", jsonBody(tokenInput)) 932 resp := httptest.NewRecorder() 933 obj, err := a.srv.ACLTokenCreate(resp, req) 934 require.NoError(t, err) 935 936 token, ok := obj.(*structs.ACLToken) 937 require.True(t, ok) 938 939 // 36 = length of the string form of uuids 940 require.Equal(t, tokenInput.SecretID, token.SecretID) 941 require.Len(t, token.AccessorID, 36) 942 require.Equal(t, tokenInput.Description, token.Description) 943 require.Equal(t, tokenInput.Policies, token.Policies) 944 require.True(t, token.CreateIndex > 0) 945 require.Equal(t, token.CreateIndex, token.ModifyIndex) 946 require.NotNil(t, token.Hash) 947 require.NotEqual(t, token.Hash, []byte{}) 948 949 idMap["token-test"] = token.AccessorID 950 tokenMap[token.AccessorID] = token 951 }) 952 953 t.Run("Create with Accessor and Secret", func(t *testing.T) { 954 tokenInput := &structs.ACLToken{ 955 AccessorID: "dee863fa-e548-4c61-a96f-9aa07999249f", 956 SecretID: "10126ffa-b28f-4137-b9a9-e89ab1e97c5b", 957 Description: "test", 958 Policies: []structs.ACLTokenPolicyLink{ 959 structs.ACLTokenPolicyLink{ 960 ID: idMap["policy-test"], 961 Name: policyMap[idMap["policy-test"]].Name, 962 }, 963 structs.ACLTokenPolicyLink{ 964 ID: idMap["policy-read-all-nodes"], 965 Name: policyMap[idMap["policy-read-all-nodes"]].Name, 966 }, 967 }, 968 } 969 970 req, _ := http.NewRequest("PUT", "/v1/acl/token?token=root", jsonBody(tokenInput)) 971 resp := httptest.NewRecorder() 972 obj, err := a.srv.ACLTokenCreate(resp, req) 973 require.NoError(t, err) 974 975 token, ok := obj.(*structs.ACLToken) 976 require.True(t, ok) 977 978 // 36 = length of the string form of uuids 979 require.Equal(t, tokenInput.SecretID, token.SecretID) 980 require.Equal(t, tokenInput.AccessorID, token.AccessorID) 981 require.Equal(t, tokenInput.Description, token.Description) 982 require.Equal(t, tokenInput.Policies, token.Policies) 983 require.True(t, token.CreateIndex > 0) 984 require.Equal(t, token.CreateIndex, token.ModifyIndex) 985 require.NotNil(t, token.Hash) 986 require.NotEqual(t, token.Hash, []byte{}) 987 988 idMap["token-test"] = token.AccessorID 989 tokenMap[token.AccessorID] = token 990 }) 991 992 t.Run("Create with Accessor Dup", func(t *testing.T) { 993 tokenInput := &structs.ACLToken{ 994 AccessorID: "dee863fa-e548-4c61-a96f-9aa07999249f", 995 Description: "test", 996 Policies: []structs.ACLTokenPolicyLink{ 997 structs.ACLTokenPolicyLink{ 998 ID: idMap["policy-test"], 999 Name: policyMap[idMap["policy-test"]].Name, 1000 }, 1001 structs.ACLTokenPolicyLink{ 1002 ID: idMap["policy-read-all-nodes"], 1003 Name: policyMap[idMap["policy-read-all-nodes"]].Name, 1004 }, 1005 }, 1006 } 1007 1008 req, _ := http.NewRequest("PUT", "/v1/acl/token?token=root", jsonBody(tokenInput)) 1009 resp := httptest.NewRecorder() 1010 _, err := a.srv.ACLTokenCreate(resp, req) 1011 require.Error(t, err) 1012 }) 1013 1014 t.Run("Create with Secret as Accessor Dup", func(t *testing.T) { 1015 tokenInput := &structs.ACLToken{ 1016 SecretID: "dee863fa-e548-4c61-a96f-9aa07999249f", 1017 Description: "test", 1018 Policies: []structs.ACLTokenPolicyLink{ 1019 structs.ACLTokenPolicyLink{ 1020 ID: idMap["policy-test"], 1021 Name: policyMap[idMap["policy-test"]].Name, 1022 }, 1023 structs.ACLTokenPolicyLink{ 1024 ID: idMap["policy-read-all-nodes"], 1025 Name: policyMap[idMap["policy-read-all-nodes"]].Name, 1026 }, 1027 }, 1028 } 1029 1030 req, _ := http.NewRequest("PUT", "/v1/acl/token?token=root", jsonBody(tokenInput)) 1031 resp := httptest.NewRecorder() 1032 _, err := a.srv.ACLTokenCreate(resp, req) 1033 require.Error(t, err) 1034 }) 1035 1036 t.Run("Create with Secret Dup", func(t *testing.T) { 1037 tokenInput := &structs.ACLToken{ 1038 SecretID: "10126ffa-b28f-4137-b9a9-e89ab1e97c5b", 1039 Description: "test", 1040 Policies: []structs.ACLTokenPolicyLink{ 1041 structs.ACLTokenPolicyLink{ 1042 ID: idMap["policy-test"], 1043 Name: policyMap[idMap["policy-test"]].Name, 1044 }, 1045 structs.ACLTokenPolicyLink{ 1046 ID: idMap["policy-read-all-nodes"], 1047 Name: policyMap[idMap["policy-read-all-nodes"]].Name, 1048 }, 1049 }, 1050 } 1051 1052 req, _ := http.NewRequest("PUT", "/v1/acl/token?token=root", jsonBody(tokenInput)) 1053 resp := httptest.NewRecorder() 1054 _, err := a.srv.ACLTokenCreate(resp, req) 1055 require.Error(t, err) 1056 }) 1057 1058 t.Run("Create with Accessor as Secret Dup", func(t *testing.T) { 1059 tokenInput := &structs.ACLToken{ 1060 AccessorID: "10126ffa-b28f-4137-b9a9-e89ab1e97c5b", 1061 Description: "test", 1062 Policies: []structs.ACLTokenPolicyLink{ 1063 structs.ACLTokenPolicyLink{ 1064 ID: idMap["policy-test"], 1065 Name: policyMap[idMap["policy-test"]].Name, 1066 }, 1067 structs.ACLTokenPolicyLink{ 1068 ID: idMap["policy-read-all-nodes"], 1069 Name: policyMap[idMap["policy-read-all-nodes"]].Name, 1070 }, 1071 }, 1072 } 1073 1074 req, _ := http.NewRequest("PUT", "/v1/acl/token?token=root", jsonBody(tokenInput)) 1075 resp := httptest.NewRecorder() 1076 _, err := a.srv.ACLTokenCreate(resp, req) 1077 require.Error(t, err) 1078 }) 1079 1080 t.Run("Create with Reserved Accessor", func(t *testing.T) { 1081 tokenInput := &structs.ACLToken{ 1082 AccessorID: "00000000-0000-0000-0000-00000000005b", 1083 Description: "test", 1084 Policies: []structs.ACLTokenPolicyLink{ 1085 structs.ACLTokenPolicyLink{ 1086 ID: idMap["policy-test"], 1087 Name: policyMap[idMap["policy-test"]].Name, 1088 }, 1089 structs.ACLTokenPolicyLink{ 1090 ID: idMap["policy-read-all-nodes"], 1091 Name: policyMap[idMap["policy-read-all-nodes"]].Name, 1092 }, 1093 }, 1094 } 1095 1096 req, _ := http.NewRequest("PUT", "/v1/acl/token?token=root", jsonBody(tokenInput)) 1097 resp := httptest.NewRecorder() 1098 _, err := a.srv.ACLTokenCreate(resp, req) 1099 require.Error(t, err) 1100 }) 1101 1102 t.Run("Create with Reserved Secret", func(t *testing.T) { 1103 tokenInput := &structs.ACLToken{ 1104 SecretID: "00000000-0000-0000-0000-00000000005b", 1105 Description: "test", 1106 Policies: []structs.ACLTokenPolicyLink{ 1107 structs.ACLTokenPolicyLink{ 1108 ID: idMap["policy-test"], 1109 Name: policyMap[idMap["policy-test"]].Name, 1110 }, 1111 structs.ACLTokenPolicyLink{ 1112 ID: idMap["policy-read-all-nodes"], 1113 Name: policyMap[idMap["policy-read-all-nodes"]].Name, 1114 }, 1115 }, 1116 } 1117 1118 req, _ := http.NewRequest("PUT", "/v1/acl/token?token=root", jsonBody(tokenInput)) 1119 resp := httptest.NewRecorder() 1120 _, err := a.srv.ACLTokenCreate(resp, req) 1121 require.Error(t, err) 1122 }) 1123 }) 1124} 1125 1126func TestACL_LoginProcedure_HTTP(t *testing.T) { 1127 // This tests AuthMethods, BindingRules, Login, and Logout. 1128 t.Parallel() 1129 a := NewTestAgent(t, TestACLConfig()) 1130 defer a.Shutdown() 1131 1132 testrpc.WaitForLeader(t, a.RPC, "dc1") 1133 1134 idMap := make(map[string]string) 1135 methodMap := make(map[string]*structs.ACLAuthMethod) 1136 ruleMap := make(map[string]*structs.ACLBindingRule) 1137 tokenMap := make(map[string]*structs.ACLToken) 1138 1139 testSessionID := testauth.StartSession() 1140 defer testauth.ResetSession(testSessionID) 1141 1142 // This is all done as a subtest for a couple reasons 1143 // 1. It uses only 1 test agent and these are 1144 // somewhat expensive to bring up and tear down often 1145 // 2. Instead of having to bring up a new agent and prime 1146 // the ACL system with some data before running the test 1147 // we can intelligently order these tests so we can still 1148 // test everything with less actual operations and do 1149 // so in a manner that is less prone to being flaky 1150 // 3. While this test will be large it should 1151 t.Run("AuthMethod", func(t *testing.T) { 1152 t.Run("Create", func(t *testing.T) { 1153 methodInput := &structs.ACLAuthMethod{ 1154 Name: "test", 1155 Type: "testing", 1156 Description: "test", 1157 Config: map[string]interface{}{ 1158 "SessionID": testSessionID, 1159 }, 1160 } 1161 1162 req, _ := http.NewRequest("PUT", "/v1/acl/auth-method?token=root", jsonBody(methodInput)) 1163 resp := httptest.NewRecorder() 1164 obj, err := a.srv.ACLAuthMethodCreate(resp, req) 1165 require.NoError(t, err) 1166 1167 method, ok := obj.(*structs.ACLAuthMethod) 1168 require.True(t, ok) 1169 1170 require.Equal(t, methodInput.Name, method.Name) 1171 require.Equal(t, methodInput.Type, method.Type) 1172 require.Equal(t, methodInput.Description, method.Description) 1173 require.Equal(t, methodInput.Config, method.Config) 1174 require.True(t, method.CreateIndex > 0) 1175 require.Equal(t, method.CreateIndex, method.ModifyIndex) 1176 1177 methodMap[method.Name] = method 1178 }) 1179 1180 t.Run("Create other", func(t *testing.T) { 1181 methodInput := &structs.ACLAuthMethod{ 1182 Name: "other", 1183 Type: "testing", 1184 Description: "test", 1185 Config: map[string]interface{}{ 1186 "SessionID": testSessionID, 1187 }, 1188 } 1189 1190 req, _ := http.NewRequest("PUT", "/v1/acl/auth-method?token=root", jsonBody(methodInput)) 1191 resp := httptest.NewRecorder() 1192 obj, err := a.srv.ACLAuthMethodCreate(resp, req) 1193 require.NoError(t, err) 1194 1195 method, ok := obj.(*structs.ACLAuthMethod) 1196 require.True(t, ok) 1197 1198 require.Equal(t, methodInput.Name, method.Name) 1199 require.Equal(t, methodInput.Type, method.Type) 1200 require.Equal(t, methodInput.Description, method.Description) 1201 require.Equal(t, methodInput.Config, method.Config) 1202 require.True(t, method.CreateIndex > 0) 1203 require.Equal(t, method.CreateIndex, method.ModifyIndex) 1204 1205 methodMap[method.Name] = method 1206 }) 1207 1208 t.Run("Update Name URL Mismatch", func(t *testing.T) { 1209 methodInput := &structs.ACLAuthMethod{ 1210 Name: "test", 1211 Type: "testing", 1212 Description: "test", 1213 Config: map[string]interface{}{ 1214 "SessionID": testSessionID, 1215 }, 1216 } 1217 1218 req, _ := http.NewRequest("PUT", "/v1/acl/auth-method/not-test?token=root", jsonBody(methodInput)) 1219 resp := httptest.NewRecorder() 1220 _, err := a.srv.ACLAuthMethodCRUD(resp, req) 1221 require.Error(t, err) 1222 _, ok := err.(BadRequestError) 1223 require.True(t, ok) 1224 }) 1225 1226 t.Run("Update", func(t *testing.T) { 1227 methodInput := &structs.ACLAuthMethod{ 1228 Name: "test", 1229 Type: "testing", 1230 Description: "updated description", 1231 Config: map[string]interface{}{ 1232 "SessionID": testSessionID, 1233 }, 1234 } 1235 1236 req, _ := http.NewRequest("PUT", "/v1/acl/auth-method/test?token=root", jsonBody(methodInput)) 1237 resp := httptest.NewRecorder() 1238 obj, err := a.srv.ACLAuthMethodCRUD(resp, req) 1239 require.NoError(t, err) 1240 1241 method, ok := obj.(*structs.ACLAuthMethod) 1242 require.True(t, ok) 1243 1244 require.Equal(t, methodInput.Name, method.Name) 1245 require.Equal(t, methodInput.Type, method.Type) 1246 require.Equal(t, methodInput.Description, method.Description) 1247 require.Equal(t, methodInput.Config, method.Config) 1248 require.True(t, method.CreateIndex > 0) 1249 require.True(t, method.CreateIndex < method.ModifyIndex) 1250 1251 methodMap[method.Name] = method 1252 }) 1253 1254 t.Run("Invalid payload", func(t *testing.T) { 1255 body := bytes.NewBuffer(nil) 1256 body.Write([]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) 1257 1258 req, _ := http.NewRequest("PUT", "/v1/acl/auth-method?token=root", body) 1259 resp := httptest.NewRecorder() 1260 _, err := a.srv.ACLAuthMethodCreate(resp, req) 1261 require.Error(t, err) 1262 _, ok := err.(BadRequestError) 1263 require.True(t, ok) 1264 }) 1265 1266 t.Run("List", func(t *testing.T) { 1267 req, _ := http.NewRequest("GET", "/v1/acl/auth-methods?token=root", nil) 1268 resp := httptest.NewRecorder() 1269 raw, err := a.srv.ACLAuthMethodList(resp, req) 1270 require.NoError(t, err) 1271 methods, ok := raw.(structs.ACLAuthMethodListStubs) 1272 require.True(t, ok) 1273 1274 // 2 we just created 1275 require.Len(t, methods, 2) 1276 1277 for methodName, expected := range methodMap { 1278 found := false 1279 for _, actual := range methods { 1280 if actual.Name == methodName { 1281 require.Equal(t, expected.Name, actual.Name) 1282 require.Equal(t, expected.Type, actual.Type) 1283 require.Equal(t, expected.Description, actual.Description) 1284 require.Equal(t, expected.CreateIndex, actual.CreateIndex) 1285 require.Equal(t, expected.ModifyIndex, actual.ModifyIndex) 1286 found = true 1287 break 1288 } 1289 } 1290 1291 require.True(t, found) 1292 } 1293 }) 1294 1295 t.Run("Delete", func(t *testing.T) { 1296 req, _ := http.NewRequest("DELETE", "/v1/acl/auth-method/other?token=root", nil) 1297 resp := httptest.NewRecorder() 1298 _, err := a.srv.ACLAuthMethodCRUD(resp, req) 1299 require.NoError(t, err) 1300 delete(methodMap, "other") 1301 }) 1302 1303 t.Run("Read", func(t *testing.T) { 1304 req, _ := http.NewRequest("GET", "/v1/acl/auth-method/test?token=root", nil) 1305 resp := httptest.NewRecorder() 1306 raw, err := a.srv.ACLAuthMethodCRUD(resp, req) 1307 require.NoError(t, err) 1308 method, ok := raw.(*structs.ACLAuthMethod) 1309 require.True(t, ok) 1310 require.Equal(t, methodMap["test"], method) 1311 }) 1312 }) 1313 1314 t.Run("BindingRule", func(t *testing.T) { 1315 t.Run("Create", func(t *testing.T) { 1316 ruleInput := &structs.ACLBindingRule{ 1317 Description: "test", 1318 AuthMethod: "test", 1319 Selector: "serviceaccount.namespace==default", 1320 BindType: structs.BindingRuleBindTypeService, 1321 BindName: "web", 1322 } 1323 1324 req, _ := http.NewRequest("PUT", "/v1/acl/binding-rule?token=root", jsonBody(ruleInput)) 1325 resp := httptest.NewRecorder() 1326 obj, err := a.srv.ACLBindingRuleCreate(resp, req) 1327 require.NoError(t, err) 1328 1329 rule, ok := obj.(*structs.ACLBindingRule) 1330 require.True(t, ok) 1331 1332 // 36 = length of the string form of uuids 1333 require.Len(t, rule.ID, 36) 1334 require.Equal(t, ruleInput.Description, rule.Description) 1335 require.Equal(t, ruleInput.AuthMethod, rule.AuthMethod) 1336 require.Equal(t, ruleInput.Selector, rule.Selector) 1337 require.Equal(t, ruleInput.BindType, rule.BindType) 1338 require.Equal(t, ruleInput.BindName, rule.BindName) 1339 require.True(t, rule.CreateIndex > 0) 1340 require.Equal(t, rule.CreateIndex, rule.ModifyIndex) 1341 1342 idMap["rule-test"] = rule.ID 1343 ruleMap[rule.ID] = rule 1344 }) 1345 1346 t.Run("Create other", func(t *testing.T) { 1347 ruleInput := &structs.ACLBindingRule{ 1348 Description: "other", 1349 AuthMethod: "test", 1350 Selector: "serviceaccount.namespace==default", 1351 BindType: structs.BindingRuleBindTypeRole, 1352 BindName: "fancy-role", 1353 } 1354 1355 req, _ := http.NewRequest("PUT", "/v1/acl/binding-rule?token=root", jsonBody(ruleInput)) 1356 resp := httptest.NewRecorder() 1357 obj, err := a.srv.ACLBindingRuleCreate(resp, req) 1358 require.NoError(t, err) 1359 1360 rule, ok := obj.(*structs.ACLBindingRule) 1361 require.True(t, ok) 1362 1363 // 36 = length of the string form of uuids 1364 require.Len(t, rule.ID, 36) 1365 require.Equal(t, ruleInput.Description, rule.Description) 1366 require.Equal(t, ruleInput.AuthMethod, rule.AuthMethod) 1367 require.Equal(t, ruleInput.Selector, rule.Selector) 1368 require.Equal(t, ruleInput.BindType, rule.BindType) 1369 require.Equal(t, ruleInput.BindName, rule.BindName) 1370 require.True(t, rule.CreateIndex > 0) 1371 require.Equal(t, rule.CreateIndex, rule.ModifyIndex) 1372 1373 idMap["rule-other"] = rule.ID 1374 ruleMap[rule.ID] = rule 1375 }) 1376 1377 t.Run("BindingRule CRUD Missing ID in URL", func(t *testing.T) { 1378 req, _ := http.NewRequest("GET", "/v1/acl/binding-rule/?token=root", nil) 1379 resp := httptest.NewRecorder() 1380 _, err := a.srv.ACLBindingRuleCRUD(resp, req) 1381 require.Error(t, err) 1382 _, ok := err.(BadRequestError) 1383 require.True(t, ok) 1384 }) 1385 1386 t.Run("Update", func(t *testing.T) { 1387 ruleInput := &structs.ACLBindingRule{ 1388 Description: "updated", 1389 AuthMethod: "test", 1390 Selector: "serviceaccount.namespace==default", 1391 BindType: structs.BindingRuleBindTypeService, 1392 BindName: "${serviceaccount.name}", 1393 } 1394 1395 req, _ := http.NewRequest("PUT", "/v1/acl/binding-rule/"+idMap["rule-test"]+"?token=root", jsonBody(ruleInput)) 1396 resp := httptest.NewRecorder() 1397 obj, err := a.srv.ACLBindingRuleCRUD(resp, req) 1398 require.NoError(t, err) 1399 1400 rule, ok := obj.(*structs.ACLBindingRule) 1401 require.True(t, ok) 1402 1403 // 36 = length of the string form of uuids 1404 require.Len(t, rule.ID, 36) 1405 require.Equal(t, ruleInput.Description, rule.Description) 1406 require.Equal(t, ruleInput.AuthMethod, rule.AuthMethod) 1407 require.Equal(t, ruleInput.Selector, rule.Selector) 1408 require.Equal(t, ruleInput.BindType, rule.BindType) 1409 require.Equal(t, ruleInput.BindName, rule.BindName) 1410 require.True(t, rule.CreateIndex > 0) 1411 require.True(t, rule.CreateIndex < rule.ModifyIndex) 1412 1413 idMap["rule-test"] = rule.ID 1414 ruleMap[rule.ID] = rule 1415 }) 1416 1417 t.Run("ID Supplied", func(t *testing.T) { 1418 ruleInput := &structs.ACLBindingRule{ 1419 ID: "12123d01-37f1-47e6-b55b-32328652bd38", 1420 Description: "with-id", 1421 AuthMethod: "test", 1422 Selector: "serviceaccount.namespace==default", 1423 BindType: structs.BindingRuleBindTypeService, 1424 BindName: "vault", 1425 } 1426 1427 req, _ := http.NewRequest("PUT", "/v1/acl/binding-rule?token=root", jsonBody(ruleInput)) 1428 resp := httptest.NewRecorder() 1429 _, err := a.srv.ACLBindingRuleCreate(resp, req) 1430 require.Error(t, err) 1431 _, ok := err.(BadRequestError) 1432 require.True(t, ok) 1433 }) 1434 1435 t.Run("Invalid payload", func(t *testing.T) { 1436 body := bytes.NewBuffer(nil) 1437 body.Write([]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) 1438 1439 req, _ := http.NewRequest("PUT", "/v1/acl/binding-rule?token=root", body) 1440 resp := httptest.NewRecorder() 1441 _, err := a.srv.ACLBindingRuleCreate(resp, req) 1442 require.Error(t, err) 1443 _, ok := err.(BadRequestError) 1444 require.True(t, ok) 1445 }) 1446 1447 t.Run("List", func(t *testing.T) { 1448 req, _ := http.NewRequest("GET", "/v1/acl/binding-rules?token=root", nil) 1449 resp := httptest.NewRecorder() 1450 raw, err := a.srv.ACLBindingRuleList(resp, req) 1451 require.NoError(t, err) 1452 rules, ok := raw.(structs.ACLBindingRules) 1453 require.True(t, ok) 1454 1455 // 2 we just created 1456 require.Len(t, rules, 2) 1457 1458 for ruleID, expected := range ruleMap { 1459 found := false 1460 for _, actual := range rules { 1461 if actual.ID == ruleID { 1462 require.Equal(t, expected.Description, actual.Description) 1463 require.Equal(t, expected.AuthMethod, actual.AuthMethod) 1464 require.Equal(t, expected.Selector, actual.Selector) 1465 require.Equal(t, expected.BindType, actual.BindType) 1466 require.Equal(t, expected.BindName, actual.BindName) 1467 require.Equal(t, expected.CreateIndex, actual.CreateIndex) 1468 require.Equal(t, expected.ModifyIndex, actual.ModifyIndex) 1469 found = true 1470 break 1471 } 1472 } 1473 1474 require.True(t, found) 1475 } 1476 }) 1477 1478 t.Run("Delete", func(t *testing.T) { 1479 req, _ := http.NewRequest("DELETE", "/v1/acl/binding-rule/"+idMap["rule-other"]+"?token=root", nil) 1480 resp := httptest.NewRecorder() 1481 _, err := a.srv.ACLBindingRuleCRUD(resp, req) 1482 require.NoError(t, err) 1483 delete(ruleMap, idMap["rule-other"]) 1484 delete(idMap, "rule-other") 1485 }) 1486 1487 t.Run("Read", func(t *testing.T) { 1488 req, _ := http.NewRequest("GET", "/v1/acl/binding-rule/"+idMap["rule-test"]+"?token=root", nil) 1489 resp := httptest.NewRecorder() 1490 raw, err := a.srv.ACLBindingRuleCRUD(resp, req) 1491 require.NoError(t, err) 1492 rule, ok := raw.(*structs.ACLBindingRule) 1493 require.True(t, ok) 1494 require.Equal(t, ruleMap[idMap["rule-test"]], rule) 1495 }) 1496 }) 1497 1498 testauth.InstallSessionToken(testSessionID, "token1", "default", "demo1", "abc123") 1499 testauth.InstallSessionToken(testSessionID, "token2", "default", "demo2", "def456") 1500 1501 t.Run("Login", func(t *testing.T) { 1502 t.Run("Create Token 1", func(t *testing.T) { 1503 loginInput := &structs.ACLLoginParams{ 1504 AuthMethod: "test", 1505 BearerToken: "token1", 1506 Meta: map[string]string{"foo": "bar"}, 1507 } 1508 1509 req, _ := http.NewRequest("POST", "/v1/acl/login?token=root", jsonBody(loginInput)) 1510 resp := httptest.NewRecorder() 1511 obj, err := a.srv.ACLLogin(resp, req) 1512 require.NoError(t, err) 1513 1514 token, ok := obj.(*structs.ACLToken) 1515 require.True(t, ok) 1516 1517 // 36 = length of the string form of uuids 1518 require.Len(t, token.AccessorID, 36) 1519 require.Len(t, token.SecretID, 36) 1520 require.Equal(t, `token created via login: {"foo":"bar"}`, token.Description) 1521 require.True(t, token.Local) 1522 require.Len(t, token.Policies, 0) 1523 require.Len(t, token.Roles, 0) 1524 require.Len(t, token.ServiceIdentities, 1) 1525 require.Equal(t, "demo1", token.ServiceIdentities[0].ServiceName) 1526 require.Len(t, token.ServiceIdentities[0].Datacenters, 0) 1527 require.True(t, token.CreateIndex > 0) 1528 require.Equal(t, token.CreateIndex, token.ModifyIndex) 1529 require.NotNil(t, token.Hash) 1530 require.NotEqual(t, token.Hash, []byte{}) 1531 1532 idMap["token-test-1"] = token.AccessorID 1533 tokenMap[token.AccessorID] = token 1534 }) 1535 t.Run("Create Token 2", func(t *testing.T) { 1536 loginInput := &structs.ACLLoginParams{ 1537 AuthMethod: "test", 1538 BearerToken: "token2", 1539 Meta: map[string]string{"blah": "woot"}, 1540 } 1541 1542 req, _ := http.NewRequest("POST", "/v1/acl/login?token=root", jsonBody(loginInput)) 1543 resp := httptest.NewRecorder() 1544 obj, err := a.srv.ACLLogin(resp, req) 1545 require.NoError(t, err) 1546 1547 token, ok := obj.(*structs.ACLToken) 1548 require.True(t, ok) 1549 1550 // 36 = length of the string form of uuids 1551 require.Len(t, token.AccessorID, 36) 1552 require.Len(t, token.SecretID, 36) 1553 require.Equal(t, `token created via login: {"blah":"woot"}`, token.Description) 1554 require.True(t, token.Local) 1555 require.Len(t, token.Policies, 0) 1556 require.Len(t, token.Roles, 0) 1557 require.Len(t, token.ServiceIdentities, 1) 1558 require.Equal(t, "demo2", token.ServiceIdentities[0].ServiceName) 1559 require.Len(t, token.ServiceIdentities[0].Datacenters, 0) 1560 require.True(t, token.CreateIndex > 0) 1561 require.Equal(t, token.CreateIndex, token.ModifyIndex) 1562 require.NotNil(t, token.Hash) 1563 require.NotEqual(t, token.Hash, []byte{}) 1564 1565 idMap["token-test-2"] = token.AccessorID 1566 tokenMap[token.AccessorID] = token 1567 }) 1568 1569 t.Run("List Tokens by (incorrect) Method", func(t *testing.T) { 1570 req, _ := http.NewRequest("GET", "/v1/acl/tokens?token=root&authmethod=other", nil) 1571 resp := httptest.NewRecorder() 1572 raw, err := a.srv.ACLTokenList(resp, req) 1573 require.NoError(t, err) 1574 tokens, ok := raw.(structs.ACLTokenListStubs) 1575 require.True(t, ok) 1576 require.Len(t, tokens, 0) 1577 }) 1578 1579 t.Run("List Tokens by (correct) Method", func(t *testing.T) { 1580 req, _ := http.NewRequest("GET", "/v1/acl/tokens?token=root&authmethod=test", nil) 1581 resp := httptest.NewRecorder() 1582 raw, err := a.srv.ACLTokenList(resp, req) 1583 require.NoError(t, err) 1584 tokens, ok := raw.(structs.ACLTokenListStubs) 1585 require.True(t, ok) 1586 require.Len(t, tokens, 2) 1587 1588 for tokenID, expected := range tokenMap { 1589 found := false 1590 for _, actual := range tokens { 1591 if actual.AccessorID == tokenID { 1592 require.Equal(t, expected.Description, actual.Description) 1593 require.Equal(t, expected.Policies, actual.Policies) 1594 require.Equal(t, expected.Roles, actual.Roles) 1595 require.Equal(t, expected.ServiceIdentities, actual.ServiceIdentities) 1596 require.Equal(t, expected.Local, actual.Local) 1597 require.Equal(t, expected.CreateTime, actual.CreateTime) 1598 require.Equal(t, expected.Hash, actual.Hash) 1599 require.Equal(t, expected.CreateIndex, actual.CreateIndex) 1600 require.Equal(t, expected.ModifyIndex, actual.ModifyIndex) 1601 found = true 1602 break 1603 } 1604 } 1605 require.True(t, found) 1606 } 1607 }) 1608 1609 t.Run("Logout", func(t *testing.T) { 1610 tok := tokenMap[idMap["token-test-1"]] 1611 req, _ := http.NewRequest("POST", "/v1/acl/logout?token="+tok.SecretID, nil) 1612 resp := httptest.NewRecorder() 1613 _, err := a.srv.ACLLogout(resp, req) 1614 require.NoError(t, err) 1615 }) 1616 1617 t.Run("Token is gone after Logout", func(t *testing.T) { 1618 req, _ := http.NewRequest("GET", "/v1/acl/token/"+idMap["token-test-1"]+"?token=root", nil) 1619 resp := httptest.NewRecorder() 1620 _, err := a.srv.ACLTokenCRUD(resp, req) 1621 require.Error(t, err) 1622 require.True(t, acl.IsErrNotFound(err), err.Error()) 1623 }) 1624 }) 1625} 1626 1627func TestACLEndpoint_LoginLogout_jwt(t *testing.T) { 1628 t.Parallel() 1629 1630 a := NewTestAgent(t, TestACLConfigWithParams(nil)) 1631 defer a.Shutdown() 1632 1633 testrpc.WaitForLeader(t, a.RPC, "dc1") 1634 1635 // spin up a fake oidc server 1636 oidcServer := startSSOTestServer(t) 1637 pubKey, privKey := oidcServer.SigningKeys() 1638 1639 type mConfig = map[string]interface{} 1640 cases := map[string]struct { 1641 f func(config mConfig) 1642 issuer string 1643 expectErr string 1644 }{ 1645 "success - jwt static keys": {func(config mConfig) { 1646 config["BoundIssuer"] = "https://legit.issuer.internal/" 1647 config["JWTValidationPubKeys"] = []string{pubKey} 1648 }, 1649 "https://legit.issuer.internal/", 1650 ""}, 1651 "success - jwt jwks": {func(config mConfig) { 1652 config["JWKSURL"] = oidcServer.Addr() + "/certs" 1653 config["JWKSCACert"] = oidcServer.CACert() 1654 }, 1655 "https://legit.issuer.internal/", 1656 ""}, 1657 "success - jwt oidc discovery": {func(config mConfig) { 1658 config["OIDCDiscoveryURL"] = oidcServer.Addr() 1659 config["OIDCDiscoveryCACert"] = oidcServer.CACert() 1660 }, 1661 oidcServer.Addr(), 1662 ""}, 1663 } 1664 1665 for name, tc := range cases { 1666 tc := tc 1667 t.Run(name, func(t *testing.T) { 1668 method, err := upsertTestCustomizedAuthMethod(a.RPC, TestDefaultMasterToken, "dc1", func(method *structs.ACLAuthMethod) { 1669 method.Type = "jwt" 1670 method.Config = map[string]interface{}{ 1671 "JWTSupportedAlgs": []string{"ES256"}, 1672 "ClaimMappings": map[string]string{ 1673 "first_name": "name", 1674 "/org/primary": "primary_org", 1675 }, 1676 "ListClaimMappings": map[string]string{ 1677 "https://consul.test/groups": "groups", 1678 }, 1679 "BoundAudiences": []string{"https://consul.test"}, 1680 } 1681 if tc.f != nil { 1682 tc.f(method.Config) 1683 } 1684 }) 1685 require.NoError(t, err) 1686 1687 t.Run("invalid bearer token", func(t *testing.T) { 1688 loginInput := &structs.ACLLoginParams{ 1689 AuthMethod: method.Name, 1690 BearerToken: "invalid", 1691 } 1692 1693 req, _ := http.NewRequest("POST", "/v1/acl/login", jsonBody(loginInput)) 1694 resp := httptest.NewRecorder() 1695 _, err := a.srv.ACLLogin(resp, req) 1696 require.Error(t, err) 1697 }) 1698 1699 cl := jwt.Claims{ 1700 Subject: "r3qXcK2bix9eFECzsU3Sbmh0K16fatW6@clients", 1701 Audience: jwt.Audience{"https://consul.test"}, 1702 Issuer: tc.issuer, 1703 NotBefore: jwt.NewNumericDate(time.Now().Add(-5 * time.Second)), 1704 Expiry: jwt.NewNumericDate(time.Now().Add(5 * time.Second)), 1705 } 1706 1707 type orgs struct { 1708 Primary string `json:"primary"` 1709 } 1710 1711 privateCl := struct { 1712 FirstName string `json:"first_name"` 1713 Org orgs `json:"org"` 1714 Groups []string `json:"https://consul.test/groups"` 1715 }{ 1716 FirstName: "jeff2", 1717 Org: orgs{"engineering"}, 1718 Groups: []string{"foo", "bar"}, 1719 } 1720 1721 jwtData, err := oidcauthtest.SignJWT(privKey, cl, privateCl) 1722 require.NoError(t, err) 1723 1724 t.Run("valid bearer token no bindings", func(t *testing.T) { 1725 loginInput := &structs.ACLLoginParams{ 1726 AuthMethod: method.Name, 1727 BearerToken: jwtData, 1728 } 1729 1730 req, _ := http.NewRequest("POST", "/v1/acl/login", jsonBody(loginInput)) 1731 resp := httptest.NewRecorder() 1732 _, err := a.srv.ACLLogin(resp, req) 1733 1734 testutil.RequireErrorContains(t, err, "Permission denied") 1735 }) 1736 1737 _, err = upsertTestCustomizedBindingRule(a.RPC, TestDefaultMasterToken, "dc1", func(rule *structs.ACLBindingRule) { 1738 rule.AuthMethod = method.Name 1739 rule.BindType = structs.BindingRuleBindTypeService 1740 rule.BindName = "test--${value.name}--${value.primary_org}" 1741 rule.Selector = "value.name == jeff2 and value.primary_org == engineering and foo in list.groups" 1742 }) 1743 require.NoError(t, err) 1744 1745 t.Run("valid bearer token 1 service binding", func(t *testing.T) { 1746 loginInput := &structs.ACLLoginParams{ 1747 AuthMethod: method.Name, 1748 BearerToken: jwtData, 1749 } 1750 1751 req, _ := http.NewRequest("POST", "/v1/acl/login", jsonBody(loginInput)) 1752 resp := httptest.NewRecorder() 1753 obj, err := a.srv.ACLLogin(resp, req) 1754 require.NoError(t, err) 1755 1756 token, ok := obj.(*structs.ACLToken) 1757 require.True(t, ok) 1758 1759 require.Equal(t, method.Name, token.AuthMethod) 1760 require.Equal(t, `token created via login`, token.Description) 1761 require.True(t, token.Local) 1762 require.Len(t, token.Roles, 0) 1763 require.Len(t, token.ServiceIdentities, 1) 1764 svcid := token.ServiceIdentities[0] 1765 require.Len(t, svcid.Datacenters, 0) 1766 require.Equal(t, "test--jeff2--engineering", svcid.ServiceName) 1767 1768 // and delete it 1769 req, _ = http.NewRequest("GET", "/v1/acl/logout", nil) 1770 req.Header.Add("X-Consul-Token", token.SecretID) 1771 resp = httptest.NewRecorder() 1772 _, err = a.srv.ACLLogout(resp, req) 1773 require.NoError(t, err) 1774 1775 // verify the token was deleted 1776 req, _ = http.NewRequest("GET", "/v1/acl/token/"+token.AccessorID, nil) 1777 req.Header.Add("X-Consul-Token", TestDefaultMasterToken) 1778 resp = httptest.NewRecorder() 1779 1780 // make the request 1781 _, err = a.srv.ACLTokenCRUD(resp, req) 1782 require.Error(t, err) 1783 require.Equal(t, acl.ErrNotFound, err) 1784 }) 1785 }) 1786 } 1787} 1788 1789func TestACL_Authorize(t *testing.T) { 1790 t.Parallel() 1791 a1 := NewTestAgent(t, TestACLConfigWithParams(nil)) 1792 defer a1.Shutdown() 1793 1794 testrpc.WaitForTestAgent(t, a1.RPC, "dc1", testrpc.WithToken(TestDefaultMasterToken)) 1795 1796 policyReq := structs.ACLPolicySetRequest{ 1797 Policy: structs.ACLPolicy{ 1798 Name: "test", 1799 Rules: `acl = "read" operator = "write" service_prefix "" { policy = "read"} node_prefix "" { policy= "write" } key_prefix "/foo" { policy = "write" } `, 1800 }, 1801 Datacenter: "dc1", 1802 WriteRequest: structs.WriteRequest{Token: TestDefaultMasterToken}, 1803 } 1804 var policy structs.ACLPolicy 1805 require.NoError(t, a1.RPC("ACL.PolicySet", &policyReq, &policy)) 1806 1807 tokenReq := structs.ACLTokenSetRequest{ 1808 ACLToken: structs.ACLToken{ 1809 Policies: []structs.ACLTokenPolicyLink{ 1810 structs.ACLTokenPolicyLink{ 1811 ID: policy.ID, 1812 }, 1813 }, 1814 }, 1815 Datacenter: "dc1", 1816 WriteRequest: structs.WriteRequest{Token: TestDefaultMasterToken}, 1817 } 1818 1819 var token structs.ACLToken 1820 require.NoError(t, a1.RPC("ACL.TokenSet", &tokenReq, &token)) 1821 1822 // secondary also needs to setup a replication token to pull tokens and policies 1823 secondaryParams := DefaulTestACLConfigParams() 1824 secondaryParams.ReplicationToken = secondaryParams.MasterToken 1825 secondaryParams.EnableTokenReplication = true 1826 1827 a2 := NewTestAgent(t, `datacenter = "dc2" `+TestACLConfigWithParams(secondaryParams)) 1828 defer a2.Shutdown() 1829 1830 addr := fmt.Sprintf("127.0.0.1:%d", a1.Config.SerfPortWAN) 1831 _, err := a2.JoinWAN([]string{addr}) 1832 require.NoError(t, err) 1833 1834 testrpc.WaitForTestAgent(t, a2.RPC, "dc2", testrpc.WithToken(TestDefaultMasterToken)) 1835 // this actually ensures a few things. First the dcs got connect okay, secondly that the policy we 1836 // are about ready to use in our local token creation exists in the secondary DC 1837 testrpc.WaitForACLReplication(t, a2.RPC, "dc2", structs.ACLReplicateTokens, policy.CreateIndex, 1, 0) 1838 1839 localTokenReq := structs.ACLTokenSetRequest{ 1840 ACLToken: structs.ACLToken{ 1841 Policies: []structs.ACLTokenPolicyLink{ 1842 structs.ACLTokenPolicyLink{ 1843 ID: policy.ID, 1844 }, 1845 }, 1846 Local: true, 1847 }, 1848 Datacenter: "dc2", 1849 WriteRequest: structs.WriteRequest{Token: TestDefaultMasterToken}, 1850 } 1851 1852 var localToken structs.ACLToken 1853 require.NoError(t, a2.RPC("ACL.TokenSet", &localTokenReq, &localToken)) 1854 1855 t.Run("master-token", func(t *testing.T) { 1856 request := []structs.ACLAuthorizationRequest{ 1857 structs.ACLAuthorizationRequest{ 1858 Resource: "acl", 1859 Access: "read", 1860 }, 1861 structs.ACLAuthorizationRequest{ 1862 Resource: "acl", 1863 Access: "write", 1864 }, 1865 structs.ACLAuthorizationRequest{ 1866 Resource: "agent", 1867 Segment: "foo", 1868 Access: "read", 1869 }, 1870 structs.ACLAuthorizationRequest{ 1871 Resource: "agent", 1872 Segment: "foo", 1873 Access: "write", 1874 }, 1875 structs.ACLAuthorizationRequest{ 1876 Resource: "event", 1877 Segment: "foo", 1878 Access: "read", 1879 }, 1880 structs.ACLAuthorizationRequest{ 1881 Resource: "event", 1882 Segment: "foo", 1883 Access: "write", 1884 }, 1885 structs.ACLAuthorizationRequest{ 1886 Resource: "intention", 1887 Segment: "foo", 1888 Access: "read", 1889 }, 1890 structs.ACLAuthorizationRequest{ 1891 Resource: "intention", 1892 Segment: "foo", 1893 Access: "write", 1894 }, 1895 structs.ACLAuthorizationRequest{ 1896 Resource: "key", 1897 Segment: "foo", 1898 Access: "read", 1899 }, 1900 structs.ACLAuthorizationRequest{ 1901 Resource: "key", 1902 Segment: "foo", 1903 Access: "list", 1904 }, 1905 structs.ACLAuthorizationRequest{ 1906 Resource: "key", 1907 Segment: "foo", 1908 Access: "write", 1909 }, 1910 structs.ACLAuthorizationRequest{ 1911 Resource: "keyring", 1912 Access: "read", 1913 }, 1914 structs.ACLAuthorizationRequest{ 1915 Resource: "keyring", 1916 Access: "write", 1917 }, 1918 structs.ACLAuthorizationRequest{ 1919 Resource: "node", 1920 Segment: "foo", 1921 Access: "read", 1922 }, 1923 structs.ACLAuthorizationRequest{ 1924 Resource: "node", 1925 Segment: "foo", 1926 Access: "write", 1927 }, 1928 structs.ACLAuthorizationRequest{ 1929 Resource: "operator", 1930 Access: "read", 1931 }, 1932 structs.ACLAuthorizationRequest{ 1933 Resource: "operator", 1934 Access: "write", 1935 }, 1936 structs.ACLAuthorizationRequest{ 1937 Resource: "query", 1938 Segment: "foo", 1939 Access: "read", 1940 }, 1941 structs.ACLAuthorizationRequest{ 1942 Resource: "query", 1943 Segment: "foo", 1944 Access: "write", 1945 }, 1946 structs.ACLAuthorizationRequest{ 1947 Resource: "service", 1948 Segment: "foo", 1949 Access: "read", 1950 }, 1951 structs.ACLAuthorizationRequest{ 1952 Resource: "service", 1953 Segment: "foo", 1954 Access: "write", 1955 }, 1956 structs.ACLAuthorizationRequest{ 1957 Resource: "session", 1958 Segment: "foo", 1959 Access: "read", 1960 }, 1961 structs.ACLAuthorizationRequest{ 1962 Resource: "session", 1963 Segment: "foo", 1964 Access: "write", 1965 }, 1966 } 1967 1968 for _, dc := range []string{"dc1", "dc2"} { 1969 t.Run(dc, func(t *testing.T) { 1970 req, _ := http.NewRequest("POST", "/v1/internal/acl/authorize?dc="+dc, jsonBody(request)) 1971 req.Header.Add("X-Consul-Token", TestDefaultMasterToken) 1972 recorder := httptest.NewRecorder() 1973 raw, err := a1.srv.ACLAuthorize(recorder, req) 1974 require.NoError(t, err) 1975 responses, ok := raw.([]structs.ACLAuthorizationResponse) 1976 require.True(t, ok) 1977 require.Len(t, responses, len(request)) 1978 1979 for idx, req := range request { 1980 resp := responses[idx] 1981 1982 require.Equal(t, req, resp.ACLAuthorizationRequest) 1983 require.True(t, resp.Allow, "should have allowed all access for master token") 1984 } 1985 }) 1986 } 1987 1988 }) 1989 1990 customAuthorizationRequests := []structs.ACLAuthorizationRequest{ 1991 structs.ACLAuthorizationRequest{ 1992 Resource: "acl", 1993 Access: "read", 1994 }, 1995 structs.ACLAuthorizationRequest{ 1996 Resource: "acl", 1997 Access: "write", 1998 }, 1999 structs.ACLAuthorizationRequest{ 2000 Resource: "agent", 2001 Segment: "foo", 2002 Access: "read", 2003 }, 2004 structs.ACLAuthorizationRequest{ 2005 Resource: "agent", 2006 Segment: "foo", 2007 Access: "write", 2008 }, 2009 structs.ACLAuthorizationRequest{ 2010 Resource: "event", 2011 Segment: "foo", 2012 Access: "read", 2013 }, 2014 structs.ACLAuthorizationRequest{ 2015 Resource: "event", 2016 Segment: "foo", 2017 Access: "write", 2018 }, 2019 structs.ACLAuthorizationRequest{ 2020 Resource: "intention", 2021 Segment: "foo", 2022 Access: "read", 2023 }, 2024 structs.ACLAuthorizationRequest{ 2025 Resource: "intention", 2026 Segment: "foo", 2027 Access: "write", 2028 }, 2029 structs.ACLAuthorizationRequest{ 2030 Resource: "key", 2031 Segment: "foo", 2032 Access: "read", 2033 }, 2034 structs.ACLAuthorizationRequest{ 2035 Resource: "key", 2036 Segment: "foo", 2037 Access: "list", 2038 }, 2039 structs.ACLAuthorizationRequest{ 2040 Resource: "key", 2041 Segment: "foo", 2042 Access: "write", 2043 }, 2044 structs.ACLAuthorizationRequest{ 2045 Resource: "keyring", 2046 Access: "read", 2047 }, 2048 structs.ACLAuthorizationRequest{ 2049 Resource: "keyring", 2050 Access: "write", 2051 }, 2052 structs.ACLAuthorizationRequest{ 2053 Resource: "node", 2054 Segment: "foo", 2055 Access: "read", 2056 }, 2057 structs.ACLAuthorizationRequest{ 2058 Resource: "node", 2059 Segment: "foo", 2060 Access: "write", 2061 }, 2062 structs.ACLAuthorizationRequest{ 2063 Resource: "operator", 2064 Access: "read", 2065 }, 2066 structs.ACLAuthorizationRequest{ 2067 Resource: "operator", 2068 Access: "write", 2069 }, 2070 structs.ACLAuthorizationRequest{ 2071 Resource: "query", 2072 Segment: "foo", 2073 Access: "read", 2074 }, 2075 structs.ACLAuthorizationRequest{ 2076 Resource: "query", 2077 Segment: "foo", 2078 Access: "write", 2079 }, 2080 structs.ACLAuthorizationRequest{ 2081 Resource: "service", 2082 Segment: "foo", 2083 Access: "read", 2084 }, 2085 structs.ACLAuthorizationRequest{ 2086 Resource: "service", 2087 Segment: "foo", 2088 Access: "write", 2089 }, 2090 structs.ACLAuthorizationRequest{ 2091 Resource: "session", 2092 Segment: "foo", 2093 Access: "read", 2094 }, 2095 structs.ACLAuthorizationRequest{ 2096 Resource: "session", 2097 Segment: "foo", 2098 Access: "write", 2099 }, 2100 } 2101 2102 expectedCustomAuthorizationResponses := []bool{ 2103 true, // acl:read 2104 false, // acl:write 2105 false, // agent:read 2106 false, // agent:write 2107 false, // event:read 2108 false, // event:write 2109 true, // intention:read 2110 false, // intention:write 2111 false, // key:read 2112 false, // key:list 2113 false, // key:write 2114 false, // keyring:read 2115 false, // keyring:write 2116 true, // node:read 2117 true, // node:write 2118 true, // operator:read 2119 true, // operator:write 2120 false, // query:read 2121 false, // query:write 2122 true, // service:read 2123 false, // service:write 2124 false, // session:read 2125 false, // session:write 2126 } 2127 2128 t.Run("custom-token", func(t *testing.T) { 2129 for _, dc := range []string{"dc1", "dc2"} { 2130 t.Run(dc, func(t *testing.T) { 2131 req, _ := http.NewRequest("POST", "/v1/internal/acl/authorize", jsonBody(customAuthorizationRequests)) 2132 req.Header.Add("X-Consul-Token", token.SecretID) 2133 recorder := httptest.NewRecorder() 2134 raw, err := a1.srv.ACLAuthorize(recorder, req) 2135 require.NoError(t, err) 2136 responses, ok := raw.([]structs.ACLAuthorizationResponse) 2137 require.True(t, ok) 2138 require.Len(t, responses, len(customAuthorizationRequests)) 2139 require.Len(t, responses, len(expectedCustomAuthorizationResponses)) 2140 2141 for idx, req := range customAuthorizationRequests { 2142 resp := responses[idx] 2143 2144 require.Equal(t, req, resp.ACLAuthorizationRequest) 2145 require.Equal(t, expectedCustomAuthorizationResponses[idx], resp.Allow, "request %d - %+v returned unexpected response", idx, resp.ACLAuthorizationRequest) 2146 } 2147 }) 2148 } 2149 }) 2150 2151 t.Run("too-many-requests", func(t *testing.T) { 2152 var request []structs.ACLAuthorizationRequest 2153 2154 for i := 0; i < 100; i++ { 2155 request = append(request, structs.ACLAuthorizationRequest{Resource: "acl", Access: "read"}) 2156 } 2157 2158 req, _ := http.NewRequest("POST", "/v1/internal/acl/authorize", jsonBody(request)) 2159 req.Header.Add("X-Consul-Token", token.SecretID) 2160 recorder := httptest.NewRecorder() 2161 raw, err := a1.srv.ACLAuthorize(recorder, req) 2162 require.Error(t, err) 2163 require.Contains(t, err.Error(), "Refusing to process more than 64 authorizations at once") 2164 require.Nil(t, raw) 2165 }) 2166 2167 t.Run("decode-failure", func(t *testing.T) { 2168 req, _ := http.NewRequest("POST", "/v1/internal/acl/authorize", jsonBody(structs.ACLAuthorizationRequest{Resource: "acl", Access: "read"})) 2169 req.Header.Add("X-Consul-Token", token.SecretID) 2170 recorder := httptest.NewRecorder() 2171 raw, err := a1.srv.ACLAuthorize(recorder, req) 2172 require.Error(t, err) 2173 require.Contains(t, err.Error(), "Failed to decode request body") 2174 require.Nil(t, raw) 2175 }) 2176 2177 t.Run("acl-not-found", func(t *testing.T) { 2178 request := []structs.ACLAuthorizationRequest{ 2179 structs.ACLAuthorizationRequest{ 2180 Resource: "acl", 2181 Access: "read", 2182 }, 2183 } 2184 2185 req, _ := http.NewRequest("POST", "/v1/internal/acl/authorize", jsonBody(request)) 2186 req.Header.Add("X-Consul-Token", "d908c0be-22e1-433e-84db-8718e1a019de") 2187 recorder := httptest.NewRecorder() 2188 raw, err := a1.srv.ACLAuthorize(recorder, req) 2189 require.Error(t, err) 2190 require.Equal(t, acl.ErrNotFound, err) 2191 require.Nil(t, raw) 2192 }) 2193 2194 t.Run("local-token-in-secondary-dc", func(t *testing.T) { 2195 req, _ := http.NewRequest("POST", "/v1/internal/acl/authorize?dc=dc2", jsonBody(customAuthorizationRequests)) 2196 req.Header.Add("X-Consul-Token", localToken.SecretID) 2197 recorder := httptest.NewRecorder() 2198 raw, err := a1.srv.ACLAuthorize(recorder, req) 2199 require.NoError(t, err) 2200 responses, ok := raw.([]structs.ACLAuthorizationResponse) 2201 require.True(t, ok) 2202 require.Len(t, responses, len(customAuthorizationRequests)) 2203 require.Len(t, responses, len(expectedCustomAuthorizationResponses)) 2204 2205 for idx, req := range customAuthorizationRequests { 2206 resp := responses[idx] 2207 2208 require.Equal(t, req, resp.ACLAuthorizationRequest) 2209 require.Equal(t, expectedCustomAuthorizationResponses[idx], resp.Allow, "request %d - %+v returned unexpected response", idx, resp.ACLAuthorizationRequest) 2210 } 2211 }) 2212 2213 t.Run("local-token-wrong-dc", func(t *testing.T) { 2214 request := []structs.ACLAuthorizationRequest{ 2215 structs.ACLAuthorizationRequest{ 2216 Resource: "acl", 2217 Access: "read", 2218 }, 2219 } 2220 2221 req, _ := http.NewRequest("POST", "/v1/internal/acl/authorize", jsonBody(request)) 2222 req.Header.Add("X-Consul-Token", localToken.SecretID) 2223 recorder := httptest.NewRecorder() 2224 raw, err := a1.srv.ACLAuthorize(recorder, req) 2225 require.Error(t, err) 2226 require.Equal(t, acl.ErrNotFound, err) 2227 require.Nil(t, raw) 2228 }) 2229} 2230 2231type rpcFn func(string, interface{}, interface{}) error 2232 2233func upsertTestCustomizedAuthMethod( 2234 rpc rpcFn, masterToken string, datacenter string, 2235 modify func(method *structs.ACLAuthMethod), 2236) (*structs.ACLAuthMethod, error) { 2237 name, err := uuid.GenerateUUID() 2238 if err != nil { 2239 return nil, err 2240 } 2241 2242 req := structs.ACLAuthMethodSetRequest{ 2243 Datacenter: datacenter, 2244 AuthMethod: structs.ACLAuthMethod{ 2245 Name: "test-method-" + name, 2246 Type: "testing", 2247 }, 2248 WriteRequest: structs.WriteRequest{Token: masterToken}, 2249 } 2250 2251 if modify != nil { 2252 modify(&req.AuthMethod) 2253 } 2254 2255 var out structs.ACLAuthMethod 2256 2257 err = rpc("ACL.AuthMethodSet", &req, &out) 2258 if err != nil { 2259 return nil, err 2260 } 2261 2262 return &out, nil 2263} 2264 2265func upsertTestCustomizedBindingRule(rpc rpcFn, masterToken string, datacenter string, modify func(rule *structs.ACLBindingRule)) (*structs.ACLBindingRule, error) { 2266 req := structs.ACLBindingRuleSetRequest{ 2267 Datacenter: datacenter, 2268 BindingRule: structs.ACLBindingRule{}, 2269 WriteRequest: structs.WriteRequest{Token: masterToken}, 2270 } 2271 2272 if modify != nil { 2273 modify(&req.BindingRule) 2274 } 2275 2276 var out structs.ACLBindingRule 2277 2278 err := rpc("ACL.BindingRuleSet", &req, &out) 2279 if err != nil { 2280 return nil, err 2281 } 2282 2283 return &out, nil 2284} 2285 2286func startSSOTestServer(t *testing.T) *oidcauthtest.Server { 2287 ports := freeport.MustTake(1) 2288 return oidcauthtest.Start(t, oidcauthtest.WithPort( 2289 ports[0], 2290 func() { freeport.Return(ports) }, 2291 )) 2292} 2293