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  }