github.com/avenga/couper@v1.12.2/config/configload/validate_test.go (about) 1 package configload 2 3 import ( 4 "context" 5 "fmt" 6 "testing" 7 8 "github.com/hashicorp/hcl/v2/hclsyntax" 9 10 "github.com/avenga/couper/cache" 11 "github.com/avenga/couper/config/runtime" 12 "github.com/avenga/couper/errors" 13 logrustest "github.com/sirupsen/logrus/hooks/test" 14 ) 15 16 func Test_VerifyBodyAttributes(t *testing.T) { 17 type testCase struct { 18 name string 19 body *hclsyntax.Body 20 expErr bool 21 } 22 23 for _, tc := range []testCase{ 24 {"without any body attributes", &hclsyntax.Body{}, false}, 25 {"body", &hclsyntax.Body{Attributes: map[string]*hclsyntax.Attribute{"body": {Name: "body"}}}, false}, 26 {"json_body", &hclsyntax.Body{Attributes: map[string]*hclsyntax.Attribute{"json_body": {Name: "json_body"}}}, false}, 27 {"form_body", &hclsyntax.Body{Attributes: map[string]*hclsyntax.Attribute{"form_body": {Name: "form_body"}}}, false}, 28 {"body/form_body", &hclsyntax.Body{Attributes: map[string]*hclsyntax.Attribute{ 29 "body": {Name: "body"}, 30 "form_body": {Name: "form_body"}, 31 }}, true}, 32 {"body/json_body", &hclsyntax.Body{Attributes: map[string]*hclsyntax.Attribute{ 33 "body": {Name: "body"}, 34 "json_body": {Name: "json_body"}, 35 }}, true}, 36 {"form_body/json_body", &hclsyntax.Body{Attributes: map[string]*hclsyntax.Attribute{ 37 "form_body": {Name: "form_body"}, 38 "json_body": {Name: "json_body"}, 39 }}, true}, 40 {"body/json_body/form_body", &hclsyntax.Body{Attributes: map[string]*hclsyntax.Attribute{ 41 "body": {Name: "body"}, 42 "json_body": {Name: "json_body"}, 43 "form_body": {Name: "form_body"}, 44 }}, true}, 45 } { 46 if err := verifyBodyAttributes(request, tc.body); !tc.expErr && err != nil { 47 t.Errorf("Want no error, got: %v", err) 48 } 49 } 50 } 51 52 func TestLabels(t *testing.T) { 53 tests := []struct { 54 name string 55 hcl string 56 error string 57 }{ 58 { 59 "missing server", 60 `definitions {}`, 61 "configuration error: missing 'server' block", 62 }, 63 { 64 "server w/o label", 65 `server {}`, 66 "", 67 }, 68 { 69 "multiple servers w/o label", 70 `server { 71 hosts = ["*:8888"] 72 } 73 server { 74 hosts = ["*:9999"] 75 }`, 76 "", 77 }, 78 { 79 "labelled and unlabelled servers", 80 `server { 81 hosts = ["*:8888"] 82 } 83 server "test" { 84 hosts = ["*:9999"] 85 } 86 `, 87 "", 88 }, 89 { 90 "duplicate server labels", 91 `server "test" { 92 hosts = ["*:8888"] 93 } 94 server "test" { 95 hosts = ["*:9999"] 96 }`, 97 "", 98 }, 99 { 100 "unique server label", 101 `server "test" { 102 hosts = ["*:8888"] 103 } 104 server "foo" { 105 hosts = ["*:9999"] 106 } 107 definitions { 108 basic_auth "test" {} 109 }`, 110 "", 111 }, 112 { 113 "anonymous api block", 114 `server "test" { 115 api {} 116 }`, 117 "", 118 }, 119 { 120 "multiple anonymous api blocks, different base_path", 121 `server "test" { 122 api { 123 base_path = "/foo" 124 } 125 api { 126 base_path = "/bar" 127 } 128 }`, 129 "", 130 }, 131 { 132 "multiple anonymous api blocks (sharing base_path)", 133 `server "test" { 134 api {} 135 api {} 136 }`, 137 "", 138 }, 139 { 140 "api blocks sharing base_path", 141 `server "test" { 142 api { 143 base_path = "/foo" 144 } 145 api { 146 base_path = "/foo" 147 } 148 }`, 149 "", 150 }, 151 152 { 153 "mixed labelled api blocks", 154 `server "test" { 155 api { 156 base_path = "/foo" 157 } 158 api "bar" { 159 base_path = "/bar" 160 } 161 }`, 162 "", 163 }, 164 { 165 "duplicate api labels", 166 `server "test" { 167 api "foo" { 168 base_path = "/foo" 169 } 170 api "foo" { 171 base_path = "/bar" 172 } 173 }`, 174 ``, 175 }, 176 { 177 "uniquely labelled api blocks per server", 178 `server "foo" { 179 hosts = ["*:8888"] 180 api "foo" { 181 base_path = "/foo" 182 } 183 api "bar" { 184 base_path = "/bar" 185 } 186 } 187 server "bar" { 188 hosts = ["*:9999"] 189 api "foo" { 190 base_path = "/foo" 191 } 192 api "bar" { 193 base_path = "/bar" 194 } 195 }`, 196 "", 197 }, 198 } 199 200 logger, _ := logrustest.NewNullLogger() 201 log := logger.WithContext(context.TODO()) 202 203 for _, tt := range tests { 204 t.Run(tt.name, func(subT *testing.T) { 205 conf, err := LoadBytes([]byte(tt.hcl), "couper.hcl") 206 if conf != nil { 207 tmpStoreCh := make(chan struct{}) 208 defer close(tmpStoreCh) 209 210 ctx, cancel := context.WithCancel(conf.Context) 211 conf.Context = ctx 212 defer cancel() 213 214 _, err = runtime.NewServerConfiguration(conf, log, cache.New(log, tmpStoreCh)) 215 } 216 217 var errMsg string 218 if err != nil { 219 errMsg = err.Error() 220 } 221 222 if tt.error != errMsg { 223 subT.Errorf("%q: Unexpected configuration error:\n\tWant: %q\n\tGot: %q", tt.name, tt.error, errMsg) 224 } 225 }) 226 } 227 } 228 229 func Test_validateBody(t *testing.T) { 230 tests := []struct { 231 name string 232 hcl string 233 error string 234 }{ 235 { 236 "missing backend label", 237 `server {} 238 definitions { 239 backend { 240 } 241 }`, 242 "couper.hcl:3,15-16: missing label; ", 243 }, 244 { 245 "empty backend label", 246 `server {} 247 definitions { 248 backend "" { 249 } 250 }`, 251 "couper.hcl:3,15-17: label is empty; ", 252 }, 253 { 254 "whitespace backend label", 255 `server {} 256 definitions { 257 backend " " { 258 } 259 }`, 260 "couper.hcl:3,15-19: label is empty; ", 261 }, 262 { 263 "invalid backend label", 264 `server {} 265 definitions { 266 backend "foo bar" { 267 } 268 }`, 269 "couper.hcl:3,15-24: label contains invalid character(s), allowed are 'a-z', 'A-Z', '0-9' and '_'; ", 270 }, 271 { 272 "anonymous_* backend label", 273 `server {} 274 definitions { 275 backend "anonymous_foo" { 276 } 277 }`, 278 "couper.hcl:3,15-30: backend label must not start with 'anonymous_'; ", 279 }, 280 { 281 "duplicate backend labels", 282 `server {} 283 definitions { 284 backend "foo" { 285 } 286 backend "foo" { 287 } 288 }`, 289 "couper.hcl:5,15-20: backend labels must be unique; ", 290 }, 291 { 292 "backend disable cert validation with tls block and server_ca_certificate", 293 `server {} 294 definitions { 295 backend "foo" { 296 disable_certificate_validation = false # value does not matter 297 tls { 298 server_ca_certificate = "asdf" 299 } 300 } 301 }`, 302 "couper.hcl:5,6-7,7: configured 'disable_certificate_validation' along with 'server_ca_certificate' attribute; ", 303 }, 304 { 305 "backend disable cert validation with tls block and server_ca_certificate_file", 306 `server {} 307 definitions { 308 backend "foo" { 309 disable_certificate_validation = true # value does not matter 310 tls { 311 server_ca_certificate_file = "asdf.crt" 312 } 313 } 314 }`, 315 "couper.hcl:5,6-7,7: configured 'disable_certificate_validation' along with 'server_ca_certificate_file' attribute; ", 316 }, 317 { 318 "backend disable cert validation with tls block and w/o server_ca_certificate*", 319 `server {} 320 definitions { 321 backend "foo" { 322 disable_certificate_validation = true # value does not matter 323 tls {} 324 } 325 }`, 326 "", 327 }, 328 { 329 "duplicate proxy labels", 330 `server {} 331 definitions { 332 proxy "foo" { 333 } 334 proxy "foo" { 335 } 336 }`, 337 "couper.hcl:5,13-18: proxy labels must be unique; ", 338 }, 339 { 340 "missing basic_auth label", 341 `server {} 342 definitions { 343 basic_auth { 344 } 345 }`, 346 "couper.hcl:3,18-19: missing label; ", 347 }, 348 { 349 "missing beta_oauth2 label", 350 `server {} 351 definitions { 352 beta_oauth2 { 353 } 354 }`, 355 "couper.hcl:3,19-20: missing label; ", 356 }, 357 { 358 "missing jwt label", 359 `server {} 360 definitions { 361 jwt { 362 } 363 }`, 364 "couper.hcl:3,11-12: missing label; ", 365 }, 366 { 367 "missing oidc label", 368 `server {} 369 definitions { 370 oidc { 371 } 372 }`, 373 "couper.hcl:3,12-13: missing label; ", 374 }, 375 { 376 "missing saml label", 377 `server {} 378 definitions { 379 saml { 380 } 381 }`, 382 "couper.hcl:3,12-13: missing label; ", 383 }, 384 { 385 "basic_auth with empty label", 386 `server {} 387 definitions { 388 basic_auth "" { 389 } 390 }`, 391 "couper.hcl:3,18-20: accessControl requires a label; ", 392 }, 393 { 394 "beta_oauth2 with empty label", 395 `server {} 396 definitions { 397 beta_oauth2 "" { 398 } 399 }`, 400 "couper.hcl:3,19-21: accessControl requires a label; ", 401 }, 402 { 403 "jwt with empty label", 404 `server {} 405 definitions { 406 jwt "" { 407 } 408 }`, 409 "couper.hcl:3,11-13: accessControl requires a label; ", 410 }, 411 { 412 "oidc with empty label", 413 `server {} 414 definitions { 415 oidc "" { 416 } 417 }`, 418 "couper.hcl:3,12-14: accessControl requires a label; ", 419 }, 420 { 421 "saml with empty label", 422 `server {} 423 definitions { 424 saml "" { 425 } 426 }`, 427 "couper.hcl:3,12-14: accessControl requires a label; ", 428 }, 429 { 430 "basic_auth with whitespace label", 431 `server {} 432 definitions { 433 basic_auth " " { 434 } 435 }`, 436 "couper.hcl:3,18-22: accessControl requires a label; ", 437 }, 438 { 439 "beta_oauth2 with whitespace label", 440 `server {} 441 definitions { 442 beta_oauth2 " " { 443 } 444 }`, 445 "couper.hcl:3,19-23: accessControl requires a label; ", 446 }, 447 { 448 "jwt with whitespace label", 449 `server {} 450 definitions { 451 jwt " " { 452 } 453 }`, 454 "couper.hcl:3,11-15: accessControl requires a label; ", 455 }, 456 { 457 "oidc with whitespace label", 458 `server {} 459 definitions { 460 oidc " " { 461 } 462 }`, 463 "couper.hcl:3,12-16: accessControl requires a label; ", 464 }, 465 { 466 "saml with whitespace label", 467 `server {} 468 definitions { 469 saml " " { 470 } 471 }`, 472 "couper.hcl:3,12-16: accessControl requires a label; ", 473 }, 474 { 475 "basic_auth reserved label granted_permissions", 476 `server {} 477 definitions { 478 basic_auth "granted_permissions" { 479 } 480 }`, 481 "couper.hcl:3,18-39: accessControl uses reserved name as label; ", 482 }, 483 { 484 "basic_auth reserved label required_permission", 485 `server {} 486 definitions { 487 basic_auth "required_permission" { 488 } 489 }`, 490 "couper.hcl:3,18-39: accessControl uses reserved name as label; ", 491 }, 492 { 493 "beta_oauth2 reserved label granted_permissions", 494 `server {} 495 definitions { 496 beta_oauth2 "granted_permissions" { 497 } 498 }`, 499 "couper.hcl:3,19-40: accessControl uses reserved name as label; ", 500 }, 501 { 502 "beta_oauth2 reserved label required_permission", 503 `server {} 504 definitions { 505 beta_oauth2 "required_permission" { 506 } 507 }`, 508 "couper.hcl:3,19-40: accessControl uses reserved name as label; ", 509 }, 510 { 511 "jwt reserved label granted_permissions", 512 `server {} 513 definitions { 514 jwt "granted_permissions" { 515 } 516 }`, 517 "couper.hcl:3,11-32: accessControl uses reserved name as label; ", 518 }, 519 { 520 "jwt reserved label required_permission", 521 `server {} 522 definitions { 523 jwt "required_permission" { 524 } 525 }`, 526 "couper.hcl:3,11-32: accessControl uses reserved name as label; ", 527 }, 528 { 529 "oidc reserved label granted_permissions", 530 `server {} 531 definitions { 532 oidc "granted_permissions" { 533 } 534 }`, 535 "couper.hcl:3,12-33: accessControl uses reserved name as label; ", 536 }, 537 { 538 "oidc reserved label required_permission", 539 `server {} 540 definitions { 541 oidc "required_permission" { 542 } 543 }`, 544 "couper.hcl:3,12-33: accessControl uses reserved name as label; ", 545 }, 546 { 547 "saml reserved label granted_permissions", 548 `server {} 549 definitions { 550 saml "granted_permissions" { 551 } 552 }`, 553 "couper.hcl:3,12-33: accessControl uses reserved name as label; ", 554 }, 555 { 556 "saml reserved label required_permission", 557 `server {} 558 definitions { 559 saml "required_permission" { 560 } 561 }`, 562 "couper.hcl:3,12-33: accessControl uses reserved name as label; ", 563 }, 564 { 565 "duplicate AC labels 1", 566 `server {} 567 definitions { 568 basic_auth "foo" { 569 } 570 beta_oauth2 "foo" { 571 } 572 }`, 573 "couper.hcl:5,19-24: AC labels must be unique; ", 574 }, 575 { 576 "duplicate AC labels 2", 577 `server {} 578 definitions { 579 beta_oauth2 "foo" { 580 } 581 jwt "foo" { 582 } 583 }`, 584 "couper.hcl:5,11-16: AC labels must be unique; ", 585 }, 586 { 587 "duplicate AC labels 3", 588 `server {} 589 definitions { 590 jwt "foo" { 591 } 592 oidc "foo" { 593 } 594 }`, 595 "couper.hcl:5,12-17: AC labels must be unique; ", 596 }, 597 { 598 "duplicate AC labels 4", 599 `server {} 600 definitions { 601 oidc "foo" { 602 } 603 saml "foo" { 604 } 605 }`, 606 "couper.hcl:5,12-17: AC labels must be unique; ", 607 }, 608 { 609 "duplicate AC labels 5", 610 `server {} 611 definitions { 612 saml "foo" { 613 } 614 basic_auth "foo" { 615 } 616 }`, 617 "couper.hcl:5,18-23: AC labels must be unique; ", 618 }, 619 { 620 "duplicate signing profile labels 1", 621 `server {} 622 definitions { 623 jwt "foo" { 624 signing_ttl = "1m" 625 } 626 jwt_signing_profile "foo" { 627 } 628 }`, 629 "couper.hcl:6,27-32: JWT signing profile labels must be unique; ", 630 }, 631 { 632 "jwt not used as signing profile", 633 `server {} 634 definitions { 635 jwt_signing_profile "foo" { 636 signature_algorithm = "HS256" 637 key = "asdf" 638 ttl = "1m" 639 } 640 jwt "foo" { 641 signature_algorithm = "HS256" 642 key = "sdfg" 643 } 644 }`, 645 "", 646 }, 647 { 648 "duplicate signing profile labels 2", 649 `server {} 650 definitions { 651 jwt_signing_profile "foo" { 652 } 653 jwt "foo" { 654 signing_ttl = "1m" 655 } 656 }`, 657 "couper.hcl:5,11-16: JWT signing profile labels must be unique; ", 658 }, 659 { 660 "same label for backend and AC", 661 `server {} 662 definitions { 663 backend "foo" { 664 } 665 basic_auth "foo" { 666 } 667 }`, 668 "", 669 }, 670 { 671 "invalid server base_path pattern single dot 1", 672 `server { 673 base_path = "./s" 674 }`, 675 `couper.hcl:2,20-23: base_path must not contain "." or ".." segments; `, 676 }, 677 { 678 "invalid server base_path pattern single dot 2", 679 `server { 680 base_path = "/./s" 681 }`, 682 `couper.hcl:2,20-24: base_path must not contain "." or ".." segments; `, 683 }, 684 { 685 "invalid server base_path pattern single dot 3", 686 `server { 687 base_path = "/s/./s" 688 }`, 689 `couper.hcl:2,20-26: base_path must not contain "." or ".." segments; `, 690 }, 691 { 692 "invalid server base_path pattern single dot 4", 693 `server { 694 base_path = "/s/." 695 }`, 696 `couper.hcl:2,20-24: base_path must not contain "." or ".." segments; `, 697 }, 698 { 699 "invalid server base_path pattern double dot 1", 700 `server { 701 base_path = "../s" 702 }`, 703 `couper.hcl:2,20-24: base_path must not contain "." or ".." segments; `, 704 }, 705 { 706 "invalid server base_path pattern double dot 2", 707 `server { 708 base_path = "/../s" 709 }`, 710 `couper.hcl:2,20-25: base_path must not contain "." or ".." segments; `, 711 }, 712 { 713 "invalid server base_path pattern double dot 3", 714 `server { 715 base_path = "/s/../s" 716 }`, 717 `couper.hcl:2,20-27: base_path must not contain "." or ".." segments; `, 718 }, 719 { 720 "invalid server base_path pattern double dot 4", 721 `server { 722 base_path = "/s/.." 723 }`, 724 `couper.hcl:2,20-25: base_path must not contain "." or ".." segments; `, 725 }, 726 { 727 "invalid api base_path pattern single dot 1", 728 `server { 729 api { 730 base_path = "./s" 731 } 732 }`, 733 `couper.hcl:3,22-25: base_path must not contain "." or ".." segments; `, 734 }, 735 { 736 "invalid api base_path pattern single dot 2", 737 `server { 738 api { 739 base_path = "/./s" 740 } 741 }`, 742 `couper.hcl:3,22-26: base_path must not contain "." or ".." segments; `, 743 }, 744 { 745 "invalid api base_path pattern single dot 3", 746 `server { 747 api { 748 base_path = "/s/./s" 749 } 750 }`, 751 `couper.hcl:3,22-28: base_path must not contain "." or ".." segments; `, 752 }, 753 { 754 "invalid api base_path pattern single dot 4", 755 `server { 756 api { 757 base_path = "/s/." 758 } 759 }`, 760 `couper.hcl:3,22-26: base_path must not contain "." or ".." segments; `, 761 }, 762 { 763 "invalid api base_path pattern double dot 1", 764 `server { 765 api { 766 base_path = "../s" 767 } 768 }`, 769 `couper.hcl:3,22-26: base_path must not contain "." or ".." segments; `, 770 }, 771 { 772 "invalid api base_path pattern double dot 2", 773 `server { 774 api { 775 base_path = "/../s" 776 } 777 }`, 778 `couper.hcl:3,22-27: base_path must not contain "." or ".." segments; `, 779 }, 780 { 781 "invalid api base_path pattern double dot 3", 782 `server { 783 api { 784 base_path = "/s/../s" 785 } 786 }`, 787 `couper.hcl:3,22-29: base_path must not contain "." or ".." segments; `, 788 }, 789 { 790 "invalid api base_path pattern double dot 4", 791 `server { 792 api { 793 base_path = "/s/.." 794 } 795 }`, 796 `couper.hcl:3,22-27: base_path must not contain "." or ".." segments; `, 797 }, 798 { 799 "invalid endpoint pattern single dot 1", 800 `server { 801 api { 802 endpoint "./foo" { 803 response { 804 body = "1" 805 } 806 } 807 } 808 }`, 809 `couper.hcl:3,18-25: endpoint path pattern must start with "/"; `, 810 }, 811 { 812 "invalid endpoint pattern single dot 2", 813 `server { 814 api { 815 endpoint "/foo/./bar" { 816 response { 817 body = "1" 818 } 819 } 820 } 821 }`, 822 `couper.hcl:3,18-30: endpoint path pattern must not contain "." or ".." segments; `, 823 }, 824 { 825 "invalid endpoint pattern single dot 3", 826 `server { 827 api { 828 endpoint "/foo/." { 829 response { 830 body = "1" 831 } 832 } 833 } 834 }`, 835 `couper.hcl:3,18-26: endpoint path pattern must not contain "." or ".." segments; `, 836 }, 837 { 838 "invalid endpoint pattern double dot 1", 839 `server { 840 api { 841 endpoint "../foo" { 842 response { 843 body = "1" 844 } 845 } 846 } 847 }`, 848 `couper.hcl:3,18-26: endpoint path pattern must start with "/"; `, 849 }, 850 { 851 "invalid endpoint pattern double dot 2", 852 `server { 853 api { 854 endpoint "/foo/../bar" { 855 response { 856 body = "1" 857 } 858 } 859 } 860 }`, 861 `couper.hcl:3,18-31: endpoint path pattern must not contain "." or ".." segments; `, 862 }, 863 { 864 "invalid endpoint pattern double dot 3", 865 `server { 866 api { 867 endpoint "/foo/.." { 868 response { 869 body = "1" 870 } 871 } 872 } 873 }`, 874 `couper.hcl:3,18-27: endpoint path pattern must not contain "." or ".." segments; `, 875 }, 876 { 877 "duplicate endpoint pattern 1", 878 `server { 879 base_path = "/s" 880 api { 881 endpoint "/" { 882 response { 883 body = "1" 884 } 885 } 886 endpoint "/" { 887 response { 888 body = "2" 889 } 890 } 891 } 892 }`, 893 "couper.hcl:9,18-21: duplicate endpoint; ", 894 }, 895 { 896 "duplicate endpoint pattern 2", 897 `server { 898 base_path = "/s" 899 api { 900 endpoint "/" { 901 response { 902 body = "1" 903 } 904 } 905 } 906 api { 907 endpoint "/" { 908 response { 909 body = "2" 910 } 911 } 912 } 913 }`, 914 "couper.hcl:11,18-21: duplicate endpoint; ", 915 }, 916 { 917 "duplicate endpoint pattern 3", 918 `server { 919 base_path = "/s" 920 api { 921 endpoint "/" { 922 response { 923 body = "1" 924 } 925 } 926 } 927 endpoint "/" { 928 response { 929 body = "2" 930 } 931 } 932 }`, 933 "couper.hcl:10,16-19: duplicate endpoint; ", 934 }, 935 { 936 "duplicate endpoint pattern 4", 937 `server { 938 base_path = "/s" 939 endpoint "/" { 940 response { 941 body = "1" 942 } 943 } 944 api { 945 endpoint "/" { 946 response { 947 body = "2" 948 } 949 } 950 } 951 }`, 952 "couper.hcl:9,18-21: duplicate endpoint; ", 953 }, 954 { 955 "duplicate endpoint pattern 5", 956 `server { 957 base_path = "/s" 958 api { 959 base_path = "/a" 960 endpoint "/b/{c}" { 961 response { 962 body = "1" 963 } 964 } 965 } 966 api { 967 base_path = "/a/b" 968 endpoint "/{d}" { 969 response { 970 body = "2" 971 } 972 } 973 } 974 }`, 975 "couper.hcl:13,18-24: duplicate endpoint; ", 976 }, 977 { 978 "duplicate endpoint pattern 6", 979 `server { 980 endpoint "/a/b" { 981 response { 982 body = "1" 983 } 984 } 985 api { 986 base_path = "/a" 987 endpoint "/b" { 988 response { 989 body = "2" 990 } 991 } 992 } 993 }`, 994 "couper.hcl:9,18-22: duplicate endpoint; ", 995 }, 996 { 997 "distinct endpoint patterns", 998 `server { 999 base_path = "/s" 1000 api { 1001 base_path = "/a" 1002 endpoint "/{b}/c" { 1003 response { 1004 body = "1" 1005 } 1006 } 1007 } 1008 api { 1009 base_path = "/a/b" 1010 endpoint "/c" { 1011 response { 1012 body = "2" 1013 } 1014 } 1015 } 1016 }`, 1017 "", 1018 }, 1019 } 1020 1021 for _, tt := range tests { 1022 t.Run(tt.name, func(subT *testing.T) { 1023 _, err := LoadBytes([]byte(tt.hcl), "couper.hcl") 1024 1025 var errMsg string 1026 if err != nil { 1027 errMsg = err.Error() 1028 } 1029 1030 if tt.error != errMsg { 1031 subT.Errorf("%q: Unexpected configuration error:\n\tWant: %q\n\tGot: %q", tt.name, tt.error, errMsg) 1032 } 1033 }) 1034 } 1035 } 1036 1037 func Test_validateBody_multiple(t *testing.T) { 1038 tests := []struct { 1039 name string 1040 hcls []string 1041 errors []string 1042 }{ 1043 { 1044 "duplicate AC labels", 1045 []string{ 1046 `server {} 1047 definitions { 1048 saml "foo" { 1049 } 1050 }`, 1051 `server {} 1052 definitions { 1053 basic_auth "foo" { 1054 } 1055 }`, 1056 }, 1057 []string{"couper_0.hcl:3,13-18: AC labels must be unique; ", "couper_1.hcl:3,19-24: AC labels must be unique; "}, 1058 }, 1059 { 1060 "duplicate endpoint patterns", 1061 []string{ 1062 `server { 1063 endpoint "/a/b" { 1064 response { 1065 body = "1" 1066 } 1067 } 1068 }`, 1069 `server { 1070 api { 1071 base_path = "/a" 1072 endpoint "/b" { 1073 response { 1074 body = "2" 1075 } 1076 } 1077 } 1078 }`, 1079 }, 1080 []string{"couper_1.hcl:4,19-23: duplicate endpoint; "}, 1081 }, 1082 { 1083 "duplicate signing profile labels", 1084 []string{ 1085 `server {} 1086 definitions { 1087 jwt "foo" { 1088 signing_ttl = "1m" 1089 } 1090 }`, 1091 `server {} 1092 definitions { 1093 jwt_signing_profile "foo" { 1094 } 1095 }`, 1096 }, 1097 []string{"couper_0.hcl:3,15-20: JWT signing profile labels must be unique; ", "couper_1.hcl:3,31-36: JWT signing profile labels must be unique; "}, 1098 }, 1099 } 1100 1101 for _, tt := range tests { 1102 t.Run(tt.name, func(subT *testing.T) { 1103 var testContents []testContent 1104 for i, hcl := range tt.hcls { 1105 testContents = append(testContents, testContent{fmt.Sprintf("couper_%d.hcl", i), []byte(hcl)}) 1106 } 1107 1108 _, err := loadTestContents(testContents) 1109 1110 var errMsg string 1111 if err != nil { 1112 errMsg = err.Error() 1113 } 1114 1115 if !oneOfErrorMsgs(tt.errors, errMsg) { 1116 subT.Errorf("%q: Unexpected configuration error:\n\tWant one of: %v\n\tGot: %q", tt.name, tt.errors, errMsg) 1117 } 1118 }) 1119 } 1120 } 1121 1122 func oneOfErrorMsgs(msgs []string, errorMsg string) bool { 1123 for _, msg := range msgs { 1124 if msg == errorMsg { 1125 return true 1126 } 1127 } 1128 return false 1129 } 1130 1131 func TestAttributeObjectKeys(t *testing.T) { 1132 tests := []struct { 1133 name string 1134 hcl string 1135 error string 1136 }{ 1137 { 1138 "add_request_headers", 1139 `server { 1140 api { 1141 endpoint "/a" { 1142 add_request_headers = { 1143 a = "a" 1144 A = "A" 1145 } 1146 } 1147 } 1148 }`, 1149 "couper.hcl:4,29-7,8: key in an attribute must be unique: 'a'; Key must be unique for a.", 1150 }, 1151 { 1152 "add_response_headers", 1153 `server { 1154 api { 1155 endpoint "/a" { 1156 add_response_headers = { 1157 a = "a" 1158 A = "A" 1159 } 1160 } 1161 } 1162 }`, 1163 "couper.hcl:4,30-7,8: key in an attribute must be unique: 'a'; Key must be unique for a.", 1164 }, 1165 { 1166 "required_permission", 1167 `server { 1168 api { 1169 endpoint "/a" { 1170 required_permission = { 1171 get = "a" 1172 GeT = "A" 1173 } 1174 } 1175 } 1176 }`, 1177 "couper.hcl:4,29-7,8: key in an attribute must be unique: 'get'; Key must be unique for get.", 1178 }, 1179 { 1180 "headers", 1181 `server { 1182 api { 1183 endpoint "/a" { 1184 request { 1185 headers = { 1186 a = "a" 1187 A = "A" 1188 } 1189 } 1190 } 1191 } 1192 }`, 1193 "couper.hcl:5,19-8,10: key in an attribute must be unique: 'a'; Key must be unique for a.", 1194 }, 1195 { 1196 "set_request_headers", 1197 `server { 1198 api { 1199 endpoint "/a" { 1200 set_request_headers = { 1201 a = "a" 1202 A = "A" 1203 } 1204 } 1205 } 1206 }`, 1207 "couper.hcl:4,29-7,8: key in an attribute must be unique: 'a'; Key must be unique for a.", 1208 }, 1209 { 1210 "set_response_headers", 1211 `server { 1212 api { 1213 endpoint "/a" { 1214 set_response_headers = { 1215 a = "a" 1216 A = "A" 1217 } 1218 } 1219 } 1220 }`, 1221 "couper.hcl:4,30-7,8: key in an attribute must be unique: 'a'; Key must be unique for a.", 1222 }, 1223 { 1224 "json_body", 1225 `server { 1226 api { 1227 endpoint "/a" { 1228 request { 1229 json_body = { 1230 a = "a" 1231 A = "A" 1232 } 1233 } 1234 } 1235 } 1236 }`, 1237 "", 1238 }, 1239 { 1240 "form_body", 1241 `server { 1242 api { 1243 endpoint "/a" { 1244 request { 1245 form_body = { 1246 a = "a" 1247 A = "A" 1248 } 1249 } 1250 } 1251 } 1252 }`, 1253 "", 1254 }, 1255 { 1256 "roles_map", 1257 `server {} 1258 definitions { 1259 jwt "a" { 1260 signature_algorithm = "HS256" 1261 key = "asdf" 1262 roles_map = { 1263 a = [] 1264 A = [] 1265 } 1266 } 1267 }`, 1268 "", 1269 }, 1270 { 1271 "permissions_map", 1272 `server {} 1273 definitions { 1274 jwt "a" { 1275 signature_algorithm = "HS256" 1276 key = "asdf" 1277 permissions_map = { 1278 a = [] 1279 A = [] 1280 } 1281 } 1282 }`, 1283 "", 1284 }, 1285 { 1286 "claims", 1287 `server {} 1288 definitions { 1289 jwt "a" { 1290 signature_algorithm = "HS256" 1291 key = "asdf" 1292 claims = { 1293 a = "a" 1294 A = "A" 1295 } 1296 } 1297 }`, 1298 "", 1299 }, 1300 { 1301 "custom_log_fields", 1302 `server {} 1303 definitions { 1304 jwt "a" { 1305 signature_algorithm = "HS256" 1306 key = "asdf" 1307 custom_log_fields = { 1308 a = "a" 1309 A = "A" 1310 } 1311 } 1312 }`, 1313 "", 1314 }, 1315 { 1316 "environment_variables", 1317 `server {} 1318 defaults { 1319 environment_variables = { 1320 a = "a" 1321 A = "A" 1322 } 1323 }`, 1324 "", 1325 }, 1326 } 1327 1328 for _, tt := range tests { 1329 t.Run(tt.name, func(subT *testing.T) { 1330 _, err := LoadBytes([]byte(tt.hcl), "couper.hcl") 1331 1332 var errMsg string 1333 if err != nil { 1334 errMsg = err.Error() 1335 } 1336 1337 if tt.error != errMsg { 1338 subT.Errorf("%q: Unexpected configuration error:\n\tWant: %q\n\tGot: %q", tt.name, tt.error, errMsg) 1339 } 1340 }) 1341 } 1342 } 1343 1344 func TestPermissionMixed(t *testing.T) { 1345 tests := []struct { 1346 name string 1347 hcl string 1348 error string 1349 }{ 1350 { 1351 "mixed config: error", 1352 `server { 1353 api "foo" { 1354 endpoint "/a" { 1355 required_permission = "a" 1356 response {} 1357 } 1358 endpoint "/b" { 1359 response {} 1360 } 1361 } 1362 }`, 1363 "configuration error: api with label \"foo\" has endpoint without required permission", 1364 }, 1365 { 1366 "no mix: all endpoints with permission set", 1367 `server { 1368 api "foo" { 1369 endpoint "/a" { 1370 required_permission = "a" 1371 response {} 1372 } 1373 endpoint "/b" { 1374 required_permission = "" 1375 response {} 1376 } 1377 } 1378 }`, 1379 "", 1380 }, 1381 { 1382 "no mix: permission set by api", 1383 `server { 1384 api "foo" { 1385 required_permission = "api" 1386 endpoint "/a" { 1387 required_permission = "a" 1388 response {} 1389 } 1390 endpoint "/b" { 1391 response {} 1392 } 1393 } 1394 }`, 1395 "", 1396 }, 1397 { 1398 "no mix: disable_access_control", 1399 `server { 1400 api "foo" { 1401 endpoint "/a" { 1402 required_permission = "a" 1403 response {} 1404 } 1405 endpoint "/b" { 1406 disable_access_control = ["foo"] 1407 response {} 1408 } 1409 } 1410 } 1411 definitions { 1412 basic_auth "foo" { 1413 password = "asdf" 1414 } 1415 }`, 1416 "", 1417 }, 1418 { 1419 "no mix: separate apis", 1420 `server { 1421 api "foo" { 1422 endpoint "/a" { 1423 required_permission = "a" 1424 response {} 1425 } 1426 } 1427 api "bar" { 1428 endpoint "/b" { 1429 response {} 1430 } 1431 } 1432 }`, 1433 "", 1434 }, 1435 } 1436 1437 for _, tt := range tests { 1438 t.Run(tt.name, func(subT *testing.T) { 1439 _, err := LoadBytes([]byte(tt.hcl), "couper.hcl") 1440 1441 var errMsg string 1442 if err != nil { 1443 gErr, _ := err.(errors.GoError) 1444 errMsg = gErr.LogError() 1445 } 1446 1447 if tt.error != errMsg { 1448 subT.Errorf("%q: Unexpected configuration error:\n\tWant: %q\n\tGot: %q", tt.name, tt.error, errMsg) 1449 } 1450 }) 1451 } 1452 } 1453 1454 func TestPathAttr(t *testing.T) { 1455 tests := []struct { 1456 name string 1457 hcl string 1458 error string 1459 }{ 1460 { 1461 "path in endpoint: error", 1462 `server { 1463 endpoint "/**" { 1464 path = "/a/**" 1465 } 1466 }`, 1467 "couper.hcl:3,5-9: Unsupported argument; An argument named \"path\" is not expected here. Use the \"path\" attribute in a backend block instead.", 1468 }, 1469 { 1470 "path in proxy: error", 1471 `server { 1472 endpoint "/**" { 1473 proxy { 1474 path = "/a/**" 1475 } 1476 } 1477 }`, 1478 "couper.hcl:4,7-11: Unsupported argument; An argument named \"path\" is not expected here. Use the \"path\" attribute in a backend block instead.", 1479 }, 1480 { 1481 "path in referenced backend: ok", 1482 `server { 1483 endpoint "/**" { 1484 proxy { 1485 backend = "a" 1486 } 1487 } 1488 } 1489 definitions { 1490 backend "a" { 1491 path = "/a/**" 1492 } 1493 }`, 1494 "", 1495 }, 1496 { 1497 "path in refined backend: ok", 1498 `server { 1499 endpoint "/**" { 1500 proxy { 1501 backend "a" { 1502 path = "/a/**" 1503 } 1504 } 1505 } 1506 } 1507 definitions { 1508 backend "a" { 1509 } 1510 }`, 1511 "", 1512 }, 1513 } 1514 1515 for _, tt := range tests { 1516 t.Run(tt.name, func(subT *testing.T) { 1517 _, err := LoadBytes([]byte(tt.hcl), "couper.hcl") 1518 1519 var errMsg string 1520 if err != nil { 1521 errMsg = err.Error() 1522 } 1523 1524 if tt.error != errMsg { 1525 subT.Errorf("%q: Unexpected configuration error:\n\tWant: %q\n\tGot: %q", tt.name, tt.error, errMsg) 1526 } 1527 }) 1528 } 1529 } 1530 1531 func Test_checkReferencedAccessControls(t *testing.T) { 1532 tests := []struct { 1533 name string 1534 hcl string 1535 error string 1536 }{ 1537 { 1538 "missing AC referenced by server access_control", 1539 `server { 1540 access_control = ["undefined"] 1541 }`, 1542 `couper.hcl:2,23-36: referenced access control "undefined" is not defined; `, 1543 }, 1544 { 1545 "missing AC referenced by server disable_access_control", 1546 `server { 1547 disable_access_control = ["undefined"] 1548 }`, 1549 `couper.hcl:2,31-44: referenced access control "undefined" is not defined; `, 1550 }, 1551 { 1552 "missing AC referenced by api access_control", 1553 `server { 1554 api { 1555 access_control = ["undefined"] 1556 } 1557 }`, 1558 `couper.hcl:3,25-38: referenced access control "undefined" is not defined; `, 1559 }, 1560 { 1561 "missing AC referenced by api disable_access_control", 1562 `server { 1563 api { 1564 disable_access_control = ["undefined"] 1565 } 1566 }`, 1567 `couper.hcl:3,33-46: referenced access control "undefined" is not defined; `, 1568 }, 1569 { 1570 "missing AC referenced by files access_control", 1571 `server { 1572 files { 1573 access_control = ["undefined"] 1574 document_root = "htdocs" 1575 } 1576 }`, 1577 `couper.hcl:3,25-38: referenced access control "undefined" is not defined; `, 1578 }, 1579 { 1580 "missing AC referenced by files disable_access_control", 1581 `server { 1582 files { 1583 disable_access_control = ["undefined"] 1584 document_root = "htdocs" 1585 } 1586 }`, 1587 `couper.hcl:3,33-46: referenced access control "undefined" is not defined; `, 1588 }, 1589 { 1590 "missing AC referenced by spa access_control", 1591 `server { 1592 spa { 1593 access_control = ["undefined"] 1594 bootstrap_file = "foo" 1595 paths = ["/**"] 1596 } 1597 }`, 1598 `couper.hcl:3,25-38: referenced access control "undefined" is not defined; `, 1599 }, 1600 { 1601 "missing AC referenced by spa disable_access_control", 1602 `server { 1603 spa { 1604 disable_access_control = ["undefined"] 1605 bootstrap_file = "foo" 1606 paths = ["/**"] 1607 } 1608 }`, 1609 `couper.hcl:3,33-46: referenced access control "undefined" is not defined; `, 1610 }, 1611 { 1612 "missing AC referenced by endpoint access_control", 1613 `server { 1614 endpoint "/" { 1615 access_control = ["undefined"] 1616 response { 1617 body = "OK" 1618 } 1619 } 1620 }`, 1621 `couper.hcl:3,25-38: referenced access control "undefined" is not defined; `, 1622 }, 1623 { 1624 "missing AC referenced by endpoint disable_access_control", 1625 `server { 1626 endpoint "/" { 1627 disable_access_control = ["undefined"] 1628 response { 1629 body = "OK" 1630 } 1631 } 1632 }`, 1633 `couper.hcl:3,33-46: referenced access control "undefined" is not defined; `, 1634 }, 1635 } 1636 1637 for _, tt := range tests { 1638 t.Run(tt.name, func(subT *testing.T) { 1639 _, err := LoadBytes([]byte(tt.hcl), "couper.hcl") 1640 1641 var errMsg string 1642 if err != nil { 1643 errMsg = err.Error() 1644 } 1645 1646 if tt.error != errMsg { 1647 subT.Errorf("%q: Unexpected configuration error:\n\tWant: %q\n\tGot: %q", tt.name, tt.error, errMsg) 1648 } 1649 }) 1650 } 1651 }