From 59321173d8672c5701ce0bf2270d779197d25701 Mon Sep 17 00:00:00 2001 From: Matt Walker Date: Sun, 1 Feb 2015 22:38:26 -0600 Subject: [PATCH] MailChimp compliance fixes that work around oauthlib issue #296 (https://github.com/idan/oauthlib/issues/296) and an unreported issue I ran into where oauthlib rejects MailChimp tokens with expires_in set to 0 --- .../compliance_fixes/__init__.py | 1 + .../compliance_fixes/mailchimp.py | 22 ++++++++++++++ tests/test_compliance_fixes.py | 30 +++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 requests_oauthlib/compliance_fixes/mailchimp.py diff --git a/requests_oauthlib/compliance_fixes/__init__.py b/requests_oauthlib/compliance_fixes/__init__.py index 30cdd10c..c7febb19 100644 --- a/requests_oauthlib/compliance_fixes/__init__.py +++ b/requests_oauthlib/compliance_fixes/__init__.py @@ -2,4 +2,5 @@ from .facebook import facebook_compliance_fix from .linkedin import linkedin_compliance_fix +from .mailchimp import mailchimp_compliance_fix from .weibo import weibo_compliance_fix diff --git a/requests_oauthlib/compliance_fixes/mailchimp.py b/requests_oauthlib/compliance_fixes/mailchimp.py new file mode 100644 index 00000000..ee9bc942 --- /dev/null +++ b/requests_oauthlib/compliance_fixes/mailchimp.py @@ -0,0 +1,22 @@ +import json + +from oauthlib.common import to_unicode + +def mailchimp_compliance_fix(session): + def _null_scope(r): + token = json.loads(r.text) + if 'scope' in token and token['scope'] is None: + token.pop('scope') + r._content = to_unicode(json.dumps(token)).encode('utf-8') + return r + + def _non_zero_expiration(r): + token = json.loads(r.text) + if 'expires_in' in token and token['expires_in'] == 0: + token['expires_in'] = 3600 + r._content = to_unicode(json.dumps(token)).encode('utf-8') + return r + + session.register_compliance_hook('access_token_response', _null_scope) + session.register_compliance_hook('access_token_response', _non_zero_expiration) + return session diff --git a/tests/test_compliance_fixes.py b/tests/test_compliance_fixes.py index 93074a0d..c556e07b 100644 --- a/tests/test_compliance_fixes.py +++ b/tests/test_compliance_fixes.py @@ -3,10 +3,12 @@ import mock import requests +import time from requests_oauthlib import OAuth2Session from requests_oauthlib.compliance_fixes import facebook_compliance_fix from requests_oauthlib.compliance_fixes import linkedin_compliance_fix +from requests_oauthlib.compliance_fixes import mailchimp_compliance_fix from requests_oauthlib.compliance_fixes import weibo_compliance_fix @@ -49,6 +51,34 @@ def test_fetch_access_token(self): self.assertEqual(token, {'access_token': 'linkedin', 'token_type': 'Bearer'}) +class MailChimpComplianceFixTest(unittest.TestCase): + + def test_fetch_access_token(self): + mailchimp = OAuth2Session('foo', redirect_uri='https://i.b') + mailchimp = mailchimp_compliance_fix(mailchimp) + + mailchimp.post = mock.MagicMock() + response = requests.Response() + response.status_code = 200 + response.request = mock.MagicMock() + response._content = '{"access_token":"mailchimp", "expires_in":0, "scope":null}'.encode('UTF-8') + mailchimp.post.return_value = response + + token = mailchimp.fetch_token('https://mocked.out', + client_secret='bar', + 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.assertFalse('scope' in token) + + class WeiboComplianceFixTest(unittest.TestCase): def test_fetch_access_token(self):