You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

oauth_test.go 8.3 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. // Copyright 2019 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package integrations
  5. import (
  6. "encoding/json"
  7. "testing"
  8. "code.gitea.io/gitea/modules/setting"
  9. "github.com/stretchr/testify/assert"
  10. )
  11. const defaultAuthorize = "/login/oauth/authorize?client_id=da7da3ba-9a13-4167-856f-3899de0b0138&redirect_uri=a&response_type=code&state=thestate"
  12. func TestNoClientID(t *testing.T) {
  13. prepareTestEnv(t)
  14. req := NewRequest(t, "GET", "/login/oauth/authorize")
  15. ctx := loginUser(t, "user2")
  16. ctx.MakeRequest(t, req, 400)
  17. }
  18. func TestLoginRedirect(t *testing.T) {
  19. prepareTestEnv(t)
  20. req := NewRequest(t, "GET", "/login/oauth/authorize")
  21. assert.Contains(t, MakeRequest(t, req, 302).Body.String(), "/user/login")
  22. }
  23. func TestShowAuthorize(t *testing.T) {
  24. prepareTestEnv(t)
  25. req := NewRequest(t, "GET", defaultAuthorize)
  26. ctx := loginUser(t, "user4")
  27. resp := ctx.MakeRequest(t, req, 200)
  28. htmlDoc := NewHTMLParser(t, resp.Body)
  29. htmlDoc.AssertElement(t, "#authorize-app", true)
  30. htmlDoc.GetCSRF()
  31. }
  32. func TestRedirectWithExistingGrant(t *testing.T) {
  33. prepareTestEnv(t)
  34. req := NewRequest(t, "GET", defaultAuthorize)
  35. ctx := loginUser(t, "user1")
  36. resp := ctx.MakeRequest(t, req, 302)
  37. u, err := resp.Result().Location()
  38. assert.NoError(t, err)
  39. assert.Equal(t, "thestate", u.Query().Get("state"))
  40. assert.Truef(t, len(u.Query().Get("code")) > 30, "authorization code '%s' should be longer then 30", u.Query().Get("code"))
  41. }
  42. func TestAccessTokenExchange(t *testing.T) {
  43. prepareTestEnv(t)
  44. req := NewRequestWithValues(t, "POST", "/login/oauth/access_token", map[string]string{
  45. "grant_type": "authorization_code",
  46. "client_id": "da7da3ba-9a13-4167-856f-3899de0b0138",
  47. "client_secret": "4MK8Na6R55smdCY0WuCCumZ6hjRPnGY5saWVRHHjJiA=",
  48. "redirect_uri": "a",
  49. "code": "authcode",
  50. "code_verifier": "N1Zo9-8Rfwhkt68r1r29ty8YwIraXR8eh_1Qwxg7yQXsonBt", // test PKCE additionally
  51. })
  52. resp := MakeRequest(t, req, 200)
  53. type response struct {
  54. AccessToken string `json:"access_token"`
  55. TokenType string `json:"token_type"`
  56. ExpiresIn int64 `json:"expires_in"`
  57. RefreshToken string `json:"refresh_token"`
  58. }
  59. parsed := new(response)
  60. assert.NoError(t, json.Unmarshal(resp.Body.Bytes(), parsed))
  61. assert.True(t, len(parsed.AccessToken) > 10)
  62. assert.True(t, len(parsed.RefreshToken) > 10)
  63. }
  64. func TestAccessTokenExchangeWithoutPKCE(t *testing.T) {
  65. prepareTestEnv(t)
  66. req := NewRequestWithValues(t, "POST", "/login/oauth/access_token", map[string]string{
  67. "grant_type": "authorization_code",
  68. "client_id": "da7da3ba-9a13-4167-856f-3899de0b0138",
  69. "client_secret": "4MK8Na6R55smdCY0WuCCumZ6hjRPnGY5saWVRHHjJiA=",
  70. "redirect_uri": "a",
  71. "code": "authcode",
  72. })
  73. MakeRequest(t, req, 400)
  74. }
  75. func TestAccessTokenExchangeWithInvalidCredentials(t *testing.T) {
  76. prepareTestEnv(t)
  77. // invalid client id
  78. req := NewRequestWithValues(t, "POST", "/login/oauth/access_token", map[string]string{
  79. "grant_type": "authorization_code",
  80. "client_id": "???",
  81. "client_secret": "4MK8Na6R55smdCY0WuCCumZ6hjRPnGY5saWVRHHjJiA=",
  82. "redirect_uri": "a",
  83. "code": "authcode",
  84. "code_verifier": "N1Zo9-8Rfwhkt68r1r29ty8YwIraXR8eh_1Qwxg7yQXsonBt", // test PKCE additionally
  85. })
  86. MakeRequest(t, req, 400)
  87. // invalid client secret
  88. req = NewRequestWithValues(t, "POST", "/login/oauth/access_token", map[string]string{
  89. "grant_type": "authorization_code",
  90. "client_id": "da7da3ba-9a13-4167-856f-3899de0b0138",
  91. "client_secret": "???",
  92. "redirect_uri": "a",
  93. "code": "authcode",
  94. "code_verifier": "N1Zo9-8Rfwhkt68r1r29ty8YwIraXR8eh_1Qwxg7yQXsonBt", // test PKCE additionally
  95. })
  96. MakeRequest(t, req, 400)
  97. // invalid redirect uri
  98. req = NewRequestWithValues(t, "POST", "/login/oauth/access_token", map[string]string{
  99. "grant_type": "authorization_code",
  100. "client_id": "da7da3ba-9a13-4167-856f-3899de0b0138",
  101. "client_secret": "4MK8Na6R55smdCY0WuCCumZ6hjRPnGY5saWVRHHjJiA=",
  102. "redirect_uri": "???",
  103. "code": "authcode",
  104. "code_verifier": "N1Zo9-8Rfwhkt68r1r29ty8YwIraXR8eh_1Qwxg7yQXsonBt", // test PKCE additionally
  105. })
  106. MakeRequest(t, req, 400)
  107. // invalid authorization code
  108. req = NewRequestWithValues(t, "POST", "/login/oauth/access_token", map[string]string{
  109. "grant_type": "authorization_code",
  110. "client_id": "da7da3ba-9a13-4167-856f-3899de0b0138",
  111. "client_secret": "4MK8Na6R55smdCY0WuCCumZ6hjRPnGY5saWVRHHjJiA=",
  112. "redirect_uri": "a",
  113. "code": "???",
  114. "code_verifier": "N1Zo9-8Rfwhkt68r1r29ty8YwIraXR8eh_1Qwxg7yQXsonBt", // test PKCE additionally
  115. })
  116. MakeRequest(t, req, 400)
  117. // invalid grant_type
  118. req = NewRequestWithValues(t, "POST", "/login/oauth/access_token", map[string]string{
  119. "grant_type": "???",
  120. "client_id": "da7da3ba-9a13-4167-856f-3899de0b0138",
  121. "client_secret": "4MK8Na6R55smdCY0WuCCumZ6hjRPnGY5saWVRHHjJiA=",
  122. "redirect_uri": "a",
  123. "code": "authcode",
  124. "code_verifier": "N1Zo9-8Rfwhkt68r1r29ty8YwIraXR8eh_1Qwxg7yQXsonBt", // test PKCE additionally
  125. })
  126. MakeRequest(t, req, 400)
  127. }
  128. func TestAccessTokenExchangeWithBasicAuth(t *testing.T) {
  129. prepareTestEnv(t)
  130. req := NewRequestWithValues(t, "POST", "/login/oauth/access_token", map[string]string{
  131. "grant_type": "authorization_code",
  132. "redirect_uri": "a",
  133. "code": "authcode",
  134. "code_verifier": "N1Zo9-8Rfwhkt68r1r29ty8YwIraXR8eh_1Qwxg7yQXsonBt", // test PKCE additionally
  135. })
  136. req.Header.Add("Authorization", "Basic ZGE3ZGEzYmEtOWExMy00MTY3LTg1NmYtMzg5OWRlMGIwMTM4OjRNSzhOYTZSNTVzbWRDWTBXdUNDdW1aNmhqUlBuR1k1c2FXVlJISGpKaUE9")
  137. resp := MakeRequest(t, req, 200)
  138. type response struct {
  139. AccessToken string `json:"access_token"`
  140. TokenType string `json:"token_type"`
  141. ExpiresIn int64 `json:"expires_in"`
  142. RefreshToken string `json:"refresh_token"`
  143. }
  144. parsed := new(response)
  145. assert.NoError(t, json.Unmarshal(resp.Body.Bytes(), parsed))
  146. assert.True(t, len(parsed.AccessToken) > 10)
  147. assert.True(t, len(parsed.RefreshToken) > 10)
  148. // use wrong client_secret
  149. req = NewRequestWithValues(t, "POST", "/login/oauth/access_token", map[string]string{
  150. "grant_type": "authorization_code",
  151. "redirect_uri": "a",
  152. "code": "authcode",
  153. "code_verifier": "N1Zo9-8Rfwhkt68r1r29ty8YwIraXR8eh_1Qwxg7yQXsonBt", // test PKCE additionally
  154. })
  155. req.Header.Add("Authorization", "Basic ZGE3ZGEzYmEtOWExMy00MTY3LTg1NmYtMzg5OWRlMGIwMTM4OmJsYWJsYQ==")
  156. resp = MakeRequest(t, req, 400)
  157. // missing header
  158. req = NewRequestWithValues(t, "POST", "/login/oauth/access_token", map[string]string{
  159. "grant_type": "authorization_code",
  160. "redirect_uri": "a",
  161. "code": "authcode",
  162. "code_verifier": "N1Zo9-8Rfwhkt68r1r29ty8YwIraXR8eh_1Qwxg7yQXsonBt", // test PKCE additionally
  163. })
  164. resp = MakeRequest(t, req, 400)
  165. }
  166. func TestRefreshTokenInvalidation(t *testing.T) {
  167. prepareTestEnv(t)
  168. req := NewRequestWithValues(t, "POST", "/login/oauth/access_token", map[string]string{
  169. "grant_type": "authorization_code",
  170. "client_id": "da7da3ba-9a13-4167-856f-3899de0b0138",
  171. "client_secret": "4MK8Na6R55smdCY0WuCCumZ6hjRPnGY5saWVRHHjJiA=",
  172. "redirect_uri": "a",
  173. "code": "authcode",
  174. "code_verifier": "N1Zo9-8Rfwhkt68r1r29ty8YwIraXR8eh_1Qwxg7yQXsonBt", // test PKCE additionally
  175. })
  176. resp := MakeRequest(t, req, 200)
  177. type response struct {
  178. AccessToken string `json:"access_token"`
  179. TokenType string `json:"token_type"`
  180. ExpiresIn int64 `json:"expires_in"`
  181. RefreshToken string `json:"refresh_token"`
  182. }
  183. parsed := new(response)
  184. assert.NoError(t, json.Unmarshal(resp.Body.Bytes(), parsed))
  185. // test without invalidation
  186. setting.OAuth2.InvalidateRefreshTokens = false
  187. refreshReq := NewRequestWithValues(t, "POST", "/login/oauth/access_token", map[string]string{
  188. "grant_type": "refresh_token",
  189. "client_id": "da7da3ba-9a13-4167-856f-3899de0b0138",
  190. "client_secret": "4MK8Na6R55smdCY0WuCCumZ6hjRPnGY5saWVRHHjJiA=",
  191. "redirect_uri": "a",
  192. "refresh_token": parsed.RefreshToken,
  193. })
  194. MakeRequest(t, refreshReq, 200)
  195. MakeRequest(t, refreshReq, 200)
  196. // test with invalidation
  197. setting.OAuth2.InvalidateRefreshTokens = true
  198. MakeRequest(t, refreshReq, 200)
  199. MakeRequest(t, refreshReq, 400)
  200. }