Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

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