Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions requests_oauthlib/compliance_fixes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
from .slack import slack_compliance_fix
from .mailchimp import mailchimp_compliance_fix
from .weibo import weibo_compliance_fix
from .fitbit import fitbit_compliance_fix
15 changes: 15 additions & 0 deletions requests_oauthlib/compliance_fixes/fitbit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import base64

from oauthlib.common import add_params_to_uri


def fitbit_compliance_fix(session, client_secret):
def _non_compliant_auth_header(url, headers, body):
basic_auth_value = "{}:{}".format(session._client.client_id, client_secret)
headers["Authorization"] = 'Basic {}'.format(base64.b64encode(basic_auth_value))
token = [('token', session._client.access_token)]
url = add_params_to_uri(url, token)
return url, headers, body

session.register_compliance_hook('refresh_token_request', _non_compliant_auth_header)
return session
6 changes: 6 additions & 0 deletions requests_oauthlib/oauth2_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ def __init__(self, client_id=None, client=None, auto_refresh_url=None,
'access_token_response': set([]),
'refresh_token_response': set([]),
'protected_request': set([]),
'refresh_token_request': set([]),
}

def new_state(self):
Expand Down Expand Up @@ -288,6 +289,10 @@ def refresh_token(self, token_url, refresh_token=None, body='', auth=None,
),
}

for hook in self.compliance_hook['refresh_token_request']:
log.debug('Invoking hook %s.', hook)
token_url, headers, body = hook(token_url, headers, body)

r = self.post(token_url, data=dict(urldecode(body)), auth=auth,
timeout=timeout, headers=headers, verify=verify)
log.debug('Request to refresh token completed with status %s.',
Expand Down Expand Up @@ -351,6 +356,7 @@ def register_compliance_hook(self, hook_type, hook):
access_token_response invoked before token parsing.
refresh_token_response invoked before refresh token parsing.
protected_request invoked before making a request.
refresh_token_request invoked before making a refresh request

If you find a new hook is needed please send a GitHub PR request
or open an issue.
Expand Down
32 changes: 32 additions & 0 deletions tests/test_compliance_fixes.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@

import requests
import requests_mock
import mock
import time
import base64
try:
from urlparse import urlparse, parse_qs
except ImportError:
Expand All @@ -18,6 +20,7 @@
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 fitbit_compliance_fix


class FacebookComplianceFixTest(TestCase):
Expand Down Expand Up @@ -216,3 +219,32 @@ def test_protected_request_override_token_url(self):
query = parse_qs(urlparse(url).query)
self.assertEqual(query["token"], ["different-token"])
self.assertIsNone(response.request.body)


class FitbitComplianceFixTest(TestCase):
def test_refresh_token(self):
fitbit = OAuth2Session('foo', redirect_uri='https://i.b')
fitbit = fitbit_compliance_fix(fitbit, "mocksecret")

fitbit.post = mock.MagicMock()
response = requests.Response()
response.status_code = 200
response.request = mock.MagicMock()
response._content = '{"access_token":"fitbit"}'.encode('UTF-8')
fitbit.post.return_value = response

token = fitbit.refresh_token('https://mocked.out',
refresh_token='foobar')

self.assertEqual(token, {'access_token': 'fitbit', 'refresh_token': 'foobar'})

auth_value = base64.b64encode("foo:mocksecret")
fitbit.post.assert_called_with(u'https://mocked.out?token=None', auth=None,
data={u'grant_type': u'refresh_token', u'refresh_token': u'foobar'},
headers={
'Accept': 'application/json',
'Content-Type': (
'application/x-www-form-urlencoded;charset=UTF-8'
),
'Authorization': 'Basic {}'.format(auth_value)
}, timeout=None, verify=True)