test_get_access_token.py 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. from unittest.mock import Mock, patch
  2. import pytest
  3. from requests.exceptions import Timeout
  4. from ...conf.test import override_dynamic_settings
  5. from .. import exceptions
  6. from ..client import REQUESTS_TIMEOUT, get_access_token
  7. ACCESS_TOKEN = "acc3ss-t0k3n"
  8. CODE_GRANT = "valid-code"
  9. @pytest.fixture
  10. def mock_request(dynamic_settings):
  11. return Mock(
  12. settings=dynamic_settings,
  13. build_absolute_uri=lambda url: f"http://mysite.com{url or ''}",
  14. )
  15. @override_dynamic_settings(
  16. oauth2_client_id="clientid123",
  17. oauth2_client_secret="secr3t",
  18. oauth2_token_url="https://example.com/oauth2/token",
  19. oauth2_token_method="GET",
  20. )
  21. def test_access_token_is_retrieved_using_get_request(mock_request):
  22. get_mock = Mock(
  23. return_value=Mock(
  24. status_code=200,
  25. json=Mock(
  26. return_value={
  27. "access_token": ACCESS_TOKEN,
  28. },
  29. ),
  30. ),
  31. )
  32. with patch("requests.get", get_mock):
  33. assert get_access_token(mock_request, CODE_GRANT) == ACCESS_TOKEN
  34. get_mock.assert_called_once_with(
  35. (
  36. "https://example.com/oauth2/token"
  37. "?grant_type=authorization_code"
  38. "&client_id=clientid123"
  39. "&client_secret=secr3t"
  40. "&redirect_uri=http%3A%2F%2Fmysite.com%2Foauth2%2Fcomplete%2F"
  41. "&code=valid-code"
  42. ),
  43. headers={},
  44. timeout=REQUESTS_TIMEOUT,
  45. )
  46. @override_dynamic_settings(
  47. oauth2_client_id="clientid123",
  48. oauth2_client_secret="secr3t",
  49. oauth2_token_url="https://example.com/oauth2/token?exchange=1",
  50. oauth2_token_method="GET",
  51. )
  52. def test_access_token_get_request_url_respects_existing_querystring(
  53. mock_request,
  54. ):
  55. get_mock = Mock(
  56. return_value=Mock(
  57. status_code=200,
  58. json=Mock(
  59. return_value={
  60. "access_token": ACCESS_TOKEN,
  61. },
  62. ),
  63. ),
  64. )
  65. with patch("requests.get", get_mock):
  66. assert get_access_token(mock_request, CODE_GRANT) == ACCESS_TOKEN
  67. get_mock.assert_called_once_with(
  68. (
  69. "https://example.com/oauth2/token?exchange=1"
  70. "&grant_type=authorization_code"
  71. "&client_id=clientid123"
  72. "&client_secret=secr3t"
  73. "&redirect_uri=http%3A%2F%2Fmysite.com%2Foauth2%2Fcomplete%2F"
  74. "&code=valid-code"
  75. ),
  76. headers={},
  77. timeout=REQUESTS_TIMEOUT,
  78. )
  79. @override_dynamic_settings(
  80. oauth2_client_id="clientid123",
  81. oauth2_client_secret="secr3t",
  82. oauth2_token_url="https://example.com/oauth2/token",
  83. oauth2_token_method="POST",
  84. )
  85. def test_access_token_is_retrieved_using_post_request(mock_request):
  86. post_mock = Mock(
  87. return_value=Mock(
  88. status_code=200,
  89. json=Mock(
  90. return_value={
  91. "access_token": ACCESS_TOKEN,
  92. },
  93. ),
  94. ),
  95. )
  96. with patch("requests.post", post_mock):
  97. assert get_access_token(mock_request, CODE_GRANT) == ACCESS_TOKEN
  98. post_mock.assert_called_once_with(
  99. "https://example.com/oauth2/token",
  100. data={
  101. "grant_type": "authorization_code",
  102. "client_id": "clientid123",
  103. "client_secret": "secr3t",
  104. "redirect_uri": "http://mysite.com/oauth2/complete/",
  105. "code": CODE_GRANT,
  106. },
  107. headers={},
  108. timeout=REQUESTS_TIMEOUT,
  109. )
  110. @override_dynamic_settings(
  111. oauth2_client_id="clientid123",
  112. oauth2_client_secret="secr3t",
  113. oauth2_token_url="https://example.com/oauth2/token",
  114. oauth2_token_method="POST",
  115. oauth2_token_extra_headers="Accept: application/json\nApi-Ver:1234",
  116. )
  117. def test_access_token_is_retrieved_using_extra_headers(mock_request):
  118. post_mock = Mock(
  119. return_value=Mock(
  120. status_code=200,
  121. json=Mock(
  122. return_value={
  123. "access_token": ACCESS_TOKEN,
  124. },
  125. ),
  126. ),
  127. )
  128. with patch("requests.post", post_mock):
  129. assert get_access_token(mock_request, CODE_GRANT) == ACCESS_TOKEN
  130. post_mock.assert_called_once_with(
  131. "https://example.com/oauth2/token",
  132. data={
  133. "grant_type": "authorization_code",
  134. "client_id": "clientid123",
  135. "client_secret": "secr3t",
  136. "redirect_uri": "http://mysite.com/oauth2/complete/",
  137. "code": CODE_GRANT,
  138. },
  139. headers={
  140. "Accept": "application/json",
  141. "Api-Ver": "1234",
  142. },
  143. timeout=REQUESTS_TIMEOUT,
  144. )
  145. @override_dynamic_settings(
  146. oauth2_client_id="clientid123",
  147. oauth2_client_secret="secr3t",
  148. oauth2_token_url="https://example.com/oauth2/token",
  149. oauth2_token_method="POST",
  150. oauth2_json_token_path="data.auth.token",
  151. )
  152. def test_access_token_is_extracted_from_json(mock_request):
  153. post_mock = Mock(
  154. return_value=Mock(
  155. status_code=200,
  156. json=Mock(
  157. return_value={
  158. "data": {
  159. "auth": {
  160. "token": ACCESS_TOKEN,
  161. },
  162. },
  163. },
  164. ),
  165. ),
  166. )
  167. with patch("requests.post", post_mock):
  168. assert get_access_token(mock_request, CODE_GRANT) == ACCESS_TOKEN
  169. post_mock.assert_called_once()
  170. @override_dynamic_settings(
  171. oauth2_client_id="clientid123",
  172. oauth2_client_secret="secr3t",
  173. oauth2_token_url="https://example.com/oauth2/token",
  174. oauth2_token_method="POST",
  175. )
  176. def test_exception_is_raised_if_access_token_request_times_out(mock_request):
  177. post_mock = Mock(side_effect=Timeout())
  178. with patch("requests.post", post_mock):
  179. with pytest.raises(exceptions.OAuth2AccessTokenRequestError):
  180. get_access_token(mock_request, CODE_GRANT)
  181. post_mock.assert_called_once()
  182. @override_dynamic_settings(
  183. oauth2_client_id="clientid123",
  184. oauth2_client_secret="secr3t",
  185. oauth2_token_url="https://example.com/oauth2/token",
  186. oauth2_token_method="POST",
  187. )
  188. def test_exception_is_raised_if_access_token_request_response_is_not_200(mock_request):
  189. post_mock = Mock(
  190. return_value=Mock(
  191. status_code=400,
  192. ),
  193. )
  194. with patch("requests.post", post_mock):
  195. with pytest.raises(exceptions.OAuth2AccessTokenResponseError):
  196. get_access_token(mock_request, CODE_GRANT)
  197. post_mock.assert_called_once()
  198. @override_dynamic_settings(
  199. oauth2_client_id="clientid123",
  200. oauth2_client_secret="secr3t",
  201. oauth2_token_url="https://example.com/oauth2/token",
  202. oauth2_token_method="POST",
  203. )
  204. def test_exception_is_raised_if_access_token_request_response_is_not_json(mock_request):
  205. post_mock = Mock(
  206. return_value=Mock(
  207. status_code=200,
  208. json=Mock(
  209. side_effect=ValueError(),
  210. ),
  211. ),
  212. )
  213. with patch("requests.post", post_mock):
  214. with pytest.raises(exceptions.OAuth2AccessTokenJSONError):
  215. get_access_token(mock_request, CODE_GRANT)
  216. post_mock.assert_called_once()
  217. @override_dynamic_settings(
  218. oauth2_client_id="clientid123",
  219. oauth2_client_secret="secr3t",
  220. oauth2_token_url="https://example.com/oauth2/token",
  221. oauth2_token_method="POST",
  222. )
  223. def test_exception_is_raised_if_access_token_request_response_json_is_not_object(
  224. mock_request,
  225. ):
  226. post_mock = Mock(
  227. return_value=Mock(
  228. status_code=200,
  229. json=Mock(
  230. return_value=["json", "list"],
  231. ),
  232. ),
  233. )
  234. with patch("requests.post", post_mock):
  235. with pytest.raises(exceptions.OAuth2AccessTokenJSONError):
  236. get_access_token(mock_request, CODE_GRANT)
  237. post_mock.assert_called_once()
  238. @override_dynamic_settings(
  239. oauth2_client_id="clientid123",
  240. oauth2_client_secret="secr3t",
  241. oauth2_token_url="https://example.com/oauth2/token",
  242. oauth2_token_method="POST",
  243. )
  244. def test_exception_is_raised_if_access_token_request_response_json_misses_token(
  245. mock_request,
  246. ):
  247. post_mock = Mock(
  248. return_value=Mock(
  249. status_code=200,
  250. json=Mock(
  251. return_value={
  252. "no_token": "nope",
  253. },
  254. ),
  255. ),
  256. )
  257. with patch("requests.post", post_mock):
  258. with pytest.raises(exceptions.OAuth2AccessTokenNotProvidedError):
  259. get_access_token(mock_request, CODE_GRANT)
  260. post_mock.assert_called_once()