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  }