github.com/outbrain/consul@v1.4.5/agent/structs/acl_test.go (about) 1 package structs 2 3 import ( 4 "fmt" 5 "strings" 6 "testing" 7 8 "github.com/hashicorp/consul/acl" 9 10 "github.com/stretchr/testify/require" 11 ) 12 13 func TestStructs_ACLToken_PolicyIDs(t *testing.T) { 14 t.Parallel() 15 16 t.Run("Basic", func(t *testing.T) { 17 t.Parallel() 18 19 token := &ACLToken{ 20 Policies: []ACLTokenPolicyLink{ 21 ACLTokenPolicyLink{ 22 ID: "one", 23 }, 24 ACLTokenPolicyLink{ 25 ID: "two", 26 }, 27 ACLTokenPolicyLink{ 28 ID: "three", 29 }, 30 }, 31 } 32 33 policyIDs := token.PolicyIDs() 34 require.Len(t, policyIDs, 3) 35 require.Equal(t, "one", policyIDs[0]) 36 require.Equal(t, "two", policyIDs[1]) 37 require.Equal(t, "three", policyIDs[2]) 38 }) 39 40 t.Run("Legacy Management", func(t *testing.T) { 41 t.Parallel() 42 43 a := &ACL{ 44 ID: "root", 45 Type: ACLTokenTypeManagement, 46 Name: "management", 47 } 48 49 token := a.Convert() 50 51 policyIDs := token.PolicyIDs() 52 require.Len(t, policyIDs, 0) 53 54 embedded := token.EmbeddedPolicy() 55 require.NotNil(t, embedded) 56 require.Equal(t, ACLPolicyGlobalManagement, embedded.Rules) 57 }) 58 59 t.Run("Legacy Management With Rules", func(t *testing.T) { 60 t.Parallel() 61 62 a := &ACL{ 63 ID: "root", 64 Type: ACLTokenTypeManagement, 65 Name: "management", 66 Rules: "operator = \"write\"", 67 } 68 69 token := a.Convert() 70 71 policyIDs := token.PolicyIDs() 72 require.Len(t, policyIDs, 0) 73 74 embedded := token.EmbeddedPolicy() 75 require.NotNil(t, embedded) 76 require.Equal(t, ACLPolicyGlobalManagement, embedded.Rules) 77 }) 78 79 t.Run("No Policies", func(t *testing.T) { 80 t.Parallel() 81 82 token := &ACLToken{} 83 84 policyIDs := token.PolicyIDs() 85 require.Len(t, policyIDs, 0) 86 }) 87 } 88 89 func TestStructs_ACLToken_EmbeddedPolicy(t *testing.T) { 90 t.Parallel() 91 92 t.Run("No Rules", func(t *testing.T) { 93 t.Parallel() 94 95 token := &ACLToken{} 96 require.Nil(t, token.EmbeddedPolicy()) 97 }) 98 99 t.Run("Legacy Client", func(t *testing.T) { 100 t.Parallel() 101 102 // None of the other fields should be considered 103 token := &ACLToken{ 104 Type: ACLTokenTypeClient, 105 Rules: `acl = "read"`, 106 } 107 108 policy := token.EmbeddedPolicy() 109 require.NotNil(t, policy) 110 require.NotEqual(t, "", policy.ID) 111 require.True(t, strings.HasPrefix(policy.Name, "legacy-policy-")) 112 require.Equal(t, token.Rules, policy.Rules) 113 require.Equal(t, policy.Syntax, acl.SyntaxLegacy) 114 require.NotNil(t, policy.Hash) 115 require.NotEqual(t, []byte{}, policy.Hash) 116 }) 117 118 t.Run("Same Policy for Tokens with same Rules", func(t *testing.T) { 119 t.Parallel() 120 121 token1 := &ACLToken{ 122 AccessorID: "f55b260c-5e05-418e-ab19-d421d1ab4b52", 123 SecretID: "b2165bac-7006-459b-8a72-7f549f0f06d6", 124 Description: "token 1", 125 Type: ACLTokenTypeClient, 126 Rules: `acl = "read"`, 127 } 128 129 token2 := &ACLToken{ 130 AccessorID: "09d1c059-961a-46bd-a2e4-76adebe35fa5", 131 SecretID: "65e98e67-9b29-470c-8ffa-7c5a23cc67c8", 132 Description: "token 2", 133 Type: ACLTokenTypeClient, 134 Rules: `acl = "read"`, 135 } 136 137 policy1 := token1.EmbeddedPolicy() 138 policy2 := token2.EmbeddedPolicy() 139 require.Equal(t, policy1, policy2) 140 }) 141 } 142 143 func TestStructs_ACLToken_SetHash(t *testing.T) { 144 t.Parallel() 145 146 token := ACLToken{ 147 AccessorID: "09d1c059-961a-46bd-a2e4-76adebe35fa5", 148 SecretID: "65e98e67-9b29-470c-8ffa-7c5a23cc67c8", 149 Description: "test", 150 Policies: []ACLTokenPolicyLink{ 151 ACLTokenPolicyLink{ 152 ID: "one", 153 }, 154 ACLTokenPolicyLink{ 155 ID: "two", 156 }, 157 ACLTokenPolicyLink{ 158 ID: "three", 159 }, 160 }, 161 } 162 163 t.Run("Nil Hash - Generate", func(t *testing.T) { 164 require.Nil(t, token.Hash) 165 h := token.SetHash(false) 166 require.NotNil(t, h) 167 require.NotEqual(t, []byte{}, h) 168 require.Equal(t, h, token.Hash) 169 }) 170 171 t.Run("Hash Set - Dont Generate", func(t *testing.T) { 172 original := token.Hash 173 h := token.SetHash(false) 174 require.Equal(t, original, h) 175 176 token.Description = "changed" 177 h = token.SetHash(false) 178 require.Equal(t, original, h) 179 }) 180 181 t.Run("Hash Set - Generate", func(t *testing.T) { 182 original := token.Hash 183 h := token.SetHash(true) 184 require.NotEqual(t, original, h) 185 }) 186 } 187 188 func TestStructs_ACLToken_EstimateSize(t *testing.T) { 189 t.Parallel() 190 191 // estimated size here should 192 token := ACLToken{ 193 AccessorID: "09d1c059-961a-46bd-a2e4-76adebe35fa5", 194 SecretID: "65e98e67-9b29-470c-8ffa-7c5a23cc67c8", 195 Description: "test", 196 Policies: []ACLTokenPolicyLink{ 197 ACLTokenPolicyLink{ 198 ID: "one", 199 }, 200 ACLTokenPolicyLink{ 201 ID: "two", 202 }, 203 ACLTokenPolicyLink{ 204 ID: "three", 205 }, 206 }, 207 } 208 209 // this test is very contrived. Basically just tests that the 210 // math is okay and returns the value. 211 require.Equal(t, 120, token.EstimateSize()) 212 } 213 214 func TestStructs_ACLToken_Stub(t *testing.T) { 215 t.Parallel() 216 217 t.Run("Basic", func(t *testing.T) { 218 t.Parallel() 219 220 token := ACLToken{ 221 AccessorID: "09d1c059-961a-46bd-a2e4-76adebe35fa5", 222 SecretID: "65e98e67-9b29-470c-8ffa-7c5a23cc67c8", 223 Description: "test", 224 Policies: []ACLTokenPolicyLink{ 225 ACLTokenPolicyLink{ 226 ID: "one", 227 }, 228 ACLTokenPolicyLink{ 229 ID: "two", 230 }, 231 ACLTokenPolicyLink{ 232 ID: "three", 233 }, 234 }, 235 } 236 237 stub := token.Stub() 238 239 require.Equal(t, token.AccessorID, stub.AccessorID) 240 require.Equal(t, token.Description, stub.Description) 241 require.Equal(t, token.Policies, stub.Policies) 242 require.Equal(t, token.Local, stub.Local) 243 require.Equal(t, token.CreateTime, stub.CreateTime) 244 require.Equal(t, token.Hash, stub.Hash) 245 require.Equal(t, token.CreateIndex, stub.CreateIndex) 246 require.Equal(t, token.ModifyIndex, stub.ModifyIndex) 247 require.False(t, stub.Legacy) 248 }) 249 250 t.Run("Legacy", func(t *testing.T) { 251 t.Parallel() 252 token := ACLToken{ 253 AccessorID: "09d1c059-961a-46bd-a2e4-76adebe35fa5", 254 SecretID: "65e98e67-9b29-470c-8ffa-7c5a23cc67c8", 255 Description: "test", 256 Type: ACLTokenTypeClient, 257 Rules: `key "" { policy = "read" }`, 258 } 259 260 stub := token.Stub() 261 require.Equal(t, token.AccessorID, stub.AccessorID) 262 require.Equal(t, token.Description, stub.Description) 263 require.Equal(t, token.Policies, stub.Policies) 264 require.Equal(t, token.Local, stub.Local) 265 require.Equal(t, token.CreateTime, stub.CreateTime) 266 require.Equal(t, token.Hash, stub.Hash) 267 require.Equal(t, token.CreateIndex, stub.CreateIndex) 268 require.Equal(t, token.ModifyIndex, stub.ModifyIndex) 269 require.True(t, stub.Legacy) 270 }) 271 } 272 273 func TestStructs_ACLTokens_Sort(t *testing.T) { 274 t.Parallel() 275 276 tokens := ACLTokens{ 277 &ACLToken{ 278 AccessorID: "9db509a9-c809-48c1-895d-99f845b7a9d5", 279 }, 280 &ACLToken{ 281 AccessorID: "6bd01084-1695-43b8-898d-b2dd7874754d", 282 }, 283 &ACLToken{ 284 AccessorID: "614a4cef-9149-4271-b878-7edb1ad661f8", 285 }, 286 &ACLToken{ 287 AccessorID: "c9dd9980-8d54-472f-9e5e-74c02143e1f4", 288 }, 289 } 290 291 tokens.Sort() 292 require.Equal(t, tokens[0].AccessorID, "614a4cef-9149-4271-b878-7edb1ad661f8") 293 require.Equal(t, tokens[1].AccessorID, "6bd01084-1695-43b8-898d-b2dd7874754d") 294 require.Equal(t, tokens[2].AccessorID, "9db509a9-c809-48c1-895d-99f845b7a9d5") 295 require.Equal(t, tokens[3].AccessorID, "c9dd9980-8d54-472f-9e5e-74c02143e1f4") 296 } 297 298 func TestStructs_ACLTokenListStubs_Sort(t *testing.T) { 299 t.Parallel() 300 301 tokens := ACLTokenListStubs{ 302 &ACLTokenListStub{ 303 AccessorID: "9db509a9-c809-48c1-895d-99f845b7a9d5", 304 }, 305 &ACLTokenListStub{ 306 AccessorID: "6bd01084-1695-43b8-898d-b2dd7874754d", 307 }, 308 &ACLTokenListStub{ 309 AccessorID: "614a4cef-9149-4271-b878-7edb1ad661f8", 310 }, 311 &ACLTokenListStub{ 312 AccessorID: "c9dd9980-8d54-472f-9e5e-74c02143e1f4", 313 }, 314 } 315 316 tokens.Sort() 317 require.Equal(t, tokens[0].AccessorID, "614a4cef-9149-4271-b878-7edb1ad661f8") 318 require.Equal(t, tokens[1].AccessorID, "6bd01084-1695-43b8-898d-b2dd7874754d") 319 require.Equal(t, tokens[2].AccessorID, "9db509a9-c809-48c1-895d-99f845b7a9d5") 320 require.Equal(t, tokens[3].AccessorID, "c9dd9980-8d54-472f-9e5e-74c02143e1f4") 321 } 322 323 func TestStructs_ACLPolicy_Stub(t *testing.T) { 324 t.Parallel() 325 326 policy := &ACLPolicy{ 327 ID: "09d1c059-961a-46bd-a2e4-76adebe35fa5", 328 Name: "test", 329 Description: "test", 330 Rules: `acl = "read"`, 331 } 332 333 stub := policy.Stub() 334 335 require.Equal(t, policy.ID, stub.ID) 336 require.Equal(t, policy.Name, stub.Name) 337 require.Equal(t, policy.Description, stub.Description) 338 require.Equal(t, policy.Datacenters, stub.Datacenters) 339 require.Equal(t, policy.Hash, stub.Hash) 340 require.Equal(t, policy.CreateIndex, stub.CreateIndex) 341 require.Equal(t, policy.ModifyIndex, stub.ModifyIndex) 342 } 343 344 func TestStructs_ACLPolicy_SetHash(t *testing.T) { 345 t.Parallel() 346 347 policy := &ACLPolicy{ 348 ID: "09d1c059-961a-46bd-a2e4-76adebe35fa5", 349 Name: "test", 350 Description: "test", 351 Rules: `acl = "read"`, 352 } 353 354 t.Run("Nil Hash - Generate", func(t *testing.T) { 355 require.Nil(t, policy.Hash) 356 h := policy.SetHash(false) 357 require.NotNil(t, h) 358 require.NotEqual(t, []byte{}, h) 359 require.Equal(t, h, policy.Hash) 360 }) 361 362 t.Run("Hash Set - Dont Generate", func(t *testing.T) { 363 original := policy.Hash 364 h := policy.SetHash(false) 365 require.Equal(t, original, h) 366 367 policy.Description = "changed" 368 h = policy.SetHash(false) 369 require.Equal(t, original, h) 370 }) 371 372 t.Run("Hash Set - Generate", func(t *testing.T) { 373 original := policy.Hash 374 h := policy.SetHash(true) 375 require.NotEqual(t, original, h) 376 }) 377 } 378 379 func TestStructs_ACLPolicy_EstimateSize(t *testing.T) { 380 t.Parallel() 381 382 policy := ACLPolicy{ 383 ID: "09d1c059-961a-46bd-a2e4-76adebe35fa5", 384 Name: "test", 385 Description: "test", 386 Rules: `acl = "read"`, 387 } 388 389 // this test is very contrived. Basically just tests that the 390 // math is okay and returns the value. 391 require.Equal(t, 84, policy.EstimateSize()) 392 policy.Datacenters = []string{"dc1", "dc2"} 393 require.Equal(t, 90, policy.EstimateSize()) 394 } 395 396 func TestStructs_ACLPolicies_Sort(t *testing.T) { 397 t.Parallel() 398 399 policies := ACLPolicies{ 400 &ACLPolicy{ 401 ID: "9db509a9-c809-48c1-895d-99f845b7a9d5", 402 }, 403 &ACLPolicy{ 404 ID: "6bd01084-1695-43b8-898d-b2dd7874754d", 405 }, 406 &ACLPolicy{ 407 ID: "614a4cef-9149-4271-b878-7edb1ad661f8", 408 }, 409 &ACLPolicy{ 410 ID: "c9dd9980-8d54-472f-9e5e-74c02143e1f4", 411 }, 412 } 413 414 policies.Sort() 415 require.Equal(t, policies[0].ID, "614a4cef-9149-4271-b878-7edb1ad661f8") 416 require.Equal(t, policies[1].ID, "6bd01084-1695-43b8-898d-b2dd7874754d") 417 require.Equal(t, policies[2].ID, "9db509a9-c809-48c1-895d-99f845b7a9d5") 418 require.Equal(t, policies[3].ID, "c9dd9980-8d54-472f-9e5e-74c02143e1f4") 419 } 420 421 func TestStructs_ACLPolicyListStubs_Sort(t *testing.T) { 422 t.Parallel() 423 424 policies := ACLPolicyListStubs{ 425 &ACLPolicyListStub{ 426 ID: "9db509a9-c809-48c1-895d-99f845b7a9d5", 427 }, 428 &ACLPolicyListStub{ 429 ID: "6bd01084-1695-43b8-898d-b2dd7874754d", 430 }, 431 &ACLPolicyListStub{ 432 ID: "614a4cef-9149-4271-b878-7edb1ad661f8", 433 }, 434 &ACLPolicyListStub{ 435 ID: "c9dd9980-8d54-472f-9e5e-74c02143e1f4", 436 }, 437 } 438 439 policies.Sort() 440 require.Equal(t, policies[0].ID, "614a4cef-9149-4271-b878-7edb1ad661f8") 441 require.Equal(t, policies[1].ID, "6bd01084-1695-43b8-898d-b2dd7874754d") 442 require.Equal(t, policies[2].ID, "9db509a9-c809-48c1-895d-99f845b7a9d5") 443 require.Equal(t, policies[3].ID, "c9dd9980-8d54-472f-9e5e-74c02143e1f4") 444 } 445 446 func TestStructs_ACLPolicies_resolveWithCache(t *testing.T) { 447 t.Parallel() 448 449 config := ACLCachesConfig{ 450 Identities: 0, 451 Policies: 0, 452 ParsedPolicies: 4, 453 Authorizers: 0, 454 } 455 cache, err := NewACLCaches(&config) 456 require.NoError(t, err) 457 458 testPolicies := ACLPolicies{ 459 &ACLPolicy{ 460 ID: "5d5653a1-2c2b-4b36-b083-fc9f1398eb7b", 461 Name: "policy1", 462 Description: "policy1", 463 Rules: `node_prefix "" { policy = "read" }`, 464 Syntax: acl.SyntaxCurrent, 465 RaftIndex: RaftIndex{ 466 CreateIndex: 1, 467 ModifyIndex: 2, 468 }, 469 }, 470 &ACLPolicy{ 471 ID: "b35541f0-a88a-48da-bc66-43553c60b628", 472 Name: "policy2", 473 Description: "policy2", 474 Rules: `agent_prefix "" { policy = "read" }`, 475 Syntax: acl.SyntaxCurrent, 476 RaftIndex: RaftIndex{ 477 CreateIndex: 3, 478 ModifyIndex: 4, 479 }, 480 }, 481 &ACLPolicy{ 482 ID: "383abb79-94ca-46c6-89b7-8ecb69046de9", 483 Name: "policy3", 484 Description: "policy3", 485 Rules: `key_prefix "" { policy = "read" }`, 486 Syntax: acl.SyntaxCurrent, 487 RaftIndex: RaftIndex{ 488 CreateIndex: 5, 489 ModifyIndex: 6, 490 }, 491 }, 492 &ACLPolicy{ 493 ID: "8bf38965-95e5-4e86-9be7-f6070cc0708b", 494 Name: "policy4", 495 Description: "policy4", 496 Rules: `service_prefix "" { policy = "read" }`, 497 Syntax: acl.SyntaxCurrent, 498 RaftIndex: RaftIndex{ 499 CreateIndex: 7, 500 ModifyIndex: 8, 501 }, 502 }, 503 } 504 505 t.Run("Cache Misses", func(t *testing.T) { 506 policies, err := testPolicies.resolveWithCache(cache, nil) 507 require.NoError(t, err) 508 require.Len(t, policies, 4) 509 for i := range testPolicies { 510 require.Equal(t, testPolicies[i].ID, policies[i].ID) 511 require.Equal(t, testPolicies[i].ModifyIndex, policies[i].Revision) 512 } 513 }) 514 515 t.Run("Check Cache", func(t *testing.T) { 516 for i := range testPolicies { 517 entry := cache.GetParsedPolicy(fmt.Sprintf("%x", testPolicies[i].Hash)) 518 require.NotNil(t, entry) 519 require.Equal(t, testPolicies[i].ID, entry.Policy.ID) 520 require.Equal(t, testPolicies[i].ModifyIndex, entry.Policy.Revision) 521 522 // set this to detect using from the cache next time 523 entry.Policy.Revision = 9999 524 } 525 }) 526 527 t.Run("Cache Hits", func(t *testing.T) { 528 policies, err := testPolicies.resolveWithCache(cache, nil) 529 require.NoError(t, err) 530 require.Len(t, policies, 4) 531 for i := range testPolicies { 532 require.Equal(t, testPolicies[i].ID, policies[i].ID) 533 require.Equal(t, uint64(9999), policies[i].Revision) 534 } 535 }) 536 } 537 538 func TestStructs_ACLPolicies_Compile(t *testing.T) { 539 t.Parallel() 540 541 config := ACLCachesConfig{ 542 Identities: 0, 543 Policies: 0, 544 ParsedPolicies: 4, 545 Authorizers: 2, 546 } 547 cache, err := NewACLCaches(&config) 548 require.NoError(t, err) 549 550 testPolicies := ACLPolicies{ 551 &ACLPolicy{ 552 ID: "5d5653a1-2c2b-4b36-b083-fc9f1398eb7b", 553 Name: "policy1", 554 Description: "policy1", 555 Rules: `node_prefix "" { policy = "read" }`, 556 Syntax: acl.SyntaxCurrent, 557 RaftIndex: RaftIndex{ 558 CreateIndex: 1, 559 ModifyIndex: 2, 560 }, 561 }, 562 &ACLPolicy{ 563 ID: "b35541f0-a88a-48da-bc66-43553c60b628", 564 Name: "policy2", 565 Description: "policy2", 566 Rules: `agent_prefix "" { policy = "read" }`, 567 Syntax: acl.SyntaxCurrent, 568 RaftIndex: RaftIndex{ 569 CreateIndex: 3, 570 ModifyIndex: 4, 571 }, 572 }, 573 &ACLPolicy{ 574 ID: "383abb79-94ca-46c6-89b7-8ecb69046de9", 575 Name: "policy3", 576 Description: "policy3", 577 Rules: `key_prefix "" { policy = "read" }`, 578 Syntax: acl.SyntaxCurrent, 579 RaftIndex: RaftIndex{ 580 CreateIndex: 5, 581 ModifyIndex: 6, 582 }, 583 }, 584 &ACLPolicy{ 585 ID: "8bf38965-95e5-4e86-9be7-f6070cc0708b", 586 Name: "policy4", 587 Description: "policy4", 588 Rules: `service_prefix "" { policy = "read" }`, 589 Syntax: acl.SyntaxCurrent, 590 RaftIndex: RaftIndex{ 591 CreateIndex: 7, 592 ModifyIndex: 8, 593 }, 594 }, 595 } 596 597 t.Run("Cache Miss", func(t *testing.T) { 598 authz, err := testPolicies.Compile(acl.DenyAll(), cache, nil) 599 require.NoError(t, err) 600 require.NotNil(t, authz) 601 602 require.True(t, authz.NodeRead("foo")) 603 require.True(t, authz.AgentRead("foo")) 604 require.True(t, authz.KeyRead("foo")) 605 require.True(t, authz.ServiceRead("foo")) 606 require.False(t, authz.ACLRead()) 607 }) 608 609 t.Run("Check Cache", func(t *testing.T) { 610 entry := cache.GetAuthorizer(testPolicies.HashKey()) 611 require.NotNil(t, entry) 612 authz := entry.Authorizer 613 require.NotNil(t, authz) 614 615 require.True(t, authz.NodeRead("foo")) 616 require.True(t, authz.AgentRead("foo")) 617 require.True(t, authz.KeyRead("foo")) 618 require.True(t, authz.ServiceRead("foo")) 619 require.False(t, authz.ACLRead()) 620 621 // setup the cache for the next test 622 cache.PutAuthorizer(testPolicies.HashKey(), acl.DenyAll()) 623 }) 624 625 t.Run("Cache Hit", func(t *testing.T) { 626 authz, err := testPolicies.Compile(acl.DenyAll(), cache, nil) 627 require.NoError(t, err) 628 require.NotNil(t, authz) 629 630 // we reset the Authorizer in the cache so now everything should be denied 631 require.False(t, authz.NodeRead("foo")) 632 require.False(t, authz.AgentRead("foo")) 633 require.False(t, authz.KeyRead("foo")) 634 require.False(t, authz.ServiceRead("foo")) 635 require.False(t, authz.ACLRead()) 636 }) 637 }