github.com/Tyktechnologies/tyk@v2.9.5+incompatible/gateway/mw_http_signature_validation_test.go (about) 1 package gateway 2 3 import ( 4 "crypto" 5 "crypto/hmac" 6 "crypto/rand" 7 "crypto/rsa" 8 "crypto/sha1" 9 "crypto/sha256" 10 "crypto/sha512" 11 "crypto/x509" 12 "encoding/base64" 13 "encoding/pem" 14 "fmt" 15 "hash" 16 "net/http" 17 "net/http/httptest" 18 "net/url" 19 "regexp" 20 "strings" 21 "sync" 22 "testing" 23 "time" 24 25 "github.com/justinas/alice" 26 "github.com/lonelycode/go-uuid/uuid" 27 28 "github.com/TykTechnologies/tyk/apidef" 29 "github.com/TykTechnologies/tyk/config" 30 "github.com/TykTechnologies/tyk/user" 31 ) 32 33 const hmacAuthDef = `{ 34 "api_id": "1", 35 "org_id": "default", 36 "enable_signature_checking": true, 37 "hmac_allowed_clock_skew": 5000, 38 "auth": {"auth_header_name": "authorization"}, 39 "version_data": { 40 "not_versioned": true, 41 "versions": { 42 "v1": {"name": "v1"} 43 } 44 }, 45 "proxy": { 46 "listen_path": "/v1", 47 "target_url": "` + TestHttpAny + `" 48 } 49 }` 50 51 func createHMACAuthSession() *user.SessionState { 52 session := new(user.SessionState) 53 session.Rate = 8.0 54 session.Allowance = session.Rate 55 session.LastCheck = time.Now().Unix() 56 session.Per = 1.0 57 session.QuotaRenewalRate = 300 // 5 minutes 58 session.QuotaRenews = time.Now().Unix() + 20 59 session.QuotaRemaining = 1 60 session.QuotaMax = -1 61 session.HMACEnabled = true 62 session.HmacSecret = "9879879878787878" 63 session.Mutex = &sync.RWMutex{} 64 return session 65 } 66 67 func createRSAAuthSession(pubCertId string) *user.SessionState { 68 session := new(user.SessionState) 69 session.Rate = 8.0 70 session.Allowance = session.Rate 71 session.LastCheck = time.Now().Unix() 72 session.Per = 1.0 73 session.QuotaRenewalRate = 300 // 5 minutes 74 session.QuotaRenews = time.Now().Unix() + 20 75 session.QuotaRemaining = 1 76 session.QuotaMax = -1 77 session.EnableHTTPSignatureValidation = true 78 session.RSACertificateId = pubCertId 79 session.Mutex = &sync.RWMutex{} 80 return session 81 } 82 83 func getHMACAuthChain(spec *APISpec) http.Handler { 84 remote, _ := url.Parse(TestHttpAny) 85 proxy := TykNewSingleHostReverseProxy(remote, spec, nil) 86 proxyHandler := ProxyHandler(proxy, spec) 87 baseMid := BaseMiddleware{Spec: spec, Proxy: proxy} 88 chain := alice.New(mwList( 89 &IPWhiteListMiddleware{baseMid}, 90 &IPBlackListMiddleware{BaseMiddleware: baseMid}, 91 &HTTPSignatureValidationMiddleware{BaseMiddleware: baseMid}, 92 &VersionCheck{BaseMiddleware: baseMid}, 93 &KeyExpired{baseMid}, 94 &AccessRightsCheck{baseMid}, 95 &RateLimitAndQuotaCheck{baseMid}, 96 )...).Then(proxyHandler) 97 return chain 98 } 99 100 type testAuthFailEventHandler struct { 101 cb func(config.EventMessage) 102 } 103 104 func (w *testAuthFailEventHandler) Init(handlerConf interface{}) error { 105 return nil 106 } 107 108 func (w *testAuthFailEventHandler) HandleEvent(em config.EventMessage) { 109 w.cb(em) 110 } 111 112 func waitTimeout(wg *sync.WaitGroup, timeout time.Duration) bool { 113 c := make(chan struct{}) 114 go func() { 115 defer close(c) 116 wg.Wait() 117 }() 118 select { 119 case <-c: 120 return false // completed normally 121 case <-time.After(timeout): 122 return true // timed out 123 } 124 } 125 126 func testPrepareHMACAuthSessionPass(tb testing.TB, hashFn func() hash.Hash, eventWG *sync.WaitGroup, withHeader bool, isBench bool) (string, *APISpec, *http.Request, string) { 127 spec := LoadSampleAPI(hmacAuthDef) 128 129 session := createHMACAuthSession() 130 131 // Should not receive an AuthFailure event 132 cb := func(em config.EventMessage) { 133 eventWG.Done() 134 } 135 spec.EventPaths = map[apidef.TykEvent][]config.TykEventHandler{ 136 "AuthFailure": {&testAuthFailEventHandler{cb}}, 137 } 138 139 sessionKey := "" 140 if isBench { 141 sessionKey = uuid.New() 142 } else { 143 sessionKey = "9876" 144 } 145 146 spec.SessionManager.UpdateSession(sessionKey, session, 60, false) 147 148 req := TestReq(tb, "GET", "/", nil) 149 150 refDate := "Mon, 02 Jan 2006 15:04:05 MST" 151 152 // Signature needs to be: Authorization: Signature keyId="hmac-key-1",algorithm="hmac-sha1",signature="Base64(HMAC-SHA1(signing string))" 153 154 // Prep the signature string 155 tim := time.Now().Format(refDate) 156 req.Header.Set("Date", tim) 157 signatureString := "" 158 if withHeader { 159 req.Header.Set("X-Test-1", "hello") 160 req.Header.Set("X-Test-2", "world") 161 signatureString = strings.ToLower("(request-target): ") + "get /\n" 162 signatureString += strings.ToLower("Date") + ": " + tim + "\n" 163 signatureString += strings.ToLower("X-Test-1") + ": " + "hello" + "\n" 164 signatureString += strings.ToLower("X-Test-2") + ": " + "world" 165 } else { 166 signatureString = strings.ToLower("Date") + ": " + tim 167 } 168 169 // Encode it 170 key := []byte(session.HmacSecret) 171 h := hmac.New(hashFn, key) 172 h.Write([]byte(signatureString)) 173 174 sigString := base64.StdEncoding.EncodeToString(h.Sum(nil)) 175 encodedString := url.QueryEscape(sigString) 176 177 return encodedString, spec, req, sessionKey 178 } 179 180 func testPrepareRSAAuthSessionPass(tb testing.TB, eventWG *sync.WaitGroup, privateKey *rsa.PrivateKey, pubCertId string, withHeader bool, isBench bool) (string, *APISpec, *http.Request, string) { 181 spec := LoadSampleAPI(hmacAuthDef) 182 session := createRSAAuthSession(pubCertId) 183 184 // Should not receive an AuthFailure event 185 cb := func(em config.EventMessage) { 186 eventWG.Done() 187 } 188 spec.EventPaths = map[apidef.TykEvent][]config.TykEventHandler{ 189 "AuthFailure": {&testAuthFailEventHandler{cb}}, 190 } 191 192 sessionKey := "" 193 if isBench { 194 sessionKey = uuid.New() 195 } else { 196 sessionKey = "9876" 197 } 198 199 spec.SessionManager.UpdateSession(sessionKey, session, 60, false) 200 201 req := TestReq(tb, "GET", "/", nil) 202 203 refDate := "Mon, 02 Jan 2006 15:04:05 MST" 204 205 // Signature needs to be: Authorization: Signature keyId="hmac-key-1",algorithm="hmac-sha1",signature="Base64(HMAC-SHA1(signing string))" 206 207 // Prep the signature string 208 tim := time.Now().Format(refDate) 209 req.Header.Set("Date", tim) 210 signatureString := "" 211 if withHeader { 212 req.Header.Set("X-Test-1", "hello") 213 req.Header.Set("X-Test-2", "world") 214 signatureString = strings.ToLower("(request-target): ") + "get /\n" 215 signatureString += strings.ToLower("Date") + ": " + tim + "\n" 216 signatureString += strings.ToLower("X-Test-1") + ": " + "hello" + "\n" 217 signatureString += strings.ToLower("X-Test-2") + ": " + "world" 218 } else { 219 signatureString = strings.ToLower("Date") + ": " + tim 220 } 221 222 h := sha256.New() 223 h.Write([]byte(signatureString)) 224 hashed := h.Sum(nil) 225 226 signature, _ := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, hashed) 227 228 sigString := base64.StdEncoding.EncodeToString(signature) 229 230 return sigString, spec, req, sessionKey 231 } 232 233 func TestHMACAuthSessionPass(t *testing.T) { 234 // Should not receive an AuthFailure event 235 var eventWG sync.WaitGroup 236 eventWG.Add(1) 237 encodedString, spec, req, sessionKey := testPrepareHMACAuthSessionPass(t, sha1.New, &eventWG, false, false) 238 239 recorder := httptest.NewRecorder() 240 req.Header.Set("Authorization", fmt.Sprintf("Signature keyId=\"%s\",algorithm=\"hmac-sha1\",signature=\"%s\"", sessionKey, encodedString)) 241 242 chain := getHMACAuthChain(spec) 243 chain.ServeHTTP(recorder, req) 244 245 if recorder.Code != 200 { 246 t.Error("Initial request failed with non-200 code, should have gone through!: \n", recorder.Code, recorder.Body.String()) 247 } 248 249 // Check we did not get our AuthFailure event 250 if !waitTimeout(&eventWG, 20*time.Millisecond) { 251 t.Error("Request should not have generated an AuthFailure event!: \n") 252 } 253 } 254 255 func TestHMACAuthSessionSHA512Pass(t *testing.T) { 256 // Should not receive an AuthFailure event 257 var eventWG sync.WaitGroup 258 eventWG.Add(1) 259 encodedString, spec, req, sessionKey := testPrepareHMACAuthSessionPass(t, sha512.New, &eventWG, false, false) 260 261 recorder := httptest.NewRecorder() 262 req.Header.Set("Authorization", fmt.Sprintf("Signature keyId=\"%s\",algorithm=\"hmac-sha512\",signature=\"%s\"", sessionKey, encodedString)) 263 264 spec.HmacAllowedAlgorithms = []string{"hmac-sha512"} 265 chain := getHMACAuthChain(spec) 266 chain.ServeHTTP(recorder, req) 267 268 if recorder.Code != 200 { 269 t.Error("Initial request failed with non-200 code, should have gone through!: \n", recorder.Code, recorder.Body.String()) 270 } 271 272 // Check we did not get our AuthFailure event 273 if !waitTimeout(&eventWG, 20*time.Millisecond) { 274 t.Error("Request should not have generated an AuthFailure event!: \n") 275 } 276 } 277 278 func BenchmarkHMACAuthSessionPass(b *testing.B) { 279 b.ReportAllocs() 280 281 var eventWG sync.WaitGroup 282 eventWG.Add(b.N) 283 encodedString, spec, req, sessionKey := testPrepareHMACAuthSessionPass(b, sha1.New, &eventWG, false, true) 284 285 recorder := httptest.NewRecorder() 286 req.Header.Set("Authorization", fmt.Sprintf("Signature keyId=\"%s\",algorithm=\"hmac-sha1\",signature=\"%s\"", sessionKey, encodedString)) 287 288 chain := getHMACAuthChain(spec) 289 290 for i := 0; i < b.N; i++ { 291 chain.ServeHTTP(recorder, req) 292 if recorder.Code != 200 { 293 b.Error("Initial request failed with non-200 code, should have gone through!: \n", recorder.Code, recorder.Body.String()) 294 } 295 } 296 } 297 298 func TestHMACAuthSessionAuxDateHeader(t *testing.T) { 299 spec := LoadSampleAPI(hmacAuthDef) 300 301 session := createHMACAuthSession() 302 303 // Should not receive an AuthFailure event 304 var eventWG sync.WaitGroup 305 eventWG.Add(1) 306 cb := func(em config.EventMessage) { 307 eventWG.Done() 308 } 309 spec.EventPaths = map[apidef.TykEvent][]config.TykEventHandler{ 310 "AuthFailure": {&testAuthFailEventHandler{cb}}, 311 } 312 313 // Basic auth sessions are stored as {org-id}{username}, so we need to append it here when we create the session. 314 spec.SessionManager.UpdateSession("9876", session, 60, false) 315 316 recorder := httptest.NewRecorder() 317 req := TestReq(t, "GET", "/", nil) 318 319 refDate := "Mon, 02 Jan 2006 15:04:05 MST" 320 321 // Signature needs to be: Authorization: Signature keyId="hmac-key-1",algorithm="hmac-sha1",signature="Base64(HMAC-SHA1(signing string))" 322 323 // Prep the signature string 324 tim := time.Now().Format(refDate) 325 req.Header.Set("x-aux-date", tim) 326 signatureString := strings.ToLower("x-aux-date") + ": " + tim 327 328 // Encode it 329 key := []byte(session.HmacSecret) 330 h := hmac.New(sha1.New, key) 331 h.Write([]byte(signatureString)) 332 333 sigString := base64.StdEncoding.EncodeToString(h.Sum(nil)) 334 encodedString := url.QueryEscape(sigString) 335 336 req.Header.Set("Authorization", fmt.Sprintf("Signature keyId=\"9876\",algorithm=\"hmac-sha1\",signature=\"%s\"", encodedString)) 337 338 chain := getHMACAuthChain(spec) 339 chain.ServeHTTP(recorder, req) 340 341 if recorder.Code != 200 { 342 t.Error("Initial request failed with non-200 code, should have gone through!: \n", recorder.Code) 343 } 344 345 // Check we did not get our AuthFailure event 346 if !waitTimeout(&eventWG, 20*time.Millisecond) { 347 t.Error("Request should not have generated an AuthFailure event!: \n") 348 } 349 } 350 351 func TestHMACAuthSessionFailureDateExpired(t *testing.T) { 352 spec := LoadSampleAPI(hmacAuthDef) 353 session := createHMACAuthSession() 354 355 // Should receive an AuthFailure event 356 var eventWG sync.WaitGroup 357 eventWG.Add(1) 358 cb := func(em config.EventMessage) { 359 eventWG.Done() 360 } 361 spec.EventPaths = map[apidef.TykEvent][]config.TykEventHandler{ 362 "AuthFailure": {&testAuthFailEventHandler{cb}}, 363 } 364 365 // Basic auth sessions are stored as {org-id}{username}, so we need to append it here when we create the session. 366 spec.SessionManager.UpdateSession("9876", session, 60, false) 367 368 recorder := httptest.NewRecorder() 369 req := TestReq(t, "GET", "/", nil) 370 371 refDate := "Mon, 02 Jan 2006 15:04:05 MST" 372 373 // Signature needs to be: Authorization: Signature keyId="hmac-key-1",algorithm="hmac-sha1",signature="Base64(HMAC-SHA1(signing string))" 374 375 // Prep the signature string 376 tim := time.Now().Format(refDate) 377 req.Header.Set("Date", tim) 378 signatureString := strings.ToLower("Date") + ":" + tim 379 380 // Encode it 381 key := []byte(session.HmacSecret) 382 h := hmac.New(sha1.New, key) 383 h.Write([]byte(signatureString)) 384 385 sigString := base64.StdEncoding.EncodeToString(h.Sum(nil)) 386 encodedString := url.QueryEscape(sigString) 387 388 req.Header.Set("Authorization", fmt.Sprintf("Signature keyId=\"9876\",algorithm=\"hmac-sha1\",signature=\"%s\"", encodedString)) 389 390 chain := getHMACAuthChain(spec) 391 chain.ServeHTTP(recorder, req) 392 393 if recorder.Code != 400 { 394 t.Error("Request should have failed with out of date error!: \n", recorder.Code) 395 } 396 397 // Check we did get our AuthFailure event 398 if waitTimeout(&eventWG, 20*time.Millisecond) { 399 t.Error("Request should have generated an AuthFailure event!: \n") 400 } 401 } 402 403 func TestHMACAuthSessionKeyMissing(t *testing.T) { 404 spec := LoadSampleAPI(hmacAuthDef) 405 session := createHMACAuthSession() 406 407 // Should receive an AuthFailure event 408 var eventWG sync.WaitGroup 409 eventWG.Add(1) 410 cb := func(em config.EventMessage) { 411 eventWG.Done() 412 } 413 spec.EventPaths = map[apidef.TykEvent][]config.TykEventHandler{ 414 "AuthFailure": {&testAuthFailEventHandler{cb}}, 415 } 416 417 // Basic auth sessions are stored as {org-id}{username}, so we need to append it here when we create the session. 418 spec.SessionManager.UpdateSession("9876", session, 60, false) 419 420 recorder := httptest.NewRecorder() 421 req := TestReq(t, "GET", "/", nil) 422 423 refDate := "Mon, 02 Jan 2006 15:04:05 MST" 424 425 // Signature needs to be: Authorization: Signature keyId="hmac-key-1",algorithm="hmac-sha1",signature="Base64(HMAC-SHA1(signing string))" 426 427 // Prep the signature string 428 tim := time.Now().Format(refDate) 429 req.Header.Set("Date", tim) 430 signatureString := strings.ToLower("Date") + ":" + tim 431 432 // Encode it 433 key := []byte(session.HmacSecret) 434 h := hmac.New(sha1.New, key) 435 h.Write([]byte(signatureString)) 436 437 sigString := base64.StdEncoding.EncodeToString(h.Sum(nil)) 438 encodedString := url.QueryEscape(sigString) 439 440 req.Header.Set("Authorization", fmt.Sprintf("Signature keyId=\"98765\",algorithm=\"hmac-sha1\",signature=\"%s\"", encodedString)) 441 442 chain := getHMACAuthChain(spec) 443 chain.ServeHTTP(recorder, req) 444 445 if recorder.Code != 400 { 446 t.Error("Request should have failed with key not found error!: \n", recorder.Code) 447 } 448 449 // Check we did get our AuthFailure event 450 if waitTimeout(&eventWG, 20*time.Millisecond) { 451 t.Error("Request should have generated an AuthFailure event!: \n") 452 } 453 } 454 455 func TestHMACAuthSessionMalformedHeader(t *testing.T) { 456 spec := LoadSampleAPI(hmacAuthDef) 457 session := createHMACAuthSession() 458 459 // Should receive an AuthFailure event 460 var eventWG sync.WaitGroup 461 eventWG.Add(1) 462 cb := func(em config.EventMessage) { 463 eventWG.Done() 464 } 465 spec.EventPaths = map[apidef.TykEvent][]config.TykEventHandler{ 466 "AuthFailure": {&testAuthFailEventHandler{cb}}, 467 } 468 469 // Basic auth sessions are stored as {org-id}{username}, so we need to append it here when we create the session. 470 spec.SessionManager.UpdateSession("9876", session, 60, false) 471 472 recorder := httptest.NewRecorder() 473 req := TestReq(t, "GET", "/", nil) 474 475 refDate := "Mon, 02 Jan 2006 15:04:05 MST" 476 477 // Signature needs to be: Authorization: Signature keyId="hmac-key-1",algorithm="hmac-sha1",signature="Base64(HMAC-SHA1(signing string))" 478 479 // Prep the signature string 480 tim := time.Now().Format(refDate) 481 req.Header.Set("Date", tim) 482 signatureString := strings.ToLower("Date") + ":" + tim 483 484 // Encode it 485 key := []byte(session.HmacSecret) 486 h := hmac.New(sha1.New, key) 487 h.Write([]byte(signatureString)) 488 489 sigString := base64.StdEncoding.EncodeToString(h.Sum(nil)) 490 encodedString := url.QueryEscape(sigString) 491 492 req.Header.Set("Authorization", fmt.Sprintf("Signature keyID=\"98765\", algorithm=\"hmac-sha256\", signature=\"%s\"", encodedString)) 493 494 chain := getHMACAuthChain(spec) 495 chain.ServeHTTP(recorder, req) 496 497 if recorder.Code != 400 { 498 t.Error("Request should have failed with key not found error!: \n", recorder.Code) 499 } 500 501 // Check we did get our AuthFailure event 502 if waitTimeout(&eventWG, 20*time.Millisecond) { 503 t.Error("Request should have generated an AuthFailure event!: \n") 504 } 505 } 506 507 func TestHMACAuthSessionPassWithHeaderField(t *testing.T) { 508 // Should not receive an AuthFailure event 509 var eventWG sync.WaitGroup 510 eventWG.Add(1) 511 encodedString, spec, req, sessionKey := testPrepareHMACAuthSessionPass(t, sha1.New, &eventWG, true, false) 512 513 recorder := httptest.NewRecorder() 514 req.Header.Set("Authorization", fmt.Sprintf("Signature keyId=\"%s\",algorithm=\"hmac-sha1\",headers=\"(request-target) date x-test-1 x-test-2\",signature=\"%s\"", sessionKey, encodedString)) 515 516 chain := getHMACAuthChain(spec) 517 chain.ServeHTTP(recorder, req) 518 519 if recorder.Code != 200 { 520 t.Error("Initial request failed with non-200 code, should have gone through!: \n", recorder.Code) 521 } 522 523 // Check we did not get our AuthFailure event 524 if !waitTimeout(&eventWG, 20*time.Millisecond) { 525 t.Error("Request should not have generated an AuthFailure event!: \n") 526 } 527 } 528 529 func BenchmarkHMACAuthSessionPassWithHeaderField(b *testing.B) { 530 b.ReportAllocs() 531 532 var eventWG sync.WaitGroup 533 eventWG.Add(b.N) 534 encodedString, spec, req, sessionKey := testPrepareHMACAuthSessionPass(b, sha1.New, &eventWG, true, true) 535 536 recorder := httptest.NewRecorder() 537 req.Header.Set("Authorization", fmt.Sprintf("Signature keyId=\"%s\",algorithm=\"hmac-sha1\",headers=\"(request-target) date x-test-1 x-test-2\",signature=\"%s\"", sessionKey, encodedString)) 538 539 chain := getHMACAuthChain(spec) 540 541 for i := 0; i < b.N; i++ { 542 chain.ServeHTTP(recorder, req) 543 if recorder.Code != 200 { 544 b.Error("Initial request failed with non-200 code, should have gone through!: \n", recorder.Code) 545 } 546 } 547 } 548 549 func getUpperCaseEscaped(signature string) []string { 550 r := regexp.MustCompile(`%[A-F0-9][A-F0-9]`) 551 foundList := r.FindAllString(signature, -1) 552 return foundList 553 } 554 555 func replaceUpperCase(originalSignature string, lowercaseList []string) string { 556 newSignature := originalSignature 557 for _, lStr := range lowercaseList { 558 asUpper := strings.ToLower(lStr) 559 newSignature = strings.Replace(newSignature, lStr, asUpper, -1) 560 } 561 562 return newSignature 563 } 564 565 func TestHMACAuthSessionPassWithHeaderFieldLowerCase(t *testing.T) { 566 spec := LoadSampleAPI(hmacAuthDef) 567 session := createHMACAuthSession() 568 569 // Should not receive an AuthFailure event 570 var eventWG sync.WaitGroup 571 eventWG.Add(1) 572 cb := func(em config.EventMessage) { 573 eventWG.Done() 574 } 575 spec.EventPaths = map[apidef.TykEvent][]config.TykEventHandler{ 576 "AuthFailure": {&testAuthFailEventHandler{cb}}, 577 } 578 579 // Basic auth sessions are stored as {org-id}{username}, so we need to append it here when we create the session. 580 spec.SessionManager.UpdateSession("9876", session, 60, false) 581 582 recorder := httptest.NewRecorder() 583 req := TestReq(t, "GET", "/", nil) 584 585 refDate := "Mon, 02 Jan 2006 15:04:05 MST" 586 587 // Signature needs to be: Authorization: Signature keyId="hmac-key-1",algorithm="hmac-sha1",signature="Base64(HMAC-SHA1(signing string))" 588 589 // Prep the signature string 590 tim := time.Now().Format(refDate) 591 req.Header.Set("Date", tim) 592 req.Header.Set("X-Test-1", "hello?") 593 req.Header.Set("X-Test-2", "world£") 594 signatureString := strings.ToLower("(request-target): ") + "get /\n" 595 signatureString += strings.ToLower("Date") + ": " + tim + "\n" 596 signatureString += strings.ToLower("X-Test-1") + ": " + "hello?" + "\n" 597 signatureString += strings.ToLower("X-Test-2") + ": " + "world£" 598 599 // Encode it 600 key := []byte(session.HmacSecret) 601 h := hmac.New(sha1.New, key) 602 h.Write([]byte(signatureString)) 603 604 sigString := base64.StdEncoding.EncodeToString(h.Sum(nil)) 605 encodedString := url.QueryEscape(sigString) 606 607 upperCaseList := getUpperCaseEscaped(encodedString) 608 newEncodedSignature := replaceUpperCase(encodedString, upperCaseList) 609 610 req.Header.Set("Authorization", fmt.Sprintf("Signature keyId=\"9876\",algorithm=\"hmac-sha1\",headers=\"(request-target) date x-test-1 x-test-2\",signature=\"%s\"", newEncodedSignature)) 611 612 chain := getHMACAuthChain(spec) 613 chain.ServeHTTP(recorder, req) 614 615 if recorder.Code != 200 { 616 t.Error("Initial request failed with non-200 code, should have gone through!: \n", recorder.Code) 617 } 618 619 // Check we did not get our AuthFailure event 620 if !waitTimeout(&eventWG, 20*time.Millisecond) { 621 t.Error("Request should not have generated an AuthFailure event!: \n") 622 } 623 } 624 625 func TestGetFieldValues(t *testing.T) { 626 key := `eyJvcmciOiI1ZDgzOTczNDk4NThkYzEwYWU3NjA2ZjQiLCJpZCI6ImU2M2M2MTg4ZjFlYzQ2NzU4N2VlMTA1MzZkYmFjMzk0IiwiaCI6Im11cm11cjY0In0=` 627 algo := `hmac-sha1` 628 sign := `j27%2FQtZHmlQuWmnQT%2BxLjHcgPl8%3D` 629 s := `KeyId="eyJvcmciOiI1ZDgzOTczNDk4NThkYzEwYWU3NjA2ZjQiLCJpZCI6ImU2M2M2MTg4ZjFlYzQ2NzU4N2VlMTA1MzZkYmFjMzk0IiwiaCI6Im11cm11cjY0In0=",algorithm="hmac-sha1",signature="j27%2FQtZHmlQuWmnQT%2BxLjHcgPl8%3D"` 630 h, err := getFieldValues(s) 631 if err != nil { 632 t.Fatal(err) 633 } 634 if h.KeyID != key { 635 t.Errorf("expected keyID:%s got %s", key, h.KeyID) 636 } 637 if h.Algorthm != algo { 638 t.Errorf("expected Algorithm:%s got %s", algo, h.Algorthm) 639 } 640 if h.Signature != sign { 641 t.Errorf("expected Signature:%s got %s", sign, h.Signature) 642 } 643 } 644 645 func TestRSAAuthSessionPass(t *testing.T) { 646 _, _, _, serverCert := genServerCertificate() 647 privateKey := serverCert.PrivateKey.(*rsa.PrivateKey) 648 x509Cert, _ := x509.ParseCertificate(serverCert.Certificate[0]) 649 pubDer, _ := x509.MarshalPKIXPublicKey(x509Cert.PublicKey) 650 pubPem := pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: pubDer}) 651 pubID, _ := CertificateManager.Add(pubPem, "") 652 defer CertificateManager.Delete(pubID, "") 653 654 // Should not receive an AuthFailure event 655 var eventWG sync.WaitGroup 656 eventWG.Add(1) 657 encodedString, spec, req, sessionKey := testPrepareRSAAuthSessionPass(t, &eventWG, privateKey, pubID, false, false) 658 659 recorder := httptest.NewRecorder() 660 req.Header.Set("Authorization", fmt.Sprintf("Signature keyId=\"%s\",algorithm=\"rsa-sha256\",signature=\"%s\"", sessionKey, encodedString)) 661 662 chain := getHMACAuthChain(spec) 663 chain.ServeHTTP(recorder, req) 664 665 if recorder.Code != 200 { 666 t.Error("Initial request failed with non-200 code, should have gone through!: \n", recorder.Code, recorder.Body.String()) 667 } 668 669 // Check we did not get our AuthFailure event 670 if !waitTimeout(&eventWG, 20*time.Millisecond) { 671 t.Error("Request should not have generated an AuthFailure event!: \n") 672 } 673 } 674 675 func BenchmarkRSAAuthSessionPass(b *testing.B) { 676 b.ReportAllocs() 677 678 _, _, _, serverCert := genServerCertificate() 679 privateKey := serverCert.PrivateKey.(*rsa.PrivateKey) 680 x509Cert, _ := x509.ParseCertificate(serverCert.Certificate[0]) 681 pubDer, _ := x509.MarshalPKIXPublicKey(x509Cert.PublicKey) 682 pubPem := pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: pubDer}) 683 pubID, _ := CertificateManager.Add(pubPem, "") 684 defer CertificateManager.Delete(pubID, "") 685 686 var eventWG sync.WaitGroup 687 eventWG.Add(b.N) 688 encodedString, spec, req, sessionKey := testPrepareRSAAuthSessionPass(b, &eventWG, privateKey, pubID, false, true) 689 690 recorder := httptest.NewRecorder() 691 req.Header.Set("Authorization", fmt.Sprintf("Signature keyId=\"%s\",algorithm=\"rsa-sha256\",signature=\"%s\"", sessionKey, encodedString)) 692 693 chain := getHMACAuthChain(spec) 694 695 for i := 0; i < b.N; i++ { 696 chain.ServeHTTP(recorder, req) 697 if recorder.Code != 200 { 698 b.Error("Initial request failed with non-200 code, should have gone through!: \n", recorder.Code, recorder.Body.String()) 699 } 700 } 701 } 702 703 func TestRSAAuthSessionKeyMissing(t *testing.T) { 704 _, _, _, serverCert := genServerCertificate() 705 privateKey := serverCert.PrivateKey.(*rsa.PrivateKey) 706 x509Cert, _ := x509.ParseCertificate(serverCert.Certificate[0]) 707 pubDer, _ := x509.MarshalPKIXPublicKey(x509Cert.PublicKey) 708 pubPem := pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: pubDer}) 709 pubID, _ := CertificateManager.Add(pubPem, "") 710 defer CertificateManager.Delete(pubID, "") 711 712 spec := LoadSampleAPI(hmacAuthDef) 713 714 // Should receive an AuthFailure event 715 var eventWG sync.WaitGroup 716 eventWG.Add(1) 717 cb := func(em config.EventMessage) { 718 eventWG.Done() 719 } 720 spec.EventPaths = map[apidef.TykEvent][]config.TykEventHandler{ 721 "AuthFailure": {&testAuthFailEventHandler{cb}}, 722 } 723 724 recorder := httptest.NewRecorder() 725 encodedString, spec, req, _ := testPrepareRSAAuthSessionPass(t, &eventWG, privateKey, pubID, false, false) 726 727 req.Header.Set("Authorization", fmt.Sprintf("Signature keyId=\"98765\",algorithm=\"rsa-sha256\",signature=\"%s\"", encodedString)) 728 729 chain := getHMACAuthChain(spec) 730 chain.ServeHTTP(recorder, req) 731 732 if recorder.Code != 400 { 733 t.Error("Request should have failed with key not found error!: \n", recorder.Code) 734 } 735 736 // Check we did get our AuthFailure event 737 if waitTimeout(&eventWG, 20*time.Millisecond) { 738 t.Error("Request should have generated an AuthFailure event!: \n") 739 } 740 }