from unittest import TestCase import requests import requests_mock import time from urllib.parse import urlparse, parse_qs from oauthlib.oauth2.rfc6749.errors import InvalidGrantError from requests_oauthlib import OAuth2Session from requests_oauthlib.compliance_fixes import facebook_compliance_fix from requests_oauthlib.compliance_fixes import fitbit_compliance_fix from requests_oauthlib.compliance_fixes import mailchimp_compliance_fix from requests_oauthlib.compliance_fixes import weibo_compliance_fix from requests_oauthlib.compliance_fixes import slack_compliance_fix from requests_oauthlib.compliance_fixes import instagram_compliance_fix from requests_oauthlib.compliance_fixes import plentymarkets_compliance_fix from requests_oauthlib.compliance_fixes import ebay_compliance_fix class FacebookComplianceFixTest(TestCase): def setUp(self): mocker = requests_mock.Mocker() mocker.post( "https://graph.facebook.com/oauth/access_token", text="access_token=urlencoded", headers={"Content-Type": "text/plain"}, ) mocker.start() self.addCleanup(mocker.stop) facebook = OAuth2Session("someclientid", redirect_uri="https://i.b") self.session = facebook_compliance_fix(facebook) def test_fetch_access_token(self): token = self.session.fetch_token( "https://graph.facebook.com/oauth/access_token", client_secret="someclientsecret", authorization_response="https://i.b/?code=hello", ) self.assertEqual(token, {"access_token": "urlencoded", "token_type": "Bearer"}) class FitbitComplianceFixTest(TestCase): def setUp(self): self.mocker = requests_mock.Mocker() self.mocker.post( "https://api.fitbit.com/oauth2/token", json={"errors": [{"errorType": "invalid_grant"}]}, ) self.mocker.start() self.addCleanup(self.mocker.stop) fitbit = OAuth2Session("someclientid", redirect_uri="https://i.b") self.session = fitbit_compliance_fix(fitbit) def test_fetch_access_token(self): self.assertRaises( InvalidGrantError, self.session.fetch_token, "https://api.fitbit.com/oauth2/token", client_secret="someclientsecret", authorization_response="https://i.b/?code=hello", ) self.mocker.post( "https://api.fitbit.com/oauth2/token", json={"access_token": "fitbit"} ) token = self.session.fetch_token( "https://api.fitbit.com/oauth2/token", client_secret="good" ) self.assertEqual(token, {"access_token": "fitbit"}) def test_refresh_token(self): self.assertRaises( InvalidGrantError, self.session.refresh_token, "https://api.fitbit.com/oauth2/token", auth=requests.auth.HTTPBasicAuth("someclientid", "someclientsecret"), ) self.mocker.post( "https://api.fitbit.com/oauth2/token", json={"access_token": "access", "refresh_token": "refresh"}, ) token = self.session.refresh_token( "https://api.fitbit.com/oauth2/token", auth=requests.auth.HTTPBasicAuth("someclientid", "someclientsecret"), ) self.assertEqual(token["access_token"], "access") self.assertEqual(token["refresh_token"], "refresh") class MailChimpComplianceFixTest(TestCase): def setUp(self): mocker = requests_mock.Mocker() mocker.post( "https://login.mailchimp.com/oauth2/token", json={"access_token": "mailchimp", "expires_in": 0, "scope": None}, ) mocker.start() self.addCleanup(mocker.stop) mailchimp = OAuth2Session("someclientid", redirect_uri="https://i.b") self.session = mailchimp_compliance_fix(mailchimp) def test_fetch_access_token(self): token = self.session.fetch_token( "https://login.mailchimp.com/oauth2/token", client_secret="someclientsecret", authorization_response="https://i.b/?code=hello", ) # Times should be close approx_expires_at = time.time() + 3600 actual_expires_at = token.pop("expires_at") self.assertAlmostEqual(actual_expires_at, approx_expires_at, places=2) # Other token values exact self.assertEqual(token, {"access_token": "mailchimp", "expires_in": 3600}) # And no scope at all self.assertNotIn("scope", token) class WeiboComplianceFixTest(TestCase): def setUp(self): mocker = requests_mock.Mocker() mocker.post( "https://api.weibo.com/oauth2/access_token", json={"access_token": "weibo"} ) mocker.start() self.addCleanup(mocker.stop) weibo = OAuth2Session("someclientid", redirect_uri="https://i.b") self.session = weibo_compliance_fix(weibo) def test_fetch_access_token(self): token = self.session.fetch_token( "https://api.weibo.com/oauth2/access_token", client_secret="someclientsecret", authorization_response="https://i.b/?code=hello", ) self.assertEqual(token, {"access_token": "weibo", "token_type": "Bearer"}) class SlackComplianceFixTest(TestCase): def setUp(self): mocker = requests_mock.Mocker() mocker.post( "https://slack.com/api/oauth.access", json={"access_token": "xoxt-23984754863-2348975623103", "scope": "read"}, ) for method in ("GET", "POST"): mocker.request( method=method, url="https://slack.com/api/auth.test", json={ "ok": True, "url": "https://myteam.slack.com/", "team": "My Team", "user": "cal", "team_id": "T12345", "user_id": "U12345", }, ) mocker.start() self.addCleanup(mocker.stop) slack = OAuth2Session("someclientid", redirect_uri="https://i.b") self.session = slack_compliance_fix(slack) def test_protected_request(self): self.session.token = {"access_token": "dummy-access-token"} response = self.session.get("https://slack.com/api/auth.test") url = response.request.url query = parse_qs(urlparse(url).query) self.assertNotIn("token", query) body = response.request.body data = parse_qs(body) self.assertEqual(data["token"], ["dummy-access-token"]) def test_protected_request_override_token_get(self): self.session.token = {"access_token": "dummy-access-token"} response = self.session.get( "https://slack.com/api/auth.test", data={"token": "different-token"} ) url = response.request.url query = parse_qs(urlparse(url).query) self.assertNotIn("token", query) body = response.request.body data = parse_qs(body) self.assertEqual(data["token"], ["different-token"]) def test_protected_request_override_token_post(self): self.session.token = {"access_token": "dummy-access-token"} response = self.session.post( "https://slack.com/api/auth.test", data={"token": "different-token"} ) url = response.request.url query = parse_qs(urlparse(url).query) self.assertNotIn("token", query) body = response.request.body data = parse_qs(body) self.assertEqual(data["token"], ["different-token"]) def test_protected_request_override_token_url(self): self.session.token = {"access_token": "dummy-access-token"} response = self.session.get( "https://slack.com/api/auth.test?token=different-token" ) url = response.request.url query = parse_qs(urlparse(url).query) self.assertEqual(query["token"], ["different-token"]) self.assertIsNone(response.request.body) class InstagramComplianceFixTest(TestCase): def setUp(self): mocker = requests_mock.Mocker() mocker.request( method="GET", url="https://api.instagram.com/v1/users/self", json={ "data": { "id": "1574083", "username": "snoopdogg", "full_name": "Snoop Dogg", "profile_picture": "http://distillery.s3.amazonaws.com/profiles/profile_1574083_75sq_1295469061.jpg", "bio": "This is my bio", "website": "http://snoopdogg.com", "is_business": False, "counts": {"media": 1320, "follows": 420, "followed_by": 3410}, } }, ) mocker.start() self.addCleanup(mocker.stop) instagram = OAuth2Session("someclientid", redirect_uri="https://i.b") self.session = instagram_compliance_fix(instagram) def test_protected_request(self): self.session.token = {"access_token": "dummy-access-token"} response = self.session.get("https://api.instagram.com/v1/users/self") url = response.request.url query = parse_qs(urlparse(url).query) self.assertIn("access_token", query) self.assertEqual(query["access_token"], ["dummy-access-token"]) def test_protected_request_dont_override(self): """check that if the access_token param already exist we don't override it""" self.session.token = {"access_token": "dummy-access-token"} response = self.session.get( "https://api.instagram.com/v1/users/self?access_token=correct-access-token" ) url = response.request.url query = parse_qs(urlparse(url).query) self.assertIn("access_token", query) self.assertEqual(query["access_token"], ["correct-access-token"]) class PlentymarketsComplianceFixTest(TestCase): def setUp(self): mocker = requests_mock.Mocker() mocker.post( "https://shop.plentymarkets-cloud02.com", json={ "accessToken": "ecUN1r8KhJewMCdLAmpHOdZ4O0ofXKB9zf6CXK61", "tokenType": "Bearer", "expiresIn": 86400, "refreshToken": "iG2kBGIjcXaRE4xmTVUnv7xwxX7XMcWCHqJmFaSX", }, headers={"Content-Type": "application/json"}, ) mocker.start() self.addCleanup(mocker.stop) plentymarkets = OAuth2Session("someclientid", redirect_uri="https://i.b") self.session = plentymarkets_compliance_fix(plentymarkets) def test_fetch_access_token(self): token = self.session.fetch_token( "https://shop.plentymarkets-cloud02.com", authorization_response="https://i.b/?code=hello", ) approx_expires_at = time.time() + 86400 actual_expires_at = token.pop("expires_at") self.assertAlmostEqual(actual_expires_at, approx_expires_at, places=2) self.assertEqual( token, { "access_token": "ecUN1r8KhJewMCdLAmpHOdZ4O0ofXKB9zf6CXK61", "expires_in": 86400, "token_type": "Bearer", "refresh_token": "iG2kBGIjcXaRE4xmTVUnv7xwxX7XMcWCHqJmFaSX", }, ) class EbayComplianceFixTest(TestCase): def setUp(self): mocker = requests_mock.Mocker() mocker.post( "https://api.ebay.com/identity/v1/oauth2/token", json={ "access_token": "this is the access token", "expires_in": 7200, "token_type": "Application Access Token", }, headers={"Content-Type": "application/json"}, ) mocker.start() self.addCleanup(mocker.stop) session = OAuth2Session() self.fixed_session = ebay_compliance_fix(session) def test_fetch_access_token(self): token = self.fixed_session.fetch_token( "https://api.ebay.com/identity/v1/oauth2/token", authorization_response="https://i.b/?code=hello", ) assert token["token_type"] == "Bearer" def access_and_refresh_token_request_compliance_fix_test(session, client_secret): def _non_compliant_header(url, headers, body): headers["X-Client-Secret"] = client_secret return url, headers, body session.register_compliance_hook("access_token_request", _non_compliant_header) session.register_compliance_hook("refresh_token_request", _non_compliant_header) return session class RefreshTokenRequestComplianceFixTest(TestCase): value_to_test_for = "value_to_test_for" def setUp(self): mocker = requests_mock.Mocker() mocker.post( "https://example.com/token", request_headers={"X-Client-Secret": self.value_to_test_for}, json={ "access_token": "this is the access token", "expires_in": 7200, "token_type": "Bearer", }, headers={"Content-Type": "application/json"}, ) mocker.post( "https://example.com/refresh", request_headers={"X-Client-Secret": self.value_to_test_for}, json={ "access_token": "this is the access token", "expires_in": 7200, "token_type": "Bearer", }, headers={"Content-Type": "application/json"}, ) mocker.start() self.addCleanup(mocker.stop) session = OAuth2Session() self.fixed_session = access_and_refresh_token_request_compliance_fix_test( session, self.value_to_test_for ) def test_access_token(self): token = self.fixed_session.fetch_token( "https://example.com/token", authorization_response="https://i.b/?code=hello", ) assert token["token_type"] == "Bearer" def test_refresh_token(self): token = self.fixed_session.refresh_token( "https://example.com/refresh", ) assert token["token_type"] == "Bearer"