github.com/Tyktechnologies/tyk@v2.9.5+incompatible/gateway/cert_test.go (about) 1 package gateway 2 3 import ( 4 "bytes" 5 "crypto/rand" 6 "crypto/rsa" 7 "crypto/tls" 8 "crypto/x509" 9 "crypto/x509/pkix" 10 "encoding/pem" 11 "fmt" 12 "io/ioutil" 13 "math/big" 14 "net" 15 "net/http" 16 "net/http/httptest" 17 "os" 18 "path/filepath" 19 "strings" 20 "sync" 21 "testing" 22 "time" 23 24 "github.com/TykTechnologies/tyk/apidef" 25 "github.com/TykTechnologies/tyk/certs" 26 "github.com/TykTechnologies/tyk/config" 27 "github.com/TykTechnologies/tyk/test" 28 "github.com/TykTechnologies/tyk/user" 29 ) 30 31 func genCertificate(template *x509.Certificate) ([]byte, []byte, []byte, tls.Certificate) { 32 priv, _ := rsa.GenerateKey(rand.Reader, 512) 33 34 serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) 35 serialNumber, _ := rand.Int(rand.Reader, serialNumberLimit) 36 template.SerialNumber = serialNumber 37 template.BasicConstraintsValid = true 38 template.NotBefore = time.Now() 39 template.NotAfter = template.NotBefore.Add(time.Hour) 40 41 derBytes, _ := x509.CreateCertificate(rand.Reader, template, template, &priv.PublicKey, priv) 42 43 var certPem, keyPem bytes.Buffer 44 pem.Encode(&certPem, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) 45 pem.Encode(&keyPem, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}) 46 47 clientCert, _ := tls.X509KeyPair(certPem.Bytes(), keyPem.Bytes()) 48 49 combinedPEM := bytes.Join([][]byte{certPem.Bytes(), keyPem.Bytes()}, []byte("\n")) 50 51 return certPem.Bytes(), keyPem.Bytes(), combinedPEM, clientCert 52 } 53 54 func genServerCertificate() ([]byte, []byte, []byte, tls.Certificate) { 55 certPem, privPem, combinedPEM, cert := genCertificate(&x509.Certificate{ 56 DNSNames: []string{"localhost"}, 57 IPAddresses: []net.IP{net.ParseIP("127.0.0.1"), net.ParseIP("::")}, 58 }) 59 60 return certPem, privPem, combinedPEM, cert 61 } 62 63 const ( 64 internalTLSErr = "tls: internal error" 65 badcertErr = "tls: bad certificate" 66 certNotMatchErr = "Client TLS certificate is required" 67 ) 68 69 func TestGatewayTLS(t *testing.T) { 70 // Configure server 71 serverCertPem, serverPrivPem, combinedPEM, _ := genServerCertificate() 72 73 dir, _ := ioutil.TempDir("", "certs") 74 defer os.RemoveAll(dir) 75 76 client := GetTLSClient(nil, nil) 77 78 t.Run("Without certificates", func(t *testing.T) { 79 globalConf := config.Global() 80 globalConf.HttpServerOptions.UseSSL = true 81 config.SetGlobal(globalConf) 82 defer ResetTestConfig() 83 84 ts := StartTest() 85 defer ts.Close() 86 87 BuildAndLoadAPI(func(spec *APISpec) { 88 spec.Proxy.ListenPath = "/" 89 }) 90 91 ts.Run(t, test.TestCase{ErrorMatch: internalTLSErr, Client: client}) 92 }) 93 94 t.Run("Legacy TLS certificate path", func(t *testing.T) { 95 certFilePath := filepath.Join(dir, "server.crt") 96 ioutil.WriteFile(certFilePath, serverCertPem, 0666) 97 98 certKeyPath := filepath.Join(dir, "server.key") 99 ioutil.WriteFile(certKeyPath, serverPrivPem, 0666) 100 101 globalConf := config.Global() 102 globalConf.HttpServerOptions.Certificates = []config.CertData{{ 103 Name: "localhost", 104 CertFile: certFilePath, 105 KeyFile: certKeyPath, 106 }} 107 globalConf.HttpServerOptions.UseSSL = true 108 config.SetGlobal(globalConf) 109 defer ResetTestConfig() 110 111 ts := StartTest() 112 defer ts.Close() 113 114 BuildAndLoadAPI(func(spec *APISpec) { 115 spec.Proxy.ListenPath = "/" 116 }) 117 118 ts.Run(t, test.TestCase{Code: 200, Client: client}) 119 120 CertificateManager.FlushCache() 121 tlsConfigCache.Flush() 122 }) 123 124 t.Run("File certificate path", func(t *testing.T) { 125 certPath := filepath.Join(dir, "server.pem") 126 ioutil.WriteFile(certPath, combinedPEM, 0666) 127 128 globalConf := config.Global() 129 globalConf.HttpServerOptions.SSLCertificates = []string{certPath} 130 globalConf.HttpServerOptions.UseSSL = true 131 config.SetGlobal(globalConf) 132 defer ResetTestConfig() 133 134 ts := StartTest() 135 defer ts.Close() 136 137 BuildAndLoadAPI(func(spec *APISpec) { 138 spec.Proxy.ListenPath = "/" 139 }) 140 141 ts.Run(t, test.TestCase{Code: 200, Client: client}) 142 143 CertificateManager.FlushCache() 144 tlsConfigCache.Flush() 145 }) 146 147 t.Run("Redis certificate", func(t *testing.T) { 148 certID, err := CertificateManager.Add(combinedPEM, "") 149 if err != nil { 150 t.Fatal(err) 151 } 152 defer CertificateManager.Delete(certID, "") 153 154 globalConf := config.Global() 155 globalConf.HttpServerOptions.SSLCertificates = []string{certID} 156 globalConf.HttpServerOptions.UseSSL = true 157 config.SetGlobal(globalConf) 158 defer ResetTestConfig() 159 160 ts := StartTest() 161 defer ts.Close() 162 163 BuildAndLoadAPI(func(spec *APISpec) { 164 spec.Proxy.ListenPath = "/" 165 }) 166 167 ts.Run(t, test.TestCase{Code: 200, Client: client}) 168 169 CertificateManager.FlushCache() 170 tlsConfigCache.Flush() 171 }) 172 } 173 174 func TestGatewayControlAPIMutualTLS(t *testing.T) { 175 // Configure server 176 serverCertPem, _, combinedPEM, _ := genServerCertificate() 177 178 globalConf := config.Global() 179 globalConf.HttpServerOptions.UseSSL = true 180 globalConf.Security.ControlAPIUseMutualTLS = true 181 config.SetGlobal(globalConf) 182 defer ResetTestConfig() 183 184 dir, _ := ioutil.TempDir("", "certs") 185 186 defer func() { 187 os.RemoveAll(dir) 188 CertificateManager.FlushCache() 189 tlsConfigCache.Flush() 190 }() 191 192 clientCertPem, _, _, clientCert := genCertificate(&x509.Certificate{}) 193 clientWithCert := GetTLSClient(&clientCert, serverCertPem) 194 195 clientWithoutCert := GetTLSClient(nil, nil) 196 197 t.Run("Separate domain", func(t *testing.T) { 198 certID, _ := CertificateManager.Add(combinedPEM, "") 199 defer CertificateManager.Delete(certID, "") 200 201 globalConf := config.Global() 202 globalConf.ControlAPIHostname = "localhost" 203 globalConf.HttpServerOptions.SSLCertificates = []string{certID} 204 config.SetGlobal(globalConf) 205 206 ts := StartTest() 207 defer ts.Close() 208 209 defer func() { 210 CertificateManager.FlushCache() 211 tlsConfigCache.Flush() 212 globalConf := config.Global() 213 globalConf.HttpServerOptions.SSLCertificates = nil 214 globalConf.Security.Certificates.ControlAPI = nil 215 config.SetGlobal(globalConf) 216 }() 217 218 unknownErr := "x509: certificate signed by unknown authority" 219 220 ts.Run(t, []test.TestCase{ 221 // Should acess tyk without client certificates 222 {Client: clientWithoutCert}, 223 // Should raise error for ControlAPI without certificate 224 {ControlRequest: true, ErrorMatch: unknownErr}, 225 // Should raise error for for unknown certificate 226 {ControlRequest: true, ErrorMatch: badcertErr, Client: clientWithCert}, 227 }...) 228 229 clientCertID, _ := CertificateManager.Add(clientCertPem, "") 230 defer CertificateManager.Delete(clientCertID, "") 231 232 globalConf = config.Global() 233 globalConf.Security.Certificates.ControlAPI = []string{clientCertID} 234 config.SetGlobal(globalConf) 235 236 // Should pass request with valid client cert 237 ts.Run(t, test.TestCase{ 238 Path: "/tyk/certs", Code: 200, ControlRequest: true, AdminAuth: true, Client: clientWithCert, 239 }) 240 }) 241 } 242 243 func TestAPIMutualTLS(t *testing.T) { 244 // Configure server 245 serverCertPem, _, combinedPEM, _ := genServerCertificate() 246 certID, _ := CertificateManager.Add(combinedPEM, "") 247 defer CertificateManager.Delete(certID, "") 248 249 globalConf := config.Global() 250 globalConf.EnableCustomDomains = true 251 globalConf.HttpServerOptions.UseSSL = true 252 globalConf.ListenPort = 0 253 globalConf.HttpServerOptions.SSLCertificates = []string{certID} 254 config.SetGlobal(globalConf) 255 defer ResetTestConfig() 256 257 ts := StartTest() 258 defer ts.Close() 259 260 // Initialize client certificates 261 clientCertPem, _, _, clientCert := genCertificate(&x509.Certificate{}) 262 clientCertPem2, _, _, clientCert2 := genCertificate(&x509.Certificate{}) 263 264 t.Run("SNI and domain per API", func(t *testing.T) { 265 t.Run("API without mutual TLS", func(t *testing.T) { 266 client := GetTLSClient(&clientCert, serverCertPem) 267 268 BuildAndLoadAPI(func(spec *APISpec) { 269 spec.Domain = "localhost" 270 spec.Proxy.ListenPath = "/" 271 }) 272 273 ts.Run(t, test.TestCase{Path: "/", Code: 200, Client: client, Domain: "localhost"}) 274 }) 275 276 t.Run("MutualTLSCertificate not set", func(t *testing.T) { 277 client := GetTLSClient(nil, nil) 278 279 BuildAndLoadAPI(func(spec *APISpec) { 280 spec.Domain = "localhost" 281 spec.Proxy.ListenPath = "/" 282 spec.UseMutualTLSAuth = true 283 }) 284 285 ts.Run(t, test.TestCase{ 286 ErrorMatch: badcertErr, 287 Client: client, 288 Domain: "localhost", 289 }) 290 }) 291 292 t.Run("Client certificate match", func(t *testing.T) { 293 client := GetTLSClient(&clientCert, serverCertPem) 294 clientCertID, _ := CertificateManager.Add(clientCertPem, "") 295 296 BuildAndLoadAPI(func(spec *APISpec) { 297 spec.Domain = "localhost" 298 spec.Proxy.ListenPath = "/" 299 spec.UseMutualTLSAuth = true 300 spec.ClientCertificates = []string{clientCertID} 301 }) 302 303 ts.Run(t, test.TestCase{ 304 Code: 200, Client: client, Domain: "localhost", 305 }) 306 307 CertificateManager.Delete(clientCertID, "") 308 CertificateManager.FlushCache() 309 tlsConfigCache.Flush() 310 311 client = GetTLSClient(&clientCert, serverCertPem) 312 ts.Run(t, test.TestCase{ 313 Client: client, Domain: "localhost", ErrorMatch: badcertErr, 314 }) 315 }) 316 317 t.Run("Client certificate differ", func(t *testing.T) { 318 client := GetTLSClient(&clientCert, serverCertPem) 319 320 clientCertPem2, _, _, _ := genCertificate(&x509.Certificate{}) 321 clientCertID2, _ := CertificateManager.Add(clientCertPem2, "") 322 defer CertificateManager.Delete(clientCertID2, "") 323 324 BuildAndLoadAPI(func(spec *APISpec) { 325 spec.Domain = "localhost" 326 spec.Proxy.ListenPath = "/" 327 spec.UseMutualTLSAuth = true 328 spec.ClientCertificates = []string{clientCertID2} 329 }) 330 331 ts.Run(t, test.TestCase{ 332 Client: client, ErrorMatch: badcertErr, Domain: "localhost", 333 }) 334 }) 335 }) 336 337 t.Run("Multiple APIs on same domain", func(t *testing.T) { 338 testSameDomain := func(t *testing.T, domain string) { 339 clientCertID, _ := CertificateManager.Add(clientCertPem, "") 340 defer CertificateManager.Delete(clientCertID, "") 341 342 loadAPIS := func(certs ...string) { 343 BuildAndLoadAPI( 344 func(spec *APISpec) { 345 spec.Proxy.ListenPath = "/without_mutual" 346 spec.Domain = domain 347 }, 348 func(spec *APISpec) { 349 spec.Proxy.ListenPath = "/with_mutual" 350 spec.UseMutualTLSAuth = true 351 spec.ClientCertificates = certs 352 spec.Domain = domain 353 }, 354 ) 355 } 356 357 t.Run("Without certificate", func(t *testing.T) { 358 clientWithoutCert := GetTLSClient(nil, nil) 359 360 loadAPIS() 361 362 ts.Run(t, []test.TestCase{ 363 { 364 Path: "/with_mutual", 365 Client: clientWithoutCert, 366 Domain: domain, 367 Code: 403, 368 BodyMatch: `"error": "` + certNotMatchErr, 369 }, 370 { 371 Path: "/without_mutual", 372 Client: clientWithoutCert, 373 Domain: domain, 374 Code: 200, 375 }, 376 }...) 377 }) 378 379 t.Run("Client certificate not match", func(t *testing.T) { 380 client := GetTLSClient(&clientCert, serverCertPem) 381 382 loadAPIS() 383 384 certNotAllowedErr := `Certificate with SHA256 ` + certs.HexSHA256(clientCert.Certificate[0]) + ` not allowed` 385 386 ts.Run(t, test.TestCase{ 387 Path: "/with_mutual", 388 Client: client, 389 Domain: domain, 390 Code: 403, 391 BodyMatch: `"error": "` + certNotAllowedErr, 392 }) 393 }) 394 395 t.Run("Client certificate match", func(t *testing.T) { 396 loadAPIS(clientCertID) 397 client := GetTLSClient(&clientCert, serverCertPem) 398 399 ts.Run(t, test.TestCase{ 400 Path: "/with_mutual", 401 Domain: domain, 402 Client: client, 403 Code: 200, 404 }) 405 }) 406 } 407 408 t.Run("Empty domain", func(t *testing.T) { 409 testSameDomain(t, "") 410 }) 411 412 t.Run("Custom domain", func(t *testing.T) { 413 testSameDomain(t, "localhost") 414 }) 415 }) 416 417 t.Run("Multiple APIs with Mutual TLS on the same domain", func(t *testing.T) { 418 testSameDomain := func(t *testing.T, domain string) { 419 clientCertID, _ := CertificateManager.Add(clientCertPem, "") 420 defer CertificateManager.Delete(clientCertID, "") 421 422 clientCertID2, _ := CertificateManager.Add(clientCertPem2, "") 423 defer CertificateManager.Delete(clientCertID2, "") 424 425 loadAPIS := func(certs []string, certs2 []string) { 426 BuildAndLoadAPI( 427 func(spec *APISpec) { 428 spec.Proxy.ListenPath = "/with_mutual" 429 spec.UseMutualTLSAuth = true 430 spec.ClientCertificates = certs 431 spec.Domain = domain 432 }, 433 func(spec *APISpec) { 434 spec.Proxy.ListenPath = "/with_mutual_2" 435 spec.UseMutualTLSAuth = true 436 spec.ClientCertificates = certs2 437 spec.Domain = domain 438 }, 439 ) 440 } 441 442 t.Run("Without certificate", func(t *testing.T) { 443 clientWithoutCert := GetTLSClient(nil, nil) 444 445 loadAPIS([]string{}, []string{}) 446 447 ts.Run(t, []test.TestCase{ 448 { 449 Path: "/with_mutual", 450 Client: clientWithoutCert, 451 Domain: domain, 452 ErrorMatch: badcertErr, 453 }, 454 { 455 Path: "/with_mutual_2", 456 Client: clientWithoutCert, 457 Domain: domain, 458 ErrorMatch: badcertErr, 459 }, 460 }...) 461 }) 462 463 t.Run("Client certificate not match", func(t *testing.T) { 464 client := GetTLSClient(&clientCert, serverCertPem) 465 466 loadAPIS([]string{}, []string{}) 467 468 ts.Run(t, test.TestCase{ 469 Path: "/with_mutual", 470 Client: client, 471 Domain: domain, 472 ErrorMatch: badcertErr, 473 }) 474 475 ts.Run(t, test.TestCase{ 476 Path: "/with_mutual_2", 477 Client: client, 478 Domain: domain, 479 ErrorMatch: badcertErr, 480 }) 481 }) 482 483 t.Run("Client certificate match", func(t *testing.T) { 484 loadAPIS([]string{clientCertID}, []string{clientCertID2}) 485 client := GetTLSClient(&clientCert, serverCertPem) 486 client2 := GetTLSClient(&clientCert2, serverCertPem) 487 488 ts.Run(t, 489 []test.TestCase{ 490 { 491 Path: "/with_mutual", 492 Domain: domain, 493 Client: client, 494 Code: 200, 495 }, 496 { 497 Path: "/with_mutual_2", 498 Domain: domain, 499 Client: client, 500 Code: 403, 501 BodyMatch: `"error": "` + `Certificate with SHA256 ` + certs.HexSHA256(clientCert.Certificate[0]) + ` not allowed`, 502 }, 503 { 504 Path: "/with_mutual_2", 505 Domain: domain, 506 Client: client2, 507 Code: 200, 508 }, 509 { 510 Path: "/with_mutual", 511 Domain: domain, 512 Client: client2, 513 Code: 403, 514 BodyMatch: `"error": "` + `Certificate with SHA256 ` + certs.HexSHA256(clientCert2.Certificate[0]) + ` not allowed`, 515 }, 516 }..., 517 ) 518 }) 519 } 520 521 t.Run("Empty domain", func(t *testing.T) { 522 testSameDomain(t, "") 523 }) 524 525 t.Run("Custom domain", func(t *testing.T) { 526 testSameDomain(t, "localhost") 527 }) 528 }) 529 530 t.Run("Multiple APIs, mutual on custom", func(t *testing.T) { 531 testSameDomain := func(t *testing.T, domain string) { 532 clientCertID, _ := CertificateManager.Add(clientCertPem, "") 533 defer CertificateManager.Delete(clientCertID, "") 534 535 loadAPIS := func(certs ...string) { 536 BuildAndLoadAPI( 537 func(spec *APISpec) { 538 spec.Proxy.ListenPath = "/with_mutual" 539 spec.UseMutualTLSAuth = true 540 spec.ClientCertificates = certs 541 spec.Domain = domain 542 }, 543 func(spec *APISpec) { 544 spec.Proxy.ListenPath = "/without_mutual" 545 }, 546 ) 547 } 548 549 t.Run("Without certificate", func(t *testing.T) { 550 clientWithoutCert := GetTLSClient(nil, nil) 551 552 loadAPIS() 553 554 if domain == "" { 555 ts.Run(t, test.TestCase{ 556 Path: "/with_mutual", 557 Client: clientWithoutCert, 558 Domain: domain, 559 Code: 403, 560 BodyMatch: `"error": "` + certNotMatchErr, 561 }) 562 } else { 563 ts.Run(t, test.TestCase{ 564 Path: "/with_mutual", 565 Client: clientWithoutCert, 566 Domain: domain, 567 ErrorMatch: badcertErr, 568 }) 569 } 570 571 ts.Run(t, test.TestCase{ 572 Path: "/without_mutual", 573 Client: clientWithoutCert, 574 Code: 200, 575 }) 576 }) 577 578 t.Run("Client certificate not match", func(t *testing.T) { 579 client := GetTLSClient(&clientCert, serverCertPem) 580 581 loadAPIS() 582 583 if domain == "" { 584 certNotAllowedErr := `Certificate with SHA256 ` + certs.HexSHA256(clientCert.Certificate[0]) + ` not allowed` 585 ts.Run(t, test.TestCase{ 586 Path: "/with_mutual", 587 Client: client, 588 Domain: domain, 589 Code: 403, 590 BodyMatch: `"error": "` + certNotAllowedErr, 591 }) 592 } else { 593 ts.Run(t, test.TestCase{ 594 Path: "/with_mutual", 595 Client: client, 596 Domain: domain, 597 ErrorMatch: badcertErr, 598 }) 599 } 600 }) 601 602 t.Run("Client certificate match", func(t *testing.T) { 603 loadAPIS(clientCertID) 604 client := GetTLSClient(&clientCert, serverCertPem) 605 606 ts.Run(t, test.TestCase{ 607 Path: "/with_mutual", 608 Domain: domain, 609 Client: client, 610 Code: 200, 611 }) 612 }) 613 } 614 615 t.Run("Empty domain", func(t *testing.T) { 616 testSameDomain(t, "") 617 }) 618 619 t.Run("Custom domain", func(t *testing.T) { 620 testSameDomain(t, "localhost") 621 }) 622 }) 623 624 t.Run("Multiple APIs, mutual on empty", func(t *testing.T) { 625 testSameDomain := func(t *testing.T, domain string) { 626 clientCertID, _ := CertificateManager.Add(clientCertPem, "") 627 defer CertificateManager.Delete(clientCertID, "") 628 629 loadAPIS := func(certs ...string) { 630 BuildAndLoadAPI( 631 func(spec *APISpec) { 632 spec.Proxy.ListenPath = "/with_mutual" 633 spec.UseMutualTLSAuth = true 634 spec.ClientCertificates = certs 635 }, 636 func(spec *APISpec) { 637 spec.Proxy.ListenPath = "/without_mutual" 638 spec.Domain = domain 639 }, 640 ) 641 } 642 643 t.Run("Without certificate", func(t *testing.T) { 644 clientWithoutCert := GetTLSClient(nil, nil) 645 646 loadAPIS() 647 648 if domain == "" { 649 ts.Run(t, test.TestCase{ 650 Path: "/with_mutual", 651 Client: clientWithoutCert, 652 Code: 403, 653 BodyMatch: `"error": "` + certNotMatchErr, 654 }) 655 } else { 656 ts.Run(t, test.TestCase{ 657 Path: "/with_mutual", 658 Client: clientWithoutCert, 659 ErrorMatch: badcertErr, 660 }) 661 } 662 663 ts.Run(t, test.TestCase{ 664 Path: "/without_mutual", 665 Client: clientWithoutCert, 666 Domain: domain, 667 Code: 200, 668 }) 669 }) 670 671 t.Run("Client certificate not match", func(t *testing.T) { 672 client := GetTLSClient(&clientCert, serverCertPem) 673 674 loadAPIS() 675 676 if domain == "" { 677 certNotAllowedErr := `Certificate with SHA256 ` + certs.HexSHA256(clientCert.Certificate[0]) + ` not allowed` 678 ts.Run(t, test.TestCase{ 679 Path: "/with_mutual", 680 Client: client, 681 Code: 403, 682 BodyMatch: `"error": "` + certNotAllowedErr, 683 }) 684 } else { 685 ts.Run(t, test.TestCase{ 686 Path: "/with_mutual", 687 Client: client, 688 ErrorMatch: badcertErr, 689 }) 690 } 691 }) 692 693 t.Run("Client certificate match", func(t *testing.T) { 694 loadAPIS(clientCertID) 695 client := GetTLSClient(&clientCert, serverCertPem) 696 697 ts.Run(t, test.TestCase{ 698 Path: "/with_mutual", 699 Client: client, 700 Code: 200, 701 }) 702 }) 703 } 704 705 t.Run("Empty domain", func(t *testing.T) { 706 testSameDomain(t, "") 707 }) 708 709 t.Run("Custom domain", func(t *testing.T) { 710 testSameDomain(t, "localhost") 711 }) 712 }) 713 } 714 715 func TestUpstreamMutualTLS(t *testing.T) { 716 _, _, combinedClientPEM, clientCert := genCertificate(&x509.Certificate{}) 717 clientCert.Leaf, _ = x509.ParseCertificate(clientCert.Certificate[0]) 718 719 upstream := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 720 })) 721 722 // Mutual TLS protected upstream 723 pool := x509.NewCertPool() 724 upstream.TLS = &tls.Config{ 725 ClientAuth: tls.RequireAndVerifyClientCert, 726 ClientCAs: pool, 727 InsecureSkipVerify: true, 728 } 729 730 upstream.StartTLS() 731 defer upstream.Close() 732 733 t.Run("Without API", func(t *testing.T) { 734 client := GetTLSClient(&clientCert, nil) 735 736 if _, err := client.Get(upstream.URL); err == nil { 737 t.Error("Should reject without certificate") 738 } 739 740 pool.AddCert(clientCert.Leaf) 741 742 if _, err := client.Get(upstream.URL); err != nil { 743 t.Error("Should pass with valid certificate") 744 } 745 }) 746 747 t.Run("Upstream API", func(t *testing.T) { 748 globalConf := config.Global() 749 globalConf.ProxySSLInsecureSkipVerify = true 750 config.SetGlobal(globalConf) 751 defer ResetTestConfig() 752 753 ts := StartTest() 754 defer ts.Close() 755 756 clientCertID, _ := CertificateManager.Add(combinedClientPEM, "") 757 defer CertificateManager.Delete(clientCertID, "") 758 759 pool.AddCert(clientCert.Leaf) 760 761 BuildAndLoadAPI(func(spec *APISpec) { 762 spec.Proxy.ListenPath = "/" 763 spec.Proxy.TargetURL = upstream.URL 764 spec.UpstreamCertificates = map[string]string{ 765 "*": clientCertID, 766 } 767 }) 768 769 // Should pass with valid upstream certificate 770 ts.Run(t, test.TestCase{Code: 200}) 771 }) 772 773 } 774 775 func TestSSLForceCommonName(t *testing.T) { 776 upstream := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 777 })) 778 779 // generate certificate Common Name as valid hostname and SAN as non-empty value 780 _, _, _, cert := genCertificate(&x509.Certificate{ 781 EmailAddresses: []string{"test@test.com"}, 782 Subject: pkix.Name{CommonName: "host1.local"}, 783 }) 784 785 upstream.TLS = &tls.Config{ 786 Certificates: []tls.Certificate{cert}, 787 } 788 789 upstream.StartTLS() 790 defer upstream.Close() 791 792 // test case to ensure that Golang doesn't check against CommonName if SAN is non empty 793 t.Run("Force Common Name Check is Disabled", func(t *testing.T) { 794 ts := StartTest() 795 defer ts.Close() 796 797 targetURL := strings.Replace(upstream.URL, "127.0.0.1", "localhost", 1) 798 BuildAndLoadAPI(func(spec *APISpec) { 799 spec.Proxy.ListenPath = "/" 800 spec.Proxy.TargetURL = targetURL 801 }) 802 ts.Run(t, test.TestCase{Code: 500, BodyMatch: "There was a problem proxying the request"}) 803 }) 804 805 t.Run("Force Common Name Check is Enabled", func(t *testing.T) { 806 globalConf := config.Global() 807 globalConf.SSLForceCommonNameCheck = true 808 config.SetGlobal(globalConf) 809 defer ResetTestConfig() 810 811 ts := StartTest() 812 defer ts.Close() 813 814 targetURL := strings.Replace(upstream.URL, "127.0.0.1", "host1.local", 1) 815 BuildAndLoadAPI(func(spec *APISpec) { 816 spec.Proxy.ListenPath = "/" 817 spec.Proxy.TargetURL = targetURL 818 }) 819 820 ts.Run(t, test.TestCase{Code: 200}) 821 }) 822 } 823 824 func TestKeyWithCertificateTLS(t *testing.T) { 825 _, _, combinedPEM, _ := genServerCertificate() 826 serverCertID, _ := CertificateManager.Add(combinedPEM, "") 827 defer CertificateManager.Delete(serverCertID, "") 828 829 globalConf := config.Global() 830 globalConf.HttpServerOptions.UseSSL = true 831 globalConf.EnableCustomDomains = true 832 globalConf.HttpServerOptions.SSLCertificates = []string{serverCertID} 833 config.SetGlobal(globalConf) 834 defer ResetTestConfig() 835 836 ts := StartTest() 837 defer ts.Close() 838 839 t.Run("Without domain", func(t *testing.T) { 840 _, _, _, clientCert := genCertificate(&x509.Certificate{}) 841 clientCertID := certs.HexSHA256(clientCert.Certificate[0]) 842 843 BuildAndLoadAPI(func(spec *APISpec) { 844 spec.UseKeylessAccess = false 845 spec.BaseIdentityProvidedBy = apidef.AuthToken 846 spec.Auth.UseCertificate = true 847 spec.Proxy.ListenPath = "/" 848 spec.OrgID = "default" 849 }) 850 851 client := GetTLSClient(&clientCert, nil) 852 853 t.Run("Cert unknown", func(t *testing.T) { 854 ts.Run(t, test.TestCase{Code: 403, Client: client}) 855 }) 856 857 t.Run("Cert known", func(t *testing.T) { 858 _, key := ts.CreateSession(func(s *user.SessionState) { 859 s.Certificate = clientCertID 860 s.SetAccessRights(map[string]user.AccessDefinition{"test": { 861 APIID: "test", Versions: []string{"v1"}, 862 }}) 863 s.Mutex = &sync.RWMutex{} 864 }) 865 866 if key == "" { 867 t.Fatal("Should create key based on certificate") 868 } 869 870 _, key = ts.CreateSession(func(s *user.SessionState) { 871 s.Certificate = clientCertID 872 s.SetAccessRights(map[string]user.AccessDefinition{"test": { 873 APIID: "test", Versions: []string{"v1"}, 874 }}) 875 s.Mutex = &sync.RWMutex{} 876 }) 877 878 if key != "" { 879 t.Fatal("Should not allow create key based on the same certificate") 880 } 881 882 ts.Run(t, test.TestCase{Path: "/", Code: 200, Client: client}) 883 884 // Domain is not set, but we still pass it, it should still work 885 ts.Run(t, test.TestCase{Path: "/", Code: 200, Domain: "localhost", Client: client}) 886 }) 887 }) 888 889 t.Run("With custom domain", func(t *testing.T) { 890 _, _, _, clientCert := genCertificate(&x509.Certificate{}) 891 clientCertID := certs.HexSHA256(clientCert.Certificate[0]) 892 893 BuildAndLoadAPI( 894 func(spec *APISpec) { 895 spec.UseKeylessAccess = false 896 spec.BaseIdentityProvidedBy = apidef.AuthToken 897 spec.Auth.UseCertificate = true 898 spec.Proxy.ListenPath = "/test1" 899 spec.OrgID = "default" 900 spec.Domain = "localhost" 901 }, 902 func(spec *APISpec) { 903 spec.Proxy.ListenPath = "/test2" 904 spec.OrgID = "default" 905 }, 906 ) 907 908 client := GetTLSClient(&clientCert, nil) 909 910 t.Run("Cert unknown", func(t *testing.T) { 911 ts.Run(t, 912 test.TestCase{Code: 404, Path: "/test1", Client: client}, 913 test.TestCase{Code: 403, Path: "/test1", Domain: "localhost", Client: client}, 914 ) 915 }) 916 917 t.Run("Cert known", func(t *testing.T) { 918 _, key := ts.CreateSession(func(s *user.SessionState) { 919 s.Certificate = clientCertID 920 s.SetAccessRights(map[string]user.AccessDefinition{"test": { 921 APIID: "test", Versions: []string{"v1"}, 922 }}) 923 s.Mutex = &sync.RWMutex{} 924 }) 925 926 if key == "" { 927 t.Fatal("Should create key based on certificate") 928 } 929 930 _, key = ts.CreateSession(func(s *user.SessionState) { 931 s.Certificate = clientCertID 932 s.SetAccessRights(map[string]user.AccessDefinition{"test": { 933 APIID: "test", Versions: []string{"v1"}, 934 }}) 935 s.Mutex = &sync.RWMutex{} 936 }) 937 938 if key != "" { 939 t.Fatal("Should not allow create key based on the same certificate") 940 } 941 942 ts.Run(t, test.TestCase{Path: "/test1", Code: 404, Client: client}) 943 944 // Domain is not set, but we still pass it, it should still work 945 ts.Run(t, test.TestCase{Path: "/test1", Code: 200, Domain: "localhost", Client: client}) 946 }) 947 }) 948 } 949 950 func TestAPICertificate(t *testing.T) { 951 _, _, combinedPEM, _ := genServerCertificate() 952 serverCertID, _ := CertificateManager.Add(combinedPEM, "") 953 defer CertificateManager.Delete(serverCertID, "") 954 955 globalConf := config.Global() 956 globalConf.HttpServerOptions.UseSSL = true 957 globalConf.HttpServerOptions.SSLCertificates = []string{} 958 config.SetGlobal(globalConf) 959 defer ResetTestConfig() 960 961 ts := StartTest() 962 defer ts.Close() 963 964 client := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{ 965 InsecureSkipVerify: true, 966 }}} 967 968 t.Run("Cert set via API", func(t *testing.T) { 969 BuildAndLoadAPI(func(spec *APISpec) { 970 spec.Certificates = []string{serverCertID} 971 spec.UseKeylessAccess = true 972 spec.Proxy.ListenPath = "/" 973 }) 974 975 ts.Run(t, test.TestCase{Code: 200, Client: client}) 976 }) 977 978 t.Run("Cert unknown", func(t *testing.T) { 979 BuildAndLoadAPI(func(spec *APISpec) { 980 spec.UseKeylessAccess = true 981 spec.Proxy.ListenPath = "/" 982 }) 983 984 ts.Run(t, test.TestCase{ErrorMatch: "tls: internal error"}) 985 }) 986 } 987 988 func TestCertificateHandlerTLS(t *testing.T) { 989 _, _, combinedServerPEM, serverCert := genServerCertificate() 990 serverCertID := certs.HexSHA256(serverCert.Certificate[0]) 991 992 clientPEM, _, _, clientCert := genCertificate(&x509.Certificate{}) 993 clientCertID := certs.HexSHA256(clientCert.Certificate[0]) 994 995 ts := StartTest() 996 defer ts.Close() 997 998 t.Run("List certificates, empty", func(t *testing.T) { 999 ts.Run(t, test.TestCase{ 1000 Path: "/tyk/certs", Code: 200, AdminAuth: true, BodyMatch: `{"certs":null}`, 1001 }) 1002 }) 1003 1004 t.Run("Should add certificates with and without private keys", func(t *testing.T) { 1005 ts.Run(t, []test.TestCase{ 1006 // Public Certificate 1007 {Method: "POST", Path: "/tyk/certs", Data: string(clientPEM), AdminAuth: true, Code: 200, BodyMatch: `"id":"` + clientCertID}, 1008 // Public + Private 1009 {Method: "POST", Path: "/tyk/certs", Data: string(combinedServerPEM), AdminAuth: true, Code: 200, BodyMatch: `"id":"` + serverCertID}, 1010 }...) 1011 }) 1012 1013 t.Run("List certificates, non empty", func(t *testing.T) { 1014 ts.Run(t, []test.TestCase{ 1015 {Method: "GET", Path: "/tyk/certs", AdminAuth: true, Code: 200, BodyMatch: clientCertID}, 1016 {Method: "GET", Path: "/tyk/certs", AdminAuth: true, Code: 200, BodyMatch: serverCertID}, 1017 }...) 1018 }) 1019 1020 certMetaTemplate := `{"id":"%s","fingerprint":"%s","has_private":%s` 1021 1022 t.Run("Certificate meta info", func(t *testing.T) { 1023 clientCertMeta := fmt.Sprintf(certMetaTemplate, clientCertID, clientCertID, "false") 1024 serverCertMeta := fmt.Sprintf(certMetaTemplate, serverCertID, serverCertID, "true") 1025 1026 ts.Run(t, []test.TestCase{ 1027 {Method: "GET", Path: "/tyk/certs/" + clientCertID, AdminAuth: true, Code: 200, BodyMatch: clientCertMeta}, 1028 {Method: "GET", Path: "/tyk/certs/" + serverCertID, AdminAuth: true, Code: 200, BodyMatch: serverCertMeta}, 1029 {Method: "GET", Path: "/tyk/certs/" + serverCertID + "," + clientCertID, AdminAuth: true, Code: 200, BodyMatch: `\[` + serverCertMeta}, 1030 {Method: "GET", Path: "/tyk/certs/" + serverCertID + "," + clientCertID, AdminAuth: true, Code: 200, BodyMatch: clientCertMeta}, 1031 }...) 1032 }) 1033 1034 t.Run("Certificate removal", func(t *testing.T) { 1035 ts.Run(t, []test.TestCase{ 1036 {Method: "DELETE", Path: "/tyk/certs/" + serverCertID, AdminAuth: true, Code: 200}, 1037 {Method: "DELETE", Path: "/tyk/certs/" + clientCertID, AdminAuth: true, Code: 200}, 1038 {Method: "GET", Path: "/tyk/certs", AdminAuth: true, Code: 200, BodyMatch: `{"certs":null}`}, 1039 }...) 1040 }) 1041 } 1042 1043 func TestCipherSuites(t *testing.T) { 1044 //configure server so we can useSSL and utilize the logic, but skip verification in the clients 1045 _, _, combinedPEM, _ := genServerCertificate() 1046 serverCertID, _ := CertificateManager.Add(combinedPEM, "") 1047 defer CertificateManager.Delete(serverCertID, "") 1048 1049 globalConf := config.Global() 1050 globalConf.HttpServerOptions.UseSSL = true 1051 globalConf.HttpServerOptions.Ciphers = []string{"TLS_RSA_WITH_RC4_128_SHA", "TLS_RSA_WITH_3DES_EDE_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA"} 1052 globalConf.HttpServerOptions.SSLCertificates = []string{serverCertID} 1053 config.SetGlobal(globalConf) 1054 defer ResetTestConfig() 1055 1056 ts := StartTest() 1057 defer ts.Close() 1058 1059 BuildAndLoadAPI(func(spec *APISpec) { 1060 spec.Proxy.ListenPath = "/" 1061 }) 1062 1063 //matching ciphers 1064 t.Run("Cipher match", func(t *testing.T) { 1065 1066 client := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{ 1067 CipherSuites: getCipherAliases([]string{"TLS_RSA_WITH_RC4_128_SHA", "TLS_RSA_WITH_3DES_EDE_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA"}), 1068 InsecureSkipVerify: true, 1069 }}} 1070 1071 // If there is an internal TLS error it will fail test 1072 ts.Run(t, test.TestCase{Client: client, Path: "/"}) 1073 }) 1074 1075 t.Run("Cipher non-match", func(t *testing.T) { 1076 1077 client := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{ 1078 CipherSuites: getCipherAliases([]string{"TLS_RSA_WITH_AES_256_CBC_SHA"}), // not matching ciphers 1079 InsecureSkipVerify: true, 1080 }}} 1081 1082 ts.Run(t, test.TestCase{Client: client, Path: "/", ErrorMatch: "tls: handshake failure"}) 1083 }) 1084 }