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