github.com/dbernstein1/tyk@v2.9.0-beta9-dl-apic+incompatible/gateway/oauth_manager_test.go (about) 1 package gateway 2 3 /* 4 NOTE: Requires the test tyk.conf to be in place and the settings to b correct - ugly, I know, but necessary for the end to end to work correctly. 5 */ 6 7 import ( 8 "bytes" 9 "encoding/json" 10 "net/url" 11 "reflect" 12 "strings" 13 "testing" 14 15 "fmt" 16 17 "net/http" 18 19 "time" 20 21 "github.com/lonelycode/osin" 22 uuid "github.com/satori/go.uuid" 23 24 "github.com/TykTechnologies/tyk/apidef" 25 "github.com/TykTechnologies/tyk/config" 26 "github.com/TykTechnologies/tyk/storage" 27 "github.com/TykTechnologies/tyk/test" 28 "github.com/TykTechnologies/tyk/user" 29 ) 30 31 const ( 32 authRedirectUri = "http://client.oauth.com" 33 authRedirectUri2 = "http://client2.oauth.com" 34 authClientID = "1234" 35 authClientSecret = "aabbccdd" 36 ) 37 38 const keyRules = `{ 39 "last_check": 1402492859, 40 "org_id": "53ac07777cbb8c2d53000002", 41 "rate": 1, 42 "per": 1, 43 "quota_max": -1, 44 "quota_renews": 1399567002, 45 "quota_remaining": 10, 46 "quota_renewal_rate": 300 47 }` 48 49 func buildTestOAuthSpec(apiGens ...func(spec *APISpec)) *APISpec { 50 return BuildAPI(func(spec *APISpec) { 51 spec.APIID = "999999" 52 spec.OrgID = "default" 53 spec.Auth = apidef.Auth{ 54 AuthHeaderName: "authorization", 55 } 56 spec.UseKeylessAccess = false 57 spec.UseOauth2 = true 58 spec.Oauth2Meta = struct { 59 AllowedAccessTypes []osin.AccessRequestType `bson:"allowed_access_types" json:"allowed_access_types"` 60 AllowedAuthorizeTypes []osin.AuthorizeRequestType `bson:"allowed_authorize_types" json:"allowed_authorize_types"` 61 AuthorizeLoginRedirect string `bson:"auth_login_redirect" json:"auth_login_redirect"` 62 }{ 63 AllowedAccessTypes: []osin.AccessRequestType{ 64 "authorization_code", 65 "refresh_token", 66 "client_credentials", 67 }, 68 AllowedAuthorizeTypes: []osin.AuthorizeRequestType{ 69 "code", 70 "token", 71 }, 72 AuthorizeLoginRedirect: testHttpPost, 73 } 74 spec.NotificationsDetails = apidef.NotificationsManager{ 75 SharedSecret: "9878767657654343123434556564444", 76 OAuthKeyChangeURL: testHttpPost, 77 } 78 spec.VersionData = struct { 79 NotVersioned bool `bson:"not_versioned" json:"not_versioned"` 80 DefaultVersion string `bson:"default_version" json:"default_version"` 81 Versions map[string]apidef.VersionInfo `bson:"versions" json:"versions"` 82 }{ 83 NotVersioned: true, 84 Versions: map[string]apidef.VersionInfo{ 85 "v1": { 86 Name: "v1", 87 }, 88 }, 89 } 90 spec.Proxy.ListenPath = "/APIID/" 91 spec.Proxy.StripListenPath = true 92 93 if len(apiGens) > 0 { 94 apiGens[0](spec) 95 } 96 })[0] 97 } 98 99 func loadTestOAuthSpec() *APISpec { 100 return LoadAPI(buildTestOAuthSpec())[0] 101 } 102 103 func createTestOAuthClient(spec *APISpec, clientID string) { 104 pID := CreatePolicy(func(p *user.Policy) { 105 p.ID = "TEST-4321" 106 p.AccessRights = map[string]user.AccessDefinition{ 107 "test": { 108 APIID: "test", 109 }, 110 "abc": { 111 APIID: "abc", 112 }, 113 } 114 }) 115 116 var redirectURI string 117 // If separator is not set that means multiple redirect uris not supported 118 if config.Global().OauthRedirectUriSeparator == "" { 119 redirectURI = "http://client.oauth.com" 120 121 // If separator config is set that means multiple redirect uris are supported 122 } else { 123 redirectURI = strings.Join([]string{"http://client.oauth.com", "http://client2.oauth.com", "http://client3.oauth.com"}, config.Global().OauthRedirectUriSeparator) 124 } 125 testClient := OAuthClient{ 126 ClientID: clientID, 127 ClientSecret: authClientSecret, 128 ClientRedirectURI: redirectURI, 129 PolicyID: pID, 130 } 131 spec.OAuthManager.OsinServer.Storage.SetClient(testClient.ClientID, &testClient, false) 132 } 133 134 func TestOauthMultipleAPIs(t *testing.T) { 135 ts := StartTest() 136 defer ts.Close() 137 138 spec := buildTestOAuthSpec(func(spec *APISpec) { 139 spec.APIID = "oauth2" 140 spec.UseOauth2 = true 141 spec.UseKeylessAccess = false 142 spec.Proxy.ListenPath = "/api1/" 143 }) 144 spec2 := buildTestOAuthSpec(func(spec *APISpec) { 145 spec.APIID = "oauth2_copy" 146 spec.UseKeylessAccess = false 147 spec.UseOauth2 = true 148 spec.Proxy.ListenPath = "/api2/" 149 }) 150 151 apis := LoadAPI(spec, spec2) 152 spec = apis[0] 153 spec2 = apis[1] 154 155 pID := CreatePolicy(func(p *user.Policy) { 156 p.AccessRights = map[string]user.AccessDefinition{ 157 "oauth2": { 158 APIID: "oauth2", 159 }, 160 "oauth2_copy": { 161 APIID: "oauth2_copy", 162 }, 163 } 164 }) 165 166 testClient := OAuthClient{ 167 ClientID: authClientID, 168 ClientSecret: authClientSecret, 169 ClientRedirectURI: authRedirectUri, 170 PolicyID: pID, 171 } 172 spec.OAuthManager.OsinServer.Storage.SetClient(testClient.ClientID, &testClient, false) 173 spec2.OAuthManager.OsinServer.Storage.SetClient(testClient.ClientID, &testClient, false) 174 175 param := make(url.Values) 176 param.Set("response_type", "token") 177 param.Set("redirect_uri", authRedirectUri) 178 param.Set("client_id", authClientID) 179 param.Set("key_rules", keyRules) 180 181 headers := map[string]string{ 182 "Content-Type": "application/x-www-form-urlencoded", 183 } 184 185 var err error 186 resp, err := ts.Run(t, test.TestCase{ 187 Path: "/api1/tyk/oauth/authorize-client/", 188 AdminAuth: true, 189 Data: param.Encode(), 190 Headers: headers, 191 Method: http.MethodPost, 192 Code: http.StatusOK, 193 BodyMatch: `"access_token"`, 194 }) 195 if err != nil { 196 t.Fatal(err) 197 } 198 199 token := tokenData{} 200 json.NewDecoder(resp.Body).Decode(&token) 201 authHeader := map[string]string{ 202 "Authorization": "Bearer " + token.AccessToken, 203 } 204 205 ts.Run(t, 206 test.TestCase{ 207 Path: "/api1/get", 208 Headers: authHeader, 209 Method: http.MethodGet, 210 Code: http.StatusOK, 211 }, 212 test.TestCase{ 213 Path: "/api2/get", 214 Headers: authHeader, 215 Method: http.MethodGet, 216 Code: http.StatusOK, 217 }, 218 ) 219 } 220 221 func TestAuthCodeRedirect(t *testing.T) { 222 ts := StartTest() 223 defer ts.Close() 224 225 spec := loadTestOAuthSpec() 226 227 createTestOAuthClient(spec, authClientID) 228 229 client := &http.Client{ 230 CheckRedirect: func(req *http.Request, via []*http.Request) error { 231 return http.ErrUseLastResponse 232 }, 233 } 234 235 t.Run("Authorize request with redirect", func(t *testing.T) { 236 param := make(url.Values) 237 param.Set("response_type", "code") 238 param.Set("redirect_uri", authRedirectUri) 239 param.Set("client_id", authClientID) 240 241 headers := map[string]string{ 242 "Content-Type": "application/x-www-form-urlencoded", 243 } 244 245 ts.Run(t, test.TestCase{ 246 Path: "/APIID/oauth/authorize/", 247 Data: param.Encode(), 248 Headers: headers, 249 Method: http.MethodPost, 250 Client: client, 251 Code: http.StatusTemporaryRedirect, 252 }) 253 }) 254 } 255 256 func TestAuthCodeRedirectMultipleURL(t *testing.T) { 257 // Enable multiple Redirect URIs 258 globalConf := config.Global() 259 globalConf.OauthRedirectUriSeparator = "," 260 config.SetGlobal(globalConf) 261 defer ResetTestConfig() 262 263 ts := StartTest() 264 defer ts.Close() 265 266 spec := loadTestOAuthSpec() 267 268 createTestOAuthClient(spec, authClientID) 269 270 client := &http.Client{ 271 CheckRedirect: func(req *http.Request, via []*http.Request) error { 272 return http.ErrUseLastResponse 273 }, 274 } 275 276 t.Run("Client authorize request with multiple redirect URI", func(t *testing.T) { 277 param := make(url.Values) 278 param.Set("response_type", "code") 279 param.Set("redirect_uri", authRedirectUri2) 280 param.Set("client_id", authClientID) 281 282 headers := map[string]string{ 283 "Content-Type": "application/x-www-form-urlencoded", 284 } 285 286 ts.Run(t, test.TestCase{ 287 Path: "/APIID/oauth/authorize/", 288 Data: param.Encode(), 289 Headers: headers, 290 Method: http.MethodPost, 291 Code: http.StatusTemporaryRedirect, 292 Client: client, 293 }) 294 }) 295 } 296 297 func TestAuthCodeRedirectInvalidMultipleURL(t *testing.T) { 298 // Disable multiple Redirect URIs 299 globalConf := config.Global() 300 globalConf.OauthRedirectUriSeparator = "" 301 config.SetGlobal(globalConf) 302 defer ResetTestConfig() 303 304 ts := StartTest() 305 defer ts.Close() 306 307 spec := loadTestOAuthSpec() 308 309 createTestOAuthClient(spec, authClientID) 310 311 t.Run("Client authorize request with invalid redirect URI", func(t *testing.T) { 312 param := make(url.Values) 313 param.Set("response_type", "code") 314 param.Set("redirect_uri", authRedirectUri2) 315 param.Set("client_id", authClientID) 316 317 headers := map[string]string{ 318 "Content-Type": "application/x-www-form-urlencoded", 319 } 320 321 ts.Run(t, test.TestCase{ 322 Path: "/APIID/oauth/authorize/", 323 Data: param.Encode(), 324 Headers: headers, 325 Method: http.MethodPost, 326 Code: http.StatusForbidden, 327 }) 328 }) 329 } 330 331 func TestAPIClientAuthorizeAuthCode(t *testing.T) { 332 ts := StartTest() 333 defer ts.Close() 334 335 spec := loadTestOAuthSpec() 336 337 createTestOAuthClient(spec, authClientID) 338 339 t.Run("Client authorize code request", func(t *testing.T) { 340 param := make(url.Values) 341 param.Set("response_type", "code") 342 param.Set("redirect_uri", authRedirectUri) 343 param.Set("client_id", authClientID) 344 param.Set("key_rules", keyRules) 345 346 headers := map[string]string{ 347 "Content-Type": "application/x-www-form-urlencoded", 348 } 349 350 ts.Run(t, test.TestCase{ 351 Path: "/APIID/tyk/oauth/authorize-client/", 352 AdminAuth: true, 353 Data: param.Encode(), 354 Headers: headers, 355 Method: http.MethodPost, 356 Code: http.StatusOK, 357 BodyMatch: `"code"`, 358 }) 359 }) 360 } 361 362 func TestAPIClientAuthorizeToken(t *testing.T) { 363 ts := StartTest() 364 defer ts.Close() 365 366 spec := loadTestOAuthSpec() 367 368 createTestOAuthClient(spec, authClientID) 369 370 t.Run("Client authorize token request", func(t *testing.T) { 371 param := make(url.Values) 372 param.Set("response_type", "token") 373 param.Set("redirect_uri", authRedirectUri) 374 param.Set("client_id", authClientID) 375 param.Set("key_rules", keyRules) 376 377 headers := map[string]string{ 378 "Content-Type": "application/x-www-form-urlencoded", 379 } 380 381 ts.Run(t, test.TestCase{ 382 Path: "/APIID/tyk/oauth/authorize-client/", 383 AdminAuth: true, 384 Data: param.Encode(), 385 Headers: headers, 386 Method: http.MethodPost, 387 Code: http.StatusOK, 388 BodyMatch: `"access_token"`, 389 }) 390 }) 391 } 392 393 func TestDeleteOauthClient(t *testing.T) { 394 ts := StartTest() 395 defer ts.Close() 396 397 spec := loadTestOAuthSpec() 398 399 createTestOAuthClient(spec, authClientID) 400 401 var resp *http.Response 402 403 t.Run("Client authorize token request", func(t *testing.T) { 404 param := make(url.Values) 405 param.Set("response_type", "token") 406 param.Set("redirect_uri", authRedirectUri) 407 param.Set("client_id", authClientID) 408 param.Set("key_rules", keyRules) 409 410 headers := map[string]string{ 411 "Content-Type": "application/x-www-form-urlencoded", 412 } 413 414 var err error 415 resp, err = ts.Run(t, test.TestCase{ 416 Path: "/APIID/tyk/oauth/authorize-client/", 417 AdminAuth: true, 418 Data: param.Encode(), 419 Headers: headers, 420 Method: http.MethodPost, 421 Code: http.StatusOK, 422 BodyMatch: `"access_token"`, 423 }) 424 if err != nil { 425 t.Error(err) 426 } 427 }) 428 429 token := tokenData{} 430 json.NewDecoder(resp.Body).Decode(&token) 431 authHeader := map[string]string{ 432 "Authorization": "Bearer " + token.AccessToken, 433 } 434 t.Run("Make request to API with supplying token", func(t *testing.T) { 435 ts.Run(t, test.TestCase{ 436 Path: "/APIID/get", 437 Headers: authHeader, 438 Method: http.MethodGet, 439 Code: http.StatusOK, 440 }) 441 }) 442 443 t.Run("Delete OAuth-client and check that it is gone", func(t *testing.T) { 444 ts.Run(t, 445 test.TestCase{ 446 Path: "/tyk/oauth/clients/999999/" + authClientID, 447 AdminAuth: true, 448 Method: http.MethodDelete, 449 Code: http.StatusOK, 450 }, 451 test.TestCase{ 452 Path: "/tyk/oauth/clients/999999/" + authClientID, 453 AdminAuth: true, 454 Method: http.MethodGet, 455 Code: http.StatusNotFound, 456 Delay: 1100 * time.Millisecond, // we need this to have deleted oauth client expired in memory cache 457 }, 458 ) 459 }) 460 461 t.Run("Make sure token issued for deleted oauth-client cannot be used", func(t *testing.T) { 462 ts.Run(t, 463 test.TestCase{ 464 Path: "/APIID/get", 465 Headers: authHeader, 466 Method: http.MethodGet, 467 Code: http.StatusForbidden, 468 }, 469 test.TestCase{ 470 Path: "/APIID/get", 471 Headers: authHeader, 472 Method: http.MethodGet, 473 Code: http.StatusForbidden, 474 }, 475 test.TestCase{ 476 Path: "/APIID/get", 477 Headers: authHeader, 478 Method: http.MethodGet, 479 Code: http.StatusForbidden, 480 }, 481 ) 482 }) 483 484 } 485 486 func TestAPIClientAuthorizeTokenWithPolicy(t *testing.T) { 487 ts := StartTest() 488 defer ts.Close() 489 490 spec := loadTestOAuthSpec() 491 492 createTestOAuthClient(spec, authClientID) 493 494 t.Run("Client authorize token with policy request", func(t *testing.T) { 495 param := make(url.Values) 496 param.Set("response_type", "token") 497 param.Set("redirect_uri", authRedirectUri) 498 param.Set("client_id", authClientID) 499 500 headers := map[string]string{ 501 "Content-Type": "application/x-www-form-urlencoded", 502 } 503 504 resp, err := ts.Run(t, test.TestCase{ 505 Path: "/APIID/tyk/oauth/authorize-client/", 506 AdminAuth: true, 507 Data: param.Encode(), 508 Headers: headers, 509 Method: http.MethodPost, 510 Code: http.StatusOK, 511 }) 512 if err != nil { 513 t.Error(err) 514 } 515 516 // check response 517 asData := make(map[string]interface{}) 518 if err := json.NewDecoder(resp.Body).Decode(&asData); err != nil { 519 t.Fatal("Decode failed:", err) 520 } 521 token, ok := asData["access_token"].(string) 522 if !ok { 523 t.Fatal("No access token found") 524 } 525 526 // Verify the token is correct 527 session, ok := spec.AuthManager.KeyAuthorised(token) 528 if !ok { 529 t.Error("Key was not created (Can't find it)!") 530 } 531 532 if !reflect.DeepEqual(session.PolicyIDs(), []string{"TEST-4321"}) { 533 t.Error("Policy not added to token!", session.PolicyIDs()) 534 } 535 }) 536 } 537 538 func getAuthCode(t *testing.T, ts *Test) map[string]string { 539 param := make(url.Values) 540 param.Set("response_type", "code") 541 param.Set("redirect_uri", authRedirectUri) 542 param.Set("client_id", authClientID) 543 param.Set("key_rules", keyRules) 544 545 headers := map[string]string{"Content-Type": "application/x-www-form-urlencoded"} 546 547 resp, err := ts.Run(t, test.TestCase{ 548 Path: "/APIID/tyk/oauth/authorize-client/", 549 AdminAuth: true, 550 Data: param.Encode(), 551 Headers: headers, 552 Method: http.MethodPost, 553 Code: http.StatusOK, 554 }) 555 556 if err != nil { 557 t.Error(err) 558 } 559 560 response := map[string]string{} 561 json.NewDecoder(resp.Body).Decode(&response) 562 return response 563 } 564 565 func TestGetPaginatedClientTokens(t *testing.T) { 566 testPagination := func(pageParam int, expectedPageNumber int, tokenRequestCount int, expectedRes int) { 567 globalConf := config.Global() 568 // set tokens to be expired after 100 seconds 569 globalConf.OauthTokenExpire = 100 570 // cleanup tokens older than 300 seconds 571 globalConf.OauthTokenExpiredRetainPeriod = 300 572 573 config.SetGlobal(globalConf) 574 575 defer ResetTestConfig() 576 577 ts := StartTest() 578 defer ts.Close() 579 580 spec := loadTestOAuthSpec() 581 582 clientID := uuid.NewV4().String() 583 createTestOAuthClient(spec, clientID) 584 585 tokensID := map[string]bool{} 586 param := make(url.Values) 587 param.Set("response_type", "token") 588 param.Set("redirect_uri", authRedirectUri) 589 param.Set("client_id", clientID) 590 param.Set("client_secret", authClientSecret) 591 param.Set("key_rules", keyRules) 592 593 headers := map[string]string{ 594 "Content-Type": "application/x-www-form-urlencoded", 595 } 596 597 for i := 0; i < tokenRequestCount; i++ { 598 resp, err := ts.Run(t, test.TestCase{ 599 Path: "/APIID/tyk/oauth/authorize-client/", 600 Data: param.Encode(), 601 AdminAuth: true, 602 Headers: headers, 603 Method: http.MethodPost, 604 Code: http.StatusOK, 605 }) 606 if err != nil { 607 t.Error(err) 608 } 609 610 response := map[string]interface{}{} 611 if err := json.NewDecoder(resp.Body).Decode(&response); err != nil { 612 t.Fatal(err) 613 } 614 615 // save tokens for future check 616 tokensID[response["access_token"].(string)] = true 617 } 618 619 resp, err := ts.Run(t, test.TestCase{ 620 // strconv#Atoi successfully parses a negative integer 621 // so make sure it is being reset to the first page 622 Path: fmt.Sprintf("/tyk/oauth/clients/999999/%s/tokens?page=%d", clientID, pageParam), 623 AdminAuth: true, 624 Method: http.MethodGet, 625 Code: http.StatusOK, 626 }) 627 if err != nil { 628 t.Error(err) 629 } 630 631 tokensResp := paginatedOAuthClientTokens{} 632 if err := json.NewDecoder(resp.Body).Decode(&tokensResp); err != nil { 633 t.Fatal(err) 634 } 635 636 // check response 637 if len(tokensResp.Tokens) != expectedRes { 638 t.Errorf("Wrong number of tokens received. Expected: %d. Got: %d", expectedRes, len(tokensResp.Tokens)) 639 } 640 641 for _, token := range tokensResp.Tokens { 642 if !tokensID[token.Token] { 643 t.Errorf("Token %s is not found in expected result. Expecting: %v", token.Token, tokensID) 644 } 645 } 646 647 // Also inspect the pagination data information 648 if expectedPageNumber != tokensResp.Pagination.PageNum { 649 t.Errorf("Page number, expected %d, got %d", expectedPageNumber, tokensResp.Pagination.PageNum) 650 } 651 } 652 653 t.Run("Negative value should return first page", func(t *testing.T) { 654 testPagination(-3, 1, 110, 100) 655 }) 656 657 t.Run("First page, less than items per page", func(t *testing.T) { 658 testPagination(1, 1, 85, 85) 659 }) 660 661 t.Run("First page, greater than items per page", func(t *testing.T) { 662 testPagination(1, 1, 110, 100) 663 }) 664 665 t.Run("Second page, greater than items per page", func(t *testing.T) { 666 testPagination(2, 2, 110, 10) 667 }) 668 669 t.Run("Second page, multiple of items per page", func(t *testing.T) { 670 testPagination(2, 2, 200, 100) 671 }) 672 } 673 674 func TestGetClientTokens(t *testing.T) { 675 t.Run("Without hashing", func(t *testing.T) { 676 testGetClientTokens(t, false) 677 }) 678 t.Run("With hashing", func(t *testing.T) { 679 testGetClientTokens(t, true) 680 }) 681 } 682 683 func testGetClientTokens(t *testing.T, hashed bool) { 684 globalConf := config.Global() 685 // set tokens to be expired after 1 second 686 globalConf.OauthTokenExpire = 1 687 // cleanup tokens older than 3 seconds 688 globalConf.OauthTokenExpiredRetainPeriod = 3 689 690 globalConf.HashKeys = hashed 691 692 config.SetGlobal(globalConf) 693 694 defer ResetTestConfig() 695 696 ts := StartTest() 697 defer ts.Close() 698 699 spec := loadTestOAuthSpec() 700 701 clientID := uuid.NewV4().String() 702 createTestOAuthClient(spec, clientID) 703 704 // make three tokens 705 tokensID := map[string]bool{} 706 t.Run("Send three token requests", func(t *testing.T) { 707 param := make(url.Values) 708 param.Set("response_type", "token") 709 param.Set("redirect_uri", authRedirectUri) 710 param.Set("client_id", clientID) 711 param.Set("client_secret", authClientSecret) 712 param.Set("key_rules", keyRules) 713 714 headers := map[string]string{ 715 "Content-Type": "application/x-www-form-urlencoded", 716 } 717 718 for i := 0; i < 3; i++ { 719 resp, err := ts.Run(t, test.TestCase{ 720 Path: "/APIID/tyk/oauth/authorize-client/", 721 Data: param.Encode(), 722 AdminAuth: true, 723 Headers: headers, 724 Method: http.MethodPost, 725 Code: http.StatusOK, 726 }) 727 if err != nil { 728 t.Error(err) 729 } 730 731 response := map[string]interface{}{} 732 if err := json.NewDecoder(resp.Body).Decode(&response); err != nil { 733 t.Fatal(err) 734 } 735 736 if hashed { 737 // save tokens for future check 738 tokensID[storage.HashKey(response["access_token"].(string))] = true 739 } else { 740 tokensID[response["access_token"].(string)] = true 741 } 742 } 743 }) 744 745 // get list of tokens 746 t.Run("Get list of tokens", func(t *testing.T) { 747 resp, err := ts.Run(t, test.TestCase{ 748 Path: fmt.Sprintf("/tyk/oauth/clients/999999/%s/tokens", clientID), 749 AdminAuth: true, 750 Method: http.MethodGet, 751 Code: http.StatusOK, 752 }) 753 if err != nil { 754 t.Error(err) 755 } 756 757 tokensResp := []OAuthClientToken{} 758 if err := json.NewDecoder(resp.Body).Decode(&tokensResp); err != nil { 759 t.Fatal(err) 760 } 761 762 // check response 763 if n := len(tokensID); len(tokensResp) != n { 764 t.Errorf("Wrong number of tokens received. Expected: %d. Got: %d", n, len(tokensResp)) 765 } 766 767 for _, token := range tokensResp { 768 if !tokensID[token.Token] { 769 t.Errorf("Token %s is not found in expected result. Expecting: %v", token.Token, tokensID) 770 } 771 } 772 }) 773 774 t.Run("Get list of tokens after they expire", func(t *testing.T) { 775 // sleep to wait until tokens expire 776 time.Sleep(2 * time.Second) 777 778 resp, err := ts.Run(t, test.TestCase{ 779 Path: fmt.Sprintf("/tyk/oauth/clients/999999/%s/tokens", clientID), 780 AdminAuth: true, 781 Method: http.MethodGet, 782 Code: http.StatusOK, 783 }) 784 if err != nil { 785 t.Error(err) 786 } 787 788 // check response 789 tokensResp := []OAuthClientToken{} 790 if err := json.NewDecoder(resp.Body).Decode(&tokensResp); err != nil { 791 t.Fatal(err) 792 } 793 if len(tokensResp) > 0 { 794 t.Errorf("Wrong number of tokens received. Expected 0 - all tokens expired. Got: %d", len(tokensResp)) 795 } 796 }) 797 } 798 799 type tokenData struct { 800 AccessToken string `json:"access_token"` 801 RefreshToken string `json:"refresh_token"` 802 } 803 804 func getToken(t *testing.T, ts *Test) tokenData { 805 authData := getAuthCode(t, ts) 806 807 param := make(url.Values) 808 param.Set("grant_type", "authorization_code") 809 param.Set("redirect_uri", authRedirectUri) 810 param.Set("client_id", authClientID) 811 param.Set("code", authData["code"]) 812 813 headers := map[string]string{ 814 "Content-Type": "application/x-www-form-urlencoded", 815 "Authorization": "Basic MTIzNDphYWJiY2NkZA==", 816 } 817 818 resp, err := ts.Run(t, test.TestCase{ 819 Path: "/APIID/oauth/token/", 820 Data: param.Encode(), 821 Headers: headers, 822 Method: http.MethodPost, 823 Code: http.StatusOK, 824 }) 825 826 if err != nil { 827 t.Error(err) 828 } 829 830 response := tokenData{} 831 json.NewDecoder(resp.Body).Decode(&response) 832 return response 833 } 834 835 func TestOAuthClientCredsGrant(t *testing.T) { 836 ts := StartTest() 837 defer ts.Close() 838 839 spec := loadTestOAuthSpec() 840 841 createTestOAuthClient(spec, authClientID) 842 843 t.Run("Client credentials grant token request", func(t *testing.T) { 844 param := make(url.Values) 845 param.Set("grant_type", "client_credentials") 846 param.Set("client_id", authClientID) 847 param.Set("client_secret", authClientSecret) 848 849 headers := map[string]string{ 850 "Content-Type": "application/x-www-form-urlencoded", 851 "Authorization": "Basic MTIzNDphYWJiY2NkZA==", 852 } 853 854 resp, err := ts.Run(t, test.TestCase{ 855 Path: "/APIID/oauth/token/", 856 Data: param.Encode(), 857 Headers: headers, 858 Method: http.MethodPost, 859 Code: http.StatusOK, 860 }) 861 if err != nil { 862 t.Error(err) 863 } 864 865 // check response content 866 response := tokenData{} 867 json.NewDecoder(resp.Body).Decode(&response) 868 if response.AccessToken == "" { 869 t.Error("Access token is empty!") 870 } 871 }) 872 } 873 874 func TestClientAccessRequest(t *testing.T) { 875 ts := StartTest() 876 defer ts.Close() 877 878 spec := loadTestOAuthSpec() 879 880 createTestOAuthClient(spec, authClientID) 881 882 authData := getAuthCode(t, &ts) 883 884 t.Run("Exchane access code for token request", func(t *testing.T) { 885 param := make(url.Values) 886 param.Set("grant_type", "authorization_code") 887 param.Set("redirect_uri", authRedirectUri) 888 param.Set("client_id", authClientID) 889 param.Set("code", authData["code"]) 890 891 headers := map[string]string{ 892 "Content-Type": "application/x-www-form-urlencoded", 893 "Authorization": "Basic MTIzNDphYWJiY2NkZA==", 894 } 895 896 ts.Run(t, test.TestCase{ 897 Path: "/APIID/oauth/token/", 898 Data: param.Encode(), 899 Headers: headers, 900 Method: http.MethodPost, 901 Code: http.StatusOK, 902 }) 903 }) 904 } 905 906 func TestOAuthAPIRefreshInvalidate(t *testing.T) { 907 ts := StartTest() 908 defer ts.Close() 909 910 spec := loadTestOAuthSpec() 911 912 createTestOAuthClient(spec, authClientID) 913 914 // Step 1 create token 915 tokenData := getToken(t, &ts) 916 917 // Step 2 - invalidate the refresh token 918 t.Run("Invalidate token request", func(t *testing.T) { 919 param := make(url.Values) 920 param.Set("api_id", "999999") 921 resp, err := ts.Run(t, test.TestCase{ 922 Path: "/tyk/oauth/refresh/" + tokenData.RefreshToken + "?" + param.Encode(), 923 AdminAuth: true, 924 Method: http.MethodDelete, 925 Code: http.StatusOK, 926 }) 927 if err != nil { 928 t.Error(err) 929 } 930 931 newSuccess := apiModifyKeySuccess{} 932 json.NewDecoder(resp.Body).Decode(&newSuccess) 933 if newSuccess.Status != "ok" { 934 t.Errorf("key not deleted, status error: %s\n", newSuccess.Status) 935 t.Error(apisByID) 936 } 937 if newSuccess.Action != "deleted" { 938 t.Errorf("Response is incorrect - action is not 'deleted': %s\n", newSuccess.Action) 939 } 940 }) 941 942 // Step 3 - try to refresh 943 t.Run("Refresh token request", func(t *testing.T) { 944 param := make(url.Values) 945 param.Set("grant_type", "refresh_token") 946 param.Set("redirect_uri", authRedirectUri) 947 param.Set("client_id", authClientID) 948 param.Set("refresh_token", tokenData.RefreshToken) 949 headers := map[string]string{ 950 "Content-Type": "application/x-www-form-urlencoded", 951 "Authorization": "Basic MTIzNDphYWJiY2NkZA==", 952 } 953 ts.Run(t, test.TestCase{ 954 Path: "/APIID/oauth/token/", 955 Data: param.Encode(), 956 Headers: headers, 957 Method: http.MethodPost, 958 Code: http.StatusForbidden, 959 }) 960 }) 961 } 962 963 func TestClientRefreshRequest(t *testing.T) { 964 ts := StartTest() 965 defer ts.Close() 966 967 spec := loadTestOAuthSpec() 968 969 createTestOAuthClient(spec, authClientID) 970 971 tokenData := getToken(t, &ts) 972 973 t.Run("Refresh token request", func(t *testing.T) { 974 param := make(url.Values) 975 param.Set("grant_type", "refresh_token") 976 param.Set("redirect_uri", authRedirectUri) 977 param.Set("client_id", authClientID) 978 param.Set("refresh_token", tokenData.RefreshToken) 979 980 headers := map[string]string{ 981 "Content-Type": "application/x-www-form-urlencoded", 982 "Authorization": "Basic MTIzNDphYWJiY2NkZA==", 983 } 984 985 ts.Run(t, test.TestCase{ 986 Path: "/APIID/oauth/token/", 987 Data: param.Encode(), 988 Headers: headers, 989 Method: http.MethodPost, 990 Code: http.StatusOK, 991 }) 992 }) 993 } 994 995 func TestClientRefreshRequestDouble(t *testing.T) { 996 ts := StartTest() 997 defer ts.Close() 998 999 spec := loadTestOAuthSpec() 1000 1001 createTestOAuthClient(spec, authClientID) 1002 1003 tokenData := getToken(t, &ts) 1004 1005 headers := map[string]string{ 1006 "Content-Type": "application/x-www-form-urlencoded", 1007 "Authorization": "Basic MTIzNDphYWJiY2NkZA==", 1008 } 1009 1010 // req 1 1011 token := "" 1012 t.Run("1st refresh token request", func(t *testing.T) { 1013 param := make(url.Values) 1014 param.Set("grant_type", "refresh_token") 1015 param.Set("redirect_uri", authRedirectUri) 1016 param.Set("client_id", authClientID) 1017 param.Set("refresh_token", tokenData.RefreshToken) 1018 1019 resp, err := ts.Run(t, test.TestCase{ 1020 Path: "/APIID/oauth/token/", 1021 Data: param.Encode(), 1022 Headers: headers, 1023 Method: http.MethodPost, 1024 Code: http.StatusOK, 1025 }) 1026 if err != nil { 1027 t.Error(err) 1028 } 1029 responseData := make(map[string]interface{}) 1030 json.NewDecoder(resp.Body).Decode(&responseData) 1031 var ok bool 1032 token, ok = responseData["refresh_token"].(string) 1033 if !ok { 1034 t.Fatal("No refresh token found") 1035 } 1036 }) 1037 1038 // req 2 1039 t.Run("2nd refresh token request", func(t *testing.T) { 1040 param := make(url.Values) 1041 param.Set("grant_type", "refresh_token") 1042 param.Set("redirect_uri", authRedirectUri) 1043 param.Set("client_id", authClientID) 1044 param.Set("refresh_token", token) 1045 1046 ts.Run(t, test.TestCase{ 1047 Path: "/APIID/oauth/token/", 1048 Data: param.Encode(), 1049 Headers: headers, 1050 Method: http.MethodPost, 1051 Code: http.StatusOK, 1052 }) 1053 }) 1054 } 1055 1056 func TestTokenEndpointHeaders(t *testing.T) { 1057 ts := StartTest() 1058 defer ts.Close() 1059 1060 spec := loadTestOAuthSpec() 1061 createTestOAuthClient(spec, authClientID) 1062 1063 param := make(url.Values) 1064 param.Set("grant_type", "client_credentials") 1065 param.Set("redirect_uri", authRedirectUri) 1066 param.Set("client_id", authClientID) 1067 1068 headers := map[string]string{ 1069 "Content-Type": "application/x-www-form-urlencoded", 1070 "Authorization": "Basic MTIzNDphYWJiY2NkZA==", 1071 } 1072 1073 securityAndCacheHeaders := map[string]string{ 1074 "X-Content-Type-Options": "nosniff", 1075 "X-XSS-Protection": "1; mode=block", 1076 "X-Frame-Options": "DENY", 1077 "Strict-Transport-Security": "max-age=63072000; includeSubDomains", 1078 "Cache-Control": "no-cache, no-store, must-revalidate", 1079 "Pragma": "no-cache", 1080 "Expires": "0", 1081 } 1082 1083 ts.Run(t, []test.TestCase{ 1084 { 1085 Path: "/APIID/oauth/token/", 1086 Data: param.Encode(), 1087 Headers: headers, 1088 Method: http.MethodPost, 1089 Code: http.StatusOK, 1090 HeadersMatch: securityAndCacheHeaders, 1091 }, { // Set security headers even if request fails 1092 Path: "/APIID/oauth/token/", 1093 Data: param.Encode(), 1094 Method: http.MethodPost, 1095 Code: http.StatusForbidden, 1096 HeadersMatch: securityAndCacheHeaders, 1097 }}...) 1098 } 1099 1100 func TestJSONToFormValues(t *testing.T) { 1101 o := map[string]string{ 1102 "username": "test@test.com", 1103 "password": "12345678", 1104 "scope": "client", 1105 "client_id": "test-client-id", 1106 "client_secret": "test-client-secret", 1107 "grant_type": "password", 1108 } 1109 b, _ := json.Marshal(o) 1110 r, err := http.NewRequest(http.MethodPost, "/token", bytes.NewReader(b)) 1111 if err != nil { 1112 t.Fatal(err) 1113 } 1114 t.Run("no application/json header", func(ts *testing.T) { 1115 err := JSONToFormValues(r) 1116 if err != nil { 1117 ts.Fatal(err) 1118 } 1119 for k, v := range o { 1120 g := r.Form.Get(k) 1121 if g == v { 1122 ts.Errorf("expected %s not to be set", v) 1123 } 1124 } 1125 }) 1126 1127 t.Run("with application/json header", func(ts *testing.T) { 1128 r.Header.Set("Content-Type", "application/json") 1129 err := JSONToFormValues(r) 1130 if err != nil { 1131 ts.Fatal(err) 1132 } 1133 for k, v := range o { 1134 g := r.Form.Get(k) 1135 if g != v { 1136 ts.Errorf("expected %s got %s", v, g) 1137 } 1138 } 1139 }) 1140 }