1package jwtauth 2 3import ( 4 "context" 5 "encoding/json" 6 "reflect" 7 "strings" 8 "testing" 9 "time" 10 11 "github.com/go-test/deep" 12 log "github.com/hashicorp/go-hclog" 13 "github.com/hashicorp/go-sockaddr" 14 "github.com/hashicorp/vault/sdk/helper/logging" 15 "github.com/hashicorp/vault/sdk/helper/tokenutil" 16 "github.com/hashicorp/vault/sdk/logical" 17) 18 19func getBackend(t *testing.T) (logical.Backend, logical.Storage) { 20 defaultLeaseTTLVal := time.Hour * 12 21 maxLeaseTTLVal := time.Hour * 24 22 23 config := &logical.BackendConfig{ 24 Logger: logging.NewVaultLogger(log.Trace), 25 26 System: &logical.StaticSystemView{ 27 DefaultLeaseTTLVal: defaultLeaseTTLVal, 28 MaxLeaseTTLVal: maxLeaseTTLVal, 29 }, 30 StorageView: &logical.InmemStorage{}, 31 } 32 b, err := Factory(context.Background(), config) 33 if err != nil { 34 t.Fatalf("unable to create backend: %v", err) 35 } 36 37 return b, config.StorageView 38} 39 40func TestPath_Create(t *testing.T) { 41 t.Run("happy path", func(t *testing.T) { 42 b, storage := getBackend(t) 43 44 data := map[string]interface{}{ 45 "role_type": "jwt", 46 "bound_subject": "testsub", 47 "bound_audiences": "vault", 48 "user_claim": "user", 49 "groups_claim": "groups", 50 "bound_cidrs": "127.0.0.1/8", 51 "policies": "test", 52 "period": "3s", 53 "ttl": "1s", 54 "num_uses": 12, 55 "max_ttl": "5s", 56 "max_age": "60s", 57 } 58 59 expectedSockAddr, err := sockaddr.NewSockAddr("127.0.0.1/8") 60 if err != nil { 61 t.Fatal(err) 62 } 63 64 expected := &jwtRole{ 65 TokenParams: tokenutil.TokenParams{ 66 TokenPolicies: []string{"test"}, 67 TokenPeriod: 3 * time.Second, 68 TokenTTL: 1 * time.Second, 69 TokenMaxTTL: 5 * time.Second, 70 TokenNumUses: 12, 71 TokenBoundCIDRs: []*sockaddr.SockAddrMarshaler{{SockAddr: expectedSockAddr}}, 72 }, 73 RoleType: "jwt", 74 Policies: []string{"test"}, 75 Period: 3 * time.Second, 76 BoundSubject: "testsub", 77 BoundAudiences: []string{"vault"}, 78 BoundClaimsType: "string", 79 UserClaim: "user", 80 GroupsClaim: "groups", 81 TTL: 1 * time.Second, 82 MaxTTL: 5 * time.Second, 83 ExpirationLeeway: 0, 84 NotBeforeLeeway: 0, 85 ClockSkewLeeway: 0, 86 NumUses: 12, 87 BoundCIDRs: []*sockaddr.SockAddrMarshaler{{SockAddr: expectedSockAddr}}, 88 AllowedRedirectURIs: []string(nil), 89 MaxAge: 60 * time.Second, 90 } 91 92 req := &logical.Request{ 93 Operation: logical.CreateOperation, 94 Path: "role/plugin-test", 95 Storage: storage, 96 Data: data, 97 } 98 99 resp, err := b.HandleRequest(context.Background(), req) 100 if err != nil || (resp != nil && resp.IsError()) { 101 t.Fatalf("err:%s resp:%#v\n", err, resp) 102 } 103 actual, err := b.(*jwtAuthBackend).role(context.Background(), storage, "plugin-test") 104 if err != nil { 105 t.Fatal(err) 106 } 107 108 if !reflect.DeepEqual(expected, actual) { 109 t.Fatalf("Unexpected role data: expected %#v\n got %#v\n", expected, actual) 110 } 111 }) 112 113 t.Run("no user claim", func(t *testing.T) { 114 b, storage := getBackend(t) 115 data := map[string]interface{}{ 116 "policies": "test", 117 } 118 119 req := &logical.Request{ 120 Operation: logical.CreateOperation, 121 Path: "role/test2", 122 Storage: storage, 123 Data: data, 124 } 125 126 resp, err := b.HandleRequest(context.Background(), req) 127 if err != nil { 128 t.Fatal(err) 129 } 130 if resp != nil && !resp.IsError() { 131 t.Fatalf("expected error") 132 } 133 if resp.Error().Error() != "a user claim must be defined on the role" { 134 t.Fatalf("unexpected err: %v", resp) 135 } 136 }) 137 138 t.Run("no binding", func(t *testing.T) { 139 b, storage := getBackend(t) 140 data := map[string]interface{}{ 141 "role_type": "jwt", 142 "user_claim": "user", 143 "policies": "test", 144 } 145 146 req := &logical.Request{ 147 Operation: logical.CreateOperation, 148 Path: "role/test3", 149 Storage: storage, 150 Data: data, 151 } 152 153 resp, err := b.HandleRequest(context.Background(), req) 154 if err != nil { 155 t.Fatal(err) 156 } 157 if resp != nil && !resp.IsError() { 158 t.Fatalf("expected error") 159 } 160 if !strings.HasPrefix(resp.Error().Error(), "must have at least one bound constraint") { 161 t.Fatalf("unexpected err: %v", resp) 162 } 163 }) 164 165 t.Run("has bound subject", func(t *testing.T) { 166 b, storage := getBackend(t) 167 data := map[string]interface{}{ 168 "role_type": "jwt", 169 "user_claim": "user", 170 "policies": "test", 171 "bound_subject": "testsub", 172 } 173 174 req := &logical.Request{ 175 Operation: logical.CreateOperation, 176 Path: "role/test4", 177 Storage: storage, 178 Data: data, 179 } 180 181 resp, err := b.HandleRequest(context.Background(), req) 182 if err != nil { 183 t.Fatal(err) 184 } 185 if resp != nil && resp.IsError() { 186 t.Fatalf("did not expect error") 187 } 188 }) 189 190 t.Run("has audience", func(t *testing.T) { 191 b, storage := getBackend(t) 192 // Test has audience 193 data := map[string]interface{}{ 194 "role_type": "jwt", 195 "user_claim": "user", 196 "policies": "test", 197 "bound_audiences": "vault", 198 } 199 200 req := &logical.Request{ 201 Operation: logical.CreateOperation, 202 Path: "role/test5", 203 Storage: storage, 204 Data: data, 205 } 206 207 resp, err := b.HandleRequest(context.Background(), req) 208 if err != nil { 209 t.Fatal(err) 210 } 211 if resp != nil && resp.IsError() { 212 t.Fatalf("did not expect error") 213 } 214 }) 215 216 t.Run("has cidr", func(t *testing.T) { 217 b, storage := getBackend(t) 218 // Test has cidr 219 data := map[string]interface{}{ 220 "role_type": "jwt", 221 "user_claim": "user", 222 "policies": "test", 223 "bound_cidrs": "127.0.0.1/8", 224 } 225 226 req := &logical.Request{ 227 Operation: logical.CreateOperation, 228 Path: "role/test6", 229 Storage: storage, 230 Data: data, 231 } 232 233 resp, err := b.HandleRequest(context.Background(), req) 234 if err != nil { 235 t.Fatal(err) 236 } 237 if resp != nil && resp.IsError() { 238 t.Fatalf("did not expect error") 239 } 240 }) 241 242 t.Run("has bound claims", func(t *testing.T) { 243 b, storage := getBackend(t) 244 data := map[string]interface{}{ 245 "role_type": "jwt", 246 "user_claim": "user", 247 "policies": "test", 248 "bound_claims": map[string]interface{}{ 249 "foo": 10, 250 "bar": "baz", 251 }, 252 } 253 254 req := &logical.Request{ 255 Operation: logical.CreateOperation, 256 Path: "role/test7", 257 Storage: storage, 258 Data: data, 259 } 260 261 resp, err := b.HandleRequest(context.Background(), req) 262 if err != nil { 263 t.Fatal(err) 264 } 265 if resp != nil && resp.IsError() { 266 t.Fatalf("did not expect error") 267 } 268 }) 269 270 t.Run("has expiration, not before custom leeways", func(t *testing.T) { 271 b, storage := getBackend(t) 272 data := map[string]interface{}{ 273 "role_type": "jwt", 274 "user_claim": "user", 275 "policies": "test", 276 "expiration_leeway": "5s", 277 "not_before_leeway": "5s", 278 "clock_skew_leeway": "5s", 279 "bound_claims": map[string]interface{}{ 280 "foo": 10, 281 "bar": "baz", 282 }, 283 } 284 285 req := &logical.Request{ 286 Operation: logical.CreateOperation, 287 Path: "role/test8", 288 Storage: storage, 289 Data: data, 290 } 291 292 resp, err := b.HandleRequest(context.Background(), req) 293 if err != nil { 294 t.Fatal(err) 295 } 296 if resp != nil && resp.IsError() { 297 t.Fatalf("did not expect error:%s", resp.Error().Error()) 298 } 299 300 actual, err := b.(*jwtAuthBackend).role(context.Background(), storage, "test8") 301 if err != nil { 302 t.Fatal(err) 303 } 304 305 expectedDuration := "5s" 306 if actual.ExpirationLeeway.String() != expectedDuration { 307 t.Fatalf("expiration_leeway - expected: %s, got: %s", expectedDuration, actual.ExpirationLeeway) 308 } 309 310 if actual.NotBeforeLeeway.String() != expectedDuration { 311 t.Fatalf("not_before_leeway - expected: %s, got: %s", expectedDuration, actual.NotBeforeLeeway) 312 } 313 314 if actual.ClockSkewLeeway.String() != expectedDuration { 315 t.Fatalf("clock_skew_leeway - expected: %s, got: %s", expectedDuration, actual.ClockSkewLeeway) 316 } 317 }) 318 319 t.Run("storing zero leeways", func(t *testing.T) { 320 b, storage := getBackend(t) 321 data := map[string]interface{}{ 322 "role_type": "jwt", 323 "user_claim": "user", 324 "policies": "test", 325 "clock_skew_leeway": "0", 326 "expiration_leeway": "0", 327 "not_before_leeway": "0", 328 "bound_claims": map[string]interface{}{ 329 "foo": 10, 330 "bar": "baz", 331 }, 332 } 333 334 req := &logical.Request{ 335 Operation: logical.CreateOperation, 336 Path: "role/test9", 337 Storage: storage, 338 Data: data, 339 } 340 341 resp, err := b.HandleRequest(context.Background(), req) 342 if err != nil { 343 t.Fatal(err) 344 } 345 if resp != nil && resp.IsError() { 346 t.Fatalf("did not expect error:%s", resp.Error().Error()) 347 } 348 349 actual, err := b.(*jwtAuthBackend).role(context.Background(), storage, "test9") 350 if err != nil { 351 t.Fatal(err) 352 } 353 354 if actual.ClockSkewLeeway.Seconds() != 0 { 355 t.Fatalf("clock_skew_leeway - expected: 0, got: %v", actual.ClockSkewLeeway.Seconds()) 356 } 357 if actual.ExpirationLeeway.Seconds() != 0 { 358 t.Fatalf("expiration_leeway - expected: 0, got: %v", actual.ExpirationLeeway.Seconds()) 359 } 360 if actual.NotBeforeLeeway.Seconds() != 0 { 361 t.Fatalf("not_before_leeway - expected: 0, got: %v", actual.NotBeforeLeeway.Seconds()) 362 } 363 }) 364 365 t.Run("storing negative leeways", func(t *testing.T) { 366 b, storage := getBackend(t) 367 data := map[string]interface{}{ 368 "role_type": "jwt", 369 "user_claim": "user", 370 "policies": "test", 371 "clock_skew_leeway": "-1", 372 "expiration_leeway": "-1", 373 "not_before_leeway": "-1", 374 "bound_claims": map[string]interface{}{ 375 "foo": 10, 376 "bar": "baz", 377 }, 378 } 379 380 req := &logical.Request{ 381 Operation: logical.CreateOperation, 382 Path: "role/test9", 383 Storage: storage, 384 Data: data, 385 } 386 387 resp, err := b.HandleRequest(context.Background(), req) 388 if err != nil { 389 t.Fatal(err) 390 } 391 if resp != nil && resp.IsError() { 392 t.Fatalf("did not expect error:%s", resp.Error().Error()) 393 } 394 395 actual, err := b.(*jwtAuthBackend).role(context.Background(), storage, "test9") 396 if err != nil { 397 t.Fatal(err) 398 } 399 400 if actual.ClockSkewLeeway.Seconds() != -1 { 401 t.Fatalf("clock_skew_leeway - expected: -1, got: %v", actual.ClockSkewLeeway.Seconds()) 402 } 403 if actual.ExpirationLeeway.Seconds() != -1 { 404 t.Fatalf("expiration_leeway - expected: -1, got: %v", actual.ExpirationLeeway.Seconds()) 405 } 406 if actual.NotBeforeLeeway.Seconds() != -1 { 407 t.Fatalf("not_before_leeway - expected: -1, got: %v", actual.NotBeforeLeeway.Seconds()) 408 } 409 }) 410 411 t.Run("storing an invalid bound_claim_type", func(t *testing.T) { 412 b, storage := getBackend(t) 413 data := map[string]interface{}{ 414 "role_type": "jwt", 415 "user_claim": "user", 416 "policies": "test", 417 "clock_skew_leeway": "-1", 418 "expiration_leeway": "-1", 419 "not_before_leeway": "-1", 420 "bound_claims_type": "invalid", 421 "bound_claims": map[string]interface{}{ 422 "foo": 10, 423 "bar": "baz", 424 }, 425 } 426 427 req := &logical.Request{ 428 Operation: logical.CreateOperation, 429 Path: "role/test10", 430 Storage: storage, 431 Data: data, 432 } 433 434 resp, err := b.HandleRequest(context.Background(), req) 435 if err != nil { 436 t.Fatal(err) 437 } 438 if resp != nil && !resp.IsError() { 439 t.Fatalf("expected error") 440 } 441 if resp.Error().Error() != "invalid 'bound_claims_type': invalid" { 442 t.Fatalf("unexpected err: %v", resp) 443 } 444 }) 445 446 t.Run("role with invalid glob in claim", func(t *testing.T) { 447 b, storage := getBackend(t) 448 data := map[string]interface{}{ 449 "role_type": "jwt", 450 "user_claim": "user", 451 "policies": "test", 452 "clock_skew_leeway": "-1", 453 "expiration_leeway": "-1", 454 "not_before_leeway": "-1", 455 "bound_claims_type": "glob", 456 "bound_claims": map[string]interface{}{ 457 "bar": "baz", 458 "foo": 25, 459 }, 460 } 461 462 req := &logical.Request{ 463 Operation: logical.CreateOperation, 464 Path: "role/test11", 465 Storage: storage, 466 Data: data, 467 } 468 469 resp, err := b.HandleRequest(context.Background(), req) 470 if err != nil { 471 t.Fatal(err) 472 } 473 if resp != nil && !resp.IsError() { 474 t.Fatalf("expected error") 475 } 476 if resp.Error().Error() != "claim is not a string or list: 25" { 477 t.Fatalf("unexpected err: %v", resp) 478 } 479 }) 480 481 t.Run("role with invalid glob in claim array", func(t *testing.T) { 482 b, storage := getBackend(t) 483 data := map[string]interface{}{ 484 "role_type": "jwt", 485 "user_claim": "user", 486 "policies": "test", 487 "clock_skew_leeway": "-1", 488 "expiration_leeway": "-1", 489 "not_before_leeway": "-1", 490 "bound_claims_type": "glob", 491 "bound_claims": map[string]interface{}{ 492 "foo": []interface{}{"baz", 10}, 493 }, 494 } 495 496 req := &logical.Request{ 497 Operation: logical.CreateOperation, 498 Path: "role/test12", 499 Storage: storage, 500 Data: data, 501 } 502 503 resp, err := b.HandleRequest(context.Background(), req) 504 if err != nil { 505 t.Fatal(err) 506 } 507 if resp != nil && !resp.IsError() { 508 t.Fatalf("expected error") 509 } 510 if resp.Error().Error() != "claim is not a string: 10" { 511 t.Fatalf("unexpected err: %v", resp) 512 } 513 }) 514} 515 516func TestPath_OIDCCreate(t *testing.T) { 517 t.Run("both explicit and default role_type", func(t *testing.T) { 518 b, storage := getBackend(t) 519 520 data := map[string]interface{}{ 521 "bound_audiences": "vault", 522 "bound_claims": map[string]interface{}{ 523 "foo": 10, 524 "bar": "baz", 525 }, 526 "oidc_scopes": []string{"email", "profile"}, 527 "allowed_redirect_uris": []string{"https://example.com", "http://localhost:8250"}, 528 "claim_mappings": map[string]string{ 529 "foo": "a", 530 "bar": "b", 531 }, 532 "user_claim": "user", 533 "groups_claim": "groups", 534 "policies": "test", 535 "period": "3s", 536 "ttl": "1s", 537 "num_uses": 12, 538 "max_ttl": "5s", 539 "expiration_leeway": "300s", 540 "not_before_leeway": "300s", 541 "clock_skew_leeway": "1s", 542 } 543 544 expected := &jwtRole{ 545 TokenParams: tokenutil.TokenParams{ 546 TokenPolicies: []string{"test"}, 547 TokenPeriod: 3 * time.Second, 548 TokenTTL: 1 * time.Second, 549 TokenMaxTTL: 5 * time.Second, 550 TokenNumUses: 12, 551 }, 552 RoleType: "oidc", 553 Policies: []string{"test"}, 554 Period: 3 * time.Second, 555 BoundAudiences: []string{"vault"}, 556 BoundClaimsType: "string", 557 BoundClaims: map[string]interface{}{ 558 "foo": json.Number("10"), 559 "bar": "baz", 560 }, 561 AllowedRedirectURIs: []string{"https://example.com", "http://localhost:8250"}, 562 ClaimMappings: map[string]string{ 563 "foo": "a", 564 "bar": "b", 565 }, 566 OIDCScopes: []string{"email", "profile"}, 567 UserClaim: "user", 568 GroupsClaim: "groups", 569 TTL: 1 * time.Second, 570 MaxTTL: 5 * time.Second, 571 ExpirationLeeway: 300 * time.Second, 572 NotBeforeLeeway: 300 * time.Second, 573 ClockSkewLeeway: 1 * time.Second, 574 NumUses: 12, 575 } 576 577 for _, roleType := range []string{"", "oidc"} { 578 data["role_type"] = roleType 579 req := &logical.Request{ 580 Operation: logical.CreateOperation, 581 Path: "role/plugin-test", 582 Storage: storage, 583 Data: data, 584 } 585 586 resp, err := b.HandleRequest(context.Background(), req) 587 if err != nil || (resp != nil && resp.IsError()) { 588 t.Fatalf("err:%s resp:%#v\n", err, resp) 589 } 590 actual, err := b.(*jwtAuthBackend).role(context.Background(), storage, "plugin-test") 591 if err != nil { 592 t.Fatal(err) 593 } 594 595 if diff := deep.Equal(expected, actual); diff != nil { 596 t.Fatal(diff) 597 } 598 } 599 }) 600 601 t.Run("invalid reserved metadata key role", func(t *testing.T) { 602 b, storage := getBackend(t) 603 604 data := map[string]interface{}{ 605 "bound_audiences": "vault", 606 "bound_claims": map[string]interface{}{ 607 "foo": 10, 608 "bar": "baz", 609 }, 610 "oidc_scopes": []string{"email", "profile"}, 611 "allowed_redirect_uris": []string{"https://example.com", "http://localhost:8250"}, 612 "claim_mappings": map[string]string{ 613 "foo": "a", 614 "some_claim": "role", 615 }, 616 "user_claim": "user", 617 "groups_claim": "groups", 618 "policies": "test", 619 "period": "3s", 620 "ttl": "1s", 621 "num_uses": 12, 622 "max_ttl": "5s", 623 "expiration_leeway": "300s", 624 "not_before_leeway": "300s", 625 "clock_skew_leeway": "1s", 626 } 627 628 req := &logical.Request{ 629 Operation: logical.CreateOperation, 630 Path: "role/test2", 631 Storage: storage, 632 Data: data, 633 } 634 635 resp, err := b.HandleRequest(context.Background(), req) 636 if err != nil { 637 t.Fatal(err) 638 } 639 if resp != nil && !resp.IsError() { 640 t.Fatalf("expected error") 641 } 642 if !strings.Contains(resp.Error().Error(), `metadata key "role" is reserved`) { 643 t.Fatalf("unexpected err: %v", resp) 644 } 645 }) 646 647 t.Run("invalid duplicate metadata destination", func(t *testing.T) { 648 b, storage := getBackend(t) 649 650 data := map[string]interface{}{ 651 "bound_audiences": "vault", 652 "bound_claims": map[string]interface{}{ 653 "foo": 10, 654 "bar": "baz", 655 }, 656 "oidc_scopes": []string{"email", "profile"}, 657 "allowed_redirect_uris": []string{"https://example.com", "http://localhost:8250"}, 658 "claim_mappings": map[string]string{ 659 "foo": "a", 660 "bar": "a", 661 }, 662 "user_claim": "user", 663 "groups_claim": "groups", 664 "policies": "test", 665 "period": "3s", 666 "ttl": "1s", 667 "num_uses": 12, 668 "max_ttl": "5s", 669 "expiration_leeway": "300s", 670 "not_before_leeway": "300s", 671 "clock_skew_leeway": "1s", 672 } 673 674 req := &logical.Request{ 675 Operation: logical.CreateOperation, 676 Path: "role/test2", 677 Storage: storage, 678 Data: data, 679 } 680 681 resp, err := b.HandleRequest(context.Background(), req) 682 if err != nil { 683 t.Fatal(err) 684 } 685 if resp != nil && !resp.IsError() { 686 t.Fatalf("expected error") 687 } 688 if !strings.Contains(resp.Error().Error(), `multiple keys are mapped to metadata key "a"`) { 689 t.Fatalf("unexpected err: %v", resp) 690 } 691 }) 692 693 t.Run("custom expiration_leeway and not_before_leeway values", func(t *testing.T) { 694 b, storage := getBackend(t) 695 696 data := map[string]interface{}{ 697 "user_claim": "user", 698 "expiration_leeway": "5s", 699 "not_before_leeway": "5s", 700 "bound_claims": map[string]interface{}{ 701 "foo": "a", 702 "bar": "b", 703 }, 704 "allowed_redirect_uris": []string{"https://example.com", "http://localhost:8250"}, 705 } 706 707 req := &logical.Request{ 708 Operation: logical.CreateOperation, 709 Path: "role/test3", 710 Storage: storage, 711 Data: data, 712 } 713 714 resp, err := b.HandleRequest(context.Background(), req) 715 if err != nil { 716 t.Fatal(err) 717 } 718 if resp != nil && resp.IsError() { 719 t.Fatalf("unexpected error: %s", resp.Error().Error()) 720 } 721 722 actual, err := b.(*jwtAuthBackend).role(context.Background(), storage, "test3") 723 if err != nil { 724 t.Fatal(err) 725 } 726 727 expectedDuration := "5s" 728 if actual.ExpirationLeeway.String() != expectedDuration { 729 t.Fatalf("expiration_leeway - expected: %s, got: %s", expectedDuration, actual.ExpirationLeeway) 730 } 731 732 if actual.NotBeforeLeeway.String() != expectedDuration { 733 t.Fatalf("not_before_leeway - expected: %s, got: %s", expectedDuration, actual.NotBeforeLeeway) 734 } 735 }) 736} 737 738func TestPath_Read(t *testing.T) { 739 b, storage := getBackend(t) 740 741 data := map[string]interface{}{ 742 "role_type": "jwt", 743 "bound_subject": "testsub", 744 "bound_audiences": "vault", 745 "allowed_redirect_uris": []string{"http://127.0.0.1"}, 746 "oidc_scopes": []string{"email", "profile"}, 747 "user_claim": "user", 748 "groups_claim": "groups", 749 "bound_cidrs": "127.0.0.1/8", 750 "policies": "test", 751 "period": "3s", 752 "ttl": "1s", 753 "num_uses": 12, 754 "max_ttl": "5s", 755 "expiration_leeway": "500s", 756 "not_before_leeway": "500s", 757 "clock_skew_leeway": "100s", 758 } 759 760 expected := map[string]interface{}{ 761 "role_type": "jwt", 762 "bound_claims_type": "string", 763 "bound_claims": map[string]interface{}(nil), 764 "claim_mappings": map[string]string(nil), 765 "bound_subject": "testsub", 766 "bound_audiences": []string{"vault"}, 767 "allowed_redirect_uris": []string{"http://127.0.0.1"}, 768 "oidc_scopes": []string{"email", "profile"}, 769 "user_claim": "user", 770 "groups_claim": "groups", 771 "token_policies": []string{"test"}, 772 "policies": []string{"test"}, 773 "token_period": int64(3), 774 "period": int64(3), 775 "token_ttl": int64(1), 776 "ttl": int64(1), 777 "token_num_uses": 12, 778 "num_uses": 12, 779 "token_max_ttl": int64(5), 780 "max_ttl": int64(5), 781 "expiration_leeway": int64(500), 782 "not_before_leeway": int64(500), 783 "clock_skew_leeway": int64(100), 784 "verbose_oidc_logging": false, 785 "token_type": logical.TokenTypeDefault.String(), 786 "token_no_default_policy": false, 787 "token_explicit_max_ttl": int64(0), 788 "max_age": int64(0), 789 } 790 791 req := &logical.Request{ 792 Operation: logical.CreateOperation, 793 Path: "role/plugin-test", 794 Storage: storage, 795 Data: data, 796 } 797 798 resp, err := b.HandleRequest(context.Background(), req) 799 if err != nil || (resp != nil && resp.IsError()) { 800 t.Fatalf("err:%s resp:%#v\n", err, resp) 801 } 802 803 readTest := func() { 804 req = &logical.Request{ 805 Operation: logical.ReadOperation, 806 Path: "role/plugin-test", 807 Storage: storage, 808 } 809 810 resp, err = b.HandleRequest(context.Background(), req) 811 if err != nil || (resp != nil && resp.IsError()) { 812 t.Fatalf("err:%s resp:%#v\n", err, resp) 813 } 814 815 if resp.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "127.0.0.1/8" { 816 t.Fatal("unexpected bound cidrs") 817 } 818 delete(resp.Data, "bound_cidrs") 819 if resp.Data["token_bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "127.0.0.1/8" { 820 t.Fatal("unexpected token bound cidrs") 821 } 822 delete(resp.Data, "token_bound_cidrs") 823 if diff := deep.Equal(expected, resp.Data); diff != nil { 824 t.Fatal(diff) 825 } 826 } 827 828 // Run read test for normal case 829 readTest() 830 831 // Remove the 'role_type' parameter in stored role to simulate a legacy role 832 rolePath := rolePrefix + "plugin-test" 833 raw, err := storage.Get(context.Background(), rolePath) 834 835 var role map[string]interface{} 836 if err := raw.DecodeJSON(&role); err != nil { 837 t.Fatal(err) 838 } 839 delete(role, "role_type") 840 entry, err := logical.StorageEntryJSON(rolePath, role) 841 if err != nil { 842 t.Fatal(err) 843 } 844 845 if err = req.Storage.Put(context.Background(), entry); err != nil { 846 t.Fatal(err) 847 } 848 849 // Run read test for "upgrade" case. The legacy role is not changed in storage, but 850 // reads will populate the `role_type` with "jwt". 851 readTest() 852 853 // Remove the 'bound_claims_type' parameter in stored role to simulate a legacy role 854 raw, err = storage.Get(context.Background(), rolePath) 855 856 if err := raw.DecodeJSON(&role); err != nil { 857 t.Fatal(err) 858 } 859 delete(role, "bound_claims_type") 860 entry, err = logical.StorageEntryJSON(rolePath, role) 861 if err != nil { 862 t.Fatal(err) 863 } 864 865 if err = req.Storage.Put(context.Background(), entry); err != nil { 866 t.Fatal(err) 867 } 868 869 // Run read test for "upgrade" case. The legacy role is not changed in storage, but 870 // reads will populate the `bound_claims_type` with "string". 871 readTest() 872} 873 874func TestPath_Delete(t *testing.T) { 875 b, storage := getBackend(t) 876 877 data := map[string]interface{}{ 878 "role_type": "jwt", 879 "bound_subject": "testsub", 880 "bound_audiences": "vault", 881 "user_claim": "user", 882 "groups_claim": "groups", 883 "bound_cidrs": "127.0.0.1/8", 884 "policies": "test", 885 "period": "3s", 886 "ttl": "1s", 887 "num_uses": 12, 888 "max_ttl": "5s", 889 "expiration_leeway": "300s", 890 "not_before_leeway": "300s", 891 } 892 893 req := &logical.Request{ 894 Operation: logical.CreateOperation, 895 Path: "role/plugin-test", 896 Storage: storage, 897 Data: data, 898 } 899 900 resp, err := b.HandleRequest(context.Background(), req) 901 if err != nil || (resp != nil && resp.IsError()) { 902 t.Fatalf("err:%s resp:%#v\n", err, resp) 903 } 904 905 req = &logical.Request{ 906 Operation: logical.DeleteOperation, 907 Path: "role/plugin-test", 908 Storage: storage, 909 } 910 911 resp, err = b.HandleRequest(context.Background(), req) 912 if err != nil || (resp != nil && resp.IsError()) { 913 t.Fatalf("err:%s resp:%#v\n", err, resp) 914 } 915 916 if resp != nil { 917 t.Fatalf("Unexpected resp data: expected nil got %#v\n", resp.Data) 918 } 919 920 req = &logical.Request{ 921 Operation: logical.ReadOperation, 922 Path: "role/plugin-test", 923 Storage: storage, 924 } 925 926 resp, err = b.HandleRequest(context.Background(), req) 927 if err != nil || (resp != nil && resp.IsError()) { 928 t.Fatalf("err:%s resp:%#v\n", err, resp) 929 } 930 931 if resp != nil { 932 t.Fatalf("Unexpected resp data: expected nil got %#v\n", resp.Data) 933 } 934} 935