test_compliance_fixes.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. from __future__ import unicode_literals
  2. from unittest import TestCase
  3. import requests
  4. import requests_mock
  5. import time
  6. try:
  7. from urlparse import urlparse, parse_qs
  8. except ImportError:
  9. from urllib.parse import urlparse, parse_qs
  10. from oauthlib.oauth2.rfc6749.errors import InvalidGrantError
  11. from requests_oauthlib import OAuth2Session
  12. from requests_oauthlib.compliance_fixes import facebook_compliance_fix
  13. from requests_oauthlib.compliance_fixes import fitbit_compliance_fix
  14. from requests_oauthlib.compliance_fixes import mailchimp_compliance_fix
  15. from requests_oauthlib.compliance_fixes import weibo_compliance_fix
  16. from requests_oauthlib.compliance_fixes import slack_compliance_fix
  17. from requests_oauthlib.compliance_fixes import instagram_compliance_fix
  18. from requests_oauthlib.compliance_fixes import plentymarkets_compliance_fix
  19. from requests_oauthlib.compliance_fixes import ebay_compliance_fix
  20. class FacebookComplianceFixTest(TestCase):
  21. def setUp(self):
  22. mocker = requests_mock.Mocker()
  23. mocker.post(
  24. "https://graph.facebook.com/oauth/access_token",
  25. text="access_token=urlencoded",
  26. headers={"Content-Type": "text/plain"},
  27. )
  28. mocker.start()
  29. self.addCleanup(mocker.stop)
  30. facebook = OAuth2Session("someclientid", redirect_uri="https://i.b")
  31. self.session = facebook_compliance_fix(facebook)
  32. def test_fetch_access_token(self):
  33. token = self.session.fetch_token(
  34. "https://graph.facebook.com/oauth/access_token",
  35. client_secret="someclientsecret",
  36. authorization_response="https://i.b/?code=hello",
  37. )
  38. self.assertEqual(token, {"access_token": "urlencoded", "token_type": "Bearer"})
  39. class FitbitComplianceFixTest(TestCase):
  40. def setUp(self):
  41. self.mocker = requests_mock.Mocker()
  42. self.mocker.post(
  43. "https://api.fitbit.com/oauth2/token",
  44. json={"errors": [{"errorType": "invalid_grant"}]},
  45. )
  46. self.mocker.start()
  47. self.addCleanup(self.mocker.stop)
  48. fitbit = OAuth2Session("someclientid", redirect_uri="https://i.b")
  49. self.session = fitbit_compliance_fix(fitbit)
  50. def test_fetch_access_token(self):
  51. self.assertRaises(
  52. InvalidGrantError,
  53. self.session.fetch_token,
  54. "https://api.fitbit.com/oauth2/token",
  55. client_secret="someclientsecret",
  56. authorization_response="https://i.b/?code=hello",
  57. )
  58. self.mocker.post(
  59. "https://api.fitbit.com/oauth2/token", json={"access_token": "fitbit"}
  60. )
  61. token = self.session.fetch_token(
  62. "https://api.fitbit.com/oauth2/token", client_secret="good"
  63. )
  64. self.assertEqual(token, {"access_token": "fitbit"})
  65. def test_refresh_token(self):
  66. self.assertRaises(
  67. InvalidGrantError,
  68. self.session.refresh_token,
  69. "https://api.fitbit.com/oauth2/token",
  70. auth=requests.auth.HTTPBasicAuth("someclientid", "someclientsecret"),
  71. )
  72. self.mocker.post(
  73. "https://api.fitbit.com/oauth2/token",
  74. json={"access_token": "access", "refresh_token": "refresh"},
  75. )
  76. token = self.session.refresh_token(
  77. "https://api.fitbit.com/oauth2/token",
  78. auth=requests.auth.HTTPBasicAuth("someclientid", "someclientsecret"),
  79. )
  80. self.assertEqual(token["access_token"], "access")
  81. self.assertEqual(token["refresh_token"], "refresh")
  82. class MailChimpComplianceFixTest(TestCase):
  83. def setUp(self):
  84. mocker = requests_mock.Mocker()
  85. mocker.post(
  86. "https://login.mailchimp.com/oauth2/token",
  87. json={"access_token": "mailchimp", "expires_in": 0, "scope": None},
  88. )
  89. mocker.start()
  90. self.addCleanup(mocker.stop)
  91. mailchimp = OAuth2Session("someclientid", redirect_uri="https://i.b")
  92. self.session = mailchimp_compliance_fix(mailchimp)
  93. def test_fetch_access_token(self):
  94. token = self.session.fetch_token(
  95. "https://login.mailchimp.com/oauth2/token",
  96. client_secret="someclientsecret",
  97. authorization_response="https://i.b/?code=hello",
  98. )
  99. # Times should be close
  100. approx_expires_at = time.time() + 3600
  101. actual_expires_at = token.pop("expires_at")
  102. self.assertAlmostEqual(actual_expires_at, approx_expires_at, places=2)
  103. # Other token values exact
  104. self.assertEqual(token, {"access_token": "mailchimp", "expires_in": 3600})
  105. # And no scope at all
  106. self.assertNotIn("scope", token)
  107. class WeiboComplianceFixTest(TestCase):
  108. def setUp(self):
  109. mocker = requests_mock.Mocker()
  110. mocker.post(
  111. "https://api.weibo.com/oauth2/access_token", json={"access_token": "weibo"}
  112. )
  113. mocker.start()
  114. self.addCleanup(mocker.stop)
  115. weibo = OAuth2Session("someclientid", redirect_uri="https://i.b")
  116. self.session = weibo_compliance_fix(weibo)
  117. def test_fetch_access_token(self):
  118. token = self.session.fetch_token(
  119. "https://api.weibo.com/oauth2/access_token",
  120. client_secret="someclientsecret",
  121. authorization_response="https://i.b/?code=hello",
  122. )
  123. self.assertEqual(token, {"access_token": "weibo", "token_type": "Bearer"})
  124. class SlackComplianceFixTest(TestCase):
  125. def setUp(self):
  126. mocker = requests_mock.Mocker()
  127. mocker.post(
  128. "https://slack.com/api/oauth.access",
  129. json={"access_token": "xoxt-23984754863-2348975623103", "scope": "read"},
  130. )
  131. for method in ("GET", "POST"):
  132. mocker.request(
  133. method=method,
  134. url="https://slack.com/api/auth.test",
  135. json={
  136. "ok": True,
  137. "url": "https://myteam.slack.com/",
  138. "team": "My Team",
  139. "user": "cal",
  140. "team_id": "T12345",
  141. "user_id": "U12345",
  142. },
  143. )
  144. mocker.start()
  145. self.addCleanup(mocker.stop)
  146. slack = OAuth2Session("someclientid", redirect_uri="https://i.b")
  147. self.session = slack_compliance_fix(slack)
  148. def test_protected_request(self):
  149. self.session.token = {"access_token": "dummy-access-token"}
  150. response = self.session.get("https://slack.com/api/auth.test")
  151. url = response.request.url
  152. query = parse_qs(urlparse(url).query)
  153. self.assertNotIn("token", query)
  154. body = response.request.body
  155. data = parse_qs(body)
  156. self.assertEqual(data["token"], ["dummy-access-token"])
  157. def test_protected_request_override_token_get(self):
  158. self.session.token = {"access_token": "dummy-access-token"}
  159. response = self.session.get(
  160. "https://slack.com/api/auth.test", data={"token": "different-token"}
  161. )
  162. url = response.request.url
  163. query = parse_qs(urlparse(url).query)
  164. self.assertNotIn("token", query)
  165. body = response.request.body
  166. data = parse_qs(body)
  167. self.assertEqual(data["token"], ["different-token"])
  168. def test_protected_request_override_token_post(self):
  169. self.session.token = {"access_token": "dummy-access-token"}
  170. response = self.session.post(
  171. "https://slack.com/api/auth.test", data={"token": "different-token"}
  172. )
  173. url = response.request.url
  174. query = parse_qs(urlparse(url).query)
  175. self.assertNotIn("token", query)
  176. body = response.request.body
  177. data = parse_qs(body)
  178. self.assertEqual(data["token"], ["different-token"])
  179. def test_protected_request_override_token_url(self):
  180. self.session.token = {"access_token": "dummy-access-token"}
  181. response = self.session.get(
  182. "https://slack.com/api/auth.test?token=different-token"
  183. )
  184. url = response.request.url
  185. query = parse_qs(urlparse(url).query)
  186. self.assertEqual(query["token"], ["different-token"])
  187. self.assertIsNone(response.request.body)
  188. class InstagramComplianceFixTest(TestCase):
  189. def setUp(self):
  190. mocker = requests_mock.Mocker()
  191. mocker.request(
  192. method="GET",
  193. url="https://api.instagram.com/v1/users/self",
  194. json={
  195. "data": {
  196. "id": "1574083",
  197. "username": "snoopdogg",
  198. "full_name": "Snoop Dogg",
  199. "profile_picture": "http://distillery.s3.amazonaws.com/profiles/profile_1574083_75sq_1295469061.jpg",
  200. "bio": "This is my bio",
  201. "website": "http://snoopdogg.com",
  202. "is_business": False,
  203. "counts": {"media": 1320, "follows": 420, "followed_by": 3410},
  204. }
  205. },
  206. )
  207. mocker.start()
  208. self.addCleanup(mocker.stop)
  209. instagram = OAuth2Session("someclientid", redirect_uri="https://i.b")
  210. self.session = instagram_compliance_fix(instagram)
  211. def test_protected_request(self):
  212. self.session.token = {"access_token": "dummy-access-token"}
  213. response = self.session.get("https://api.instagram.com/v1/users/self")
  214. url = response.request.url
  215. query = parse_qs(urlparse(url).query)
  216. self.assertIn("access_token", query)
  217. self.assertEqual(query["access_token"], ["dummy-access-token"])
  218. def test_protected_request_dont_override(self):
  219. """check that if the access_token param
  220. already exist we don't override it"""
  221. self.session.token = {"access_token": "dummy-access-token"}
  222. response = self.session.get(
  223. "https://api.instagram.com/v1/users/self?access_token=correct-access-token"
  224. )
  225. url = response.request.url
  226. query = parse_qs(urlparse(url).query)
  227. self.assertIn("access_token", query)
  228. self.assertEqual(query["access_token"], ["correct-access-token"])
  229. class PlentymarketsComplianceFixTest(TestCase):
  230. def setUp(self):
  231. mocker = requests_mock.Mocker()
  232. mocker.post(
  233. "https://shop.plentymarkets-cloud02.com",
  234. json={
  235. "accessToken": "ecUN1r8KhJewMCdLAmpHOdZ4O0ofXKB9zf6CXK61",
  236. "tokenType": "Bearer",
  237. "expiresIn": 86400,
  238. "refreshToken": "iG2kBGIjcXaRE4xmTVUnv7xwxX7XMcWCHqJmFaSX",
  239. },
  240. headers={"Content-Type": "application/json"},
  241. )
  242. mocker.start()
  243. self.addCleanup(mocker.stop)
  244. plentymarkets = OAuth2Session("someclientid", redirect_uri="https://i.b")
  245. self.session = plentymarkets_compliance_fix(plentymarkets)
  246. def test_fetch_access_token(self):
  247. token = self.session.fetch_token(
  248. "https://shop.plentymarkets-cloud02.com",
  249. authorization_response="https://i.b/?code=hello",
  250. )
  251. approx_expires_at = time.time() + 86400
  252. actual_expires_at = token.pop("expires_at")
  253. self.assertAlmostEqual(actual_expires_at, approx_expires_at, places=2)
  254. self.assertEqual(
  255. token,
  256. {
  257. "access_token": "ecUN1r8KhJewMCdLAmpHOdZ4O0ofXKB9zf6CXK61",
  258. "expires_in": 86400,
  259. "token_type": "Bearer",
  260. "refresh_token": "iG2kBGIjcXaRE4xmTVUnv7xwxX7XMcWCHqJmFaSX",
  261. },
  262. )
  263. class EbayComplianceFixTest(TestCase):
  264. def setUp(self):
  265. mocker = requests_mock.Mocker()
  266. mocker.post(
  267. "https://api.ebay.com/identity/v1/oauth2/token",
  268. json={
  269. "access_token": "this is the access token",
  270. "expires_in": 7200,
  271. "token_type": "Application Access Token",
  272. },
  273. headers={"Content-Type": "application/json"},
  274. )
  275. mocker.start()
  276. self.addCleanup(mocker.stop)
  277. session = OAuth2Session()
  278. self.fixed_session = ebay_compliance_fix(session)
  279. def test_fetch_access_token(self):
  280. token = self.fixed_session.fetch_token(
  281. "https://api.ebay.com/identity/v1/oauth2/token",
  282. authorization_response="https://i.b/?code=hello",
  283. )
  284. assert token["token_type"] == "Bearer"