github.com/trustbloc/kms-go@v1.1.2/kms/webkms/remotekms_test.go (about) 1 /* 2 Copyright SecureKey Technologies Inc. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package webkms 8 9 import ( 10 "crypto/ecdsa" 11 "crypto/ed25519" 12 "crypto/elliptic" 13 "crypto/rand" 14 "crypto/tls" 15 "crypto/x509" 16 "encoding/json" 17 "encoding/pem" 18 "errors" 19 "fmt" 20 "io" 21 "io/ioutil" 22 "net" 23 "net/http" 24 "path/filepath" 25 "strings" 26 "testing" 27 "time" 28 29 "github.com/stretchr/testify/require" 30 31 kmsapi "github.com/trustbloc/kms-go/spi/kms" 32 ) 33 34 const ( 35 certPrefix = "testdata/" 36 clientTimeout = 5 * time.Second 37 controller = "did:example:123456789" 38 defaultKeyStoreID = "12345" 39 defaultKID = "99999" 40 ) 41 42 func TestRemoteKeyStore(t *testing.T) { 43 xRootCapabilityHeaderValue := []byte("DUMMY") 44 45 secret := make([]byte, 10) 46 _, err := rand.Read(secret) 47 require.NoError(t, err) 48 49 pvKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 50 require.NoError(t, err) 51 52 marshalledPubKey := elliptic.Marshal(pvKey.PublicKey.Curve, pvKey.PublicKey.X, pvKey.PublicKey.Y) 53 54 hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 55 err = processPOSTRequest(w, r, defaultKeyStoreID, defaultKID, marshalledPubKey, kmsapi.ECDSAP256TypeIEEEP1363) 56 w.WriteHeader(http.StatusCreated) 57 require.NoError(t, err) 58 }) 59 60 server, url, client := CreateMockHTTPServerAndClient(t, hf) 61 defaultKeystoreURL := fmt.Sprintf("%s/%s", strings.ReplaceAll(KeystoreEndpoint, 62 "{serverEndpoint}", url), defaultKeyStoreID) 63 64 defer func() { 65 e := server.Close() 66 require.NoError(t, e) 67 }() 68 69 t.Run("CreateKeyStore failures", func(t *testing.T) { 70 blankClient := &http.Client{} 71 _, _, err = CreateKeyStore(blankClient, url, controller, "", nil) 72 require.Contains(t, err.Error(), "posting Create keystore failed") 73 74 _, _, err = CreateKeyStore(blankClient, "``#$%", controller, "", nil) 75 require.EqualError(t, err, "build request for Create keystore error: parse \"``#$%/v1/keystores\": "+ 76 "invalid URL escape \"%/v\"") 77 }) 78 79 t.Run("CreateKeyStore API error", func(t *testing.T) { 80 _hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 81 w.WriteHeader(http.StatusInternalServerError) 82 _, err = w.Write([]byte(`{"errMessage": "api error msg"}`)) 83 require.NoError(t, err) 84 }) 85 86 srv, _url, _client := CreateMockHTTPServerAndClient(t, _hf) 87 88 defer func() { require.NoError(t, srv.Close()) }() 89 90 _, _, err = CreateKeyStore(_client, _url, controller, "", nil) 91 require.Contains(t, err.Error(), "api error msg") 92 }) 93 94 t.Run("CreateKeyStore json error", func(t *testing.T) { 95 _hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 96 w.WriteHeader(http.StatusInternalServerError) 97 _, err = w.Write([]byte(`[]`)) 98 require.NoError(t, err) 99 }) 100 101 srv, _url, _client := CreateMockHTTPServerAndClient(t, _hf) 102 103 defer func() { require.NoError(t, srv.Close()) }() 104 105 _, _, err = CreateKeyStore(_client, _url, controller, "", nil) 106 require.Contains(t, err.Error(), "cannot unmarshal array into Go value") 107 }) 108 109 t.Run("CreateKeyStore json marshal failure", func(t *testing.T) { 110 _, _, err = CreateKeyStore(client, url, controller, "", nil, WithMarshalFn(failingMarshal)) 111 require.Contains(t, err.Error(), "failed to marshal Create keystore request") 112 require.Contains(t, err.Error(), "failingMarshal always fails") 113 }) 114 115 t.Run("CreateKeyStore success", func(t *testing.T) { 116 ksID, capability, e := CreateKeyStore(client, url, controller, "vaultID", []byte("capability")) 117 require.NoError(t, e) 118 require.Equal(t, capability, xRootCapabilityHeaderValue) 119 require.EqualValues(t, defaultKeystoreURL, ksID) 120 }) 121 122 t.Run("Create API error", func(t *testing.T) { 123 _hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 124 w.WriteHeader(http.StatusInternalServerError) 125 _, err = w.Write([]byte(`{"errMessage": "api error msg"}`)) 126 require.NoError(t, err) 127 }) 128 129 srv, _url, _client := CreateMockHTTPServerAndClient(t, _hf) 130 131 defer func() { require.NoError(t, srv.Close()) }() 132 133 tmpKMS := New(_url, _client) 134 135 _, _, err = tmpKMS.Create(kmsapi.ED25519Type) 136 require.Contains(t, err.Error(), "api error msg") 137 }) 138 139 t.Run("Create Key failure", func(t *testing.T) { 140 blankClient := &http.Client{} 141 tmpKMS := New(defaultKeystoreURL, blankClient) 142 143 _, _, err = tmpKMS.Create(kmsapi.ED25519Type) 144 require.Contains(t, err.Error(), "posting Create key failed") 145 146 _, _, err = tmpKMS.CreateAndExportPubKeyBytes(kmsapi.ED25519Type) 147 require.Contains(t, err.Error(), "posting Create key failed") 148 149 tmpKMS = New("``#$%", blankClient) 150 _, _, err = tmpKMS.Create(kmsapi.ED25519Type) 151 require.EqualError(t, err, "posting Create key failed [``#$%/keys, build post request error: parse"+ 152 " \"``#$%/keys\": invalid URL escape \"%/k\"]") 153 }) 154 155 t.Run("New, Create, Get, Export/Import success, all other functions should fail", func(t *testing.T) { 156 remoteKMS := New(defaultKeystoreURL, client) 157 158 kid, keyURL, err := remoteKMS.Create(kmsapi.ECDSAP256TypeIEEEP1363) 159 require.NoError(t, err) 160 require.Equal(t, defaultKID, kid) 161 require.Contains(t, keyURL, fmt.Sprintf("%s/keys/%s", defaultKeystoreURL, defaultKID)) 162 163 t.Run("CreateKey json marshal failure", func(t *testing.T) { 164 remoteKMS2 := New(defaultKeystoreURL, client) 165 166 remoteKMS2.marshalFunc = failingMarshal 167 _, _, err = remoteKMS2.Create(kmsapi.ED25519Type) 168 require.Contains(t, err.Error(), "failed to marshal Create key request") 169 require.Contains(t, err.Error(), "failingMarshal always fails") 170 }) 171 172 kh, err := remoteKMS.Get(kid) 173 require.NoError(t, err) 174 require.EqualValues(t, keyURL, kh) 175 176 pubKey, kt, err := remoteKMS.ExportPubKeyBytes(kid) 177 require.NoError(t, err) 178 require.EqualValues(t, marshalledPubKey, pubKey) 179 require.Equal(t, kmsapi.ECDSAP256TypeIEEEP1363, kt) 180 181 t.Run("ExportPubKeyBytes API error", func(t *testing.T) { 182 _hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 183 w.WriteHeader(http.StatusInternalServerError) 184 _, err = w.Write([]byte(`{"errMessage": "api error msg"}`)) 185 require.NoError(t, err) 186 }) 187 188 srv, _url, _client := CreateMockHTTPServerAndClient(t, _hf) 189 190 defer func() { require.NoError(t, srv.Close()) }() 191 192 tmpKMS := New(_url, _client) 193 194 _, _, err = tmpKMS.ExportPubKeyBytes("kid") 195 require.Contains(t, err.Error(), "api error msg") 196 }) 197 198 t.Run("ExportPubKeyBytes json unmarshal failure", func(t *testing.T) { 199 remoteKMS3 := New(defaultKeystoreURL, client) 200 201 kid1, keyURL1, e := remoteKMS3.Create(kmsapi.ED25519Type) 202 require.NoError(t, e) 203 require.Equal(t, defaultKID, kid1) 204 require.Contains(t, keyURL1, fmt.Sprintf("%s/keys/%s", defaultKeystoreURL, defaultKID)) 205 206 // switch the marshaller in remoteKMS3 to force an error in ExportPubKeyBytes 207 remoteKMS3.unmarshalFunc = failingUnmarshal 208 _, _, err = remoteKMS3.ExportPubKeyBytes(kid1) 209 require.Contains(t, err.Error(), "unmarshal failed") 210 require.Contains(t, err.Error(), "failingUnmarshal always fails") 211 212 remoteKMS3.unmarshalFunc = json.Unmarshal 213 214 t.Logf("kid1 : %v", kid1) 215 216 // test GET http function failure 217 remoteKMS3.keystoreURL = "``#$%" 218 _, _, err = remoteKMS3.ExportPubKeyBytes(kid1) 219 require.Contains(t, err.Error(), "posting GET ExportPubKeyBytes key failed") 220 require.Contains(t, err.Error(), "build get request error") 221 }) 222 223 nKID, _, err := remoteKMS.CreateAndExportPubKeyBytes(kmsapi.AES128GCMType) 224 require.NoError(t, err) 225 require.Equal(t, kid, nKID) 226 227 t.Run("ExportPubKeyBytes should fail with bad http client", func(t *testing.T) { 228 blankClient := &http.Client{} 229 remoteKMS2 := New(defaultKeystoreURL, blankClient) 230 231 _, _, err = remoteKMS2.ExportPubKeyBytes(kid) 232 require.Contains(t, err.Error(), "posting GET ExportPubKeyBytes key failed") 233 }) 234 235 _, _, err = remoteKMS.Rotate(kmsapi.AES128GCMType, "") 236 require.EqualError(t, err, "function Rotate is not implemented in remoteKMS") 237 238 _, err = remoteKMS.PubKeyBytesToHandle(nil, kmsapi.AES128GCMType) 239 require.EqualError(t, err, "function PubKeyBytesToHandle is not implemented in remoteKMS") 240 }) 241 } 242 243 func TestCreateKeyWithLocationInResponseBody(t *testing.T) { 244 secret := make([]byte, 10) 245 _, err := rand.Read(secret) 246 require.NoError(t, err) 247 248 hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 249 err = processPOSTRequestForCreateWithResponseBody(w, r, defaultKeyStoreID, defaultKID) 250 require.NoError(t, err) 251 }) 252 253 server, url, client := CreateMockHTTPServerAndClient(t, hf) 254 defaultKeystoreURL := fmt.Sprintf("%s/%s", strings.ReplaceAll(KeystoreEndpoint, 255 "{serverEndpoint}", url), defaultKeyStoreID) 256 257 defer func() { 258 e := server.Close() 259 require.NoError(t, e) 260 }() 261 262 remoteKMS := New(defaultKeystoreURL, client) 263 264 kid1, keyURL1, err := remoteKMS.Create(kmsapi.ED25519Type) 265 require.NoError(t, err) 266 require.Equal(t, defaultKID, kid1) 267 require.Contains(t, keyURL1, fmt.Sprintf("%s/keys/%s", defaultKeystoreURL, defaultKID)) 268 269 // no error if options passed 270 _, _, err = remoteKMS.Create(kmsapi.ED25519Type, kmsapi.WithAttrs([]string{"attr1"})) 271 require.NoError(t, err) 272 _, _, err = remoteKMS.CreateAndExportPubKeyBytes(kmsapi.ED25519Type, kmsapi.WithAttrs([]string{"attr2"})) 273 require.NoError(t, err) 274 275 remoteKMS.unmarshalFunc = failingUnmarshal 276 _, _, err = remoteKMS.Create(kmsapi.ED25519Type) 277 require.Contains(t, err.Error(), "unmarshal failed") 278 require.Contains(t, err.Error(), "failingUnmarshal always fails") 279 } 280 281 func TestHealthCheck(t *testing.T) { 282 hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 283 w.WriteHeader(http.StatusServiceUnavailable) 284 }) 285 286 server, url, client := CreateMockHTTPServerAndClient(t, hf) 287 defaultKeystoreURL := fmt.Sprintf("%s/%s", strings.ReplaceAll(KeystoreEndpoint, 288 "{serverEndpoint}", url), defaultKeyStoreID) 289 290 defer func() { 291 e := server.Close() 292 require.NoError(t, e) 293 }() 294 295 remoteKMS := New(defaultKeystoreURL, client) 296 297 err := remoteKMS.HealthCheck() 298 require.Error(t, err) 299 require.Contains(t, err.Error(), "kms health check return 503 status code") 300 } 301 302 func TestRemoteKeyStoreWithHeadersFunc(t *testing.T) { 303 xRootCapabilityHeaderValue := []byte("DUMMY") 304 305 secret := make([]byte, 10) 306 _, err := rand.Read(secret) 307 require.NoError(t, err) 308 309 pvKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 310 require.NoError(t, err) 311 312 marshalledPubKey := elliptic.Marshal(pvKey.PublicKey.Curve, pvKey.PublicKey.X, pvKey.PublicKey.Y) 313 314 hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 315 err = processPOSTRequest(w, r, defaultKeyStoreID, defaultKID, marshalledPubKey, kmsapi.ECDSAP256TypeIEEEP1363) 316 w.WriteHeader(http.StatusCreated) 317 require.NoError(t, err) 318 }) 319 320 server, url, client := CreateMockHTTPServerAndClient(t, hf) 321 defaultKeystoreURL := fmt.Sprintf("%s/%s", strings.ReplaceAll(KeystoreEndpoint, 322 "{serverEndpoint}", url), defaultKeyStoreID) 323 324 defer func() { 325 e := server.Close() 326 require.NoError(t, e) 327 }() 328 329 t.Run("CreateKeyStore with http header opt success", func(t *testing.T) { 330 ksID, capability, e := CreateKeyStore(client, url, controller, "vaultID", []byte("capability"), 331 WithHeaders(mockAddHeadersFuncSuccess), WithCache(1)) 332 require.NoError(t, e) 333 require.Equal(t, capability, xRootCapabilityHeaderValue) 334 require.EqualValues(t, defaultKeystoreURL, ksID) 335 }) 336 337 t.Run("CreateKeyStore with http header opt failure", func(t *testing.T) { 338 _, _, e := CreateKeyStore(client, url, controller, "vaultID", []byte("capability"), 339 WithHeaders(mockAddHeadersFuncError)) 340 require.EqualError(t, e, fmt.Errorf("add optional request headers error: %w", errAddHeadersFunc).Error()) 341 }) 342 343 t.Run("test New with valid http header func option", func(t *testing.T) { 344 remoteKMS := New(defaultKeystoreURL, client, WithHeaders(mockAddHeadersFuncSuccess)) 345 346 kid, keyURL, e := remoteKMS.Create(kmsapi.ED25519Type) 347 require.NoError(t, e) 348 require.Equal(t, defaultKID, kid) 349 require.Contains(t, keyURL, fmt.Sprintf("/v1/keystores/%s/keys/%s", defaultKeyStoreID, defaultKID)) 350 }) 351 352 t.Run("test New with invalid http header func option", func(t *testing.T) { 353 remoteKMS := New(defaultKeystoreURL, client, WithHeaders(mockAddHeadersFuncError)) 354 355 _, _, err = remoteKMS.Create(kmsapi.ED25519Type) 356 require.EqualError(t, err, fmt.Errorf("posting Create key failed [%s/keys, add optional request "+ 357 "headers error: %w]", defaultKeystoreURL, errAddHeadersFunc).Error()) 358 }) 359 } 360 361 func TestImportPrivateKey(t *testing.T) { 362 secret := make([]byte, 10) 363 _, err := rand.Read(secret) 364 require.NoError(t, err) 365 366 hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 367 err = processPOSTRequestForImportKey(w, r, defaultKeyStoreID, defaultKID) 368 require.NoError(t, err) 369 }) 370 371 server, url, client := CreateMockHTTPServerAndClient(t, hf) 372 defaultKeystoreURL := fmt.Sprintf("%s/%s", strings.ReplaceAll(KeystoreEndpoint, 373 "{serverEndpoint}", url), defaultKeyStoreID) 374 375 defer func() { 376 e := server.Close() 377 require.NoError(t, e) 378 }() 379 380 remoteKMS := New(defaultKeystoreURL, client) 381 382 _, privateKey, err := ed25519.GenerateKey(rand.Reader) 383 require.NoError(t, err) 384 385 keyID, keyURL, err := remoteKMS.ImportPrivateKey(privateKey, kmsapi.ED25519Type) 386 require.NoError(t, err) 387 require.Equal(t, defaultKID, keyID) 388 require.Contains(t, keyURL, fmt.Sprintf("%s/keys/%s", defaultKeystoreURL, defaultKID)) 389 390 _, _, err = remoteKMS.ImportPrivateKey([]byte("invalid key bytes"), kmsapi.ED25519Type) 391 require.Contains(t, err.Error(), "failed to marshal private key") 392 393 remoteKMS.marshalFunc = failingMarshal 394 395 _, _, err = remoteKMS.ImportPrivateKey(privateKey, kmsapi.ED25519Type) 396 require.Contains(t, err.Error(), "failed to marshal ImportKey request") 397 require.Contains(t, err.Error(), "failingMarshal always fails") 398 399 remoteKMS.marshalFunc = json.Marshal 400 401 remoteKMS.unmarshalFunc = failingUnmarshal 402 403 _, _, err = remoteKMS.ImportPrivateKey(privateKey, kmsapi.ED25519Type) 404 require.Contains(t, err.Error(), "unmarshal failed") 405 require.Contains(t, err.Error(), "failingUnmarshal always fails") 406 407 remoteKMS.unmarshalFunc = json.Unmarshal 408 409 t.Run("ImportPrivateKey API error", func(t *testing.T) { 410 _hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 411 w.WriteHeader(http.StatusInternalServerError) 412 _, err = w.Write([]byte(`{"errMessage": "api error msg"}`)) 413 require.NoError(t, err) 414 }) 415 416 srv, _url, _client := CreateMockHTTPServerAndClient(t, _hf) 417 418 defer func() { require.NoError(t, srv.Close()) }() 419 420 tmpKMS := New(_url, _client) 421 422 _, _, err = tmpKMS.ImportPrivateKey(privateKey, kmsapi.ED25519Type) 423 require.Contains(t, err.Error(), "api error msg") 424 }) 425 } 426 427 func TestCloseResponseBody(t *testing.T) { 428 closeResponseBody(&errFailingCloser{}, "testing close fail should log: errFailingCloser always fails") 429 } 430 431 func processPOSTRequest(w http.ResponseWriter, r *http.Request, keysetID, kid string, 432 defaultExportPubKey []byte, defaultExportKeyType kmsapi.KeyType) error { 433 xRootCapabilityHeaderValue := []byte("DUMMY") 434 435 if valid := validateHTTPMethod(w, r); !valid { 436 return errors.New("http method invalid") 437 } 438 439 if valid := validatePostPayload(r, w); !valid { 440 return errors.New("http request body invalid") 441 } 442 443 if strings.LastIndex(r.URL.Path, "/keys") == len(r.URL.Path)-len("/keys") { 444 return processCreateKeyRequest(w, r, keysetID, kid, defaultExportPubKey) 445 } 446 447 if strings.LastIndex(r.URL.Path, "/export") == len(r.URL.Path)-len("/export") { 448 return processExportKeyRequest(w, defaultExportPubKey, defaultExportKeyType) 449 } 450 451 resp := &createKeyStoreResp{ 452 KeyStoreURL: fmt.Sprintf("https://%s/v1/keystores/%s", r.Host, keysetID), 453 Capability: xRootCapabilityHeaderValue, 454 } 455 456 mResp, err := json.Marshal(resp) 457 if err != nil { 458 return err 459 } 460 461 _, err = w.Write(mResp) 462 if err != nil { 463 return err 464 } 465 466 return nil 467 } 468 469 func processCreateKeyRequest(w http.ResponseWriter, r *http.Request, keysetID, kid string, 470 defaultExportPubKey []byte) error { 471 var req createKeyReq 472 if err := json.NewDecoder(r.Body).Decode(&req); err != nil { 473 return err 474 } 475 476 resp := &createKeyResp{ 477 KeyURL: fmt.Sprintf("https://%s/v1/keystores/%s/keys/%s", r.Host, keysetID, kid), 478 PublicKey: defaultExportPubKey, 479 } 480 481 mResp, err := json.Marshal(resp) 482 if err != nil { 483 return err 484 } 485 486 _, err = w.Write(mResp) 487 if err != nil { 488 return err 489 } 490 491 return nil 492 } 493 494 func processExportKeyRequest(w io.Writer, defaultExportPubKey []byte, defaultExportKeyType kmsapi.KeyType) error { 495 resp := &exportKeyResp{ 496 PublicKey: defaultExportPubKey, 497 KeyType: string(defaultExportKeyType), 498 } 499 500 mResp, err := json.Marshal(resp) 501 if err != nil { 502 return err 503 } 504 505 _, err = w.Write(mResp) 506 if err != nil { 507 return err 508 } 509 510 return nil 511 } 512 513 func processPOSTRequestForCreateWithResponseBody(w http.ResponseWriter, r *http.Request, keysetID, kid string) error { 514 if valid := validateHTTPMethod(w, r); !valid { 515 return errors.New("http method invalid") 516 } 517 518 if valid := validatePostPayload(r, w); !valid { 519 return errors.New("http request body invalid") 520 } 521 522 locationHeaderURL := "https://" + r.Host + "/v1/keystores/" + keysetID 523 524 if strings.LastIndex(r.URL.Path, "/keys") == len(r.URL.Path)-len("/keys") { 525 locationHeaderURL += "/keys/" + kid 526 527 resp := &createKeyResp{ 528 KeyURL: locationHeaderURL, 529 } 530 531 mResp, err := json.Marshal(resp) 532 if err != nil { 533 return err 534 } 535 536 _, err = w.Write(mResp) 537 if err != nil { 538 return err 539 } 540 } 541 542 return nil 543 } 544 545 func processPOSTRequestForImportKey(w http.ResponseWriter, r *http.Request, keysetID, kid string) error { 546 if valid := validateHTTPMethod(w, r); !valid { 547 return errors.New("http method invalid") 548 } 549 550 if valid := validatePostPayload(r, w); !valid { 551 return errors.New("http request body invalid") 552 } 553 554 locationHeaderURL := "https://" + r.Host + "/v1/keystores/" + keysetID 555 556 if strings.LastIndex(r.URL.Path, "/keys") == len(r.URL.Path)-len("/keys") { 557 locationHeaderURL += "/keys/" + kid 558 559 resp := &importKeyResp{ 560 KeyURL: locationHeaderURL, 561 } 562 563 mResp, err := json.Marshal(resp) 564 if err != nil { 565 return err 566 } 567 568 _, err = w.Write(mResp) 569 if err != nil { 570 return err 571 } 572 } 573 574 return nil 575 } 576 577 // validateHTTPMethod validate HTTP method and content-type. 578 func validateHTTPMethod(w http.ResponseWriter, r *http.Request) bool { 579 switch r.Method { 580 case http.MethodPost, http.MethodPut, http.MethodGet: 581 default: 582 http.Error(w, "HTTP Method not allowed", http.StatusMethodNotAllowed) 583 return false 584 } 585 586 ct := r.Header.Get("Content-type") 587 if ct != ContentType && r.Method == http.MethodPost { 588 http.Error(w, fmt.Sprintf("Unsupported Content-type \"%s\"", ct), http.StatusUnsupportedMediaType) 589 return false 590 } 591 592 return true 593 } 594 595 // validatePayload validate and get the payload from the request. 596 func validatePostPayload(r *http.Request, w http.ResponseWriter) bool { 597 if r.ContentLength == 0 && r.Method == http.MethodPost { // empty payload should not be accepted for POST request 598 http.Error(w, "Empty payload", http.StatusBadRequest) 599 return false 600 } 601 602 return true 603 } 604 605 // CreateMockHTTPServerAndClient creates mock http server and client using tls and returns them. 606 func CreateMockHTTPServerAndClient(t *testing.T, inHandler http.Handler) (net.Listener, string, *http.Client) { 607 server := startMockServer(inHandler) 608 port := getServerPort(server) 609 serverURL := fmt.Sprintf("https://localhost:%d", port) 610 611 // build a mock cert pool 612 cp := x509.NewCertPool() 613 err := addCertsToCertPool(cp) 614 require.NoError(t, err) 615 616 // build a tls.Config instance to be used by the outbound transport 617 tlsConfig := &tls.Config{ //nolint:gosec 618 RootCAs: cp, 619 Certificates: nil, 620 } 621 622 // create an http client to communicate with the server that has our inbound handlers set above 623 client := &http.Client{ 624 Timeout: clientTimeout, 625 Transport: &http.Transport{ 626 TLSClientConfig: tlsConfig, 627 }, 628 } 629 630 return server, serverURL, client 631 } 632 633 func startMockServer(handler http.Handler) net.Listener { 634 // ":0" will make the listener auto assign a free port 635 listener, err := net.Listen("tcp", "127.0.0.1:0") 636 if err != nil { 637 errorLogger.Fatalf("HTTP listener failed to start: %s", err) 638 } 639 640 go func() { 641 err := http.ServeTLS(listener, handler, certPrefix+"ec-pubCert1.pem", certPrefix+"ec-key1.pem") 642 if err != nil && !strings.Contains(err.Error(), "use of closed network connection") { 643 errorLogger.Fatalf("HTTP server failed to start: %s", err) 644 } 645 }() 646 647 return listener 648 } 649 650 func getServerPort(server net.Listener) int { 651 // read dynamic port assigned to the server to be used by the client 652 return server.Addr().(*net.TCPAddr).Port 653 } 654 655 func addCertsToCertPool(pool *x509.CertPool) error { 656 var rawCerts []string 657 658 // add contents of ec-pubCert(1, 2 and 3).pem to rawCerts 659 for i := 1; i <= 3; i++ { 660 certPath := fmt.Sprintf("%sec-pubCert%d.pem", certPrefix, i) 661 // Create a pool with server certificates 662 cert, e := ioutil.ReadFile(filepath.Clean(certPath)) 663 if e != nil { 664 return fmt.Errorf("reading certificate failed: %w", e) 665 } 666 667 rawCerts = append(rawCerts, string(cert)) 668 } 669 670 certs := decodeCerts(rawCerts) 671 for i := range certs { 672 pool.AddCert(certs[i]) 673 } 674 675 return nil 676 } 677 678 // decodeCerts will decode a list of pemCertsList (string) into a list of x509 certificates. 679 func decodeCerts(pemCertsList []string) []*x509.Certificate { 680 var certs []*x509.Certificate 681 682 for _, pemCertsString := range pemCertsList { 683 pemCerts := []byte(pemCertsString) 684 for len(pemCerts) > 0 { 685 var block *pem.Block 686 687 block, pemCerts = pem.Decode(pemCerts) 688 if block == nil { 689 break 690 } 691 692 if block.Type != "CERTIFICATE" || len(block.Headers) != 0 { 693 continue 694 } 695 696 cert, err := x509.ParseCertificate(block.Bytes) 697 if err != nil { 698 continue 699 } 700 701 certs = append(certs, cert) 702 } 703 } 704 705 return certs 706 } 707 708 var errFailingMarshal = errors.New("failingMarshal always fails") 709 710 func failingMarshal(interface{}) ([]byte, error) { 711 return nil, errFailingMarshal 712 } 713 714 var errFailingUnmarshal = errors.New("failingUnmarshal always fails") 715 716 func failingUnmarshal([]byte, interface{}) error { 717 return errFailingUnmarshal 718 } 719 720 type errFailingCloser struct{} 721 722 func (c *errFailingCloser) Close() error { 723 return errors.New("errFailingCloser always fails") 724 } 725 726 func mockAddHeadersFuncSuccess(req *http.Request) (*http.Header, error) { 727 // mocking a call to an auth server to get necessary credentials. 728 // It only sets mock http.Header entries for testing purposes. 729 req.Header.Set("controller", "mockController") 730 req.Header.Set("authServerURL", "mockAuthServerURL") 731 req.Header.Set("secret", "mockSecret") 732 733 return &req.Header, nil 734 } 735 736 var errAddHeadersFunc = errors.New("mockAddHeadersFuncError always fails") 737 738 func mockAddHeadersFuncError(_ *http.Request) (*http.Header, error) { 739 return nil, errAddHeadersFunc 740 }