diff --git a/requests_oauthlib/oauth2_session.py b/requests_oauthlib/oauth2_session.py index 5c46c2d1..eba305c5 100644 --- a/requests_oauthlib/oauth2_session.py +++ b/requests_oauthlib/oauth2_session.py @@ -1,15 +1,33 @@ from __future__ import unicode_literals import logging +import warnings from oauthlib.common import generate_token, urldecode from oauthlib.oauth2 import WebApplicationClient, InsecureTransportError from oauthlib.oauth2 import TokenExpiredError, is_secure_transport + import requests log = logging.getLogger(__name__) +# Preserve so we can call it. +old_showwarning = warnings.showwarning + +def logwarning(message, category, filename, lineno, file=None): + """ + Log warnings as well as print them. + """ + log.warning( + '%s:%s: %s:%s' % + (filename, lineno, category.__name__, message)) + old_showwarning(message, category, filename, lineno, file=file) + +# Install our new handler. +warnings.showwarning = logwarning + + class TokenUpdated(Warning): def __init__(self, token): super(TokenUpdated, self).__init__() @@ -279,9 +297,6 @@ def refresh_token(self, token_url, refresh_token=None, body='', auth=None, refresh_token = refresh_token or self.token.get('refresh_token') - log.debug('Adding auto refresh key word arguments %s.', - self.auto_refresh_kwargs) - kwargs.update(self.auto_refresh_kwargs) body = self._client.prepare_refresh_body(body=body, refresh_token=refresh_token, scope=self.scope, **kwargs) log.debug('Prepared refresh token request body %s', body) @@ -334,13 +349,42 @@ def request(self, method, url, data=None, headers=None, withhold_token=False, log.debug('Auto refresh is set, attempting to refresh at %s.', self.auto_refresh_url) - # We mustn't pass auth twice. - auth = kwargs.pop('auth', None) - if client_id and client_secret and (auth is None): + # Someday this code can be eliminated, we should be able to + # simply pass **self.auto_refresh_kwargs to + # `refresh_token()` what follows is to maintain + # compatibility + + # Start with kwargs explicitly requested for refresh. + refresh_kwargs = self.auto_refresh_kwargs.copy() + + if kwargs.get('auth', None): + # If user supplied `auth` to `request()` warn them to + # instead use `auto_refresh_kwargs`. But honor their + # intent for now. + warnings.warn('auth argument supplied. Please specify ' + 'token refresh authentication in ' + 'auto_refresh_kwargs.') + refresh_kwargs['auth'] = kwargs.pop('auth') + elif client_id: + # If no auth was provided, but `client_id` and + # `client_secret` were, warn the user and create an + # HTTP Basic auth header. It is preferred if the user + # instead place an auth param into `auto_refresh_kwargs` + warnings.warn('client_id argument supplied, Please ' + 'specify token refresh authentication in' + 'auto_refresh_kwargs') log.debug('Encoding client_id "%s" with client_secret as Basic auth credentials.', client_id) - auth = requests.auth.HTTPBasicAuth(client_id, client_secret) + if not client_secret: + warnings.warn('client_id provided, but ' + 'client_secret missing') + client_secret = '' + refresh_kwargs['auth'] = \ + requests.auth.HTTPBasicAuth(client_id, client_secret) + + # End of compat. code. + token = self.refresh_token( - self.auto_refresh_url, auth=auth, **kwargs + self.auto_refresh_url, **refresh_kwargs ) if self.token_updater: log.debug('Updating token to %s using %s.', diff --git a/tests/test_oauth2_session.py b/tests/test_oauth2_session.py index a222df00..ec850e14 100644 --- a/tests/test_oauth2_session.py +++ b/tests/test_oauth2_session.py @@ -15,7 +15,7 @@ from oauthlib.oauth2 import WebApplicationClient, MobileApplicationClient from oauthlib.oauth2 import LegacyApplicationClient, BackendApplicationClient from requests_oauthlib import OAuth2Session, TokenUpdated - +from requests.auth import HTTPBasicAuth fake_time = time.time() @@ -131,6 +131,9 @@ def fake_refresh_with_auth(r, **kwargs): resp.text = json.dumps(self.token) return resp + # Make sure client_id and client_secret are converted to Basic Auth. + # This is a deprecated implicit auth method and should be removed in + # favor of auto_refresh_kwargs. for client in self.clients: auth = OAuth2Session(client=client, token=self.expired_token, auto_refresh_url='https://i.b/refresh', @@ -138,6 +141,33 @@ def fake_refresh_with_auth(r, **kwargs): auth.send = fake_refresh_with_auth auth.get('https://i.b', client_id='foo', client_secret='bar') + # Make sure auth param is passed through, this is a deprecated implicit + # auth method and should be removed in favor of auto_refresh_kwargs. + for client in self.clients: + auth = OAuth2Session(client=client, token=self.expired_token, + auto_refresh_url='https://i.b/refresh', + token_updater=token_updater) + auth.send = fake_refresh_with_auth + auth.get('https://i.b', auth=HTTPBasicAuth('foo', 'bar')) + + def explicit_refresh_post(r, **kwargs): + if "/refresh" in r.url: + self.assertIn('foo-client-id', r.body) + self.assertIn('foo-client-secret', r.body) + self.assertNotIn("Authorization", r.headers) + resp = mock.MagicMock() + resp.text = json.dumps(self.token) + return resp + + for client in self.clients: + auth = OAuth2Session(client=client, token=self.expired_token, + auto_refresh_url='https://i.b/refresh', + auto_refresh_kwargs={'client_id': 'foo-client-id', + 'client_secret': 'foo-client-secret'}, + token_updater=token_updater) + auth.send = explicit_refresh_post + auth.post('https://i.b') + @mock.patch("time.time", new=lambda: fake_time) def test_token_from_fragment(self): mobile = MobileApplicationClient(self.client_id)