requests-oauthlib-1.0.0/0000755000076500000240000000000013305201162017344 5ustar singingwolfboystaff00000000000000requests-oauthlib-1.0.0/PKG-INFO0000644000076500000240000002227413305201162020450 0ustar singingwolfboystaff00000000000000Metadata-Version: 2.1 Name: requests-oauthlib Version: 1.0.0 Summary: OAuthlib authentication support for Requests. Home-page: https://github.com/requests/requests-oauthlib Author: Kenneth Reitz Author-email: me@kennethreitz.com License: ISC Description: Requests-OAuthlib |build-status| |coverage-status| |docs| ========================================================= This project provides first-class OAuth library support for `Requests `_. The OAuth 1 workflow -------------------- OAuth 1 can seem overly complicated and it sure has its quirks. Luckily, requests_oauthlib hides most of these and let you focus at the task at hand. Accessing protected resources using requests_oauthlib is as simple as: .. code-block:: pycon >>> from requests_oauthlib import OAuth1Session >>> twitter = OAuth1Session('client_key', client_secret='client_secret', resource_owner_key='resource_owner_key', resource_owner_secret='resource_owner_secret') >>> url = 'https://api.twitter.com/1/account/settings.json' >>> r = twitter.get(url) Before accessing resources you will need to obtain a few credentials from your provider (e.g. Twitter) and authorization from the user for whom you wish to retrieve resources for. You can read all about this in the full `OAuth 1 workflow guide on RTD `_. The OAuth 2 workflow -------------------- OAuth 2 is generally simpler than OAuth 1 but comes in more flavours. The most common being the Authorization Code Grant, also known as the WebApplication flow. Fetching a protected resource after obtaining an access token can be extremely simple. However, before accessing resources you will need to obtain a few credentials from your provider (e.g. Google) and authorization from the user for whom you wish to retrieve resources for. You can read all about this in the full `OAuth 2 workflow guide on RTD `_. Installation ------------- To install requests and requests_oauthlib you can use pip: .. code-block:: bash $ pip install requests requests_oauthlib .. |build-status| image:: https://travis-ci.org/requests/requests-oauthlib.svg?branch=master :target: https://travis-ci.org/requests/requests-oauthlib .. |coverage-status| image:: https://img.shields.io/coveralls/requests/requests-oauthlib.svg :target: https://coveralls.io/r/requests/requests-oauthlib .. |docs| image:: https://readthedocs.org/projects/requests-oauthlib/badge/ :alt: Documentation Status :scale: 100% :target: https://requests-oauthlib.readthedocs.io/ History ------- UNRELEASED ++++++++++ nothing yet v1.0.0 (4 June 2018) ++++++++++++++++++++ - **Removed support for Python 2.6 and Python 3.3.** This project now supports Python 2.7, and Python 3.4 and above. - Added several examples to the documentation. - Added plentymarkets compliance fix. - Added a ``token`` property to OAuth1Session, to match the corresponding ``token`` property on OAuth2Session. v0.8.0 (14 February 2017) +++++++++++++++++++++++++ - Added Fitbit compliance fix. - Fixed an issue where newlines in the response body for the access token request would cause errors when trying to extract the token. - Fixed an issue introduced in v0.7.0 where users passing ``auth`` to several methods would encounter conflicts with the ``client_id`` and ``client_secret``-derived auth. The user-supplied ``auth`` argument is now used in preference to those options. v0.7.0 (22 September 2016) ++++++++++++++++++++++++++ - Allowed ``OAuth2Session.request`` to take the ``client_id`` and ``client_secret`` parameters for the purposes of automatic token refresh, which may need them. v0.6.2 (12 July 2016) +++++++++++++++++++++ - Use ``client_id`` and ``client_secret`` for the Authorization header if provided. - Allow explicit bypass of the Authorization header by setting ``auth=False``. - Pass through the ``proxies`` kwarg when refreshing tokens. - Miscellaneous cleanups. v0.6.1 (19 February 2016) +++++++++++++++++++++++++ - Fixed a bug when sending authorization in headers with no username and password present. - Make sure we clear the session token before obtaining a new one. - Some improvements to the Slack compliance fix. - Avoid timing problems around token refresh. - Allow passing arbitrary arguments to requests when calling ``fetch_request_token`` and ``fetch_access_token``. v0.6.0 (14 December 2015) +++++++++++++++++++++++++ - Add compliance fix for Slack. - Add compliance fix for Mailchimp. - ``TokenRequestDenied`` exceptions now carry the entire response, not just the status code. - Pass through keyword arguments when refreshing tokens automatically. - Send authorization in headers, not just body, to maximize compatibility. - More getters/setters available for OAuth2 session client values. - Allow sending custom headers when refreshing tokens, and set some defaults. v0.5.0 (4 May 2015) +++++++++++++++++++ - Fix ``TypeError`` being raised instead of ``TokenMissing`` error. - Raise requests exceptions on 4XX and 5XX responses in the OAuth2 flow. - Avoid ``AttributeError`` when initializing the ``OAuth2Session`` class without complete client information. v0.4.2 (16 October 2014) ++++++++++++++++++++++++ - New ``authorized`` property on OAuth1Session and OAuth2Session, which allows you to easily determine if the session is already authorized with OAuth tokens or not. - New ``TokenMissing`` and ``VerifierMissing`` exception classes for OAuth1Session: this will make it easier to catch and identify these exceptions. v0.4.1 (6 June 2014) ++++++++++++++++++++ - New install target ``[rsa]`` for people using OAuth1 RSA-SHA1 signature method. - Fixed bug in OAuth2 where supplied state param was not used in auth url. - OAuth2 HTTPS checking can be disabled by setting environment variable ``OAUTHLIB_INSECURE_TRANSPORT``. - OAuth1 now re-authorize upon redirects. - OAuth1 token fetching now raise a detailed error message when the response body is incorrectly encoded or the request was denied. - Added support for custom OAuth1 clients. - OAuth2 compliance fix for Sina Weibo. - Multiple fixes to facebook compliance fix. - Compliance fixes now re-encode body properly as bytes in Python 3. - Logging now properly done under ``requests_oauthlib`` namespace instead of piggybacking on oauthlib namespace. - Logging introduced for OAuth1 auth and session. v0.4.0 (29 September 2013) ++++++++++++++++++++++++++ - OAuth1Session methods only return unicode strings. #55. - Renamed requests_oauthlib.core to requests_oauthlib.oauth1_auth for consistency. #79. - Added Facebook compliance fix and access_token_response hook to OAuth2Session. #63. - Added LinkedIn compliance fix. - Added refresh_token_response compliance hook, invoked before parsing the refresh token. - Correctly limit compliance hooks to running only once! - Content type guessing should only be done when no content type is given - OAuth1 now updates r.headers instead of replacing it with non case insensitive dict - Remove last use of Response.content (in OAuth1Session). #44. - State param can now be supplied in OAuth2Session.authorize_url Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: Natural Language :: English Classifier: License :: OSI Approved :: BSD License Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* Provides-Extra: rsa requests-oauthlib-1.0.0/requests_oauthlib/0000755000076500000240000000000013305201162023106 5ustar singingwolfboystaff00000000000000requests-oauthlib-1.0.0/requests_oauthlib/oauth2_session.py0000644000076500000240000004147213263226123026444 0ustar singingwolfboystaff00000000000000from __future__ import unicode_literals import logging 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__) class TokenUpdated(Warning): def __init__(self, token): super(TokenUpdated, self).__init__() self.token = token class OAuth2Session(requests.Session): """Versatile OAuth 2 extension to :class:`requests.Session`. Supports any grant type adhering to :class:`oauthlib.oauth2.Client` spec including the four core OAuth 2 grants. Can be used to create authorization urls, fetch tokens and access protected resources using the :class:`requests.Session` interface you are used to. - :class:`oauthlib.oauth2.WebApplicationClient` (default): Authorization Code Grant - :class:`oauthlib.oauth2.MobileApplicationClient`: Implicit Grant - :class:`oauthlib.oauth2.LegacyApplicationClient`: Password Credentials Grant - :class:`oauthlib.oauth2.BackendApplicationClient`: Client Credentials Grant Note that the only time you will be using Implicit Grant from python is if you are driving a user agent able to obtain URL fragments. """ def __init__(self, client_id=None, client=None, auto_refresh_url=None, auto_refresh_kwargs=None, scope=None, redirect_uri=None, token=None, state=None, token_updater=None, **kwargs): """Construct a new OAuth 2 client session. :param client_id: Client id obtained during registration :param client: :class:`oauthlib.oauth2.Client` to be used. Default is WebApplicationClient which is useful for any hosted application but not mobile or desktop. :param scope: List of scopes you wish to request access to :param redirect_uri: Redirect URI you registered as callback :param token: Token dictionary, must include access_token and token_type. :param state: State string used to prevent CSRF. This will be given when creating the authorization url and must be supplied when parsing the authorization response. Can be either a string or a no argument callable. :auto_refresh_url: Refresh token endpoint URL, must be HTTPS. Supply this if you wish the client to automatically refresh your access tokens. :auto_refresh_kwargs: Extra arguments to pass to the refresh token endpoint. :token_updater: Method with one argument, token, to be used to update your token database on automatic token refresh. If not set a TokenUpdated warning will be raised when a token has been refreshed. This warning will carry the token in its token argument. :param kwargs: Arguments to pass to the Session constructor. """ super(OAuth2Session, self).__init__(**kwargs) self._client = client or WebApplicationClient(client_id, token=token) self.token = token or {} self.scope = scope self.redirect_uri = redirect_uri self.state = state or generate_token self._state = state self.auto_refresh_url = auto_refresh_url self.auto_refresh_kwargs = auto_refresh_kwargs or {} self.token_updater = token_updater # Allow customizations for non compliant providers through various # hooks to adjust requests and responses. self.compliance_hook = { 'access_token_response': set(), 'refresh_token_response': set(), 'protected_request': set(), } def new_state(self): """Generates a state string to be used in authorizations.""" try: self._state = self.state() log.debug('Generated new state %s.', self._state) except TypeError: self._state = self.state log.debug('Re-using previously supplied state %s.', self._state) return self._state @property def client_id(self): return getattr(self._client, "client_id", None) @client_id.setter def client_id(self, value): self._client.client_id = value @client_id.deleter def client_id(self): del self._client.client_id @property def token(self): return getattr(self._client, "token", None) @token.setter def token(self, value): self._client.token = value self._client._populate_attributes(value) @property def access_token(self): return getattr(self._client, "access_token", None) @access_token.setter def access_token(self, value): self._client.access_token = value @access_token.deleter def access_token(self): del self._client.access_token @property def authorized(self): """Boolean that indicates whether this session has an OAuth token or not. If `self.authorized` is True, you can reasonably expect OAuth-protected requests to the resource to succeed. If `self.authorized` is False, you need the user to go through the OAuth authentication dance before OAuth-protected requests to the resource will succeed. """ return bool(self.access_token) def authorization_url(self, url, state=None, **kwargs): """Form an authorization URL. :param url: Authorization endpoint url, must be HTTPS. :param state: An optional state string for CSRF protection. If not given it will be generated for you. :param kwargs: Extra parameters to include. :return: authorization_url, state """ state = state or self.new_state() return self._client.prepare_request_uri(url, redirect_uri=self.redirect_uri, scope=self.scope, state=state, **kwargs), state def fetch_token(self, token_url, code=None, authorization_response=None, body='', auth=None, username=None, password=None, method='POST', timeout=None, headers=None, verify=True, proxies=None, **kwargs): """Generic method for fetching an access token from the token endpoint. If you are using the MobileApplicationClient you will want to use token_from_fragment instead of fetch_token. :param token_url: Token endpoint URL, must use HTTPS. :param code: Authorization code (used by WebApplicationClients). :param authorization_response: Authorization response URL, the callback URL of the request back to you. Used by WebApplicationClients instead of code. :param body: Optional application/x-www-form-urlencoded body to add the include in the token request. Prefer kwargs over body. :param auth: An auth tuple or method as accepted by requests. :param username: Username used by LegacyApplicationClients. :param password: Password used by LegacyApplicationClients. :param method: The HTTP method used to make the request. Defaults to POST, but may also be GET. Other methods should be added as needed. :param headers: Dict to default request headers with. :param timeout: Timeout of the request in seconds. :param verify: Verify SSL certificate. :param kwargs: Extra parameters to include in the token request. :return: A token dict """ if not is_secure_transport(token_url): raise InsecureTransportError() if not code and authorization_response: self._client.parse_request_uri_response(authorization_response, state=self._state) code = self._client.code elif not code and isinstance(self._client, WebApplicationClient): code = self._client.code if not code: raise ValueError('Please supply either code or ' 'authorization_response parameters.') body = self._client.prepare_request_body(code=code, body=body, redirect_uri=self.redirect_uri, username=username, password=password, **kwargs) client_id = kwargs.get('client_id', '') if auth is None: if client_id: log.debug('Encoding client_id "%s" with client_secret as Basic auth credentials.', client_id) client_secret = kwargs.get('client_secret', '') client_secret = client_secret if client_secret is not None else '' auth = requests.auth.HTTPBasicAuth(client_id, client_secret) elif username: if password is None: raise ValueError('Username was supplied, but not password.') log.debug('Encoding username, password as Basic auth credentials.') auth = requests.auth.HTTPBasicAuth(username, password) headers = headers or { 'Accept': 'application/json', 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', } self.token = {} if method.upper() == 'POST': r = self.post(token_url, data=dict(urldecode(body)), timeout=timeout, headers=headers, auth=auth, verify=verify, proxies=proxies) log.debug('Prepared fetch token request body %s', body) elif method.upper() == 'GET': # if method is not 'POST', switch body to querystring and GET r = self.get(token_url, params=dict(urldecode(body)), timeout=timeout, headers=headers, auth=auth, verify=verify, proxies=proxies) log.debug('Prepared fetch token request querystring %s', body) else: raise ValueError('The method kwarg must be POST or GET.') log.debug('Request to fetch token completed with status %s.', r.status_code) log.debug('Request headers were %s', r.request.headers) log.debug('Request body was %s', r.request.body) log.debug('Response headers were %s and content %s.', r.headers, r.text) log.debug('Invoking %d token response hooks.', len(self.compliance_hook['access_token_response'])) for hook in self.compliance_hook['access_token_response']: log.debug('Invoking hook %s.', hook) r = hook(r) self._client.parse_request_body_response(r.text, scope=self.scope) self.token = self._client.token log.debug('Obtained token %s.', self.token) return self.token def token_from_fragment(self, authorization_response): """Parse token from the URI fragment, used by MobileApplicationClients. :param authorization_response: The full URL of the redirect back to you :return: A token dict """ self._client.parse_request_uri_response(authorization_response, state=self._state) self.token = self._client.token return self.token def refresh_token(self, token_url, refresh_token=None, body='', auth=None, timeout=None, headers=None, verify=True, proxies=None, **kwargs): """Fetch a new access token using a refresh token. :param token_url: The token endpoint, must be HTTPS. :param refresh_token: The refresh_token to use. :param body: Optional application/x-www-form-urlencoded body to add the include in the token request. Prefer kwargs over body. :param auth: An auth tuple or method as accepted by requests. :param timeout: Timeout of the request in seconds. :param verify: Verify SSL certificate. :param kwargs: Extra parameters to include in the token request. :return: A token dict """ if not token_url: raise ValueError('No token endpoint set for auto_refresh.') if not is_secure_transport(token_url): raise InsecureTransportError() 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) if headers is None: headers = { 'Accept': 'application/json', 'Content-Type': ( 'application/x-www-form-urlencoded;charset=UTF-8' ), } r = self.post(token_url, data=dict(urldecode(body)), auth=auth, timeout=timeout, headers=headers, verify=verify, withhold_token=True, proxies=proxies) log.debug('Request to refresh token completed with status %s.', r.status_code) log.debug('Response headers were %s and content %s.', r.headers, r.text) log.debug('Invoking %d token response hooks.', len(self.compliance_hook['refresh_token_response'])) for hook in self.compliance_hook['refresh_token_response']: log.debug('Invoking hook %s.', hook) r = hook(r) self.token = self._client.parse_request_body_response(r.text, scope=self.scope) if not 'refresh_token' in self.token: log.debug('No new refresh token given. Re-using old.') self.token['refresh_token'] = refresh_token return self.token def request(self, method, url, data=None, headers=None, withhold_token=False, client_id=None, client_secret=None, **kwargs): """Intercept all requests and add the OAuth 2 token if present.""" if not is_secure_transport(url): raise InsecureTransportError() if self.token and not withhold_token: log.debug('Invoking %d protected resource request hooks.', len(self.compliance_hook['protected_request'])) for hook in self.compliance_hook['protected_request']: log.debug('Invoking hook %s.', hook) url, headers, data = hook(url, headers, data) log.debug('Adding token %s to request.', self.token) try: url, headers, data = self._client.add_token(url, http_method=method, body=data, headers=headers) # Attempt to retrieve and save new access token if expired except TokenExpiredError: if self.auto_refresh_url: 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): log.debug('Encoding client_id "%s" with client_secret as Basic auth credentials.', client_id) auth = requests.auth.HTTPBasicAuth(client_id, client_secret) token = self.refresh_token( self.auto_refresh_url, auth=auth, **kwargs ) if self.token_updater: log.debug('Updating token to %s using %s.', token, self.token_updater) self.token_updater(token) url, headers, data = self._client.add_token(url, http_method=method, body=data, headers=headers) else: raise TokenUpdated(token) else: raise log.debug('Requesting url %s using method %s.', url, method) log.debug('Supplying headers %s and data %s', headers, data) log.debug('Passing through key word arguments %s.', kwargs) return super(OAuth2Session, self).request(method, url, headers=headers, data=data, **kwargs) def register_compliance_hook(self, hook_type, hook): """Register a hook for request/response tweaking. Available hooks are: access_token_response invoked before token parsing. refresh_token_response invoked before refresh token parsing. protected_request invoked before making a request. If you find a new hook is needed please send a GitHub PR request or open an issue. """ if hook_type not in self.compliance_hook: raise ValueError('Hook type %s is not in %s.', hook_type, self.compliance_hook) self.compliance_hook[hook_type].add(hook) requests-oauthlib-1.0.0/requests_oauthlib/__init__.py0000644000076500000240000000100513305200743025217 0ustar singingwolfboystaff00000000000000import logging from .oauth1_auth import OAuth1 from .oauth1_session import OAuth1Session from .oauth2_auth import OAuth2 from .oauth2_session import OAuth2Session, TokenUpdated __version__ = '1.0.0' import requests if requests.__version__ < '2.0.0': msg = ('You are using requests version %s, which is older than ' 'requests-oauthlib expects, please upgrade to 2.0.0 or later.') raise Warning(msg % requests.__version__) logging.getLogger('requests_oauthlib').addHandler(logging.NullHandler()) requests-oauthlib-1.0.0/requests_oauthlib/oauth2_auth.py0000644000076500000240000000300612760373502025716 0ustar singingwolfboystaff00000000000000from __future__ import unicode_literals from oauthlib.oauth2 import WebApplicationClient, InsecureTransportError from oauthlib.oauth2 import is_secure_transport from requests.auth import AuthBase class OAuth2(AuthBase): """Adds proof of authorization (OAuth2 token) to the request.""" def __init__(self, client_id=None, client=None, token=None): """Construct a new OAuth 2 authorization object. :param client_id: Client id obtained during registration :param client: :class:`oauthlib.oauth2.Client` to be used. Default is WebApplicationClient which is useful for any hosted application but not mobile or desktop. :param token: Token dictionary, must include access_token and token_type. """ self._client = client or WebApplicationClient(client_id, token=token) if token: for k, v in token.items(): setattr(self._client, k, v) def __call__(self, r): """Append an OAuth 2 token to the request. Note that currently HTTPS is required for all requests. There may be a token type that allows for plain HTTP in the future and then this should be updated to allow plain HTTP on a white list basis. """ if not is_secure_transport(r.url): raise InsecureTransportError() r.url, r.headers, r.body = self._client.add_token(r.url, http_method=r.method, body=r.body, headers=r.headers) return r requests-oauthlib-1.0.0/requests_oauthlib/oauth1_session.py0000644000076500000240000004131013277061160026435 0ustar singingwolfboystaff00000000000000from __future__ import unicode_literals try: from urlparse import urlparse except ImportError: from urllib.parse import urlparse import logging from oauthlib.common import add_params_to_uri from oauthlib.common import urldecode as _urldecode from oauthlib.oauth1 import ( SIGNATURE_HMAC, SIGNATURE_RSA, SIGNATURE_TYPE_AUTH_HEADER ) import requests from . import OAuth1 log = logging.getLogger(__name__) def urldecode(body): """Parse query or json to python dictionary""" try: return _urldecode(body) except: import json return json.loads(body) class TokenRequestDenied(ValueError): def __init__(self, message, response): super(TokenRequestDenied, self).__init__(message) self.response = response @property def status_code(self): """For backwards-compatibility purposes""" return self.response.status_code class TokenMissing(ValueError): def __init__(self, message, response): super(TokenMissing, self).__init__(message) self.response = response class VerifierMissing(ValueError): pass class OAuth1Session(requests.Session): """Request signing and convenience methods for the oauth dance. What is the difference between OAuth1Session and OAuth1? OAuth1Session actually uses OAuth1 internally and its purpose is to assist in the OAuth workflow through convenience methods to prepare authorization URLs and parse the various token and redirection responses. It also provide rudimentary validation of responses. An example of the OAuth workflow using a basic CLI app and Twitter. >>> # Credentials obtained during the registration. >>> client_key = 'client key' >>> client_secret = 'secret' >>> callback_uri = 'https://127.0.0.1/callback' >>> >>> # Endpoints found in the OAuth provider API documentation >>> request_token_url = 'https://api.twitter.com/oauth/request_token' >>> authorization_url = 'https://api.twitter.com/oauth/authorize' >>> access_token_url = 'https://api.twitter.com/oauth/access_token' >>> >>> oauth_session = OAuth1Session(client_key,client_secret=client_secret, callback_uri=callback_uri) >>> >>> # First step, fetch the request token. >>> oauth_session.fetch_request_token(request_token_url) { 'oauth_token': 'kjerht2309u', 'oauth_token_secret': 'lsdajfh923874', } >>> >>> # Second step. Follow this link and authorize >>> oauth_session.authorization_url(authorization_url) 'https://api.twitter.com/oauth/authorize?oauth_token=sdf0o9823sjdfsdf&oauth_callback=https%3A%2F%2F127.0.0.1%2Fcallback' >>> >>> # Third step. Fetch the access token >>> redirect_response = raw_input('Paste the full redirect URL here.') >>> oauth_session.parse_authorization_response(redirect_response) { 'oauth_token: 'kjerht2309u', 'oauth_token_secret: 'lsdajfh923874', 'oauth_verifier: 'w34o8967345', } >>> oauth_session.fetch_access_token(access_token_url) { 'oauth_token': 'sdf0o9823sjdfsdf', 'oauth_token_secret': '2kjshdfp92i34asdasd', } >>> # Done. You can now make OAuth requests. >>> status_url = 'http://api.twitter.com/1/statuses/update.json' >>> new_status = {'status': 'hello world!'} >>> oauth_session.post(status_url, data=new_status) """ def __init__(self, client_key, client_secret=None, resource_owner_key=None, resource_owner_secret=None, callback_uri=None, signature_method=SIGNATURE_HMAC, signature_type=SIGNATURE_TYPE_AUTH_HEADER, rsa_key=None, verifier=None, client_class=None, force_include_body=False, **kwargs): """Construct the OAuth 1 session. :param client_key: A client specific identifier. :param client_secret: A client specific secret used to create HMAC and plaintext signatures. :param resource_owner_key: A resource owner key, also referred to as request token or access token depending on when in the workflow it is used. :param resource_owner_secret: A resource owner secret obtained with either a request or access token. Often referred to as token secret. :param callback_uri: The URL the user is redirect back to after authorization. :param signature_method: Signature methods determine how the OAuth signature is created. The three options are oauthlib.oauth1.SIGNATURE_HMAC (default), oauthlib.oauth1.SIGNATURE_RSA and oauthlib.oauth1.SIGNATURE_PLAIN. :param signature_type: Signature type decides where the OAuth parameters are added. Either in the Authorization header (default) or to the URL query parameters or the request body. Defined as oauthlib.oauth1.SIGNATURE_TYPE_AUTH_HEADER, oauthlib.oauth1.SIGNATURE_TYPE_QUERY and oauthlib.oauth1.SIGNATURE_TYPE_BODY respectively. :param rsa_key: The private RSA key as a string. Can only be used with signature_method=oauthlib.oauth1.SIGNATURE_RSA. :param verifier: A verifier string to prove authorization was granted. :param client_class: A subclass of `oauthlib.oauth1.Client` to use with `requests_oauthlib.OAuth1` instead of the default :param force_include_body: Always include the request body in the signature creation. :param **kwargs: Additional keyword arguments passed to `OAuth1` """ super(OAuth1Session, self).__init__() self._client = OAuth1(client_key, client_secret=client_secret, resource_owner_key=resource_owner_key, resource_owner_secret=resource_owner_secret, callback_uri=callback_uri, signature_method=signature_method, signature_type=signature_type, rsa_key=rsa_key, verifier=verifier, client_class=client_class, force_include_body=force_include_body, **kwargs) self.auth = self._client @property def token(self): oauth_token = self._client.client.resource_owner_key oauth_token_secret = self._client.client.resource_owner_secret oauth_verifier = self._client.client.verifier token_dict = {} if oauth_token: token_dict["oauth_token"] = oauth_token if oauth_token_secret: token_dict["oauth_token_secret"] = oauth_token_secret if oauth_verifier: token_dict["oauth_verifier"] = oauth_verifier return token_dict @token.setter def token(self, value): self._populate_attributes(value) @property def authorized(self): """Boolean that indicates whether this session has an OAuth token or not. If `self.authorized` is True, you can reasonably expect OAuth-protected requests to the resource to succeed. If `self.authorized` is False, you need the user to go through the OAuth authentication dance before OAuth-protected requests to the resource will succeed. """ if self._client.client.signature_method == SIGNATURE_RSA: # RSA only uses resource_owner_key return bool(self._client.client.resource_owner_key) else: # other methods of authentication use all three pieces return ( bool(self._client.client.client_secret) and bool(self._client.client.resource_owner_key) and bool(self._client.client.resource_owner_secret) ) def authorization_url(self, url, request_token=None, **kwargs): """Create an authorization URL by appending request_token and optional kwargs to url. This is the second step in the OAuth 1 workflow. The user should be redirected to this authorization URL, grant access to you, and then be redirected back to you. The redirection back can either be specified during client registration or by supplying a callback URI per request. :param url: The authorization endpoint URL. :param request_token: The previously obtained request token. :param kwargs: Optional parameters to append to the URL. :returns: The authorization URL with new parameters embedded. An example using a registered default callback URI. >>> request_token_url = 'https://api.twitter.com/oauth/request_token' >>> authorization_url = 'https://api.twitter.com/oauth/authorize' >>> oauth_session = OAuth1Session('client-key', client_secret='secret') >>> oauth_session.fetch_request_token(request_token_url) { 'oauth_token': 'sdf0o9823sjdfsdf', 'oauth_token_secret': '2kjshdfp92i34asdasd', } >>> oauth_session.authorization_url(authorization_url) 'https://api.twitter.com/oauth/authorize?oauth_token=sdf0o9823sjdfsdf' >>> oauth_session.authorization_url(authorization_url, foo='bar') 'https://api.twitter.com/oauth/authorize?oauth_token=sdf0o9823sjdfsdf&foo=bar' An example using an explicit callback URI. >>> request_token_url = 'https://api.twitter.com/oauth/request_token' >>> authorization_url = 'https://api.twitter.com/oauth/authorize' >>> oauth_session = OAuth1Session('client-key', client_secret='secret', callback_uri='https://127.0.0.1/callback') >>> oauth_session.fetch_request_token(request_token_url) { 'oauth_token': 'sdf0o9823sjdfsdf', 'oauth_token_secret': '2kjshdfp92i34asdasd', } >>> oauth_session.authorization_url(authorization_url) 'https://api.twitter.com/oauth/authorize?oauth_token=sdf0o9823sjdfsdf&oauth_callback=https%3A%2F%2F127.0.0.1%2Fcallback' """ kwargs['oauth_token'] = request_token or self._client.client.resource_owner_key log.debug('Adding parameters %s to url %s', kwargs, url) return add_params_to_uri(url, kwargs.items()) def fetch_request_token(self, url, realm=None, **request_kwargs): """Fetch a request token. This is the first step in the OAuth 1 workflow. A request token is obtained by making a signed post request to url. The token is then parsed from the application/x-www-form-urlencoded response and ready to be used to construct an authorization url. :param url: The request token endpoint URL. :param realm: A list of realms to request access to. :param \*\*request_kwargs: Optional arguments passed to ''post'' function in ''requests.Session'' :returns: The response in dict format. Note that a previously set callback_uri will be reset for your convenience, or else signature creation will be incorrect on consecutive requests. >>> request_token_url = 'https://api.twitter.com/oauth/request_token' >>> oauth_session = OAuth1Session('client-key', client_secret='secret') >>> oauth_session.fetch_request_token(request_token_url) { 'oauth_token': 'sdf0o9823sjdfsdf', 'oauth_token_secret': '2kjshdfp92i34asdasd', } """ self._client.client.realm = ' '.join(realm) if realm else None token = self._fetch_token(url, **request_kwargs) log.debug('Resetting callback_uri and realm (not needed in next phase).') self._client.client.callback_uri = None self._client.client.realm = None return token def fetch_access_token(self, url, verifier=None, **request_kwargs): """Fetch an access token. This is the final step in the OAuth 1 workflow. An access token is obtained using all previously obtained credentials, including the verifier from the authorization step. Note that a previously set verifier will be reset for your convenience, or else signature creation will be incorrect on consecutive requests. >>> access_token_url = 'https://api.twitter.com/oauth/access_token' >>> redirect_response = 'https://127.0.0.1/callback?oauth_token=kjerht2309uf&oauth_token_secret=lsdajfh923874&oauth_verifier=w34o8967345' >>> oauth_session = OAuth1Session('client-key', client_secret='secret') >>> oauth_session.parse_authorization_response(redirect_response) { 'oauth_token: 'kjerht2309u', 'oauth_token_secret: 'lsdajfh923874', 'oauth_verifier: 'w34o8967345', } >>> oauth_session.fetch_access_token(access_token_url) { 'oauth_token': 'sdf0o9823sjdfsdf', 'oauth_token_secret': '2kjshdfp92i34asdasd', } """ if verifier: self._client.client.verifier = verifier if not getattr(self._client.client, 'verifier', None): raise VerifierMissing('No client verifier has been set.') token = self._fetch_token(url, **request_kwargs) log.debug('Resetting verifier attribute, should not be used anymore.') self._client.client.verifier = None return token def parse_authorization_response(self, url): """Extract parameters from the post authorization redirect response URL. :param url: The full URL that resulted from the user being redirected back from the OAuth provider to you, the client. :returns: A dict of parameters extracted from the URL. >>> redirect_response = 'https://127.0.0.1/callback?oauth_token=kjerht2309uf&oauth_token_secret=lsdajfh923874&oauth_verifier=w34o8967345' >>> oauth_session = OAuth1Session('client-key', client_secret='secret') >>> oauth_session.parse_authorization_response(redirect_response) { 'oauth_token: 'kjerht2309u', 'oauth_token_secret: 'lsdajfh923874', 'oauth_verifier: 'w34o8967345', } """ log.debug('Parsing token from query part of url %s', url) token = dict(urldecode(urlparse(url).query)) log.debug('Updating internal client token attribute.') self._populate_attributes(token) self.token = token return token def _populate_attributes(self, token): if 'oauth_token' in token: self._client.client.resource_owner_key = token['oauth_token'] else: raise TokenMissing( 'Response does not contain a token: {resp}'.format(resp=token), token, ) if 'oauth_token_secret' in token: self._client.client.resource_owner_secret = ( token['oauth_token_secret']) if 'oauth_verifier' in token: self._client.client.verifier = token['oauth_verifier'] def _fetch_token(self, url, **request_kwargs): log.debug('Fetching token from %s using client %s', url, self._client.client) r = self.post(url, **request_kwargs) if r.status_code >= 400: error = "Token request failed with code %s, response was '%s'." raise TokenRequestDenied(error % (r.status_code, r.text), r) log.debug('Decoding token from response "%s"', r.text) try: token = dict(urldecode(r.text.strip())) except ValueError as e: error = ("Unable to decode token from token response. " "This is commonly caused by an unsuccessful request where" " a non urlencoded error message is returned. " "The decoding error was %s""" % e) raise ValueError(error) log.debug('Obtained token %s', token) log.debug('Updating internal client attributes from token data.') self._populate_attributes(token) self.token = token return token def rebuild_auth(self, prepared_request, response): """ When being redirected we should always strip Authorization header, since nonce may not be reused as per OAuth spec. """ if 'Authorization' in prepared_request.headers: # If we get redirected to a new host, we should strip out # any authentication headers. prepared_request.headers.pop('Authorization', True) prepared_request.prepare_auth(self.auth) return requests-oauthlib-1.0.0/requests_oauthlib/compliance_fixes/0000755000076500000240000000000013305201162026416 5ustar singingwolfboystaff00000000000000requests-oauthlib-1.0.0/requests_oauthlib/compliance_fixes/mailchimp.py0000644000076500000240000000136412726270216030753 0ustar singingwolfboystaff00000000000000import 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 requests-oauthlib-1.0.0/requests_oauthlib/compliance_fixes/fitbit.py0000644000076500000240000000161213263226123030260 0ustar singingwolfboystaff00000000000000""" The Fitbit API breaks from the OAuth2 RFC standard by returning an "errors" object list, rather than a single "error" string. This puts hooks in place so that oauthlib can process an error in the results from access token and refresh token responses. This is necessary to prevent getting the generic red herring MissingTokenError. """ from json import loads, dumps from oauthlib.common import to_unicode def fitbit_compliance_fix(session): def _missing_error(r): token = loads(r.text) if 'errors' in token: # Set the error to the first one we have token['error'] = token['errors'][0]['errorType'] r._content = to_unicode(dumps(token)).encode('UTF-8') return r session.register_compliance_hook('access_token_response', _missing_error) session.register_compliance_hook('refresh_token_response', _missing_error) return session requests-oauthlib-1.0.0/requests_oauthlib/compliance_fixes/plentymarkets.py0000644000076500000240000000137113263226123031703 0ustar singingwolfboystaff00000000000000from json import dumps, loads import re from oauthlib.common import to_unicode def plentymarkets_compliance_fix(session): def _to_snake_case(n): return re.sub('(.)([A-Z][a-z]+)', r'\1_\2', n).lower() def _compliance_fix(r): # Plenty returns the Token in CamelCase instead of _ if 'application/json' in r.headers.get('content-type', {}) and r.status_code == 200: token = loads(r.text) else: return r fixed_token = {} for k, v in token.items(): fixed_token[_to_snake_case(k)] = v r._content = to_unicode(dumps(fixed_token)).encode('UTF-8') return r session.register_compliance_hook('access_token_response', _compliance_fix) return session requests-oauthlib-1.0.0/requests_oauthlib/compliance_fixes/douban.py0000644000076500000240000000073112726270216030255 0ustar singingwolfboystaff00000000000000import json from oauthlib.common import to_unicode def douban_compliance_fix(session): def fix_token_type(r): token = json.loads(r.text) token.setdefault('token_type', 'Bearer') fixed_token = json.dumps(token) r._content = to_unicode(fixed_token).encode('utf-8') return r session._client_default_token_placement = 'query' session.register_compliance_hook('access_token_response', fix_token_type) return session requests-oauthlib-1.0.0/requests_oauthlib/compliance_fixes/__init__.py0000644000076500000240000000054613263226123030543 0ustar singingwolfboystaff00000000000000from __future__ import absolute_import from .facebook import facebook_compliance_fix from .fitbit import fitbit_compliance_fix from .linkedin import linkedin_compliance_fix from .slack import slack_compliance_fix from .mailchimp import mailchimp_compliance_fix from .weibo import weibo_compliance_fix from .plentymarkets import plentymarkets_compliance_fix requests-oauthlib-1.0.0/requests_oauthlib/compliance_fixes/facebook.py0000644000076500000240000000213712726270216030560 0ustar singingwolfboystaff00000000000000from json import dumps try: from urlparse import parse_qsl except ImportError: from urllib.parse import parse_qsl from oauthlib.common import to_unicode def facebook_compliance_fix(session): def _compliance_fix(r): # if Facebook claims to be sending us json, let's trust them. if 'application/json' in r.headers.get('content-type', {}): return r # Facebook returns a content-type of text/plain when sending their # x-www-form-urlencoded responses, along with a 200. If not, let's # assume we're getting JSON and bail on the fix. if 'text/plain' in r.headers.get('content-type', {}) and r.status_code == 200: token = dict(parse_qsl(r.text, keep_blank_values=True)) else: return r expires = token.get('expires') if expires is not None: token['expires_in'] = expires token['token_type'] = 'Bearer' r._content = to_unicode(dumps(token)).encode('UTF-8') return r session.register_compliance_hook('access_token_response', _compliance_fix) return session requests-oauthlib-1.0.0/requests_oauthlib/compliance_fixes/weibo.py0000644000076500000240000000074212726270216030114 0ustar singingwolfboystaff00000000000000from json import loads, dumps from oauthlib.common import to_unicode def weibo_compliance_fix(session): def _missing_token_type(r): token = loads(r.text) token['token_type'] = 'Bearer' r._content = to_unicode(dumps(token)).encode('UTF-8') return r session._client.default_token_placement = 'query' session.register_compliance_hook('access_token_response', _missing_token_type) return session requests-oauthlib-1.0.0/requests_oauthlib/compliance_fixes/linkedin.py0000644000076500000240000000147012726270216030603 0ustar singingwolfboystaff00000000000000from json import loads, dumps from oauthlib.common import add_params_to_uri, to_unicode def linkedin_compliance_fix(session): def _missing_token_type(r): token = loads(r.text) token['token_type'] = 'Bearer' r._content = to_unicode(dumps(token)).encode('UTF-8') return r def _non_compliant_param_name(url, headers, data): token = [('oauth2_access_token', session.access_token)] url = add_params_to_uri(url, token) return url, headers, data session._client.default_token_placement = 'query' session.register_compliance_hook('access_token_response', _missing_token_type) session.register_compliance_hook('protected_request', _non_compliant_param_name) return session requests-oauthlib-1.0.0/requests_oauthlib/compliance_fixes/slack.py0000644000076500000240000000265512726270216030111 0ustar singingwolfboystaff00000000000000try: from urlparse import urlparse, parse_qs except ImportError: from urllib.parse import urlparse, parse_qs from oauthlib.common import add_params_to_uri def slack_compliance_fix(session): def _non_compliant_param_name(url, headers, data): # If the user has already specified the token, either in the URL # or in a data dictionary, then there's nothing to do. # If the specified token is different from ``session.access_token``, # we assume the user intends to override the access token. url_query = dict(parse_qs(urlparse(url).query)) token = url_query.get("token") if not token and isinstance(data, dict): token = data.get("token") if token: # Nothing to do, just return. return url, headers, data if not data: data = {"token": session.access_token} elif isinstance(data, dict): data["token"] = session.access_token else: # ``data`` is something other than a dict: maybe a stream, # maybe a file object, maybe something else. We can't easily # modify it, so we'll set the token by modifying the URL instead. token = [('token', session.access_token)] url = add_params_to_uri(url, token) return url, headers, data session.register_compliance_hook('protected_request', _non_compliant_param_name) return session requests-oauthlib-1.0.0/requests_oauthlib/oauth1_auth.py0000644000076500000240000000673512760373502025731 0ustar singingwolfboystaff00000000000000# -*- coding: utf-8 -*- from __future__ import unicode_literals import logging from oauthlib.common import extract_params from oauthlib.oauth1 import Client, SIGNATURE_HMAC, SIGNATURE_TYPE_AUTH_HEADER from oauthlib.oauth1 import SIGNATURE_TYPE_BODY from requests.compat import is_py3 from requests.utils import to_native_string from requests.auth import AuthBase CONTENT_TYPE_FORM_URLENCODED = 'application/x-www-form-urlencoded' CONTENT_TYPE_MULTI_PART = 'multipart/form-data' if is_py3: unicode = str log = logging.getLogger(__name__) # OBS!: Correct signing of requests are conditional on invoking OAuth1 # as the last step of preparing a request, or at least having the # content-type set properly. class OAuth1(AuthBase): """Signs the request using OAuth 1 (RFC5849)""" client_class = Client def __init__(self, client_key, client_secret=None, resource_owner_key=None, resource_owner_secret=None, callback_uri=None, signature_method=SIGNATURE_HMAC, signature_type=SIGNATURE_TYPE_AUTH_HEADER, rsa_key=None, verifier=None, decoding='utf-8', client_class=None, force_include_body=False, **kwargs): try: signature_type = signature_type.upper() except AttributeError: pass client_class = client_class or self.client_class self.force_include_body = force_include_body self.client = client_class(client_key, client_secret, resource_owner_key, resource_owner_secret, callback_uri, signature_method, signature_type, rsa_key, verifier, decoding=decoding, **kwargs) def __call__(self, r): """Add OAuth parameters to the request. Parameters may be included from the body if the content-type is urlencoded, if no content type is set a guess is made. """ # Overwriting url is safe here as request will not modify it past # this point. log.debug('Signing request %s using client %s', r, self.client) content_type = r.headers.get('Content-Type', '') if (not content_type and extract_params(r.body) or self.client.signature_type == SIGNATURE_TYPE_BODY): content_type = CONTENT_TYPE_FORM_URLENCODED if not isinstance(content_type, unicode): content_type = content_type.decode('utf-8') is_form_encoded = (CONTENT_TYPE_FORM_URLENCODED in content_type) log.debug('Including body in call to sign: %s', is_form_encoded or self.force_include_body) if is_form_encoded: r.headers['Content-Type'] = CONTENT_TYPE_FORM_URLENCODED r.url, headers, r.body = self.client.sign( unicode(r.url), unicode(r.method), r.body or '', r.headers) elif self.force_include_body: # To allow custom clients to work on non form encoded bodies. r.url, headers, r.body = self.client.sign( unicode(r.url), unicode(r.method), r.body or '', r.headers) else: # Omit body data in the signing of non form-encoded requests r.url, headers, _ = self.client.sign( unicode(r.url), unicode(r.method), None, r.headers) r.prepare_headers(headers) r.url = to_native_string(r.url) log.debug('Updated url: %s', r.url) log.debug('Updated headers: %s', headers) log.debug('Updated body: %r', r.body) return r requests-oauthlib-1.0.0/LICENSE0000644000076500000240000000135112760373257020374 0ustar singingwolfboystaff00000000000000ISC License Copyright (c) 2014 Kenneth Reitz. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. requests-oauthlib-1.0.0/requirements.txt0000644000076500000240000000005512726270216022644 0ustar singingwolfboystaff00000000000000requests>=2.0.0 oauthlib[signedtoken]>=0.6.2 requests-oauthlib-1.0.0/tests/0000755000076500000240000000000013305201162020506 5ustar singingwolfboystaff00000000000000requests-oauthlib-1.0.0/tests/test_oauth2_session.pyc0000644000076500000240000002650212760400535025245 0ustar singingwolfboystaff00000000000000ó EÂWc@s3ddlmZddlZddlZddlZddlmZddlmZyddl m Z Wn!e k r‹ddl m Z nXddl mZddlmZmZddlmZdd lmZmZdd lmZmZdd lmZmZejƒZd „Zd e fd„ƒYZdS(iÿÿÿÿ(tunicode_literalsN(t b64encode(tdeepcopy(tTestCase(t urlencode(tTokenExpiredErrort OAuth2Error(tMismatchingStateError(tWebApplicationClienttMobileApplicationClient(tLegacyApplicationClienttBackendApplicationClient(t OAuth2Sessiont TokenUpdatedcs‡fd†}|S(Ncs"tjƒ}tjˆƒ|_|S(N(tmockt MagicMocktjsontdumpsttext(trtkwargstresp(ttoken(sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth2_session.pyt fake_sends ((RR((RsK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth2_session.pyt fake_tokenstOAuth2SessionTestcBsÝeZd„Zd„Zd„Zejddd„ƒd„ƒZejddd„ƒd„ƒZejddd „ƒd „ƒZ d „Z d „Z d „Z d„Z d„Zd„Zejddd„ƒd„ƒZRS(cs°tˆdƒs$‡fd†ˆ_nidd6dd6dd6d d 6td d 6ˆ_d ˆ_tˆjddƒtˆjƒtˆjƒgˆ_ˆjt ˆjƒgˆ_ dS(NuassertIncsˆj||kƒS(N(t assertTrue(tatb(tself(sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth2_session.pyt%suBeareru token_typeuasdfoiw37850234lkjsdfsdfu access_tokenusldvafkjw34509s8dfsdfu refresh_tokenu3600u expires_iniu expires_atufootcodeu asdf345xdf( thasattrtassertInt fake_timeRt client_idRR R tclientsR t all_clients(R((RsK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth2_session.pytsetUp"s  csidˆjd‰‡‡fd†}x?ˆjD]4}td|dˆjƒ}||_|jdƒq-WdS(NuBearer u access_tokencso|jjddƒ}djdƒ|jkrF|jdjdƒ}nˆj|ˆƒtjƒ}g|_|S(Nu Authorizationuutf-8(theaderstgettNonetencodet assertEqualRRtcookes(RRt auth_headerR(RR(sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth2_session.pytverifier9s  tclientRu https://i.b(RR%R tsendR((RR.R/tauth((RRsK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth2_session.pyttest_add_token6s   cCsÖd}t|jƒ}td|ƒ}|j|ƒ\}}|j||ƒ|j|j|ƒ|jd|ƒt|jƒ}td|ƒ}|j|ƒ\}}|j||ƒ|j|j|ƒ|jd|ƒdS(Nu%https://example.com/authorize?foo=barR/uresponse_type=codeuresponse_type=token(RR#R tauthorization_urlR!R (Rturltwebtstauth_urltstatetmobile((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth2_session.pyttest_authorization_urlGsu time.timetnewcCstS(N(R"(((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth2_session.pyRXsc s•tˆjƒˆ_dˆjd<ˆjd=‡fd†}x?ˆjD]4}td|dˆjƒ}ˆjt|jdƒqBWxNˆjD]C}td|dˆjdd ƒ}||_ˆjt |jdƒq„W‡fd †}xKˆjD]@}td|dˆjdd d |ƒ}||_|jdƒqäW‡fd †}xWˆjD]L}td|dˆjdd d |ƒ}||_|jdd dddƒqAWdS(Nu-1u expires_inu expires_atcsJd|jkr%ˆjd|jƒntjƒ}tjˆjƒ|_|S(Nu/refreshu Authorization( R4t assertNotInR'RRRRRR(RRR(R(sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth2_session.pyt fake_refresh^s  R/Ru https://i.btauto_refresh_urluhttps://i.b/refreshcsˆj|ˆjƒdS(N(R+R(R(R(sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth2_session.pyt token_updaterrsR?csqd|jkrLˆjd|jƒtdƒ}ˆj|jdd|ƒntjƒ}tjˆj ƒ|_ |S(Nu/refreshu Authorizationsfoo:barsBasic ( R4R!R'RR+RRRRRR(RRtencodedR(R(sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth2_session.pytfake_refresh_with_auth|s  R#ufoot client_secretubar( tdictRt expired_tokenR$R t assertRaisesRR(R0R (RR=R/R1R?RA((RsK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth2_session.pyttest_refresh_token_requestXs4         cCstS(N(R"(((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth2_session.pyRŒscCsWt|jƒ}dt|jjƒƒ}td|ƒ}|j|j|ƒ|jƒdS(Nuhttps://i.b/callback#R/(R R#RRtitemsR R+ttoken_from_fragment(RR9t response_urlR1((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth2_session.pyttest_token_from_fragmentŒscCstS(N(R"(((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth2_session.pyR“scCsÂd}xW|jD]L}td|d|jƒ}t|jƒ|_|j|j|ƒ|jƒqWidd6}xN|jD]C}td|d|jƒ}t|ƒ|_|jt|j|ƒqwWdS(Nuhttps://example.com/tokenR/Ruinvalid_requestuerror( R$R RRR0R+t fetch_tokenRER(RR4R/R1terror((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth2_session.pyttest_fetch_token“s  c sÆt|jƒ}tjƒd}tjƒ‰||jd<ˆd|ds$      requests-oauthlib-1.0.0/tests/test_core.pyc0000644000076500000240000001420712760374422023234 0ustar singingwolfboystaff00000000000000ó ŽpYWc@sùddlmZddlZddlZddlZddlZddlZddlZyddl m Z Wn!e k rddl m Z nXddl Z ej ddkr¸eZneZejdƒejdƒde jfd „ƒYƒƒZdS( iÿÿÿÿ(tunicode_literalsN(tStringIOiu3u*oauthlib.oauth1.rfc5849.generate_timestampu&oauthlib.oauth1.rfc5849.generate_noncet OAuth1TestcBsGeZd„Zd„Zd„Zd„Zd„Zd„Zd„ZRS(cs‡fd†}|ˆ_dS(NcsVt|tƒr!|jdƒ}nt|tƒrB|jdƒ}nˆj||ƒdS(Nuutf-8(t isinstancet bytes_typetdecodet assertEquals(tatb(tself(sA/Users/singingwolfboy/clones/requests-oauthlib/tests/test_core.pytconverting_equalss (t assertEqual(R R ((R sA/Users/singingwolfboy/clones/requests-oauthlib/tests/test_core.pytsetUpsc CsDd|_d|_tjdƒ}idd6}tjdddd d |d d d |ƒ}|jƒ}|j|jd ƒ|j|jd ƒ|j|j j dƒdƒtjdddd d |d d ƒ}|jƒ}|j|jd ƒ|j|jd ƒ|j|j j dƒdƒ|j|j j dƒ|j j dƒƒdS(u=OAuth1 assumes form encoded if content type is not specified.uabcu1u client_keyu!application/x-www-form-urlencodedu Content-typetmethoduPOSTturluhttp://a.b/path?query=retaintauthtdatauthis=really&is=&+form=encodedtheadersu Content-Typeu AuthorizationN( t return_valuetrequests_oauthlibtOAuth1trequeststRequesttprepareR RtbodyRtget(R tgenerate_noncetgenerate_timestamptoauthRtrRR((sA/Users/singingwolfboy/clones/requests-oauthlib/tests/test_core.pyttestFormEncoded#s$     c Cs d|_d|_tjdƒ}tjddddd|d d ƒ}|jƒ}tjddddd|ƒ}|jƒ}|j|jjd ƒ|jjd ƒƒtjddddd|d it d ƒd6ƒ}|jƒ}|j|jjd ƒ|jjd ƒƒdS(u:OAuth signature only depend on body if it is form encoded.uabcu1u client_keyR uPOSTRuhttp://a.b/path?query=retainRRuthis really is not form encodedu AuthorizationtfilesuhelloutestN( RRRRRRR RRR(R RRRRRRtc((sA/Users/singingwolfboy/clones/requests-oauthlib/tests/test_core.pyttestNonFormEncoded<s       cCsÈd|_d|_tjdƒ}tjjtƒ}tjj|dƒ}t|dƒk}t j ddidd 6d itjj |j ƒ|fd 6d id d6d|ƒ}|j |jdƒWdQXdS(ur Test we can post binary data. Should prevent regression of the UnicodeDecodeError issue. uabcu1u client_keyutest.binurbuhttp://httpbin.org/postRuthereuhiRumediaRuapplication/octet-streamu content-typeRiÈN(RRRtostpathtdirnamet__file__tjointopenRtposttbasenametnameR t status_code(R RRRR$tfnametfR((sA/Users/singingwolfboy/clones/requests-oauthlib/tests/test_core.pyttestCanPostBinaryDataTs  "  cCsVd|_d|_tjdƒ}tjdd|ƒ}|jt|jjt ƒƒdS(u> Test that the URL is always a native string. uabcu1u client_keyuhttp://httpbin.org/getRN( RRRRRt assertTrueRtrequestRtstr(R RRRR((sA/Users/singingwolfboy/clones/requests-oauthlib/tests/test_core.pyttest_url_is_native_strfs   c Cs¬d|_d|_tjdƒ}d}tjdd|d|ƒ}|j|jjjdƒd ƒtjdd|d|d id d 6ƒ}|j|jjjdƒd ƒd S(uG Content type should only be guessed if none is given. uabcu1u client_keyuauhttp://httpbin.org/getRRu Content-Typeu!application/x-www-form-urlencodedRuapplication/jsonu Content-typeN( RRRRR(R R0RR(R RRRRR((sA/Users/singingwolfboy/clones/requests-oauthlib/tests/test_core.pyttest_content_type_overrideqs  cCsXdtjjfd„ƒY}|jttjdƒƒ|jtjjtjjƒtjdƒ}|jt |j tjjƒƒ|j t |j |ƒƒ|tj_|jtjj|ƒtjdƒ}|jt |j tjjƒƒ|jt |j |ƒƒtjddtjjƒ}|jt |j tjjƒƒ|j t |j |ƒƒdS(NtClientSubclasscBseZRS((t__name__t __module__(((sA/Users/singingwolfboy/clones/requests-oauthlib/tests/test_core.pyR4ƒsu client_classu client_keyt client_class( toauthlibtoauth1tClientR/thasattrRRR R7Rtclientt assertFalse(R RRR4tnormaltcustomt overridden((sA/Users/singingwolfboy/clones/requests-oauthlib/tests/test_core.pyttest_register_client_class‚s"    ( R5R6R RR!R.R2R3RA(((sA/Users/singingwolfboy/clones/requests-oauthlib/tests/test_core.pyRs    (t __future__RtmocktsysRRR8tos.pathR"tioRt ImportErrortunittesttversiontbytesRR1tpatchtTestCaseR(((sA/Users/singingwolfboy/clones/requests-oauthlib/tests/test_core.pyts"          requests-oauthlib-1.0.0/tests/test_core.py0000644000076500000240000001324313263226123023061 0ustar singingwolfboystaff00000000000000# -*- coding: utf-8 -*- from __future__ import unicode_literals import mock import sys import requests import requests_oauthlib import oauthlib import os.path from io import StringIO import unittest @mock.patch('oauthlib.oauth1.rfc5849.generate_timestamp') @mock.patch('oauthlib.oauth1.rfc5849.generate_nonce') class OAuth1Test(unittest.TestCase): def testFormEncoded(self, generate_nonce, generate_timestamp): """OAuth1 assumes form encoded if content type is not specified.""" generate_nonce.return_value = 'abc' generate_timestamp.return_value = '1' oauth = requests_oauthlib.OAuth1('client_key') headers = {'Content-type': 'application/x-www-form-urlencoded'} r = requests.Request(method='POST', url='http://a.b/path?query=retain', auth=oauth, data='this=really&is=&+form=encoded', headers=headers) a = r.prepare() self.assertEqual(a.url, 'http://a.b/path?query=retain') self.assertEqual(a.body, b'this=really&is=&+form=encoded') self.assertEqual(a.headers.get('Content-Type'), b'application/x-www-form-urlencoded') # guess content-type r = requests.Request(method='POST', url='http://a.b/path?query=retain', auth=oauth, data='this=really&is=&+form=encoded') b = r.prepare() self.assertEqual(b.url, 'http://a.b/path?query=retain') self.assertEqual(b.body, b'this=really&is=&+form=encoded') self.assertEqual(b.headers.get('Content-Type'), b'application/x-www-form-urlencoded') self.assertEqual(a.headers.get('Authorization'), b.headers.get('Authorization')) def testNonFormEncoded(self, generate_nonce, generate_timestamp): """OAuth signature only depend on body if it is form encoded.""" generate_nonce.return_value = 'abc' generate_timestamp.return_value = '1' oauth = requests_oauthlib.OAuth1('client_key') r = requests.Request(method='POST', url='http://a.b/path?query=retain', auth=oauth, data='this really is not form encoded') a = r.prepare() r = requests.Request(method='POST', url='http://a.b/path?query=retain', auth=oauth) b = r.prepare() self.assertEqual(a.headers.get('Authorization'), b.headers.get('Authorization')) r = requests.Request(method='POST', url='http://a.b/path?query=retain', auth=oauth, files={'test': StringIO('hello')}) c = r.prepare() self.assertEqual(b.headers.get('Authorization'), c.headers.get('Authorization')) def testCanPostBinaryData(self, generate_nonce, generate_timestamp): """ Test we can post binary data. Should prevent regression of the UnicodeDecodeError issue. """ generate_nonce.return_value = 'abc' generate_timestamp.return_value = '1' oauth = requests_oauthlib.OAuth1('client_key') dirname = os.path.dirname(__file__) fname = os.path.join(dirname, 'test.bin') with open(fname, 'rb') as f: r = requests.post('http://httpbin.org/post', data={'hi': 'there'}, files={'media': (os.path.basename(f.name), f)}, headers={'content-type':'application/octet-stream'}, auth=oauth) self.assertEqual(r.status_code, 200) def test_url_is_native_str(self, generate_nonce, generate_timestamp): """ Test that the URL is always a native string. """ generate_nonce.return_value = 'abc' generate_timestamp.return_value = '1' oauth = requests_oauthlib.OAuth1('client_key') r = requests.get('http://httpbin.org/get', auth=oauth) self.assertTrue(isinstance(r.request.url, str)) def test_content_type_override(self, generate_nonce, generate_timestamp): """ Content type should only be guessed if none is given. """ generate_nonce.return_value = 'abc' generate_timestamp.return_value = '1' oauth = requests_oauthlib.OAuth1('client_key') data = 'a' r = requests.post('http://httpbin.org/get', data=data, auth=oauth) self.assertEqual(r.request.headers.get('Content-Type'), b'application/x-www-form-urlencoded') r = requests.post('http://httpbin.org/get', auth=oauth, data=data, headers={'Content-type': 'application/json'}) self.assertEqual(r.request.headers.get('Content-Type'), b'application/json') def test_register_client_class(self, generate_timestamp, generate_nonce): class ClientSubclass(oauthlib.oauth1.Client): pass self.assertTrue(hasattr(requests_oauthlib.OAuth1, 'client_class')) self.assertEqual( requests_oauthlib.OAuth1.client_class, oauthlib.oauth1.Client) normal = requests_oauthlib.OAuth1('client_key') self.assertTrue(isinstance(normal.client, oauthlib.oauth1.Client)) self.assertFalse(isinstance(normal.client, ClientSubclass)) requests_oauthlib.OAuth1.client_class = ClientSubclass self.assertEqual(requests_oauthlib.OAuth1.client_class, ClientSubclass) custom = requests_oauthlib.OAuth1('client_key') self.assertTrue(isinstance(custom.client, oauthlib.oauth1.Client)) self.assertTrue(isinstance(custom.client, ClientSubclass)) overridden = requests_oauthlib.OAuth1('client_key', client_class = oauthlib.oauth1.Client) self.assertTrue(isinstance(overridden.client, oauthlib.oauth1.Client)) self.assertFalse(isinstance(normal.client, ClientSubclass)) requests-oauthlib-1.0.0/tests/test_oauth1_session.pyc0000644000076500000240000004046412760374422025254 0ustar singingwolfboystaff00000000000000ó ŽpYWc@s}ddlmZmZddlZddlZddlZddlZddlmZm Z ddlm Z m Z ddl m Z yddlmZWn!ek r¹ddlmZnXyddlZWnek rãdZnXejddkreZeZn eZeZeed ƒsTee_ejjej_d „Zeej_nd Z d Z!d ej"fd„ƒYZ#dS(iÿÿÿÿ(tunicode_literalstprint_functionN(tSIGNATURE_TYPE_QUERYtSIGNATURE_TYPE_BODY(t SIGNATURE_RSAtSIGNATURE_PLAINTEXT(t OAuth1Session(tStringIOiu3uSkipTestcCsK|dtkr7tt|dƒdddtjƒdS|j||ƒdS(Niitendu tfile(tRuntimeWarningtprinttstrtsyststderrtreal_add_error(tselfttesttexc_info((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pytpatched_addError!s#uŠ-----BEGIN RSA PRIVATE KEY----- MIIEogIBAAKCAQEApF1JaMSN8TEsh4N4O/5SpEAVLivJyLH+Cgl3OQBPGgJkt8cg 49oasl+5iJS+VdrILxWM9/JCJyURpUuslX4Eb4eUBtQ0x5BaPa8+S2NLdGTaL7nB OO8o8n0C5FEUU+qlEip79KE8aqOj+OC44VsIquSmOvWIQD26n3fCVlgwoRBD1gzz sDOeaSyzpKrZR851Kh6rEmF2qjJ8jt6EkxMsRNACmBomzgA4M1TTsisSUO87444p e35Z4/n5c735o2fZMrGgMwiJNh7rT8SYxtIkxngioiGnwkxGQxQ4NzPAHg+XSY0J 04pNm7KqTkgtxyrqOANJLIjXlR+U9SQ90NjHVQIDAQABAoIBABuBPOKaWcJt3yzC NGGduoif7KtwSnEaUA+v69KPGa2Zju8uFHPssKD+4dZYRc2qMeunKJLpaGaSjnRh yHyvvOBJCN1nr3lhz6gY5kzJTfwpUFXCOPJlGy4Q+2Xnp4YvcvYqQ9n5DVovDiZ8 vJOBn16xqpudMPLHIa7D5LJ8SY76HBjE+imTXw1EShdh5TOV9bmPFQqH6JFzowRH hyH2DPHuyHJj6cl8FyqJw5lVWzG3n6Prvk7bYHsjmGjurN35UsumNAp6VouNyUP1 RAEcUJega49aIs6/FJ0ENJzQjlsAzVbTleHkpez2aIok+wsWJGJ4SVxAjADOWAaZ uEJPc3UCgYEA1g4ZGrXOuo75p9/MRIepXGpBWxip4V7B9XmO9WzPCv8nMorJntWB msYV1I01aITxadHatO4Gl2xLniNkDyrEQzJ7w38RQgsVK+CqbnC0K9N77QPbHeC1 YQd9RCNyUohOimKvb7jyv798FBU1GO5QI2eNgfnnfteSVXhD2iOoTOsCgYEAxJJ+ 8toxJdnLa0uUsAbql6zeNXGbUBMzu3FomKlyuWuq841jS2kIalaO/TRj5hbnE45j mCjeLgTVO6Ach3Wfk4zrqajqfFJ0zUg/Wexp49lC3RWiV4icBb85Q6bzeJD9Dn9v hjpfWVkczf/NeA1fGH/pcgfkT6Dm706GFFttLL8CgYBl/HeXk1H47xAiHO4dJKnb v0B+X8To/RXamF01r+8BpUoOubOQetdyX7ic+d6deuHu8i6LD/GSCeYJZYFR/KVg AtiW757QYalnq3ZogkhFrVCZP8IRfTPOFBxp752TlyAcrSI7T9pQ47IBe4094KXM CJWSfPgAJkOxd0iU0XJpmwKBgGfQxuMTgSlwYRKFlD1zKap5TdID8fbUbVnth0Q5 GbH7vwlp/qrxCdS/aj0n0irOpbOaW9ccnlrHiqY25VpVMLYIkt3DrDOEiNNx+KNR TItdTwbcSiTYrS4L0/56ydM/H6bsfsXxRjI18hSJqMZiqXqS84OZz2aOn+h7HCzc LEiZAoGASk20wFvilpRKHq79xxFWiDUPHi0x0pp82dYIEntGQkKUWkbSlhgf3MAi 5NEQTDmXdnB+rVeWIvEi+BXfdnNgdn8eC4zSdtF4sIAhYr5VWZo0WVWDhT7u2ccv ZBFymiz8lo3gN57wGUCi9pbZqzV1+ZppX6YTNDdDCE0q+KO3Cec= -----END RSA PRIVATE KEY-----upj8WF8PGjojT82aUDd2EL%2Bz7HCoHInFzWUpiEKMCy%2BJ2cYHWcBS7mXlmFDLgAKV0P%2FyX4TrpXODYnJ6dRWdfghqwDpi%2FlQmB2jxCiGMdJoYxh3c5zDf26gEbGdP6D7OSsp5HUnzH6sNkmVjuE%2FxoJcHJdc23H6GhOs7VJ2LWNdbhKWP%2FMMlTrcoQDn8lz%2Fb24WsJ6ae1txkUzpFOOlLM8aTdNtGL4OtsubOlRhNqnAFq93FyhXg0KjzUyIZzmMX9Vx90jTks5QeBGYcLE0Op2iHb2u%2FO%2BEgdwFchgEwE5LgMUyHUI4F3Wglp28yHOAMjPkI%2FkWMvpxtMrU3Z3KN31WQ%3D%3DtOAuth1SessionTestcBs@eZd„Zd„Zejdƒejdƒd„ƒƒZejdƒejdƒd„ƒƒZejdƒejdƒd„ƒƒZd„Z d„Z d „Z d „Z d „Z d „Zd „Zd„Zd„Zd„Zd„Zd„Zd„Zejdƒejdƒd„ƒƒZd„Zdd„ZRS(cs(tˆdƒs$‡fd†ˆ_ndS(NuassertIncsˆj||kƒS(N(t assertTrue(tatb(R(sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pytWs(thasattrtassertIn(R((RsK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pytsetUpTscs¹‡fd†}tdƒ}|d„ƒ|_|jdƒtddtƒ}|d„ƒ|_|jdƒtddtƒ}idd6}|d „ƒ|_|jdd |d d ƒdS( Ncs‡‡fd†}|S(Ncs_ˆ|ƒ}t|tƒr-|jdƒ}nˆjd|ƒtjdtjƒ}g|_|S(Nuutf-8uoauth_signaturetspec( t isinstancet bytes_typetdecodeRtmockt MagicMocktrequeststResponsetcookies(trtkwargst signaturetresp(tgetterR(sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyt fake_send[s  ((R)R*(R(R)sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pytverify_signatureZsufoocSs |jdS(Nu Authorization(theaders(R%((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyRfsu https://i.btsignature_typecSs|jS(N(turl(R%((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyRjsu!application/x-www-form-urlencodedu Content-TypecSs|jS(N(tbody(R%((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyRosR,tdatau(RtsendtpostRR(RR+theadertqueryR/R,((RsK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyttest_signature_typesYs    u*oauthlib.oauth1.rfc5849.generate_timestampu&oauthlib.oauth1.rfc5849.generate_noncecCsßtstjdƒ‚nd|_d|_d}tdƒ}|j|ƒ|_|jdƒd}tddtƒ}|j|ƒ|_|jdƒd j d t ƒ}tddt d t ƒ}|j|ƒ|_|jdƒdS( Nucryptography module is requireduabcu123u³OAuth oauth_nonce="abc", oauth_timestamp="123", oauth_version="1.0", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="foo", oauth_signature="h2sRqLArjhlc5p3FTkuNogVHlKE%3D"ufoou https://i.bu˜OAuth oauth_nonce="abc", oauth_timestamp="123", oauth_version="1.0", oauth_signature_method="PLAINTEXT", oauth_consumer_key="foo", oauth_signature="%26"tsignature_methodu™OAuth oauth_nonce="abc", oauth_timestamp="123", oauth_version="1.0", oauth_signature_method="RSA-SHA1", oauth_consumer_key="foo", oauth_signature="{sig}"tsigtrsa_key( t cryptographytunittesttSkipTestt return_valueRR+R1R2RtformattTEST_RSA_OAUTH_SIGNATURERt TEST_RSA_KEY(Rtgenerate_noncetgenerate_timestampR'tauth((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyttest_signature_methodsrs$        cCsud|_d|_tdƒ}idd6}d}tdƒ}|j|ƒ|_|jdd |d d |fgƒdS( Nuabcu123u hello worlduapplication/xmlu Content-Typeu³OAuth oauth_nonce="abc", oauth_timestamp="123", oauth_version="1.0", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="foo", oauth_signature="h2sRqLArjhlc5p3FTkuNogVHlKE%3D"ufoou https://i.bR,tfilesufake(R<RRR+R1R2(RR@RAtfake_xmlR,R'RB((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyttest_binary_uploads     cCsGd|_d|_d}tdƒ}|j|ƒ|_|jdƒdS(Nuabcu123u³OAuth oauth_nonce="abc", oauth_timestamp="123", oauth_version="1.0", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="foo", oauth_signature="W0haoue5IZAZoaJiYCtfqwMf8x8%3D"ufoou"https://i.b?cjk=%E5%95%A6%E5%95%A6(R<RR+R1R2(RR@RAR'RB((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyt test_nonascii›s    cCsItdƒ}d}d}|j|d|ƒ}|j||d|ƒdS(Nufoouhttps://example.comm/authorizeu asluif023sft request_tokenu ?oauth_token=(Rtauthorization_urlt assertEqual(RRBR.ttokentauth_url((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyttest_authorization_url¥s  cCs–d}tdƒ}|j|ƒ}|j|ddƒ|j|ddƒxF|jƒD]8\}}|jt|tƒƒ|jt|tƒƒqVWdS(Nu7https://i.b/callback?oauth_token=foo&oauth_verifier=barufoou oauth_tokenuoauth_verifierubar(Rtparse_authorization_responseRJtitemsRRt unicode_type(RR.RBR(tktv((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyttest_parse_response_url¬s cCsŽtdƒ}|jdƒ|_|jdƒ}|j|ddƒxF|jƒD]8\}}|jt|tƒƒ|jt|tƒƒqNWdS(Nufoouoauth_token=foouhttps://example.com/tokenu oauth_token( Rt fake_bodyR1tfetch_request_tokenRJRORRRP(RRBR(RQRR((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyttest_fetch_request_token¶s cCsštdƒ}|jdƒ|_|jddtdtƒ}|j|ddƒxF|jƒD]8\}}|jt |t ƒƒ|jt |t ƒƒqZWdS(Nufoouoauth_token=foouhttps://example.com/tokentverifytstreamu oauth_token( RRTR1RUtFalsetTrueRJRORRRP(RRBR(RQRR((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyt0test_fetch_request_token_with_optional_arguments¿s  cCs”tdddƒ}|jdƒ|_|jdƒ}|j|ddƒxF|jƒD]8\}}|jt|tƒƒ|jt|tƒƒqTWdS(Nufootverifierubaruoauth_token=foouhttps://example.com/tokenu oauth_token( RRTR1tfetch_access_tokenRJRORRRP(RRBR(RQRR((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyttest_fetch_access_tokenÉscCs tdddƒ}|jdƒ|_|jddtdtƒ}|j|ddƒxF|jƒD]8\}}|jt |t ƒƒ|jt |t ƒƒq`WdS( NufooR\ubaruoauth_token=foouhttps://example.com/tokenRWRXu oauth_token( RRTR1R]RYRZRJRORRRP(RRBR(RQRR((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyt/test_fetch_access_token_with_optional_argumentsÒs cCsS|jdƒ|_y|jdƒWn)tk rN}|jdt|ƒƒnXdS(ukAssert that an error is being raised whenever there's no verifier passed in to the client. uoauth_token=foouhttps://example.com/tokenu No client verifier has been set.N(RTR1R]t ValueErrorRJR (RRBtexc((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyt%_test_fetch_access_token_raises_errorÜs cCsÁtdƒ}|jdƒ|_|jt|jdƒx†d D]~}|jd|ƒ|_y|jdƒWnBtk r«}|j|j|ƒ|jt |j t j ƒƒq;X|j dƒq;WdS( Nufoounot valid urlencoded response!uhttps://example.com/tokenii‘i“uvalid=responseuValueError not raised(ii‘i“(RRTR1t assertRaisesR`RURJt status_codeRRtresponseR"R#tfail(RRBtcodeterr((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyt!test_fetch_token_invalid_responseês   cCs|jtdƒƒdS(Nufoo(RbR(R((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyt(test_fetch_access_token_missing_verifierüscCs)tdƒ}|jj`|j|ƒdS(Nufoo(Rt_clienttclientR\Rb(RRB((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyt,test_fetch_access_token_has_verifier_is_noneÿs  cCs tdƒ}|j|jƒdS(Nufoo(Rt assertFalset authorized(Rtsess((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyttest_authorized_falses cCsPdjdtƒ}tddtdtƒ}|j|ƒ|_|j|jƒdS(Nu™OAuth oauth_nonce="abc", oauth_timestamp="123", oauth_version="1.0", oauth_signature_method="RSA-SHA1", oauth_consumer_key="foo", oauth_signature="{sig}"R7ufooR6R8( R=R>RRR?R+R1RnRo(RR'Rp((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyttest_authorized_false_rsas    cCsHtddddƒ}|jdƒ|_|jdƒ|j|jƒdS(NukeyusecretR\ubaru&oauth_token=foo&oauth_token_secret=baruhttps://example.com/token(RRTR1R]RRo(RRp((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyttest_authorized_trues c Cststjdƒ‚nd|_d|_djdtƒ}tdddtd td d ƒ}|j d ƒ|_ |j d ƒ|j |j ƒdS(Nucryptography module is requireduabcu123u¯OAuth oauth_nonce="abc", oauth_timestamp="123", oauth_version="1.0", oauth_signature_method="RSA-SHA1", oauth_consumer_key="foo", oauth_verifier="bar", oauth_signature="{sig}"R7ukeyusecretR6R8R\ubaru&oauth_token=foo&oauth_token_secret=baruhttps://example.com/token(R9R:R;R<R=R>RRR?RTR1R]RRo(RR@RAR'Rp((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyttest_authorized_true_rsas     cs‡‡fd†}|S(Ncs`|jd}t|tƒr.|jdƒ}nˆj|ˆƒtjdtjƒ}g|_ |S(Nu Authorizationuutf-8R( R,RRRRJR R!R"R#R$(R%R&t auth_headerR((RR'(sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyR*-s  ((RR'R*((RR'sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyR+,siÈcs‡‡fd†}|S(Ncs4tjdtjƒ}g|_ˆ|_ˆ|_|S(NR(R R!R"R#R$ttextRd(R%R&R((R/Rd(sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyR*8s    ((RR/RdR*((R/RdsK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyRT7s(t__name__t __module__RR5R tpatchRCRFRGRMRSRVR[R^R_RbRiRjRmRqRrRsRtR+RT(((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyRRs2              ($t __future__RRR R:R R"toauthlib.oauth1RRRRtrequests_oauthlibRRt ImportErrortioR9tNonetversionR RPtbytesRtunicodeRR R;t TestResulttaddErrorRRR?R>tTestCaseR(((sK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyts8           requests-oauthlib-1.0.0/tests/__init__.py0000644000076500000240000000000012726270216022621 0ustar singingwolfboystaff00000000000000requests-oauthlib-1.0.0/tests/__pycache__/0000755000076500000240000000000013305201162022716 5ustar singingwolfboystaff00000000000000requests-oauthlib-1.0.0/tests/__pycache__/test_oauth1_session.cpython-36-PYTEST.pyc0000644000076500000240000003431113265672624032423 0ustar singingwolfboystaff000000000000003 Eu×Z<ã @sàddlmZmZddlZddljjZddl Z ddl Z ddl Z ddl Z ddl mZddlmZmZddlmZmZddlmZy ddlZWnek r dZYnXe jddkrºeZeZneZeZdZd ZGd d „d e j ƒZ!dS) é)Úunicode_literalsÚprint_functionN)ÚStringIO)ÚSIGNATURE_TYPE_QUERYÚSIGNATURE_TYPE_BODY)Ú SIGNATURE_RSAÚSIGNATURE_PLAINTEXT)Ú OAuth1SessionÚ3aŠ-----BEGIN RSA PRIVATE KEY----- MIIEogIBAAKCAQEApF1JaMSN8TEsh4N4O/5SpEAVLivJyLH+Cgl3OQBPGgJkt8cg 49oasl+5iJS+VdrILxWM9/JCJyURpUuslX4Eb4eUBtQ0x5BaPa8+S2NLdGTaL7nB OO8o8n0C5FEUU+qlEip79KE8aqOj+OC44VsIquSmOvWIQD26n3fCVlgwoRBD1gzz sDOeaSyzpKrZR851Kh6rEmF2qjJ8jt6EkxMsRNACmBomzgA4M1TTsisSUO87444p e35Z4/n5c735o2fZMrGgMwiJNh7rT8SYxtIkxngioiGnwkxGQxQ4NzPAHg+XSY0J 04pNm7KqTkgtxyrqOANJLIjXlR+U9SQ90NjHVQIDAQABAoIBABuBPOKaWcJt3yzC NGGduoif7KtwSnEaUA+v69KPGa2Zju8uFHPssKD+4dZYRc2qMeunKJLpaGaSjnRh yHyvvOBJCN1nr3lhz6gY5kzJTfwpUFXCOPJlGy4Q+2Xnp4YvcvYqQ9n5DVovDiZ8 vJOBn16xqpudMPLHIa7D5LJ8SY76HBjE+imTXw1EShdh5TOV9bmPFQqH6JFzowRH hyH2DPHuyHJj6cl8FyqJw5lVWzG3n6Prvk7bYHsjmGjurN35UsumNAp6VouNyUP1 RAEcUJega49aIs6/FJ0ENJzQjlsAzVbTleHkpez2aIok+wsWJGJ4SVxAjADOWAaZ uEJPc3UCgYEA1g4ZGrXOuo75p9/MRIepXGpBWxip4V7B9XmO9WzPCv8nMorJntWB msYV1I01aITxadHatO4Gl2xLniNkDyrEQzJ7w38RQgsVK+CqbnC0K9N77QPbHeC1 YQd9RCNyUohOimKvb7jyv798FBU1GO5QI2eNgfnnfteSVXhD2iOoTOsCgYEAxJJ+ 8toxJdnLa0uUsAbql6zeNXGbUBMzu3FomKlyuWuq841jS2kIalaO/TRj5hbnE45j mCjeLgTVO6Ach3Wfk4zrqajqfFJ0zUg/Wexp49lC3RWiV4icBb85Q6bzeJD9Dn9v hjpfWVkczf/NeA1fGH/pcgfkT6Dm706GFFttLL8CgYBl/HeXk1H47xAiHO4dJKnb v0B+X8To/RXamF01r+8BpUoOubOQetdyX7ic+d6deuHu8i6LD/GSCeYJZYFR/KVg AtiW757QYalnq3ZogkhFrVCZP8IRfTPOFBxp752TlyAcrSI7T9pQ47IBe4094KXM CJWSfPgAJkOxd0iU0XJpmwKBgGfQxuMTgSlwYRKFlD1zKap5TdID8fbUbVnth0Q5 GbH7vwlp/qrxCdS/aj0n0irOpbOaW9ccnlrHiqY25VpVMLYIkt3DrDOEiNNx+KNR TItdTwbcSiTYrS4L0/56ydM/H6bsfsXxRjI18hSJqMZiqXqS84OZz2aOn+h7HCzc LEiZAoGASk20wFvilpRKHq79xxFWiDUPHi0x0pp82dYIEntGQkKUWkbSlhgf3MAi 5NEQTDmXdnB+rVeWIvEi+BXfdnNgdn8eC4zSdtF4sIAhYr5VWZo0WVWDhT7u2ccv ZBFymiz8lo3gN57wGUCi9pbZqzV1+ZppX6YTNDdDCE0q+KO3Cec= -----END RSA PRIVATE KEY-----apj8WF8PGjojT82aUDd2EL%2Bz7HCoHInFzWUpiEKMCy%2BJ2cYHWcBS7mXlmFDLgAKV0P%2FyX4TrpXODYnJ6dRWdfghqwDpi%2FlQmB2jxCiGMdJoYxh3c5zDf26gEbGdP6D7OSsp5HUnzH6sNkmVjuE%2FxoJcHJdc23H6GhOs7VJ2LWNdbhKWP%2FMMlTrcoQDn8lz%2Fb24WsJ6ae1txkUzpFOOlLM8aTdNtGL4OtsubOlRhNqnAFq93FyhXg0KjzUyIZzmMX9Vx90jTks5QeBGYcLE0Op2iHb2u%2FO%2BEgdwFchgEwE5LgMUyHUI4F3Wglp28yHOAMjPkI%2FkWMvpxtMrU3Z3KN31WQ%3D%3Dc@seZdZdd„Zdd„Zejdƒejdƒdd„ƒƒZejdƒejdƒd d „ƒƒZejdƒejdƒd d „ƒƒZ d d„Z dd„Z dd„Z dd„Z dd„Zdd„Zdd„Zdd„Zdd„Zdd „Zd!d"„Zd#d$„Zd%d&„Zd'd(„Zd)d*„Zejdƒejdƒd+d,„ƒƒZd-d.„Zd3d0d1„Zd2S)4ÚOAuth1SessionTestcstˆdƒs‡fdd„ˆ_dS)NÚassertIncsˆj||kƒS)N)Ú assertTrue)ÚaÚb)Úself©úK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth1_session.pyÚGsz)OAuth1SessionTest.setUp..)Úhasattrr )rr)rrÚsetUpDs zOAuth1SessionTest.setUpcs†‡fdd„}tdƒ}|dd„ƒ|_|jdƒtdtd}|dd„ƒ|_|jdƒtdtd}d d i}|d d„ƒ|_|jd|d d dS)Ncs‡‡fdd„}|S)Ncs@ˆ|ƒ}t|tƒr|jdƒ}ˆjd|ƒtjtjd}g|_|S)Nzutf-8Zoauth_signature)Úspec) Ú isinstanceÚ bytes_typeÚdecoder ÚmockÚ MagicMockÚrequestsÚResponseÚcookies)ÚrÚkwargsÚ signatureÚresp)ÚgetterrrrÚ fake_sendKs   zSOAuth1SessionTest.test_signature_types..verify_signature..fake_sendr)r#r$)r)r#rÚverify_signatureJsz@OAuth1SessionTest.test_signature_types..verify_signatureÚfoocSs |jdS)NÚ Authorization)Úheaders)rrrrrVsz8OAuth1SessionTest.test_signature_types..z https://i.b)Zsignature_typecSs|jS)N)Úurl)rrrrrZsz Content-Typez!application/x-www-form-urlencodedcSs|jS)N)Úbody)rrrrr_sÚ)r(Údata)r ÚsendÚpostrr)rr%ÚheaderÚqueryr*r(r)rrÚtest_signature_typesIs     z&OAuth1SessionTest.test_signature_typesz*oauthlib.oauth1.rfc5849.generate_timestampz&oauthlib.oauth1.rfc5849.generate_noncecCs–tstjdƒ‚d|_d|_d}tdƒ}|j|ƒ|_|jdƒd}tdtd}|j|ƒ|_|jdƒd j t d }tdt t d }|j|ƒ|_|jdƒdS) Nzcryptography module is requiredÚabcÚ123z³OAuth oauth_nonce="abc", oauth_timestamp="123", oauth_version="1.0", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="foo", oauth_signature="h2sRqLArjhlc5p3FTkuNogVHlKE%3D"r&z https://i.bz˜OAuth oauth_nonce="abc", oauth_timestamp="123", oauth_version="1.0", oauth_signature_method="PLAINTEXT", oauth_consumer_key="foo", oauth_signature="%26")Úsignature_methodz™OAuth oauth_nonce="abc", oauth_timestamp="123", oauth_version="1.0", oauth_signature_method="RSA-SHA1", oauth_consumer_key="foo", oauth_signature="{sig}")Úsig)r4Úrsa_key) Ú cryptographyÚunittestÚSkipTestÚ return_valuer r%r-r.rÚformatÚTEST_RSA_OAUTH_SIGNATURErÚ TEST_RSA_KEY)rÚgenerate_nonceÚgenerate_timestampr!ÚauthrrrÚtest_signature_methodsbs$       z(OAuth1SessionTest.test_signature_methodscCsNd|_d|_tdƒ}ddi}d}tdƒ}|j|ƒ|_|jd|d |fgd dS) Nr2r3z hello worldz Content-Typezapplication/xmlz³OAuth oauth_nonce="abc", oauth_timestamp="123", oauth_version="1.0", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="foo", oauth_signature="h2sRqLArjhlc5p3FTkuNogVHlKE%3D"r&z https://i.bZfake)r(Úfiles)r:rr r%r-r.)rr>r?Zfake_xmlr(r!r@rrrÚtest_binary_uploads z$OAuth1SessionTest.test_binary_uploadcCs2d|_d|_d}tdƒ}|j|ƒ|_|jdƒdS)Nr2r3z³OAuth oauth_nonce="abc", oauth_timestamp="123", oauth_version="1.0", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="foo", oauth_signature="W0haoue5IZAZoaJiYCtfqwMf8x8%3D"r&z"https://i.b?cjk=%E5%95%A6%E5%95%A6)r:r r%r-r.)rr>r?r!r@rrrÚ test_nonascii‹s  zOAuth1SessionTest.test_nonasciicCs6tdƒ}d}d}|j||d}|j||d|ƒdS)Nr&zhttps://example.comm/authorizeZ asluif023sf)Z request_tokenz ?oauth_token=)r Zauthorization_urlÚ assertEqual)rr@r)ÚtokenZauth_urlrrrÚtest_authorization_url•s z(OAuth1SessionTest.test_authorization_urlcCspd}tdƒ}|j|ƒ}|j|ddƒ|j|ddƒx4|jƒD](\}}|jt|tƒƒ|jt|tƒƒq@WdS)Nz7https://i.b/callback?oauth_token=foo&oauth_verifier=barr&Ú oauth_tokenÚoauth_verifierÚbar)r Zparse_authorization_responserEÚitemsr rÚ unicode_type)rr)r@r"ÚkÚvrrrÚtest_parse_response_urlœs z)OAuth1SessionTest.test_parse_response_urlcCshtdƒ}|jdƒ|_|jdƒ}|j|ddƒx4|jƒD](\}}|jt|tƒƒ|jt|tƒƒq8WdS)Nr&zoauth_token=foozhttps://example.com/tokenrH) r Ú fake_bodyr-Úfetch_request_tokenrErKr rrL)rr@r"rMrNrrrÚtest_fetch_request_token¦s  z*OAuth1SessionTest.test_fetch_request_tokencCsntdƒ}|jdƒ|_|jdddd}|j|ddƒx4|jƒD](\}}|jt|tƒƒ|jt|tƒƒq>WdS)Nr&zoauth_token=foozhttps://example.com/tokenFT)ÚverifyÚstreamrH) r rPr-rQrErKr rrL)rr@r"rMrNrrrÚ0test_fetch_request_token_with_optional_arguments¯s  zBOAuth1SessionTest.test_fetch_request_token_with_optional_argumentscCsltddd}|jdƒ|_|jdƒ}|j|ddƒx4|jƒD](\}}|jt|tƒƒ|jt|tƒƒqOAuth1SessionTest.test_fetch_access_token_has_verifier_is_nonecCs’ddddœ}tdƒ}|j|jjjƒ|j|jjjƒ|j|jjjƒ|j|jiƒ||_|j|jjjdƒ|j|jjjdƒ|j|jjjdƒdS)Nzfake-keyz fake-secretz fake-verifier)rHÚoauth_token_secretrIr&) r Ú assertIsNonerirjÚresource_owner_keyÚresource_owner_secretrVrErF)rrFÚsessrrrÚtest_token_proxy_setôsz&OAuth1SessionTest.test_token_proxy_setcCsZddddœ}td|d|d|dd }|j|j|ƒd |jj_d |d<|j|j|ƒdS) Nzfake-keyz fake-secretz fake-verifier)rHrlrIr&rHrlrI)rnrorVz different-key)r rErFrirjrn)rrFrprrrÚtest_token_proxy_gets  z&OAuth1SessionTest.test_token_proxy_getcCstdƒ}|j|jƒdS)Nr&)r Ú assertFalseÚ authorized)rrprrrÚtest_authorized_falsesz'OAuth1SessionTest.test_authorized_falsecCs6djtd}tdttd}|j|ƒ|_|j|jƒdS)Nz™OAuth oauth_nonce="abc", oauth_timestamp="123", oauth_version="1.0", oauth_signature_method="RSA-SHA1", oauth_consumer_key="foo", oauth_signature="{sig}")r5r&)r4r6) r;r<r rr=r%r-rsrt)rr!rprrrÚtest_authorized_false_rsas  z+OAuth1SessionTest.test_authorized_false_rsacCs4tdddd}|jdƒ|_|jdƒ|j|jƒdS)NÚkeyÚsecretrJ)rVz&oauth_token=foo&oauth_token_secret=barzhttps://example.com/token)r rPr-rWr rt)rrprrrÚtest_authorized_true's  z&OAuth1SessionTest.test_authorized_truecCs^tstjdƒ‚d|_d|_djtd}tddttdd }|j d ƒ|_ |j d ƒ|j |j ƒdS) Nzcryptography module is requiredr2r3z¯OAuth oauth_nonce="abc", oauth_timestamp="123", oauth_version="1.0", oauth_signature_method="RSA-SHA1", oauth_consumer_key="foo", oauth_verifier="bar", oauth_signature="{sig}")r5rwrxrJ)r4r6rVz&oauth_token=foo&oauth_token_secret=barzhttps://example.com/token)r7r8r9r:r;r<r rr=rPr-rWr rt)rr>r?r!rprrrÚtest_authorized_true_rsa-s    z*OAuth1SessionTest.test_authorized_true_rsacs‡‡fdd„}|S)NcsB|jd}t|tƒr|jdƒ}ˆj|ˆƒtjtjd}g|_ |S)Nr'zutf-8)r) r(rrrrErrrrr)rr Ú auth_headerr")rr!rrr$As    z5OAuth1SessionTest.verify_signature..fake_sendr)rr!r$r)rr!rr%@sz"OAuth1SessionTest.verify_signatureéÈcs‡‡fdd„}|S)Ncs$tjtjd}g|_ˆ|_ˆ|_|S)N)r)rrrrrÚtextrb)rr r")r*rbrrr$Ls z.OAuth1SessionTest.fake_body..fake_sendr)rr*rbr$r)r*rbrrPKszOAuth1SessionTest.fake_bodyN)r|)Ú__name__Ú __module__Ú __qualname__rr1rÚpatchrArCrDrGrOrRrUrXrYr]rgrhrkrqrrrurvryrzr%rPrrrrr Bs6         r )"Ú __future__rrÚbuiltinsÚ @py_builtinsÚ_pytest.assertion.rewriteÚ assertionÚrewriteÚ @pytest_arrr8ÚsysrÚiorZoauthlib.oauth1rrrrÚrequests_oauthlibr r7Ú ImportErrorÚversionr[rLÚbytesrÚunicoder=r<ÚTestCaser rrrrÚs,      requests-oauthlib-1.0.0/tests/__pycache__/test_core.cpython-36-PYTEST.pyc0000644000076500000240000001113113265672624030402 0ustar singingwolfboystaff000000000000003 S,ÍZ£ã@sŽddlmZddlZddljjZddlZddl Z ddl Z ddl Z ddl Z ddl ZddlmZddlZejdƒejdƒGdd„dejƒƒƒZdS)é)Úunicode_literalsN)ÚStringIOz*oauthlib.oauth1.rfc5849.generate_timestampz&oauthlib.oauth1.rfc5849.generate_noncec@s<eZdZdd„Zdd„Zdd„Zdd„Zd d „Zd d „Zd S)Ú OAuth1TestcCsÔd|_d|_tjdƒ}ddi}tjdd|d|d }|jƒ}|j|jdƒ|j|jd ƒ|j|j j d ƒd ƒtjdd|dd }|jƒ}|j|jdƒ|j|jd ƒ|j|j j d ƒd ƒ|j|j j dƒ|j j dƒƒdS)z=OAuth1 assumes form encoded if content type is not specified.ÚabcÚ1Ú client_keyz Content-typez!application/x-www-form-urlencodedÚPOSTzhttp://a.b/path?query=retainzthis=really&is=&+form=encoded)ÚmethodÚurlÚauthÚdataÚheaderssthis=really&is=&+form=encodedz Content-Types!application/x-www-form-urlencoded)r r r r Ú AuthorizationN) Ú return_valueÚrequests_oauthlibÚOAuth1ÚrequestsÚRequestÚprepareÚ assertEqualr Úbodyr Úget)ÚselfÚgenerate_nonceÚgenerate_timestampÚoauthr ÚrÚaÚb©rúA/Users/singingwolfboy/clones/requests-oauthlib/tests/test_core.pyÚtestFormEncodeds$   zOAuth1Test.testFormEncodedcCs¦d|_d|_tjdƒ}tjdd|dd}|jƒ}tjdd|d}|jƒ}|j|jjd ƒ|jjd ƒƒtjdd|d t d ƒid }|jƒ}|j|jjd ƒ|jjd ƒƒd S)z:OAuth signature only depend on body if it is form encoded.rrrrzhttp://a.b/path?query=retainzthis really is not form encoded)r r r r )r r r rÚtestZhello)r r r ÚfilesN) rrrrrrrr rr)rrrrrrrÚcrrr ÚtestNonFormEncoded*s   zOAuth1Test.testNonFormEncodedcCs†d|_d|_tjdƒ}tjjtƒ}tjj|dƒ}t|dƒB}t j dddid tjj |j ƒ|fid d i|d }|j |jd ƒWdQRXdS)zr Test we can post binary data. Should prevent regression of the UnicodeDecodeError issue. rrrztest.binÚrbzhttp://httpbin.org/postÚhiZthereZmediaz content-typezapplication/octet-stream)r r#r r éÈN)rrrÚosÚpathÚdirnameÚ__file__ÚjoinÚopenrÚpostÚbasenameÚnamerÚ status_code)rrrrr+ÚfnameÚfrrrr ÚtestCanPostBinaryDataBs    z OAuth1Test.testCanPostBinaryDatacCs<d|_d|_tjdƒ}tjd|d}|jt|jjt ƒƒdS)z> Test that the URL is always a native string. rrrzhttp://httpbin.org/get)r N) rrrrrÚ assertTrueÚ isinstanceÚrequestr Ústr)rrrrrrrr Útest_url_is_native_strTs  z!OAuth1Test.test_url_is_native_strcCspd|_d|_tjdƒ}d}tjd||d}|j|jjjdƒdƒtjd||d d id }|j|jjjdƒd ƒd S)zG Content type should only be guessed if none is given. rrrrzhttp://httpbin.org/get)r r z Content-Types!application/x-www-form-urlencodedz Content-typezapplication/json)r r r sapplication/jsonN) rrrrr/rr8r r)rrrrr rrrr Útest_content_type_override_s   z%OAuth1Test.test_content_type_overridecCsôGdd„dtjjƒ}|jttjdƒƒ|jtjjtjjƒtjdƒ}|jt |j tjjƒƒ|j t |j |ƒƒ|tj_|jtjj|ƒtjdƒ}|jt |j tjjƒƒ|jt |j |ƒƒtjdtjjd}|jt |j tjjƒƒ|j t |j |ƒƒdS)Nc@s eZdZdS)z=OAuth1Test.test_register_client_class..ClientSubclassN)Ú__name__Ú __module__Ú __qualname__rrrr ÚClientSubclassqsr?Ú client_classr)r@) ÚoauthlibZoauth1ZClientr6Úhasattrrrrr@r7ÚclientÚ assertFalse)rrrr?ZnormalÚcustomZ overriddenrrr Útest_register_client_classps"    z%OAuth1Test.test_register_client_classN) r<r=r>r!r%r5r:r;rFrrrr r s  r)Ú __future__rÚbuiltinsÚ @py_builtinsÚ_pytest.assertion.rewriteÚ assertionÚrewriteÚ @pytest_arÚmockÚsysrrrAÚos.pathr)ÚiorÚunittestÚpatchÚTestCaserrrrr Ús   requests-oauthlib-1.0.0/tests/__pycache__/test_oauth2_auth.cpython-36-PYTEST.pyc0000644000076500000240000000504013265672624031677 0ustar singingwolfboystaff000000000000003 ŽpYWbã@svddlmZddlZddljjZddlZddl m Z m Z ddl m Z m Z ddlmZddlmZGdd„dejƒZdS) é)Úunicode_literalsN)ÚWebApplicationClientÚMobileApplicationClient)ÚLegacyApplicationClientÚBackendApplicationClient)ÚRequest)ÚOAuth2c@s4eZdZdd„Zdd„Zdd„Zdd„Zd d „Zd S) ÚOAuth2AuthTestcCs>ddddœ|_d|_t|jƒt|jƒt|jƒt|jƒg|_dS)NÚBearerZasdfoiw37850234lkjsdfsdfZ3600)Ú token_typeÚ access_tokenÚ expires_inÚfoo)ÚtokenZ client_idrrrrÚclients)Úself©rúH/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth2_auth.pyÚsetUp s zOAuth2AuthTest.setUpcCs^d}|d|jd}xB|jD]8}d|_t||jd}td||djƒ}|j|j|ƒqWdS)Nz$https://example.com/resource?foo=barz&access_token=r Úquery)ÚclientrÚGET)Úauth)rrÚdefault_token_placementrrÚprepareÚ assertEqualÚurl)rrZnew_urlrrÚrrrrÚtest_add_token_to_urls z$OAuth2AuthTest.test_add_token_to_urlcCsTd|jd}x@|jD]6}t||jd}tdd|djƒ}|j|jd|ƒqWdS)NzBearer r )rrrz https://i.b)rÚ Authorization)rrrrrrÚheaders)rrrrrrrrÚtest_add_token_to_headers#s  z(OAuth2AuthTest.test_add_token_to_headerscCs`d}|d|jd}xD|jD]:}d|_t||jd}tdd||djƒ}|j|j|ƒqWdS) Nzfoo=barz&access_token=r Úbody)rrrz https://i.b)Údatar)rrrrrrrr")rr"Znew_bodyrrrrrrÚtest_add_token_to_body*s z%OAuth2AuthTest.test_add_token_to_bodycCs:x4|jD]*}t|d}tdd|d}|jt|jƒqWdS)N)rrz https://i.b)r)rrrÚ assertRaisesÚ ValueErrorr)rrrrrrrÚtest_add_nonexisting_token3s  z)OAuth2AuthTest.test_add_nonexisting_tokenN)Ú__name__Ú __module__Ú __qualname__rrr!r$r'rrrrr s   r )Ú __future__rÚbuiltinsÚ @py_builtinsÚ_pytest.assertion.rewriteÚ assertionÚrewriteÚ @pytest_arÚunittestZoauthlib.oauth2rrrrÚrequestsrÚrequests_oauthlibrÚTestCaser rrrrÚs    requests-oauthlib-1.0.0/tests/__pycache__/test_compliance_fixes.cpython-36-PYTEST.pyc0000644000076500000240000002413113265672624032766 0ustar singingwolfboystaff000000000000003 S,ÍZÛ*ã @s^ddlmZddlZddljjZddlm Z ddl Z ddl Z ddl Z yddl m Z mZWn$ek r|ddlm Z mZYnXddlmZddlmZddlmZddlmZdd lmZdd lmZdd lmZdd lmZdd lmZGdd„de ƒZGdd„de ƒZGdd„de ƒZGdd„de ƒZ Gdd„de ƒZ!Gdd„de ƒZ"Gdd„de ƒZ#dS)é)Úunicode_literalsN)ÚTestCase)ÚurlparseÚparse_qs)ÚInvalidGrantError)Ú OAuth2Session)Úfacebook_compliance_fix)Úfitbit_compliance_fix)Úlinkedin_compliance_fix)Úmailchimp_compliance_fix)Úweibo_compliance_fix)Úslack_compliance_fix)Úplentymarkets_compliance_fixc@seZdZdd„Zdd„ZdS)ÚFacebookComplianceFixTestcCsJtjƒ}|jddddid|jƒ|j|jƒtddd}t|ƒ|_dS) Nz-https://graph.facebook.com/oauth/access_tokenzaccess_token=urlencodedz Content-Typez text/plain)ÚtextÚheadersÚfooz https://i.b)Ú redirect_uri) Ú requests_mockÚMockerÚpostÚstartÚ addCleanupÚstoprrÚsession)ÚselfÚmockerZfacebook©rúM/Users/singingwolfboy/clones/requests-oauthlib/tests/test_compliance_fixes.pyÚsetUps   zFacebookComplianceFixTest.setUpcCs(|jjdddd}|j|dddœƒdS)Nz-https://graph.facebook.com/oauth/access_tokenÚbarzhttps://i.b/?code=hello)Ú client_secretÚauthorization_responseZ urlencodedÚBearer)Ú access_tokenÚ token_type)rÚ fetch_tokenÚ assertEqual)rÚtokenrrrÚtest_fetch_access_token&s z1FacebookComplianceFixTest.test_fetch_access_tokenN)Ú__name__Ú __module__Ú __qualname__rr)rrrrrs rc@s$eZdZdd„Zdd„Zdd„ZdS)ÚFitbitComplianceFixTestcCsVtjƒ|_|jjddddigid|jjƒ|j|jjƒtddd}t|ƒ|_ dS) Nz#https://api.fitbit.com/oauth2/tokenÚerrorsZ errorTypeZ invalid_grant)Újsonrz https://i.b)r) rrrrrrrrr r)rÚfitbitrrrr1s   zFitbitComplianceFixTest.setUpcCsP|jt|jjdddd|jjdddid|jjddd }|j|ddiƒdS) Nz#https://api.fitbit.com/oauth2/tokenr zhttps://i.b/?code=hello)r!r"r$r0)r/Zgood)r!)Ú assertRaisesrrr&rrr')rr(rrrr)=s z/FitbitComplianceFixTest.test_fetch_access_tokencCst|jt|jjdtjjddƒd|jjddddœd|jjdtjjddƒd}|j |d dƒ|j |d dƒdS) Nz#https://api.fitbit.com/oauth2/tokenrr )ÚauthÚaccessZrefresh)r$Ú refresh_token)r/r$r4) r1rrr4Úrequestsr2Z HTTPBasicAuthrrr')rr(rrrÚtest_refresh_tokenRsz*FitbitComplianceFixTest.test_refresh_tokenN)r*r+r,rr)r6rrrrr-/s r-c@s$eZdZdd„Zdd„Zdd„ZdS)ÚLinkedInComplianceFixTestcCs^tjƒ}|jdddid|jddddd œd |jƒ|j|jƒtd d d }t|ƒ|_dS)Nz/https://www.linkedin.com/uas/oauth2/accessTokenr$Úlinkedin)r/z+https://api.linkedin.com/v1/people/~/shareséÉzUPDATE-3346389-595113200z6https://www.linkedin.com/updates?discuss=abc&scope=xyz)Z updateKeyZ updateUrl)Z status_coder/rz https://i.b)r) rrrrrrrr r)rrr8rrrrjs    zLinkedInComplianceFixTest.setUpcCs(|jjdddd}|j|dddœƒdS)Nz/https://www.linkedin.com/uas/oauth2/accessTokenr zhttps://i.b/?code=hello)r!r"r8r#)r$r%)rr&r')rr(rrrr)~s z1LinkedInComplianceFixTest.test_fetch_access_tokencCsDddi|j_|jjdƒ}|jj}tt|ƒjƒ}|j|ddgƒdS)Nr$zdummy-access-tokenz+https://api.linkedin.com/v1/people/~/sharesZoauth2_access_token) rr(rÚrequestÚurlrrÚqueryr')rÚresponser;r<rrrÚtest_protected_request†s  z0LinkedInComplianceFixTest.test_protected_requestN)r*r+r,rr)r>rrrrr7hsr7c@seZdZdd„Zdd„ZdS)ÚMailChimpComplianceFixTestcCsLtjƒ}|jdddddœd|jƒ|j|jƒtddd}t|ƒ|_dS) Nz(https://login.mailchimp.com/oauth2/tokenÚ mailchimpr)r$Ú expires_inÚscope)r/rz https://i.b)r) rrrrrrrr r)rrr@rrrr’s  z MailChimpComplianceFixTest.setUpcCsZ|jjdddd}tjƒd}|jdƒ}|j||dd|j|d dd œƒ|jd |ƒdS) Nz(https://login.mailchimp.com/oauth2/tokenr zhttps://i.b/?code=hello)r!r"iÚ expires_até)Úplacesr@)r$rArB)rr&ÚtimeÚpopÚassertAlmostEqualr'Ú assertNotIn)rr(Úapprox_expires_atÚactual_expires_atrrrr)žs  z2MailChimpComplianceFixTest.test_fetch_access_tokenN)r*r+r,rr)rrrrr?s r?c@seZdZdd„Zdd„ZdS)ÚWeiboComplianceFixTestcCsHtjƒ}|jdddid|jƒ|j|jƒtddd}t|ƒ|_dS)Nz)https://api.weibo.com/oauth2/access_tokenr$Úweibo)r/rz https://i.b)r) rrrrrrrr r)rrrMrrrr²s   zWeiboComplianceFixTest.setUpcCs(|jjdddd}|j|dddœƒdS)Nz)https://api.weibo.com/oauth2/access_tokenr zhttps://i.b/?code=hello)r!r"rMr#)r$r%)rr&r')rr(rrrr)¾s z.WeiboComplianceFixTest.test_fetch_access_tokenN)r*r+r,rr)rrrrrL°s rLc@s4eZdZdd„Zdd„Zdd„Zdd„Zd d „Zd S) ÚSlackComplianceFixTestc Csvtjƒ}|jddddœdx*dD]"}|j|dd d d d d ddœdq"W|jƒ|j|jƒtddd}t|ƒ|_ dS)Nz"https://slack.com/api/oauth.accesszxoxt-23984754863-2348975623103Úread)r$rB)r/ÚGETÚPOSTzhttps://slack.com/api/auth.testTzhttps://myteam.slack.com/zMy TeamÚcalZT12345ZU12345)Úokr;ZteamÚuserZteam_idZuser_id)Úmethodr;r/rz https://i.b)r)rPrQ) rrrr:rrrrr r)rrrUZslackrrrrÉs&    zSlackComplianceFixTest.setUpcCs`ddi|j_|jjdƒ}|jj}tt|ƒjƒ}|jd|ƒ|jj }t|ƒ}|j |ddgƒdS)Nr$zdummy-access-tokenzhttps://slack.com/api/auth.testr() rr(Úgetr:r;rrr<rIÚbodyr')rr=r;r<rWÚdatarrrr>ås  z-SlackComplianceFixTest.test_protected_requestcCshddi|j_|jjdddid}|jj}tt|ƒjƒ}|jd|ƒ|jj }t|ƒ}|j |ddgƒdS)Nr$zdummy-access-tokenzhttps://slack.com/api/auth.testr(zdifferent-token)rX) rr(rVr:r;rrr<rIrWr')rr=r;r<rWrXrrrÚ)test_protected_request_override_token_getñs   z@SlackComplianceFixTest.test_protected_request_override_token_getcCshddi|j_|jjdddid}|jj}tt|ƒjƒ}|jd|ƒ|jj }t|ƒ}|j |ddgƒdS)Nr$zdummy-access-tokenzhttps://slack.com/api/auth.testr(zdifferent-token)rX) rr(rr:r;rrr<rIrWr')rr=r;r<rWrXrrrÚ*test_protected_request_override_token_postþs   zASlackComplianceFixTest.test_protected_request_override_token_postcCsRddi|j_|jjdƒ}|jj}tt|ƒjƒ}|j|ddgƒ|j |jj ƒdS)Nr$zdummy-access-tokenz5https://slack.com/api/auth.test?token=different-tokenr(zdifferent-token) rr(rVr:r;rrr<r'Ú assertIsNonerW)rr=r;r<rrrÚ)test_protected_request_override_token_url s z@SlackComplianceFixTest.test_protected_request_override_token_urlN)r*r+r,rr>rYrZr\rrrrrNÇs    rNc@seZdZdd„Zdd„ZdS)ÚPlentymarketsComplianceFixTestcCsTtjƒ}|jddddddœddid |jƒ|j|jƒtd d d }t|ƒ|_dS) Nz&https://shop.plentymarkets-cloud02.comÚ(ecUN1r8KhJewMCdLAmpHOdZ4O0ofXKB9zf6CXK61r#i€QÚ(iG2kBGIjcXaRE4xmTVUnv7xwxX7XMcWCHqJmFaSX)Z accessTokenZ tokenTypeZ expiresInZ refreshTokenz Content-Typezapplication/json)r/rrz https://i.b)r) rrrrrrrrr)rrZ plentymarketsrrrrs   z$PlentymarketsComplianceFixTest.setUpcCsP|jjddd}tjƒd}|jdƒ}|j||dd|j|ddd d d œƒdS) Nz&https://shop.plentymarkets-cloud02.comzhttps://i.b/?code=hello)r"i€QrCrD)rEr^r#r_)r$rAr%r4)rr&rFrGrHr')rr(rJrKrrrr)+s  z6PlentymarketsComplianceFixTest.test_fetch_access_tokenN)r*r+r,rr)rrrrr]sr])$Ú __future__rÚbuiltinsÚ @py_builtinsÚ_pytest.assertion.rewriteÚ assertionÚrewriteÚ @pytest_arÚunittestrr5rrFrrÚ ImportErrorÚ urllib.parseZoauthlib.oauth2.rfc6749.errorsrZrequests_oauthlibrZ"requests_oauthlib.compliance_fixesrr r r r r rrr-r7r?rLrNr]rrrrÚs4           9( Orequests-oauthlib-1.0.0/tests/__pycache__/test_oauth2_session.cpython-36-PYTEST.pyc0000644000076500000240000002167413265672625032435 0ustar singingwolfboystaff000000000000003 S,ÍZˆ$ã@sØddlmZddlZddljjZddlZddl Z ddl Z ddl m Z ddl mZddlmZddlmZddlmZmZddlmZdd lmZmZdd lmZmZdd lmZmZe j ƒZd d „ZGdd„deƒZ dS)é)Úunicode_literalsN)Ú b64encode)Údeepcopy)ÚTestCase)Ú urlencode)ÚTokenExpiredErrorÚ OAuth2Error)ÚMismatchingStateError)ÚWebApplicationClientÚMobileApplicationClient)ÚLegacyApplicationClientÚBackendApplicationClient)Ú OAuth2SessionÚ TokenUpdatedcs‡fdd„}|S)Ncstjƒ}tjˆƒ|_|S)N)ÚmockÚ MagicMockÚjsonÚdumpsÚtext)ÚrÚkwargsÚresp)Útoken©úK/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth2_session.pyÚ fake_sends zfake_token..fake_sendr)rrr)rrÚ fake_tokens rc@s¼eZdZdd„Zdd„Zdd„Zejddd „d d d „ƒZejdd d „d dd„ƒZ ejddd „d dd„ƒZ dd„Z dd„Z dd„Z dd„Zdd„Zdd„Zejddd „d d d!„ƒZd"S)#ÚOAuth2SessionTestcsntˆdƒs‡fdd„ˆ_ddddtdd œˆ_d ˆ_tˆjd d tˆjƒtˆjƒgˆ_ˆjt ˆjƒgˆ_ dS) NÚassertIncsˆj||kƒS)N)Ú assertTrue)ÚaÚb)ÚselfrrÚ"sz)OAuth2SessionTest.setUp..ÚBearerÚasdfoiw37850234lkjsdfsdfZsldvafkjw34509s8dfsdfÚ3600i)Ú token_typeÚ access_tokenÚ refresh_tokenÚ expires_inÚ expires_atÚfooZ asdf345xdf)Úcode) ÚhasattrrÚ fake_timerÚ client_idr r r Úclientsr Ú all_clients)r"r)r"rÚsetUps  zOAuth2SessionTest.setUpcsNdˆjd‰‡‡fdd„}x,ˆjD]"}t|ˆjd}||_|jdƒq$WdS)NzBearer r(cs0|jjtdƒdƒ}ˆj|ˆƒtjƒ}g|_|S)NÚ Authorization)ÚheadersÚgetÚstrÚ assertEqualrrZcookes)rrÚ auth_headerr)r"rrrÚverifier6s  z2OAuth2SessionTest.test_add_token..verifier)Úclientrz https://i.b)rr2rÚsendr6)r"r:r;Úauthr)r"rrÚtest_add_token3s  z OAuth2SessionTest.test_add_tokencCs˜d}t|jƒ}t|d}|j|ƒ\}}|j||ƒ|j|j|ƒ|jd|ƒt|jƒ}t|d}|j|ƒ\}}|j||ƒ|j|j|ƒ|jd|ƒdS)Nz%https://example.com/authorize?foo=bar)r;zresponse_type=codezresponse_type=token)r r0rÚauthorization_urlrr )r"ÚurlZwebÚsÚauth_urlÚstateÚmobilerrrÚtest_authorization_urlBs       z(OAuth2SessionTest.test_authorization_urlz time.timecCstS)N)r/rrrrr#SszOAuth2SessionTest.)Únewcstˆjƒˆ_dˆjd<ˆjd=‡fdd„}x,ˆjD]"}t|ˆjd}ˆjt|jdƒq2Wx4ˆjD]*}t|ˆjdd }||_ˆjt |jdƒq`W‡fd d „}x0ˆjD]&}t|ˆjd|d }||_|jdƒq¢W‡fd d„}x6ˆjD],}t|ˆjd|d }||_|jddddqàWdS)Nz-1r*r+cs2d|jkrˆjd|jƒtjƒ}tjˆjƒ|_|S)Nz/refreshr4) r@Ú assertNotInr5rrrrrr)rrr)r"rrÚ fake_refreshYs  zBOAuth2SessionTest.test_refresh_token_request..fake_refresh)r;rz https://i.bzhttps://i.b/refresh)r;rÚauto_refresh_urlcsˆj|ˆjƒdS)N)r8r)r)r"rrÚ token_updatermszCOAuth2SessionTest.test_refresh_token_request..token_updater)r;rrIrJcsZd|jkr@ˆjd|jƒtdƒ}d|jdƒ}ˆj|jd|ƒtjƒ}tj ˆj ƒ|_ |S)Nz/refreshr4sfoo:barsBasic Úlatin1) r@rr5rÚdecoder8rrrrrr)rrÚencodedÚcontentr)r"rrÚfake_refresh_with_authws zLOAuth2SessionTest.test_refresh_token_request..fake_refresh_with_authr,Úbar)r0Ú client_secret) ÚdictrZ expired_tokenr1rÚ assertRaisesrr6r<r)r"rHr;r=rJrOr)r"rÚtest_refresh_token_requestSs4        z,OAuth2SessionTest.test_refresh_token_requestcCstS)N)r/rrrrr#ˆscCs>t|jƒ}dt|jjƒƒ}t|d}|j|j|ƒ|jƒdS)Nzhttps://i.b/callback#)r;)r r0rrÚitemsrr8Útoken_from_fragment)r"rDZ response_urlr=rrrÚtest_token_from_fragmentˆs  z*OAuth2SessionTest.test_token_from_fragmentcCstS)N)r/rrrrr#scCs†d}x<|jD]2}t||jd}t|jƒ|_|j|j|ƒ|jƒq Wddi}x6|jD],}t||jd}t|ƒ|_|jt|j|ƒqRWdS)Nzhttps://example.com/token)r;rÚerrorÚinvalid_request) r1rrrr<r8Ú fetch_tokenrSr)r"r@r;r=rXrrrÚtest_fetch_tokens    z"OAuth2SessionTest.test_fetch_tokenc s–t|jƒ}tjƒd}tjƒ‰||jd<ˆd|d<d}tjd‡fdd„ƒ@x8|jD].}t||jd}t|ƒ|_|j |j |ƒ|ƒqVWWd QRXd S) a Makes sure the previous token is cleaned before fetching a new one. The reason behind it is that, if the previous token is expired, this method shouldn't fail with a TokenExpiredError, since it's attempting to get a new one (which shouldn't be expired). i r+izhttps://example.com/tokenz time.timecsˆS)Nrr)Únowrrr#­szVOAuth2SessionTest.test_cleans_previous_token_before_fetching_new_one..)r;rN) rrÚtimerÚpatchr1rrr<r8rZ)r"Z new_tokenZpastr@r;r=r)r\rÚ2test_cleans_previous_token_before_fetching_new_onežs      zDOAuth2SessionTest.test_cleans_previous_token_before_fetching_new_onecCs$tddd}|jt|jddddS)Nr,Z somestate)rCzhttps://i.b/tokenzhttps://i.b/no-state?code=abc)Úauthorization_response)rrSr rZ)r"r;rrrÚtest_web_app_fetch_token´s  z*OAuth2SessionTest.test_web_app_fetch_tokencCsTtdƒ}|j|jdƒd|_|j|jdƒd|j_|j|jdƒ|`|j|jƒdS)Nztest-idz different-idzsomething-else)rr8r0Ú_clientÚ assertIsNone)r"ÚsessrrrÚtest_client_id_proxy»sz&OAuth2SessionTest.test_client_id_proxycCsRtdƒ}|j|jƒd|_|j|jdƒd|j_|j|jdƒ|`|j|jƒdS)Nztest-idz test-tokenzdifferent-token)rrcr(r8rb)r"rdrrrÚtest_access_token_proxyÅs z)OAuth2SessionTest.test_access_token_proxyc Cs¤ddi}td|d}|j|jdƒ|j|j|ƒd|d<||_|j|jdƒ|j|j|ƒd|j_d|d<|j|jdƒ|j|j|ƒ|jtƒ |`WdQRXdS)Nr(z test-accessztest-id)rzsomething-elsezdifferent-token)rr8r(rrbrSÚAttributeError)r"rrdrrrÚtest_token_proxyÏs  z"OAuth2SessionTest.test_token_proxycCstdƒ}|j|jƒdS)Nr,)rÚ assertFalseÚ authorized)r"rdrrrÚtest_authorized_falseâsz'OAuth2SessionTest.test_authorized_falsecCstS)N)r/rrrrr#æscCsXdd„}d}xF|jD]<}t|d}||jƒ|_|j|jƒ|j|ƒ|j|jƒqWdS)Ncs‡fdd„}|S)Ncstjƒ}tjˆƒ|_|S)N)rrrrr)rrr)rrrrés zMOAuth2SessionTest.test_authorized_true..fake_token..fake_sendr)rrr)rrrès z:OAuth2SessionTest.test_authorized_true..fake_tokenzhttps://example.com/token)r;)r1rrr<rirjrZr)r"rr@r;rdrrrÚtest_authorized_trueæs     z&OAuth2SessionTest.test_authorized_trueN)Ú__name__Ú __module__Ú __qualname__r3r>rErr^rTrWr[r_rarerfrhrkrlrrrrrs5  r)!Ú __future__rÚbuiltinsÚ @py_builtinsÚ_pytest.assertion.rewriteÚ assertionÚrewriteÚ @pytest_arrrr]Úbase64rÚcopyrÚunittestrÚoauthlib.commonrÚoauthlib.oauth2rrr r r r r Úrequests_oauthlibrrr/rrrrrrÚs"       requests-oauthlib-1.0.0/tests/__pycache__/__init__.cpython-36.pyc0000644000076500000240000000022313265672624027124 0ustar singingwolfboystaff000000000000003 ŽpYWã@sdS)N©rrrú@/Users/singingwolfboy/clones/requests-oauthlib/tests/__init__.pyÚsrequests-oauthlib-1.0.0/tests/test_oauth1_session.py0000644000076500000240000003600613277061160025102 0ustar singingwolfboystaff00000000000000from __future__ import unicode_literals, print_function import mock import unittest import sys import requests from io import StringIO from oauthlib.oauth1 import SIGNATURE_TYPE_QUERY, SIGNATURE_TYPE_BODY from oauthlib.oauth1 import SIGNATURE_RSA, SIGNATURE_PLAINTEXT from requests_oauthlib import OAuth1Session try: import cryptography except ImportError: cryptography = None if sys.version[0] == '3': unicode_type = str bytes_type = bytes else: unicode_type = unicode bytes_type = str TEST_RSA_KEY = ( "-----BEGIN RSA PRIVATE KEY-----\n" "MIIEogIBAAKCAQEApF1JaMSN8TEsh4N4O/5SpEAVLivJyLH+Cgl3OQBPGgJkt8cg\n" "49oasl+5iJS+VdrILxWM9/JCJyURpUuslX4Eb4eUBtQ0x5BaPa8+S2NLdGTaL7nB\n" "OO8o8n0C5FEUU+qlEip79KE8aqOj+OC44VsIquSmOvWIQD26n3fCVlgwoRBD1gzz\n" "sDOeaSyzpKrZR851Kh6rEmF2qjJ8jt6EkxMsRNACmBomzgA4M1TTsisSUO87444p\n" "e35Z4/n5c735o2fZMrGgMwiJNh7rT8SYxtIkxngioiGnwkxGQxQ4NzPAHg+XSY0J\n" "04pNm7KqTkgtxyrqOANJLIjXlR+U9SQ90NjHVQIDAQABAoIBABuBPOKaWcJt3yzC\n" "NGGduoif7KtwSnEaUA+v69KPGa2Zju8uFHPssKD+4dZYRc2qMeunKJLpaGaSjnRh\n" "yHyvvOBJCN1nr3lhz6gY5kzJTfwpUFXCOPJlGy4Q+2Xnp4YvcvYqQ9n5DVovDiZ8\n" "vJOBn16xqpudMPLHIa7D5LJ8SY76HBjE+imTXw1EShdh5TOV9bmPFQqH6JFzowRH\n" "hyH2DPHuyHJj6cl8FyqJw5lVWzG3n6Prvk7bYHsjmGjurN35UsumNAp6VouNyUP1\n" "RAEcUJega49aIs6/FJ0ENJzQjlsAzVbTleHkpez2aIok+wsWJGJ4SVxAjADOWAaZ\n" "uEJPc3UCgYEA1g4ZGrXOuo75p9/MRIepXGpBWxip4V7B9XmO9WzPCv8nMorJntWB\n" "msYV1I01aITxadHatO4Gl2xLniNkDyrEQzJ7w38RQgsVK+CqbnC0K9N77QPbHeC1\n" "YQd9RCNyUohOimKvb7jyv798FBU1GO5QI2eNgfnnfteSVXhD2iOoTOsCgYEAxJJ+\n" "8toxJdnLa0uUsAbql6zeNXGbUBMzu3FomKlyuWuq841jS2kIalaO/TRj5hbnE45j\n" "mCjeLgTVO6Ach3Wfk4zrqajqfFJ0zUg/Wexp49lC3RWiV4icBb85Q6bzeJD9Dn9v\n" "hjpfWVkczf/NeA1fGH/pcgfkT6Dm706GFFttLL8CgYBl/HeXk1H47xAiHO4dJKnb\n" "v0B+X8To/RXamF01r+8BpUoOubOQetdyX7ic+d6deuHu8i6LD/GSCeYJZYFR/KVg\n" "AtiW757QYalnq3ZogkhFrVCZP8IRfTPOFBxp752TlyAcrSI7T9pQ47IBe4094KXM\n" "CJWSfPgAJkOxd0iU0XJpmwKBgGfQxuMTgSlwYRKFlD1zKap5TdID8fbUbVnth0Q5\n" "GbH7vwlp/qrxCdS/aj0n0irOpbOaW9ccnlrHiqY25VpVMLYIkt3DrDOEiNNx+KNR\n" "TItdTwbcSiTYrS4L0/56ydM/H6bsfsXxRjI18hSJqMZiqXqS84OZz2aOn+h7HCzc\n" "LEiZAoGASk20wFvilpRKHq79xxFWiDUPHi0x0pp82dYIEntGQkKUWkbSlhgf3MAi\n" "5NEQTDmXdnB+rVeWIvEi+BXfdnNgdn8eC4zSdtF4sIAhYr5VWZo0WVWDhT7u2ccv\n" "ZBFymiz8lo3gN57wGUCi9pbZqzV1+ZppX6YTNDdDCE0q+KO3Cec=\n" "-----END RSA PRIVATE KEY-----" ) TEST_RSA_OAUTH_SIGNATURE = ( "j8WF8PGjojT82aUDd2EL%2Bz7HCoHInFzWUpiEKMCy%2BJ2cYHWcBS7mXlmFDLgAKV0" "P%2FyX4TrpXODYnJ6dRWdfghqwDpi%2FlQmB2jxCiGMdJoYxh3c5zDf26gEbGdP6D7O" "Ssp5HUnzH6sNkmVjuE%2FxoJcHJdc23H6GhOs7VJ2LWNdbhKWP%2FMMlTrcoQDn8lz" "%2Fb24WsJ6ae1txkUzpFOOlLM8aTdNtGL4OtsubOlRhNqnAFq93FyhXg0KjzUyIZzmMX" "9Vx90jTks5QeBGYcLE0Op2iHb2u%2FO%2BEgdwFchgEwE5LgMUyHUI4F3Wglp28yHOAM" "jPkI%2FkWMvpxtMrU3Z3KN31WQ%3D%3D" ) class OAuth1SessionTest(unittest.TestCase): def setUp(self): # For python 2.6 if not hasattr(self, 'assertIn'): self.assertIn = lambda a, b: self.assertTrue(a in b) def test_signature_types(self): def verify_signature(getter): def fake_send(r, **kwargs): signature = getter(r) if isinstance(signature, bytes_type): signature = signature.decode('utf-8') self.assertIn('oauth_signature', signature) resp = mock.MagicMock(spec=requests.Response) resp.cookies = [] return resp return fake_send header = OAuth1Session('foo') header.send = verify_signature(lambda r: r.headers['Authorization']) header.post('https://i.b') query = OAuth1Session('foo', signature_type=SIGNATURE_TYPE_QUERY) query.send = verify_signature(lambda r: r.url) query.post('https://i.b') body = OAuth1Session('foo', signature_type=SIGNATURE_TYPE_BODY) headers = {'Content-Type': 'application/x-www-form-urlencoded'} body.send = verify_signature(lambda r: r.body) body.post('https://i.b', headers=headers, data='') @mock.patch('oauthlib.oauth1.rfc5849.generate_timestamp') @mock.patch('oauthlib.oauth1.rfc5849.generate_nonce') def test_signature_methods(self, generate_nonce, generate_timestamp): if not cryptography: raise unittest.SkipTest('cryptography module is required') generate_nonce.return_value = 'abc' generate_timestamp.return_value = '123' signature = 'OAuth oauth_nonce="abc", oauth_timestamp="123", oauth_version="1.0", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="foo", oauth_signature="h2sRqLArjhlc5p3FTkuNogVHlKE%3D"' auth = OAuth1Session('foo') auth.send = self.verify_signature(signature) auth.post('https://i.b') signature = 'OAuth oauth_nonce="abc", oauth_timestamp="123", oauth_version="1.0", oauth_signature_method="PLAINTEXT", oauth_consumer_key="foo", oauth_signature="%26"' auth = OAuth1Session('foo', signature_method=SIGNATURE_PLAINTEXT) auth.send = self.verify_signature(signature) auth.post('https://i.b') signature = ('OAuth ' 'oauth_nonce="abc", oauth_timestamp="123", oauth_version="1.0", ' 'oauth_signature_method="RSA-SHA1", oauth_consumer_key="foo", ' 'oauth_signature="{sig}"' ).format(sig=TEST_RSA_OAUTH_SIGNATURE) auth = OAuth1Session('foo', signature_method=SIGNATURE_RSA, rsa_key=TEST_RSA_KEY) auth.send = self.verify_signature(signature) auth.post('https://i.b') @mock.patch('oauthlib.oauth1.rfc5849.generate_timestamp') @mock.patch('oauthlib.oauth1.rfc5849.generate_nonce') def test_binary_upload(self, generate_nonce, generate_timestamp): generate_nonce.return_value = 'abc' generate_timestamp.return_value = '123' fake_xml = StringIO('hello world') headers = {'Content-Type': 'application/xml'} signature = 'OAuth oauth_nonce="abc", oauth_timestamp="123", oauth_version="1.0", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="foo", oauth_signature="h2sRqLArjhlc5p3FTkuNogVHlKE%3D"' auth = OAuth1Session('foo') auth.send = self.verify_signature(signature) auth.post('https://i.b', headers=headers, files=[('fake', fake_xml)]) @mock.patch('oauthlib.oauth1.rfc5849.generate_timestamp') @mock.patch('oauthlib.oauth1.rfc5849.generate_nonce') def test_nonascii(self, generate_nonce, generate_timestamp): generate_nonce.return_value = 'abc' generate_timestamp.return_value = '123' signature = 'OAuth oauth_nonce="abc", oauth_timestamp="123", oauth_version="1.0", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="foo", oauth_signature="W0haoue5IZAZoaJiYCtfqwMf8x8%3D"' auth = OAuth1Session('foo') auth.send = self.verify_signature(signature) auth.post('https://i.b?cjk=%E5%95%A6%E5%95%A6') def test_authorization_url(self): auth = OAuth1Session('foo') url = 'https://example.comm/authorize' token = 'asluif023sf' auth_url = auth.authorization_url(url, request_token=token) self.assertEqual(auth_url, url + '?oauth_token=' + token) def test_parse_response_url(self): url = 'https://i.b/callback?oauth_token=foo&oauth_verifier=bar' auth = OAuth1Session('foo') resp = auth.parse_authorization_response(url) self.assertEqual(resp['oauth_token'], 'foo') self.assertEqual(resp['oauth_verifier'], 'bar') for k, v in resp.items(): self.assertTrue(isinstance(k, unicode_type)) self.assertTrue(isinstance(v, unicode_type)) def test_fetch_request_token(self): auth = OAuth1Session('foo') auth.send = self.fake_body('oauth_token=foo') resp = auth.fetch_request_token('https://example.com/token') self.assertEqual(resp['oauth_token'], 'foo') for k, v in resp.items(): self.assertTrue(isinstance(k, unicode_type)) self.assertTrue(isinstance(v, unicode_type)) def test_fetch_request_token_with_optional_arguments(self): auth = OAuth1Session('foo') auth.send = self.fake_body('oauth_token=foo') resp = auth.fetch_request_token('https://example.com/token', verify=False, stream=True) self.assertEqual(resp['oauth_token'], 'foo') for k, v in resp.items(): self.assertTrue(isinstance(k, unicode_type)) self.assertTrue(isinstance(v, unicode_type)) def test_fetch_access_token(self): auth = OAuth1Session('foo', verifier='bar') auth.send = self.fake_body('oauth_token=foo') resp = auth.fetch_access_token('https://example.com/token') self.assertEqual(resp['oauth_token'], 'foo') for k, v in resp.items(): self.assertTrue(isinstance(k, unicode_type)) self.assertTrue(isinstance(v, unicode_type)) def test_fetch_access_token_with_optional_arguments(self): auth = OAuth1Session('foo', verifier='bar') auth.send = self.fake_body('oauth_token=foo') resp = auth.fetch_access_token('https://example.com/token', verify=False, stream=True) self.assertEqual(resp['oauth_token'], 'foo') for k, v in resp.items(): self.assertTrue(isinstance(k, unicode_type)) self.assertTrue(isinstance(v, unicode_type)) def _test_fetch_access_token_raises_error(self, auth): """Assert that an error is being raised whenever there's no verifier passed in to the client. """ auth.send = self.fake_body('oauth_token=foo') # Use a try-except block so that we can assert on the exception message # being raised and also keep the Python2.6 compatibility where # assertRaises is not a context manager. try: auth.fetch_access_token('https://example.com/token') except ValueError as exc: self.assertEqual('No client verifier has been set.', str(exc)) def test_fetch_token_invalid_response(self): auth = OAuth1Session('foo') auth.send = self.fake_body('not valid urlencoded response!') self.assertRaises(ValueError, auth.fetch_request_token, 'https://example.com/token') for code in (400, 401, 403): auth.send = self.fake_body('valid=response', code) # use try/catch rather than self.assertRaises, so we can # assert on the properties of the exception try: auth.fetch_request_token('https://example.com/token') except ValueError as err: self.assertEqual(err.status_code, code) self.assertTrue(isinstance(err.response, requests.Response)) else: # no exception raised self.fail("ValueError not raised") def test_fetch_access_token_missing_verifier(self): self._test_fetch_access_token_raises_error(OAuth1Session('foo')) def test_fetch_access_token_has_verifier_is_none(self): auth = OAuth1Session('foo') del auth._client.client.verifier self._test_fetch_access_token_raises_error(auth) def test_token_proxy_set(self): token = { 'oauth_token': 'fake-key', 'oauth_token_secret': 'fake-secret', 'oauth_verifier': 'fake-verifier', } sess = OAuth1Session('foo') self.assertIsNone(sess._client.client.resource_owner_key) self.assertIsNone(sess._client.client.resource_owner_secret) self.assertIsNone(sess._client.client.verifier) self.assertEqual(sess.token, {}) sess.token = token self.assertEqual(sess._client.client.resource_owner_key, 'fake-key') self.assertEqual(sess._client.client.resource_owner_secret, 'fake-secret') self.assertEqual(sess._client.client.verifier, 'fake-verifier') def test_token_proxy_get(self): token = { 'oauth_token': 'fake-key', 'oauth_token_secret': 'fake-secret', 'oauth_verifier': 'fake-verifier', } sess = OAuth1Session( 'foo', resource_owner_key=token['oauth_token'], resource_owner_secret=token['oauth_token_secret'], verifier=token['oauth_verifier'], ) self.assertEqual(sess.token, token) sess._client.client.resource_owner_key = "different-key" token['oauth_token'] = "different-key" self.assertEqual(sess.token, token) def test_authorized_false(self): sess = OAuth1Session('foo') self.assertFalse(sess.authorized) def test_authorized_false_rsa(self): signature = ('OAuth ' 'oauth_nonce="abc", oauth_timestamp="123", oauth_version="1.0", ' 'oauth_signature_method="RSA-SHA1", oauth_consumer_key="foo", ' 'oauth_signature="{sig}"' ).format(sig=TEST_RSA_OAUTH_SIGNATURE) sess = OAuth1Session('foo', signature_method=SIGNATURE_RSA, rsa_key=TEST_RSA_KEY) sess.send = self.verify_signature(signature) self.assertFalse(sess.authorized) def test_authorized_true(self): sess = OAuth1Session('key', 'secret', verifier='bar') sess.send = self.fake_body('oauth_token=foo&oauth_token_secret=bar') sess.fetch_access_token('https://example.com/token') self.assertTrue(sess.authorized) @mock.patch('oauthlib.oauth1.rfc5849.generate_timestamp') @mock.patch('oauthlib.oauth1.rfc5849.generate_nonce') def test_authorized_true_rsa(self, generate_nonce, generate_timestamp): if not cryptography: raise unittest.SkipTest('cryptography module is required') generate_nonce.return_value = 'abc' generate_timestamp.return_value = '123' signature = ('OAuth ' 'oauth_nonce="abc", oauth_timestamp="123", oauth_version="1.0", ' 'oauth_signature_method="RSA-SHA1", oauth_consumer_key="foo", ' 'oauth_verifier="bar", oauth_signature="{sig}"' ).format(sig=TEST_RSA_OAUTH_SIGNATURE) sess = OAuth1Session('key', 'secret', signature_method=SIGNATURE_RSA, rsa_key=TEST_RSA_KEY, verifier='bar') sess.send = self.fake_body('oauth_token=foo&oauth_token_secret=bar') sess.fetch_access_token('https://example.com/token') self.assertTrue(sess.authorized) def verify_signature(self, signature): def fake_send(r, **kwargs): auth_header = r.headers['Authorization'] if isinstance(auth_header, bytes_type): auth_header = auth_header.decode('utf-8') self.assertEqual(auth_header, signature) resp = mock.MagicMock(spec=requests.Response) resp.cookies = [] return resp return fake_send def fake_body(self, body, status_code=200): def fake_send(r, **kwargs): resp = mock.MagicMock(spec=requests.Response) resp.cookies = [] resp.text = body resp.status_code = status_code return resp return fake_send requests-oauthlib-1.0.0/tests/test_oauth2_session.py0000644000076500000240000002221013263226123025070 0ustar singingwolfboystaff00000000000000from __future__ import unicode_literals import json import mock import time from base64 import b64encode from copy import deepcopy from unittest import TestCase from oauthlib.common import urlencode from oauthlib.oauth2 import TokenExpiredError, OAuth2Error from oauthlib.oauth2 import MismatchingStateError from oauthlib.oauth2 import WebApplicationClient, MobileApplicationClient from oauthlib.oauth2 import LegacyApplicationClient, BackendApplicationClient from requests_oauthlib import OAuth2Session, TokenUpdated fake_time = time.time() def fake_token(token): def fake_send(r, **kwargs): resp = mock.MagicMock() resp.text = json.dumps(token) return resp return fake_send class OAuth2SessionTest(TestCase): def setUp(self): # For python 2.6 if not hasattr(self, 'assertIn'): self.assertIn = lambda a, b: self.assertTrue(a in b) self.token = { 'token_type': 'Bearer', 'access_token': 'asdfoiw37850234lkjsdfsdf', 'refresh_token': 'sldvafkjw34509s8dfsdf', 'expires_in': '3600', 'expires_at': fake_time + 3600, } self.client_id = 'foo' self.clients = [ WebApplicationClient(self.client_id, code='asdf345xdf'), LegacyApplicationClient(self.client_id), BackendApplicationClient(self.client_id), ] self.all_clients = self.clients + [MobileApplicationClient(self.client_id)] def test_add_token(self): token = 'Bearer ' + self.token['access_token'] def verifier(r, **kwargs): auth_header = r.headers.get(str('Authorization'), None) self.assertEqual(auth_header, token) resp = mock.MagicMock() resp.cookes = [] return resp for client in self.all_clients: auth = OAuth2Session(client=client, token=self.token) auth.send = verifier auth.get('https://i.b') def test_authorization_url(self): url = 'https://example.com/authorize?foo=bar' web = WebApplicationClient(self.client_id) s = OAuth2Session(client=web) auth_url, state = s.authorization_url(url) self.assertIn(state, auth_url) self.assertIn(self.client_id, auth_url) self.assertIn('response_type=code', auth_url) mobile = MobileApplicationClient(self.client_id) s = OAuth2Session(client=mobile) auth_url, state = s.authorization_url(url) self.assertIn(state, auth_url) self.assertIn(self.client_id, auth_url) self.assertIn('response_type=token', auth_url) @mock.patch("time.time", new=lambda: fake_time) def test_refresh_token_request(self): self.expired_token = dict(self.token) self.expired_token['expires_in'] = '-1' del self.expired_token['expires_at'] def fake_refresh(r, **kwargs): if "/refresh" in r.url: self.assertNotIn("Authorization", r.headers) resp = mock.MagicMock() resp.text = json.dumps(self.token) return resp # No auto refresh setup for client in self.clients: auth = OAuth2Session(client=client, token=self.expired_token) self.assertRaises(TokenExpiredError, auth.get, 'https://i.b') # Auto refresh but no auto update for client in self.clients: auth = OAuth2Session(client=client, token=self.expired_token, auto_refresh_url='https://i.b/refresh') auth.send = fake_refresh self.assertRaises(TokenUpdated, auth.get, 'https://i.b') # Auto refresh and auto update def token_updater(token): self.assertEqual(token, self.token) 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 auth.get('https://i.b') def fake_refresh_with_auth(r, **kwargs): if "/refresh" in r.url: self.assertIn("Authorization", r.headers) encoded = b64encode(b"foo:bar") content = (b"Basic " + encoded).decode('latin1') self.assertEqual(r.headers["Authorization"], content) 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', token_updater=token_updater) auth.send = fake_refresh_with_auth auth.get('https://i.b', client_id='foo', client_secret='bar') @mock.patch("time.time", new=lambda: fake_time) def test_token_from_fragment(self): mobile = MobileApplicationClient(self.client_id) response_url = 'https://i.b/callback#' + urlencode(self.token.items()) auth = OAuth2Session(client=mobile) self.assertEqual(auth.token_from_fragment(response_url), self.token) @mock.patch("time.time", new=lambda: fake_time) def test_fetch_token(self): url = 'https://example.com/token' for client in self.clients: auth = OAuth2Session(client=client, token=self.token) auth.send = fake_token(self.token) self.assertEqual(auth.fetch_token(url), self.token) error = {'error': 'invalid_request'} for client in self.clients: auth = OAuth2Session(client=client, token=self.token) auth.send = fake_token(error) self.assertRaises(OAuth2Error, auth.fetch_token, url) def test_cleans_previous_token_before_fetching_new_one(self): """Makes sure the previous token is cleaned before fetching a new one. The reason behind it is that, if the previous token is expired, this method shouldn't fail with a TokenExpiredError, since it's attempting to get a new one (which shouldn't be expired). """ new_token = deepcopy(self.token) past = time.time() - 7200 now = time.time() self.token['expires_at'] = past new_token['expires_at'] = now + 3600 url = 'https://example.com/token' with mock.patch('time.time', lambda: now): for client in self.clients: auth = OAuth2Session(client=client, token=self.token) auth.send = fake_token(new_token) self.assertEqual(auth.fetch_token(url), new_token) def test_web_app_fetch_token(self): # Ensure the state parameter is used, see issue #105. client = OAuth2Session('foo', state='somestate') self.assertRaises(MismatchingStateError, client.fetch_token, 'https://i.b/token', authorization_response='https://i.b/no-state?code=abc') def test_client_id_proxy(self): sess = OAuth2Session('test-id') self.assertEqual(sess.client_id, 'test-id') sess.client_id = 'different-id' self.assertEqual(sess.client_id, 'different-id') sess._client.client_id = 'something-else' self.assertEqual(sess.client_id, 'something-else') del sess.client_id self.assertIsNone(sess.client_id) def test_access_token_proxy(self): sess = OAuth2Session('test-id') self.assertIsNone(sess.access_token) sess.access_token = 'test-token' self.assertEqual(sess.access_token, 'test-token') sess._client.access_token = 'different-token' self.assertEqual(sess.access_token, 'different-token') del sess.access_token self.assertIsNone(sess.access_token) def test_token_proxy(self): token = { 'access_token': 'test-access', } sess = OAuth2Session('test-id', token=token) self.assertEqual(sess.access_token, 'test-access') self.assertEqual(sess.token, token) token['access_token'] = 'something-else' sess.token = token self.assertEqual(sess.access_token, 'something-else') self.assertEqual(sess.token, token) sess._client.access_token = 'different-token' token['access_token'] = 'different-token' self.assertEqual(sess.access_token, 'different-token') self.assertEqual(sess.token, token) # can't delete token attribute with self.assertRaises(AttributeError): del sess.token def test_authorized_false(self): sess = OAuth2Session('foo') self.assertFalse(sess.authorized) @mock.patch("time.time", new=lambda: fake_time) def test_authorized_true(self): def fake_token(token): def fake_send(r, **kwargs): resp = mock.MagicMock() resp.text = json.dumps(token) return resp return fake_send url = 'https://example.com/token' for client in self.clients: sess = OAuth2Session(client=client) sess.send = fake_token(self.token) self.assertFalse(sess.authorized) sess.fetch_token(url) self.assertTrue(sess.authorized) requests-oauthlib-1.0.0/tests/test_compliance_fixes.py0000644000076500000240000002533313263226123025444 0ustar singingwolfboystaff00000000000000from __future__ import unicode_literals from unittest import TestCase import requests import requests_mock import time try: from urlparse import urlparse, parse_qs except ImportError: 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 linkedin_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 plentymarkets_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('foo', 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='bar', 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('foo', 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='bar', 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('foo', 'bar') ) 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('foo', 'bar') ) self.assertEqual(token['access_token'], 'access') self.assertEqual(token['refresh_token'], 'refresh') class LinkedInComplianceFixTest(TestCase): def setUp(self): mocker = requests_mock.Mocker() mocker.post( "https://www.linkedin.com/uas/oauth2/accessToken", json={"access_token": "linkedin"}, ) mocker.post( "https://api.linkedin.com/v1/people/~/shares", status_code=201, json={ "updateKey": "UPDATE-3346389-595113200", "updateUrl": "https://www.linkedin.com/updates?discuss=abc&scope=xyz" } ) mocker.start() self.addCleanup(mocker.stop) linkedin = OAuth2Session('foo', redirect_uri='https://i.b') self.session = linkedin_compliance_fix(linkedin) def test_fetch_access_token(self): token = self.session.fetch_token( 'https://www.linkedin.com/uas/oauth2/accessToken', client_secret='bar', authorization_response='https://i.b/?code=hello', ) self.assertEqual(token, {'access_token': 'linkedin', 'token_type': 'Bearer'}) def test_protected_request(self): self.session.token = {"access_token": 'dummy-access-token'} response = self.session.post( "https://api.linkedin.com/v1/people/~/shares" ) url = response.request.url query = parse_qs(urlparse(url).query) self.assertEqual(query["oauth2_access_token"], ["dummy-access-token"]) 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('foo', 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='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.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('foo', 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='bar', 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('foo', 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 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('foo', 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, {u'access_token': u'ecUN1r8KhJewMCdLAmpHOdZ4O0ofXKB9zf6CXK61', u'expires_in': 86400, u'token_type': u'Bearer', u'refresh_token': u'iG2kBGIjcXaRE4xmTVUnv7xwxX7XMcWCHqJmFaSX'}) requests-oauthlib-1.0.0/tests/__init__.pyc0000644000076500000240000000022712760374422023001 0ustar singingwolfboystaff00000000000000ó ŽpYWc@sdS(N((((s@/Users/singingwolfboy/clones/requests-oauthlib/tests/__init__.pytsrequests-oauthlib-1.0.0/tests/test.bin0000644000076500000240000000000212726270216022163 0ustar singingwolfboystaff00000000000000¥Ærequests-oauthlib-1.0.0/tests/test_oauth2_auth.py0000644000076500000240000000414212726270216024357 0ustar singingwolfboystaff00000000000000from __future__ import unicode_literals import unittest from oauthlib.oauth2 import WebApplicationClient, MobileApplicationClient from oauthlib.oauth2 import LegacyApplicationClient, BackendApplicationClient from requests import Request from requests_oauthlib import OAuth2 class OAuth2AuthTest(unittest.TestCase): def setUp(self): self.token = { 'token_type': 'Bearer', 'access_token': 'asdfoiw37850234lkjsdfsdf', 'expires_in': '3600' } self.client_id = 'foo' self.clients = [ WebApplicationClient(self.client_id), MobileApplicationClient(self.client_id), LegacyApplicationClient(self.client_id), BackendApplicationClient(self.client_id), ] def test_add_token_to_url(self): url = 'https://example.com/resource?foo=bar' new_url = url + '&access_token=' + self.token['access_token'] for client in self.clients: client.default_token_placement = 'query' auth = OAuth2(client=client, token=self.token) r = Request('GET', url, auth=auth).prepare() self.assertEqual(r.url, new_url) def test_add_token_to_headers(self): token = 'Bearer ' + self.token['access_token'] for client in self.clients: auth = OAuth2(client=client, token=self.token) r = Request('GET', 'https://i.b', auth=auth).prepare() self.assertEqual(r.headers['Authorization'], token) def test_add_token_to_body(self): body = 'foo=bar' new_body = body + '&access_token=' + self.token['access_token'] for client in self.clients: client.default_token_placement = 'body' auth = OAuth2(client=client, token=self.token) r = Request('GET', 'https://i.b', data=body, auth=auth).prepare() self.assertEqual(r.body, new_body) def test_add_nonexisting_token(self): for client in self.clients: auth = OAuth2(client=client) r = Request('GET', 'https://i.b', auth=auth) self.assertRaises(ValueError, r.prepare) requests-oauthlib-1.0.0/tests/test_oauth2_auth.pyc0000644000076500000240000000614012760374422024524 0ustar singingwolfboystaff00000000000000ó ŽpYWc@s…ddlmZddlZddlmZmZddlmZmZddlm Z ddl m Z dej fd„ƒYZ dS( iÿÿÿÿ(tunicode_literalsN(tWebApplicationClienttMobileApplicationClient(tLegacyApplicationClienttBackendApplicationClient(tRequest(tOAuth2tOAuth2AuthTestcBs5eZd„Zd„Zd„Zd„Zd„ZRS(cCsdidd6dd6dd6|_d|_t|jƒt|jƒt|jƒt|jƒg|_dS(NuBeareru token_typeuasdfoiw37850234lkjsdfsdfu access_tokenu3600u expires_inufoo(ttokent client_idRRRRtclients(tself((sH/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth2_auth.pytsetUp s     cCs‚d}|d|jd}x`|jD]U}d|_td|d|jƒ}td|d|ƒjƒ}|j|j|ƒq%WdS( Nu$https://example.com/resource?foo=baru&access_token=u access_tokenuquerytclientRuGETtauth(RR tdefault_token_placementRRtpreparet assertEqualturl(R Rtnew_urlR Rtr((sH/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth2_auth.pyttest_add_token_to_urls cCssd|jd}x[|jD]P}td|d|jƒ}tddd|ƒjƒ}|j|jd|ƒqWdS( NuBearer u access_tokenR RuGETu https://i.bRu Authorization(RR RRRRtheaders(R RR RR((sH/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth2_auth.pyttest_add_token_to_headers#s cCsˆd}|d|jd}xf|jD][}d|_td|d|jƒ}tddd |d |ƒjƒ}|j|j|ƒq%WdS( Nufoo=baru&access_token=u access_tokenubodyR RuGETu https://i.btdataR(RR RRRRRtbody(R Rtnew_bodyR RR((sH/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth2_auth.pyttest_add_token_to_body*s !cCsOxH|jD]=}td|ƒ}tddd|ƒ}|jt|jƒq WdS(NR uGETu https://i.bR(R RRt assertRaisest ValueErrorR(R R RR((sH/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth2_auth.pyttest_add_nonexisting_token3s(t__name__t __module__R RRRR(((sH/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth2_auth.pyR s    (t __future__Rtunittesttoauthlib.oauth2RRRRtrequestsRtrequests_oauthlibRtTestCaseR(((sH/Users/singingwolfboy/clones/requests-oauthlib/tests/test_oauth2_auth.pyts  requests-oauthlib-1.0.0/tests/test_compliance_fixes.pyc0000644000076500000240000002302612760374422025613 0ustar singingwolfboystaff00000000000000ó ŽpYWc@s‚ddlmZyddlmZWn!ek rGddlmZnXddlZddlZddlZyddl m Z m Z Wn'ek r¯ddl m Z m Z nXddl m Z ddlmZddlmZddlmZdd lmZdd lmZd efd „ƒYZd efd„ƒYZdefd„ƒYZdefd„ƒYZdefd„ƒYZdS(iÿÿÿÿ(tunicode_literals(tTestCaseN(turlparsetparse_qs(t OAuth2Session(tfacebook_compliance_fix(tlinkedin_compliance_fix(tmailchimp_compliance_fix(tweibo_compliance_fix(tslack_compliance_fixtFacebookComplianceFixTestcBseZd„Zd„ZRS(cCsktjƒ}|jddddidd6ƒ|jƒ|j|jƒtddd ƒ}t|ƒ|_dS( Nu-https://graph.facebook.com/oauth/access_tokenttextuaccess_token=urlencodedtheadersu text/plainu Content-Typeufoot redirect_uriu https://i.b( t requests_mocktMockertposttstartt addCleanuptstopRRtsession(tselftmockertfacebook((sM/Users/singingwolfboy/clones/requests-oauthlib/tests/test_compliance_fixes.pytsetUps  cCs@|jjdddddƒ}|j|idd6dd 6ƒdS( Nu-https://graph.facebook.com/oauth/access_tokent client_secretubartauthorization_responseuhttps://i.b/?code=hellou urlencodedu access_tokenuBeareru token_type(Rt fetch_tokent assertEqual(Rttoken((sM/Users/singingwolfboy/clones/requests-oauthlib/tests/test_compliance_fixes.pyttest_fetch_access_token&s   (t__name__t __module__RR(((sM/Users/singingwolfboy/clones/requests-oauthlib/tests/test_compliance_fixes.pyR s tLinkedInComplianceFixTestcBs#eZd„Zd„Zd„ZRS(cCsŒtjƒ}|jddidd6ƒ|jddddidd 6d d 6ƒ|jƒ|j|jƒtd d dƒ}t|ƒ|_dS(Nu/https://www.linkedin.com/uas/oauth2/accessTokentjsonulinkedinu access_tokenu+https://api.linkedin.com/v1/people/~/sharest status_codeiÉuUPDATE-3346389-595113200u updateKeyu6https://www.linkedin.com/updates?discuss=abc&scope=xyzu updateUrlufooR u https://i.b( RRRRRRRRR(RRtlinkedin((sM/Users/singingwolfboy/clones/requests-oauthlib/tests/test_compliance_fixes.pyR1s   cCs@|jjdddddƒ}|j|idd6dd 6ƒdS( Nu/https://www.linkedin.com/uas/oauth2/accessTokenRubarRuhttps://i.b/?code=helloulinkedinu access_tokenuBeareru token_type(RRR(RR((sM/Users/singingwolfboy/clones/requests-oauthlib/tests/test_compliance_fixes.pyREs   cCsaidd6|j_|jjdƒ}|jj}tt|ƒjƒ}|j|ddgƒdS(Nudummy-access-tokenu access_tokenu+https://api.linkedin.com/v1/people/~/sharesuoauth2_access_token( RRRtrequestturlRRtqueryR(RtresponseR&R'((sM/Users/singingwolfboy/clones/requests-oauthlib/tests/test_compliance_fixes.pyttest_protected_requestMs    (RR RRR)(((sM/Users/singingwolfboy/clones/requests-oauthlib/tests/test_compliance_fixes.pyR!/s  tMailChimpComplianceFixTestcBseZd„Zd„ZRS(cCsstjƒ}|jddidd6dd6dd6ƒ|jƒ|j|jƒtdd d ƒ}t|ƒ|_ dS( Nu(https://login.mailchimp.com/oauth2/tokenR"u mailchimpu access_tokeniu expires_inuscopeufooR u https://i.b( RRRtNoneRRRRRR(RRt mailchimp((sM/Users/singingwolfboy/clones/requests-oauthlib/tests/test_compliance_fixes.pyRYs  cCs…|jjdddddƒ}tjƒd}|jdƒ}|j||dd ƒ|j|id d 6dd 6ƒ|jd |ƒdS(Nu(https://login.mailchimp.com/oauth2/tokenRubarRuhttps://i.b/?code=helloiu expires_attplacesiu mailchimpu access_tokenu expires_inuscope(RRttimetpoptassertAlmostEqualRt assertNotIn(RRtapprox_expires_attactual_expires_at((sM/Users/singingwolfboy/clones/requests-oauthlib/tests/test_compliance_fixes.pyRes  (RR RR(((sM/Users/singingwolfboy/clones/requests-oauthlib/tests/test_compliance_fixes.pyR*Ws tWeiboComplianceFixTestcBseZd„Zd„ZRS(cCsetjƒ}|jddidd6ƒ|jƒ|j|jƒtdddƒ}t|ƒ|_dS(Nu)https://api.weibo.com/oauth2/access_tokenR"uweibou access_tokenufooR u https://i.b( RRRRRRRRR(RRtweibo((sM/Users/singingwolfboy/clones/requests-oauthlib/tests/test_compliance_fixes.pyRys  cCs@|jjdddddƒ}|j|idd6dd 6ƒdS( Nu)https://api.weibo.com/oauth2/access_tokenRubarRuhttps://i.b/?code=hellouweibou access_tokenuBeareru token_type(RRR(RR((sM/Users/singingwolfboy/clones/requests-oauthlib/tests/test_compliance_fixes.pyR…s   (RR RR(((sM/Users/singingwolfboy/clones/requests-oauthlib/tests/test_compliance_fixes.pyR4ws tSlackComplianceFixTestcBs5eZd„Zd„Zd„Zd„Zd„ZRS(c CsÃtjƒ}|jddidd6dd6ƒxTdD]L}|jd |d d ditd 6d d6dd6dd6dd6dd6ƒq4W|jƒ|j|jƒtdddƒ}t |ƒ|_ dS(Nu"https://slack.com/api/oauth.accessR"uxoxt-23984754863-2348975623103u access_tokenureaduscopeuGETuPOSTtmethodR&uhttps://slack.com/api/auth.testuokuhttps://myteam.slack.com/uurluMy TeamuteamucaluuseruT12345uteam_iduU12345uuser_idufooR u https://i.b(uGETuPOST( RRRR%tTrueRRRRR R(RRR7tslack((sM/Users/singingwolfboy/clones/requests-oauthlib/tests/test_compliance_fixes.pyRs*     cCs‰idd6|j_|jjdƒ}|jj}tt|ƒjƒ}|jd|ƒ|jj }t|ƒ}|j |ddgƒdS(Nudummy-access-tokenu access_tokenuhttps://slack.com/api/auth.testutoken( RRtgetR%R&RRR'R1tbodyR(RR(R&R'R;tdata((sM/Users/singingwolfboy/clones/requests-oauthlib/tests/test_compliance_fixes.pyR)¬s     cCs–idd6|j_|jjddidd6ƒ}|jj}tt|ƒjƒ}|jd|ƒ|jj }t|ƒ}|j |ddgƒdS(Nudummy-access-tokenu access_tokenuhttps://slack.com/api/auth.testR<udifferent-tokenutoken( RRR:R%R&RRR'R1R;R(RR(R&R'R;R<((sM/Users/singingwolfboy/clones/requests-oauthlib/tests/test_compliance_fixes.pyt)test_protected_request_override_token_get¸s    cCs–idd6|j_|jjddidd6ƒ}|jj}tt|ƒjƒ}|jd|ƒ|jj }t|ƒ}|j |ddgƒdS(Nudummy-access-tokenu access_tokenuhttps://slack.com/api/auth.testR<udifferent-tokenutoken( RRRR%R&RRR'R1R;R(RR(R&R'R;R<((sM/Users/singingwolfboy/clones/requests-oauthlib/tests/test_compliance_fixes.pyt*test_protected_request_override_token_postÅs    cCstidd6|j_|jjdƒ}|jj}tt|ƒjƒ}|j|ddgƒ|j |jj ƒdS(Nudummy-access-tokenu access_tokenu5https://slack.com/api/auth.test?token=different-tokenutokenudifferent-token( RRR:R%R&RRR'Rt assertIsNoneR;(RR(R&R'((sM/Users/singingwolfboy/clones/requests-oauthlib/tests/test_compliance_fixes.pyt)test_protected_request_override_token_urlÒs   (RR RR)R=R>R@(((sM/Users/singingwolfboy/clones/requests-oauthlib/tests/test_compliance_fixes.pyR6Žs   (t __future__Rt unittest2Rt ImportErrortunittesttrequestsRR.RRt urllib.parsetrequests_oauthlibRt"requests_oauthlib.compliance_fixesRRRRR R R!R*R4R6(((sM/Users/singingwolfboy/clones/requests-oauthlib/tests/test_compliance_fixes.pyts,     ( requests-oauthlib-1.0.0/MANIFEST.in0000644000076500000240000000014712726270216021120 0ustar singingwolfboystaff00000000000000include README.rst LICENSE HISTORY.rst requirements.txt AUTHORS.rst graft tests graft docs prune *.pyc requests-oauthlib-1.0.0/docs/0000755000076500000240000000000013305201162020274 5ustar singingwolfboystaff00000000000000requests-oauthlib-1.0.0/docs/index.rst0000644000076500000240000000427312726270216022157 0ustar singingwolfboystaff00000000000000.. Requests-OAuthlib documentation master file, created by sphinx-quickstart on Fri May 10 11:49:01 2013. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Requests-OAuthlib: OAuth for Humans =================================== Requests-OAuthlib uses the Python `Requests `_ and `OAuthlib `_ libraries to provide an easy-to-use Python interface for building OAuth1 and OAuth2 clients. Overview -------- A simple Flask application which connects to the Github OAuth2 API looks approximately like this: .. code-block:: python from requests_oauthlib import OAuth2Session from flask import Flask, request, redirect, session, url_for from flask.json import jsonify # This information is obtained upon registration of a new GitHub client_id = "" client_secret = "" authorization_base_url = 'https://github.com/login/oauth/authorize' token_url = 'https://github.com/login/oauth/access_token' @app.route("/login") def login(): github = OAuth2Session(client_id) authorization_url, state = github.authorization_url(authorization_base_url) # State is used to prevent CSRF, keep this for later. session['oauth_state'] = state return redirect(authorization_url) @app.route("/callback") def callback(): github = OAuth2Session(client_id, state=session['oauth_state']) token = github.fetch_token(token_url, client_secret=client_secret, authorization_response=request.url) return jsonify(github.get('https://api.github.com/user').json()) The above is a truncated example. A full working example is available here: :ref:`real_example` Installation ============ Requests-OAuthlib can be installed with `pip `_: :: $ pip install requests_oauthlib Getting Started: ================ .. toctree:: :maxdepth: 2 oauth1_workflow oauth2_workflow examples/examples api Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` requests-oauthlib-1.0.0/docs/oauth1_workflow.rst0000644000076500000240000002115112726270216024175 0ustar singingwolfboystaff00000000000000OAuth 1 Workflow ================ You will be forced to go through a few steps when you are using OAuth. Below is an example of the most common OAuth workflow using HMAC-SHA1 signed requests where the signature is supplied in the Authorization header. The example assumes an interactive prompt which is good for demonstration but in practice you will likely be using a web application (which makes authorizing much less awkward since you can simply redirect). The guide will show two ways of carrying out the OAuth1 workflow. One using the authentication helper OAuth1 and the alternative using OAuth1Session. The latter is usually more convenient and requires less code. Workflow example showing use of both OAuth1 and OAuth1Session ------------------------------------------------------------- 0. Manual client signup with the OAuth provider (i.e. Google, Twitter) to get a set of client credentials. Usually a client key and secret. Client might sometimes be referred to as consumer. For example: .. code-block:: pycon >>> # Using OAuth1Session >>> from requests_oauthlib import OAuth1Session >>> # Using OAuth1 auth helper >>> import requests >>> from requests_oauthlib import OAuth1 >>> client_key = '...' >>> client_secret = '...' 1. Obtain a request token which will identify you (the client) in the next step. At this stage you will only need your client key and secret. .. code-block:: pycon >>> request_token_url = 'https://api.twitter.com/oauth/request_token' >>> # Using OAuth1Session >>> oauth = OAuth1Session(client_key, client_secret=client_secret) >>> fetch_response = oauth.fetch_request_token(request_token_url) { "oauth_token": "Z6eEdO8MOmk394WozF5oKyuAv855l4Mlqo7hhlSLik", "oauth_token_secret": "Kd75W4OQfb2oJTV0vzGzeXftVAwgMnEK9MumzYcM" } >>> resource_owner_key = fetch_response.get('oauth_token') >>> resource_owner_secret = fetch_response.get('oauth_token_secret') >>> # Using OAuth1 auth helper >>> oauth = OAuth1(client_key, client_secret=client_secret) >>> r = requests.post(url=request_token_url, auth=oauth) >>> r.content "oauth_token=Z6eEdO8MOmk394WozF5oKyuAv855l4Mlqo7hhlSLik&oauth_token_secret=Kd75W4OQfb2oJTV0vzGzeXftVAwgMnEK9MumzYcM" >>> from urlparse import parse_qs >>> credentials = parse_qs(r.content) >>> resource_owner_key = credentials.get('oauth_token')[0] >>> resource_owner_secret = credentials.get('oauth_token_secret')[0] 2. Obtain authorization from the user (resource owner) to access their protected resources (images, tweets, etc.). This is commonly done by redirecting the user to a specific url to which you add the request token as a query parameter. Note that not all services will give you a verifier even if they should. Also the oauth_token given here will be the same as the one in the previous step. .. code-block:: pycon >>> base_authorization_url = 'https://api.twitter.com/oauth/authorize' >>> # Using OAuth1Session >>> authorization_url = oauth.authorization_url(base_authorization_url) >>> print 'Please go here and authorize,', authorization_url >>> redirect_response = raw_input('Paste the full redirect URL here: ') >>> oauth_response = oauth.parse_authorization_response(redirect_response) { "oauth_token": "Z6eEdO8MOmk394WozF5oKyuAv855l4Mlqo7hhlSLik", "oauth_verifier": "sdflk3450FASDLJasd2349dfs" } >>> verifier = oauth_response.get('oauth_verifier') >>> # Using OAuth1 auth helper >>> authorize_url = base_authorization_url + '?oauth_token=' >>> authorize_url = authorize_url + resource_owner_key >>> print 'Please go here and authorize,', authorize_url >>> verifier = raw_input('Please input the verifier') 3. Obtain an access token from the OAuth provider. Save this token as it can be re-used later. In this step we will re-use most of the credentials obtained uptil this point. .. code-block:: pycon >>> access_token_url = 'https://api.twitter.com/oauth/access_token' >>> # Using OAuth1Session >>> oauth = OAuth1Session(client_key, client_secret=client_secret, resource_owner_key=resource_owner_key, resource_owner_secret=resource_owner_secret, verifier=verifier) >>> oauth_tokens = oauth.fetch_access_token(access_token_url) { "oauth_token": "6253282-eWudHldSbIaelX7swmsiHImEL4KinwaGloHANdrY", "oauth_token_secret": "2EEfA6BG3ly3sR3RjE0IBSnlQu4ZrUzPiYKmrkVU" } >>> resource_owner_key = oauth_tokens.get('oauth_token') >>> resource_owner_secret = oauth_tokens.get('oauth_token_secret') >>> # Using OAuth1 auth helper >>> oauth = OAuth1(client_key, client_secret=client_secret, resource_owner_key=resource_owner_key, resource_owner_secret=resource_owner_secret, verifier=verifier) >>> r = requests.post(url=access_token_url, auth=oauth) >>> r.content "oauth_token=6253282-eWudHldSbIaelX7swmsiHImEL4KinwaGloHANdrY&oauth_token_secret=2EEfA6BG3ly3sR3RjE0IBSnlQu4ZrUzPiYKmrkVU" >>> credentials = parse_qs(r.content) >>> resource_owner_key = credentials.get('oauth_token')[0] >>> resource_owner_secret = credentials.get('oauth_token_secret')[0] 4. Access protected resources. OAuth1 access tokens typically do not expire and may be re-used until revoked by the user or yourself. .. code-block:: pycon >>> protected_url = 'https://api.twitter.com/1/account/settings.json' >>> # Using OAuth1Session >>> oauth = OAuth1Session(client_key, client_secret=client_secret, resource_owner_key=resource_owner_key, resource_owner_secret=resource_owner_secret) >>> r = oauth.get(protected_url) >>> # Using OAuth1 auth helper >>> oauth = OAuth1(client_key, client_secret=client_secret, resource_owner_key=resource_owner_key, resource_owner_secret=resource_owner_secret) >>> r = requests.get(url=protected_url, auth=oauth) Signature placement - header, query or body? -------------------------------------------- OAuth takes many forms, so let's take a look at a few different forms: .. code-block:: python import requests from requests_oauthlib import OAuth1 url = u'https://api.twitter.com/1/account/settings.json' client_key = u'...' client_secret = u'...' resource_owner_key = u'...' resource_owner_secret = u'...' Header signing (recommended): .. code-block:: python headeroauth = OAuth1(client_key, client_secret, resource_owner_key, resource_owner_secret, signature_type='auth_header') r = requests.get(url, auth=headeroauth) Query signing: .. code-block:: python queryoauth = OAuth1(client_key, client_secret, resource_owner_key, resource_owner_secret, signature_type='query') r = requests.get(url, auth=queryoauth) Body signing: .. code-block:: python bodyoauth = OAuth1(client_key, client_secret, resource_owner_key, resource_owner_secret, signature_type='body') r = requests.post(url, auth=bodyoauth) Signature types - HMAC (most common), RSA, Plaintext ---------------------------------------------------- OAuth1 defaults to using HMAC and examples can be found in the previous sections. Plaintext work on the same credentials as HMAC and the only change you will need to make when using it is to add signature_type='PLAINTEXT' to the OAuth1 constructor: .. code-block:: python headeroauth = OAuth1(client_key, client_secret, resource_owner_key, resource_owner_secret, signature_method='PLAINTEXT') RSA is different in that it does not use client_secret nor resource_owner_secret. Instead it uses public and private keys. The public key is provided to the OAuth provider during client registration. The private key is used to sign requests. The previous section can be summarized as: .. code-block:: python key = open("your_rsa_key.pem").read() queryoauth = OAuth1(client_key, signature_method=SIGNATURE_RSA, rsa_key=key, signature_type='query') headeroauth = OAuth1(client_key, signature_method=SIGNATURE_RSA, rsa_key=key, signature_type='auth_header') bodyoauth = OAuth1(client_key, signature_method=SIGNATURE_RSA, rsa_key=key, signature_type='body') requests-oauthlib-1.0.0/docs/Makefile0000644000076500000240000001522612726270216021756 0ustar singingwolfboystaff00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Requests-OAuthlib.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Requests-OAuthlib.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/Requests-OAuthlib" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Requests-OAuthlib" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." requests-oauthlib-1.0.0/docs/conf.py0000644000076500000240000002045113305200330021571 0ustar singingwolfboystaff00000000000000# -*- coding: utf-8 -*- # # Requests-OAuthlib documentation build configuration file, created by # sphinx-quickstart on Fri May 10 11:49:01 2013. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath('..')) from requests_oauthlib import __version__ # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'Requests-OAuthlib' copyright = u'2014, Kenneth Reitz' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = __version__ # The full version, including alpha/beta/rc tags. release = version # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. #keep_warnings = False # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'Requests-OAuthlibdoc' # -- Options for LaTeX output -------------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'Requests-OAuthlib.tex', u'Requests-OAuthlib Documentation', u'Requests-OAuthlib Contributors', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'requests-oauthlib', u'Requests-OAuthlib Documentation', [u'Requests-OAuthlib Contributors'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'Requests-OAuthlib', u'Requests-OAuthlib Documentation', u'Requests-OAuthlib Contributors', 'Requests-OAuthlib', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { 'python': ('https://python.readthedocs.io/en/latest/', None), 'requests': ('https://requests.readthedocs.io/en/latest/', None), 'oauthlib': ('https://oauthlib.readthedocs.io/en/latest/', None), } requests-oauthlib-1.0.0/docs/make.bat0000644000076500000240000001510312726270216021715 0ustar singingwolfboystaff00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. xml to make Docutils-native XML files echo. pseudoxml to make pseudoxml-XML files for display purposes echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) %SPHINXBUILD% 2> nul if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Requests-OAuthlib.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Requests-OAuthlib.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdfja" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf-ja cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) if "%1" == "xml" ( %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml if errorlevel 1 exit /b 1 echo. echo.Build finished. The XML files are in %BUILDDIR%/xml. goto end ) if "%1" == "pseudoxml" ( %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml if errorlevel 1 exit /b 1 echo. echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. goto end ) :end requests-oauthlib-1.0.0/docs/examples/0000755000076500000240000000000013305201162022112 5ustar singingwolfboystaff00000000000000requests-oauthlib-1.0.0/docs/examples/fitbit.rst0000644000076500000240000000357513263226123024146 0ustar singingwolfboystaff00000000000000.. _fitbit: Fitbit OAuth 2 (Mobile Application Flow) Tutorial ================================================= This makes use of the Implicit Grant Flow to obtain an access token for the `Fitbit API`_. Register a new client application there with a callback URL, and have your client ID handy. Based on an `another example`_ of the Mobile Application Flow. .. _`Fitbit API`: https://dev.fitbit.com/ .. _`another example`: https://github.com/requests/requests-oauthlib/issues/104 .. code-block:: pycon >>> import requests >>> from requests_oauthlib import OAuth2Session >>> from oauthlib.oauth2 import MobileApplicationClient # Set up your client ID and scope: the scope must match that which you requested when you set up your application. >>> client_id = "" >>> scope = ["activity", "heartrate", "location", "nutrition", "profile", "settings", "sleep", "social", "weight"] # Initialize client >>> client = MobileApplicationClient(client_id) >>> fitbit = OAuth2Session(client_id, client=client, scope=scope) >>> authorization_url = "https://www.fitbit.com/oauth2/authorize" # Grab the URL for Fitbit's authorization page. >>> auth_url, state = fitbit.authorization_url(authorization_url) >>> print("Visit this page in your browser: {}".format(auth_url)) # After authenticating, Fitbit will redirect you to the URL you specified in your application settings. It contains the access token. >>> callback_url = input("Paste URL you get back here: ") # Now we extract the token from the URL to make use of it. >>> fitbit.token_from_fragment(callback_url) # We can also store the token for use later. >>> token = fitbit['token'] # At this point, assuming nothing blew up, we can make calls to the API as normal, for example: >>> r = fitbit.get('https://api.fitbit.com/1/user/-/sleep/goal.json') requests-oauthlib-1.0.0/docs/examples/real_world_example_with_refresh.rst0000644000076500000240000001463313305200330031265 0ustar singingwolfboystaff00000000000000.. _token_refresh: Refreshing tokens in OAuth 2 ============================ OAuth 2 providers may allow you to refresh access tokens using refresh tokens. Commonly, only clients that authenticate may refresh tokens, e.g. web applications but not javascript clients. The provider will mention whether they allow token refresh in their API documentation and if you see a "refresh_token" in your token response you are good to go. This example shows how a simple web application (using the `Flask web framework `_) can refresh Google OAuth 2 tokens. It should be trivial to transfer to any other web framework and provider. .. code-block:: python from pprint import pformat from time import time from flask import Flask, request, redirect, session, url_for from flask.json import jsonify import requests from requests_oauthlib import OAuth2Session app = Flask(__name__) # This information is obtained upon registration of a new Google OAuth # application at https://code.google.com/apis/console client_id = "" client_secret = "" redirect_uri = 'https://your.registered/callback' # Uncomment for detailed oauthlib logs #import logging #import sys #log = logging.getLogger('oauthlib') #log.addHandler(logging.StreamHandler(sys.stdout)) #log.setLevel(logging.DEBUG) # OAuth endpoints given in the Google API documentation authorization_base_url = "https://accounts.google.com/o/oauth2/auth" token_url = "https://accounts.google.com/o/oauth2/token" refresh_url = token_url # True for Google but not all providers. scope = [ "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile", ] @app.route("/") def demo(): """Step 1: User Authorization. Redirect the user/resource owner to the OAuth provider (i.e. Google) using an URL with a few key OAuth parameters. """ google = OAuth2Session(client_id, scope=scope, redirect_uri=redirect_uri) authorization_url, state = google.authorization_url(authorization_base_url, # offline for refresh token # force to always make user click authorize access_type="offline", prompt="select_account") # State is used to prevent CSRF, keep this for later. session['oauth_state'] = state return redirect(authorization_url) # Step 2: User authorization, this happens on the provider. @app.route("/callback", methods=["GET"]) def callback(): """ Step 3: Retrieving an access token. The user has been redirected back from the provider to your registered callback URL. With this redirection comes an authorization code included in the redirect URL. We will use that to obtain an access token. """ google = OAuth2Session(client_id, redirect_uri=redirect_uri, state=session['oauth_state']) token = google.fetch_token(token_url, client_secret=client_secret, authorization_response=request.url) # We use the session as a simple DB for this example. session['oauth_token'] = token return redirect(url_for('.menu')) @app.route("/menu", methods=["GET"]) def menu(): """""" return """

Congratulations, you have obtained an OAuth 2 token!

What would you like to do next?

        %s
        
""" % pformat(session['oauth_token'], indent=4) @app.route("/profile", methods=["GET"]) def profile(): """Fetching a protected resource using an OAuth 2 token. """ google = OAuth2Session(client_id, token=session['oauth_token']) return jsonify(google.get('https://www.googleapis.com/oauth2/v1/userinfo').json()) @app.route("/automatic_refresh", methods=["GET"]) def automatic_refresh(): """Refreshing an OAuth 2 token using a refresh token. """ token = session['oauth_token'] # We force an expiration by setting expired at in the past. # This will trigger an automatic refresh next time we interact with # Googles API. token['expires_at'] = time() - 10 extra = { 'client_id': client_id, 'client_secret': client_secret, } def token_updater(token): session['oauth_token'] = token google = OAuth2Session(client_id, token=token, auto_refresh_kwargs=extra, auto_refresh_url=refresh_url, token_updater=token_updater) # Trigger the automatic refresh jsonify(google.get('https://www.googleapis.com/oauth2/v1/userinfo').json()) return jsonify(session['oauth_token']) @app.route("/manual_refresh", methods=["GET"]) def manual_refresh(): """Refreshing an OAuth 2 token using a refresh token. """ token = session['oauth_token'] extra = { 'client_id': client_id, 'client_secret': client_secret, } google = OAuth2Session(client_id, token=token) session['oauth_token'] = google.refresh_token(refresh_url, **extra) return jsonify(session['oauth_token']) @app.route("/validate", methods=["GET"]) def validate(): """Validate a token with the OAuth provider Google. """ token = session['oauth_token'] # Defined at https://developers.google.com/accounts/docs/OAuth2LoginV1#validatingtoken validate_url = ('https://www.googleapis.com/oauth2/v1/tokeninfo?' 'access_token=%s' % token['access_token']) # No OAuth2Session is needed, just a plain GET request return jsonify(requests.get(validate_url).json()) if __name__ == "__main__": # This allows us to use a plain HTTP callback import os os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = "1" app.secret_key = os.urandom(24) app.run(debug=True) requests-oauthlib-1.0.0/docs/examples/wso2.rst0000644000076500000240000000210613263226123023544 0ustar singingwolfboystaff00000000000000WSO2 OAuth 2 Tutorial ========================== Setup subscriptions following the instructions on your WSO2 gateway. When you have obtained a ``client_id`` and a ``client_secret`` you can try out the command line interactive example below. .. code-block:: pycon >>> from requests.auth import HTTPBasicAuth >>> from oauthlib.oauth2 import BackendApplicationClient >>> from requests_oauthlib import OAuth2Session >>> #grab client_id and client_secret: >>> client_id = u'' >>> client_secret = u'' >>> token_url = 'https://wso2gateway.myorg.org/token' >>> #generate HTTPBasicAuth Header >>> basic_auth = HTTPBasicAuth(client_id, client_secret) >>> client = BackendApplicationClient(client_id=client_id) >>> #start oauth session >>> oauth = OAuth2Session(client=client) >>> token = oauth.fetch_token(token_url=token_url, auth=basic_auth) >>> r = oauth.get(u'https://wso2gateway.myorg.org/api/v1/api', >>> headers={'Accept':'application/json'}) >>> print(r.json()) requests-oauthlib-1.0.0/docs/examples/mediawiki.rst0000644000076500000240000001435512726270216024633 0ustar singingwolfboystaff00000000000000MediaWiki OAuth 1 Tutorial ========================== Start with setting up a new consumer by following the instructions on `MediaWiki`_. When you have obtained a ``key`` and a ``secret`` you can try out the command line interactive example below. You'll also have to set a callback url while registering. See also this library implementing all the flow below, plus the `/identify` custom call: `mwoauth`_. .. _`MediaWiki`: https://www.mediawiki.org/wiki/Extension:OAuth#Using_OAuth .. _`mwoauth`: https://github.com/halfak/MediaWiki-OAuth Using OAuth1Session ------------------- .. code-block:: python from requests_oauthlib import OAuth1Session # Get the anonymous oauth_token and secret request_token_url = 'https://www.mediawiki.org/w/index.php?title=Special%3aOAuth%2finitiate' # Note the custom callback_uri arg! oauth = OAuth1Session(CLIENT_KEY, client_secret=CLIENT_SECRET, callback_uri='oob') fetch_response = oauth.fetch_request_token(request_token_url) # fetch_response: {u'oauth_token_secret': u'3768a660fcdc5ba958268decc11bf590', u'oauth_token': u'5d684692fe129665c9f967f54bbc525d', u'oauth_callback_confirmed': u'true'} resource_owner_key = fetch_response.get('oauth_token') resource_owner_secret = fetch_response.get('oauth_token_secret') # Redirect the user to /authorize and get the callback base_authorization_url = 'https://www.mediawiki.org/wiki/Special:OAuth/authorize' # Note the extra oauth_consumer_key argument! authorization_url = oauth.authorization_url(base_authorization_url, oauth_consumer_key=CLIENT_KEY) print 'Please go here and authorize,', authorization_url # OUT: Please go here and authorize, https://www.mediawiki.org/wiki/Special:OAuth/authorize?oauth_consumer_key=85c9f176fcb96952f1b3b967cbb4ef9e&oauth_token=5d684692fe129665c9f967f54bbc525d redirect_response = raw_input('Paste the full redirect URL here: ') # OUT: Paste the full redirect URL here: https://snuggle.wmflabs.org/oauth/callback?oauth_verifier=7f98e940b58745e14602e0522c7e5e90&oauth_token=5d684692fe129665c9f967f54bbc525d oauth_response = oauth.parse_authorization_response(redirect_response) # oauth_response: {u'oauth_token': u'5d684692fe129665c9f967f54bbc525d', u'oauth_verifier': u'7f98e940b58745e14602e0522c7e5e90'} verifier = oauth_response.get('oauth_verifier') # Get the final oauth_token and secret access_token_url = 'https://www.mediawiki.org/w/index.php?title=Special%3aOAuth%2ftoken' oauth = OAuth1Session(CLIENT_KEY, client_secret=CLIENT_SECRET, resource_owner_key=resource_owner_key, resource_owner_secret=resource_owner_secret, verifier=verifier) oauth_tokens = oauth.fetch_access_token(access_token_url) # oauth_tokens: {u'oauth_token_secret': u'10e284c0ce48c2c2c6ce4f58fca358d6ff495a55', u'oauth_token': u'2f227cce369edad1ff3880bb4dab84f2', u'oauth_callback_confirmed': u'true'} resource_owner_key = oauth_tokens.get('oauth_token') resource_owner_secret = oauth_tokens.get('oauth_token_secret') # Make authenticated calls to the API data = {'action': 'query', 'meta': 'userinfo', 'format': 'json'} from urllib import urlencode url = 'https://www.mediawiki.org/w/api.php?' + urlencode(data) oauth = OAuth1Session(CLIENT_KEY, client_secret=CLIENT_SECRET, resource_owner_key=resource_owner_key, resource_owner_secret=resource_owner_secret) r = oauth.get(url) r.json() # OUT: {u'query': {u'userinfo': {u'id': 32663, u'name': u'FiloSottile'}}} Using OAuth1 auth helper (stateless) ------------------------------------ .. code-block:: python import requests from requests_oauthlib import OAuth1 # Get the anonymous oauth_token and secret request_token_url = 'https://www.mediawiki.org/w/index.php?title=Special%3aOAuth%2finitiate' oauth = OAuth1(CLIENT_KEY, client_secret=CLIENT_SECRET, callback_uri='oob') r = requests.post(url=request_token_url, auth=oauth) r.content # OUT: 'oauth_token=d44ce3a59d2d8cbcc0ebbae4d0157f4a&oauth_token_secret=a10676b7e6c4ae44db1411d1dece9267&oauth_callback_confirmed=true' from urlparse import parse_qs credentials = parse_qs(r.content) resource_owner_key = credentials.get('oauth_token')[0] resource_owner_secret = credentials.get('oauth_token_secret')[0] # Redirect the user to /authorize and get the callback base_authorization_url = 'https://www.mediawiki.org/wiki/Special:OAuth/authorize' authorize_url = base_authorization_url + '?oauth_token=' + resource_owner_key + '&oauth_consumer_key=' + CLIENT_KEY print 'Please go here and authorize,', authorize_url # OUT: Please go here and authorize, https://www.mediawiki.org/wiki/Special:OAuth/authorize?oauth_token=d44ce3a59d2d8cbcc0ebbae4d0157f4a&oauth_consumer_key=85c9f176fcb96952f1b3b967cbb4ef9e callback_qs = raw_input('Please input the callback query string: ') # OUT: Please input the callback query string: oauth_verifier=5eb313f9b4006e922c3e4a7d2493df98&oauth_token=d44ce3a59d2d8cbcc0ebbae4d0157f4a callback_data = parse_qs(callback_qs) verifier = callback_data.get('oauth_verifier')[0] assert callback_data.get('oauth_token')[0] == resource_owner_key # Get the final oauth_token and secret access_token_url = 'https://www.mediawiki.org/w/index.php?title=Special%3aOAuth%2ftoken' oauth = OAuth1(CLIENT_KEY, client_secret=CLIENT_SECRET, resource_owner_key=resource_owner_key, resource_owner_secret=resource_owner_secret, verifier=verifier) r = requests.post(url=access_token_url, auth=oauth) r.content # OUT: 'oauth_token=2f227cce369edad1ff3880bb4dab84f2&oauth_token_secret=10e284c0ce48c2c2c6ce4f58fca358d6ff495a55&oauth_callback_confirmed=true' credentials = parse_qs(r.content) resource_owner_key = credentials.get('oauth_token')[0] resource_owner_secret = credentials.get('oauth_token_secret')[0] # Make authenticated calls to the API data = {'action': 'query', 'meta': 'userinfo', 'format': 'json'} from urllib import urlencode url = 'https://www.mediawiki.org/w/api.php?' + urlencode(data) oauth = OAuth1(CLIENT_KEY, client_secret=CLIENT_SECRET, resource_owner_key=resource_owner_key, resource_owner_secret=resource_owner_secret) r = requests.get(url=url, auth=oauth) r.json() # OUT: {u'query': {u'userinfo': {u'id': 32663, u'name': u'FiloSottile'}}} requests-oauthlib-1.0.0/docs/examples/real_world_example.rst0000644000076500000240000000760213305200330026512 0ustar singingwolfboystaff00000000000000.. _real_example: Web App Example of OAuth 2 web application flow =============================================== OAuth is commonly used by web applications. The example below shows what such a web application might look like using the `Flask web framework `_ and GitHub as a provider. It should be easily transferrable to any web framework. .. note:: While the flow remains the same across most providers, Github is special in that the ``redirect_uri`` parameter is optional. This means that it may be necessary to explicitly pass a redirect_uri to the ``OAuth2Session`` object (e.g. when creating a custom OAuthProvider with ``flask-oauthlib``). .. code-block:: python from requests_oauthlib import OAuth2Session from flask import Flask, request, redirect, session, url_for from flask.json import jsonify import os app = Flask(__name__) # This information is obtained upon registration of a new GitHub OAuth # application here: https://github.com/settings/applications/new client_id = "" client_secret = "" authorization_base_url = 'https://github.com/login/oauth/authorize' token_url = 'https://github.com/login/oauth/access_token' @app.route("/") def demo(): """Step 1: User Authorization. Redirect the user/resource owner to the OAuth provider (i.e. Github) using an URL with a few key OAuth parameters. """ github = OAuth2Session(client_id) authorization_url, state = github.authorization_url(authorization_base_url) # State is used to prevent CSRF, keep this for later. session['oauth_state'] = state return redirect(authorization_url) # Step 2: User authorization, this happens on the provider. @app.route("/callback", methods=["GET"]) def callback(): """ Step 3: Retrieving an access token. The user has been redirected back from the provider to your registered callback URL. With this redirection comes an authorization code included in the redirect URL. We will use that to obtain an access token. """ github = OAuth2Session(client_id, state=session['oauth_state']) token = github.fetch_token(token_url, client_secret=client_secret, authorization_response=request.url) # At this point you can fetch protected resources but lets save # the token and show how this is done from a persisted token # in /profile. session['oauth_token'] = token return redirect(url_for('.profile')) @app.route("/profile", methods=["GET"]) def profile(): """Fetching a protected resource using an OAuth 2 token. """ github = OAuth2Session(client_id, token=session['oauth_token']) return jsonify(github.get('https://api.github.com/user').json()) if __name__ == "__main__": # This allows us to use a plain HTTP callback os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = "1" app.secret_key = os.urandom(24) app.run(debug=True) This example is lovingly borrowed from `this gist `_. **N.B:** You should note that Oauth2 works through SSL layer. If your server is not parametrized to allow HTTPS, the *fetch_token* method will raise an **oauthlib.oauth2.rfc6749.errors.InsecureTransportError**. Most people don't set SSL on their server while testing and that is fine. You can disable this check in two ways: 1. By setting an environment variable. .. code-block:: bash export OAUTHLIB_INSECURE_TRANSPORT=1 2. Equivalent to above you can set this in Python (if you have problems setting environment variables) .. code-block:: python # Somewhere in webapp_example.py, before the app.run for example import os os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' requests-oauthlib-1.0.0/docs/examples/tumblr.rst0000644000076500000240000000274712726270216024177 0ustar singingwolfboystaff00000000000000Tumblr OAuth1 Tutorial ====================== Register a new application on the `tumblr application page`_. Enter a call back url (can just be http://www.tumblr.com/dashboard) and get the ``OAuth Consumer Key`` and ``Secret Key``. .. _`tumblr application page`: http://www.tumblr.com/oauth/apps .. code-block:: pycon >>> # Credentials from the application page >>> key = '' >>> secret = '' >>> # OAuth URLs given on the application page >>> request_token_url = 'http://www.tumblr.com/oauth/request_token' >>> authorization_base_url = 'http://www.tumblr.com/oauth/authorize' >>> access_token_url = 'http://www.tumblr.com/oauth/access_token' >>> # Fetch a request token >>> from requests_oauthlib import OAuth1Session >>> tumblr = OAuth1Session(key, client_secret=secret, callback_uri='http://www.tumblr.com/dashboard') >>> tumblr.fetch_request_token(request_token_url) >>> # Link user to authorization page >>> authorization_url = tumblr.authorization_url(authorization_base_url) >>> print 'Please go here and authorize,', authorization_url >>> # Get the verifier code from the URL >>> redirect_response = raw_input('Paste the full redirect URL here: ') >>> tumblr.parse_authorization_response(redirect_response) >>> # Fetch the access token >>> tumblr.fetch_access_token(access_token_url) >>> # Fetch a protected resource >>> print tumblr.get('http://api.tumblr.com/v2/user/dashboard') requests-oauthlib-1.0.0/docs/examples/examples.rst0000644000076500000240000000030313263226123024465 0ustar singingwolfboystaff00000000000000Examples ========= .. toctree:: :maxdepth: 2 bitbucket github google facebook fitbit linkedin outlook tumblr real_world_example real_world_example_with_refresh requests-oauthlib-1.0.0/docs/examples/outlook.rst0000644000076500000240000000344213263226123024352 0ustar singingwolfboystaff00000000000000Outlook Calender OAuth 2 Tutorial ========================== Create a new web application client in the `Microsoft Application Registration Portal`_ When you have obtained a ``client_id``, ``client_secret`` and registered a callback URL then you can try out the command line interactive example below. .. _`Outlook App console`: https://apps.dev.microsoft.com .. code-block:: pycon >>> # This information is obtained upon registration of a new Outlook Application >>> client_id = '' >>> client_secret = '' >>> # OAuth endpoints given in Outlook API documentation >>> authorization_base_url = 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize' >>> token_url = 'https://login.microsoftonline.com/common/oauth2/v2.0/token' >>> scope = ['https://outlook.office.com/calendars.readwrite'] >>> redirect_uri = 'https://localhost/' # Should match Site URL >>> from requests_oauthlib import OAuth2Session >>> outlook = OAuth2Session(client_id,scope=scope,redirect_uri=redirect_uri) >>> # Redirect the user owner to the OAuth provider (i.e. Outlook) using an URL with a few key OAuth parameters. >>> authorization_url, state = outlook.authorization_url(authorization_base_url) >>> print 'Please go here and authorize,', authorization_url >>> # Get the authorization verifier code from the callback url >>> redirect_response = raw_input('Paste the full redirect URL here:') >>> # Fetch the access token >>> token = outlook.fetch_token(token_url,client_secret=client_secret,authorization_response=redirect_response) >>> # Fetch a protected resource, i.e. calender information >>> o = outlook.get('https://outlook.office.com/api/v1.0/me/calendars') >>> print o.content requests-oauthlib-1.0.0/docs/examples/github.rst0000644000076500000240000000263412726270216024147 0ustar singingwolfboystaff00000000000000GitHub OAuth 2 Tutorial ========================== Setup credentials following the instructions on `GitHub`_. When you have obtained a ``client_id`` and a ``client_secret`` you can try out the command line interactive example below. .. _`GitHub`: https://github.com/settings/applications/new .. code-block:: pycon >>> # Credentials you get from registering a new application >>> client_id = '' >>> client_secret = '' >>> # OAuth endpoints given in the GitHub API documentation >>> authorization_base_url = 'https://github.com/login/oauth/authorize' >>> token_url = 'https://github.com/login/oauth/access_token' >>> from requests_oauthlib import OAuth2Session >>> github = OAuth2Session(client_id) >>> # Redirect user to GitHub for authorization >>> authorization_url, state = github.authorization_url(authorization_base_url) >>> print 'Please go here and authorize,', authorization_url >>> # Get the authorization verifier code from the callback url >>> redirect_response = raw_input('Paste the full redirect URL here:') >>> # Fetch the access token >>> github.fetch_token(token_url, client_secret=client_secret, >>> authorization_response=redirect_response) >>> # Fetch a protected resource, i.e. user profile >>> r = github.get('https://api.github.com/user') >>> print r.content requests-oauthlib-1.0.0/docs/examples/bitbucket.rst0000644000076500000240000000342312726270216024636 0ustar singingwolfboystaff00000000000000Bitbucket OAuth 1 Tutorial ========================== Start with setting up a new consumer by following the instructions on `Bitbucket`_. When you have obtained a ``key`` and a ``secret`` you can try out the command line interactive example below. .. _`Bitbucket`: https://confluence.atlassian.com/display/BITBUCKET/OAuth+on+Bitbucket .. code-block:: pycon # Credentials you get from adding a new consumer in bitbucket -> manage account # -> integrated applications. >>> key = '' >>> secret = '' >>> # OAuth endpoints given in the Bitbucket API documentation >>> request_token_url = 'https://bitbucket.org/!api/1.0/oauth/request_token' >>> authorization_base_url = 'https://bitbucket.org/!api/1.0/oauth/authenticate' >>> access_token_url = 'https://bitbucket.org/!api/1.0/oauth/access_token' >>> # 2. Fetch a request token >>> from requests_oauthlib import OAuth1Session >>> bitbucket = OAuth1Session(key, client_secret=secret, >>> callback_uri='http://127.0.0.1/cb') >>> bitbucket.fetch_request_token(request_token_url) >>> # 3. Redirect user to Bitbucket for authorization >>> authorization_url = bitbucket.authorization_url(authorization_base_url) >>> print 'Please go here and authorize,', authorization_url >>> # 4. Get the authorization verifier code from the callback url >>> redirect_response = raw_input('Paste the full redirect URL here:') >>> bitbucket.parse_authorization_response(redirect_response) >>> # 5. Fetch the access token >>> bitbucket.fetch_access_token(access_token_url) >>> # 6. Fetch a protected resource, i.e. user profile >>> r = bitbucket.get('https://bitbucket.org/api/1.0/user') >>> print r.content requests-oauthlib-1.0.0/docs/examples/linkedin.rst0000644000076500000240000000316712726270216024464 0ustar singingwolfboystaff00000000000000LinkedIn OAuth 2 Tutorial ========================= Setup credentials following the instructions on `LinkedIn`_. When you have obtained a ``client_id`` and a ``client_secret`` you can try out the command line interactive example below. .. _`LinkedIn`: https://www.linkedin.com/secure/developer .. code-block:: pycon >>> # Credentials you get from registering a new application >>> client_id = '' >>> client_secret = '' >>> # OAuth endpoints given in the LinkedIn API documentation >>> authorization_base_url = 'https://www.linkedin.com/uas/oauth2/authorization' >>> token_url = 'https://www.linkedin.com/uas/oauth2/accessToken' >>> from requests_oauthlib import OAuth2Session >>> from requests_oauthlib.compliance_fixes import linkedin_compliance_fix >>> linkedin = OAuth2Session(client_id, redirect_uri='http://127.0.0.1') >>> linkedin = linkedin_compliance_fix(linkedin) >>> # Redirect user to LinkedIn for authorization >>> authorization_url, state = linkedin.authorization_url(authorization_base_url) >>> print 'Please go here and authorize,', authorization_url >>> # Get the authorization verifier code from the callback url >>> redirect_response = raw_input('Paste the full redirect URL here:') >>> # Fetch the access token >>> linkedin.fetch_token(token_url, client_secret=client_secret, ... authorization_response=redirect_response) >>> # Fetch a protected resource, i.e. user profile >>> r = linkedin.get('https://api.linkedin.com/v1/people/~') >>> print r.content requests-oauthlib-1.0.0/docs/examples/facebook.rst0000644000076500000240000000331512726270216024433 0ustar singingwolfboystaff00000000000000Facebook OAuth 2 Tutorial ========================= Setup a new web application client in the `Facebook APP console`_ When you have obtained a ``client_id``, ``client_secret`` and registered a callback URL then you can try out the command line interactive example below. .. _`Facebook APP console`: https://developers.facebook.com/apps .. code-block:: pycon >>> # Credentials you get from registering a new application >>> client_id = '' >>> client_secret = '' >>> # OAuth endpoints given in the Facebook API documentation >>> authorization_base_url = 'https://www.facebook.com/dialog/oauth' >>> token_url = 'https://graph.facebook.com/oauth/access_token' >>> redirect_uri = 'https://localhost/' # Should match Site URL >>> from requests_oauthlib import OAuth2Session >>> from requests_oauthlib.compliance_fixes import facebook_compliance_fix >>> facebook = OAuth2Session(client_id, redirect_uri=redirect_uri) >>> facebook = facebook_compliance_fix(facebook) >>> # Redirect user to Facebook for authorization >>> authorization_url, state = facebook.authorization_url(authorization_base_url) >>> print 'Please go here and authorize,', authorization_url >>> # Get the authorization verifier code from the callback url >>> redirect_response = raw_input('Paste the full redirect URL here:') >>> # Fetch the access token >>> facebook.fetch_token(token_url, client_secret=client_secret, ..> authorization_response=redirect_response) >>> # Fetch a protected resource, i.e. user profile >>> r = facebook.get('https://graph.facebook.com/me?') >>> print r.content requests-oauthlib-1.0.0/docs/examples/google.rst0000644000076500000240000000360613263226123024134 0ustar singingwolfboystaff00000000000000Google OAuth 2 Tutorial ========================== Setup a new web project in the `Google Cloud Console`_ When you have obtained a ``client_id``, ``client_secret`` and registered a callback URL then you can try out the command line interactive example below. .. _`Google Cloud Console`: https://cloud.google.com/console/project .. code-block:: pycon >>> # Credentials you get from registering a new application >>> client_id = '.apps.googleusercontent.com' >>> client_secret = '' >>> redirect_uri = 'https://your.registered/callback' >>> # OAuth endpoints given in the Google API documentation >>> authorization_base_url = "https://accounts.google.com/o/oauth2/v2/auth" >>> token_url = "https://www.googleapis.com/oauth2/v4/token" >>> scope = [ ... "https://www.googleapis.com/auth/userinfo.email", ... "https://www.googleapis.com/auth/userinfo.profile" ... ] >>> from requests_oauthlib import OAuth2Session >>> google = OAuth2Session(client_id, scope=scope, redirect_uri=redirect_uri) >>> # Redirect user to Google for authorization >>> authorization_url, state = google.authorization_url(authorization_base_url, ... # offline for refresh token ... # force to always make user click authorize ... access_type="offline", prompt="select_account") >>> print 'Please go here and authorize,', authorization_url >>> # Get the authorization verifier code from the callback url >>> redirect_response = raw_input('Paste the full redirect URL here:') >>> # Fetch the access token >>> google.fetch_token(token_url, client_secret=client_secret, ... authorization_response=redirect_response) >>> # Fetch a protected resource, i.e. user profile >>> r = google.get('https://www.googleapis.com/oauth2/v1/userinfo') >>> print r.content requests-oauthlib-1.0.0/docs/oauth2_workflow.rst0000644000076500000240000002462713263226123024204 0ustar singingwolfboystaff00000000000000OAuth 2 Workflow ================ .. contents:: :depth: 3 :local: Introduction ------------ The following sections provide some example code that demonstrates some of the possible OAuth2 flows you can use with requests-oauthlib. We provide four examples: one for each of the grant types defined by the OAuth2 RFC. These grant types (or workflows) are the Authorization Code Grant (or Web Application Flow), the Implicit Grant (or Mobile Application Flow), the Resource Owner Password Credentials Grant (or, more succinctly, the Legacy Application Flow), and the Client Credentials Grant (or Backend Application Flow). Available Workflows ~~~~~~~~~~~~~~~~~~~ There are four core work flows: 1. :ref:`Authorization Code Grant ` (Web Application Flow). 2. :ref:`Implicit Grant ` (Mobile Application flow). 3. :ref:`Resource Owner Password Credentials Grant ` (Legacy Application flow). 4. :ref:`Client Credentials Grant ` (Backend Application flow). .. _web-application-flow: Web Application Flow -------------------- The steps below outline how to use the default Authorization Grant Type flow to obtain an access token and fetch a protected resource. In this example the provider is Google and the protected resource is the user's profile. 0. Obtain credentials from your OAuth provider manually. At minimum you will need a ``client_id`` but likely also a ``client_secret``. During this process you might also be required to register a default redirect URI to be used by your application. Save these things in your Python script: .. code-block:: pycon >>> client_id = r'your_client_id' >>> client_secret = r'your_client_secret' >>> redirect_uri = 'https://your.callback/uri' 1. User authorization through redirection. First we will create an authorization url from the base URL given by the provider and the credentials previously obtained. In addition most providers will request that you ask for access to a certain scope. In this example we will ask Google for access to the email address of the user and the users profile. .. code-block:: pycon # Note that these are Google specific scopes >>> scope = ['https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/userinfo.profile'] >>> oauth = OAuth2Session(client_id, redirect_uri=redirect_uri, scope=scope) >>> authorization_url, state = oauth.authorization_url( 'https://accounts.google.com/o/oauth2/auth', # access_type and prompt are Google specific extra # parameters. access_type="offline", prompt="select_account") >>> print 'Please go to %s and authorize access.' % authorization_url >>> authorization_response = raw_input('Enter the full callback URL') 2. Fetch an access token from the provider using the authorization code obtained during user authorization. .. code-block:: pycon >>> token = oauth.fetch_token( 'https://accounts.google.com/o/oauth2/token', authorization_response=authorization_response, # Google specific extra parameter used for client # authentication client_secret=client_secret) 3. Access protected resources using the access token you just obtained. For example, get the users profile info. .. code-block:: pycon >>> r = oauth.get('https://www.googleapis.com/oauth2/v1/userinfo') >>> # Enjoy =) .. _mobile-application-flow: Mobile Application Flow ----------------------- The steps below outline how to use the Implicit Code Grant Type flow to obtain an access token. 0. You will need the following settings. .. code-block:: pycon >>> client_id = 'your_client_id' >>> scopes = ['scope_1', 'scope_2'] >>> auth_url = 'https://your.oauth2/auth' 1. Get the authorization_url .. code-block:: pycon >>> from oauthlib.oauth2 import MobileApplicationClient >>> from requests_oauthlib import OAuth2Session >>> oauth = OAuth2Session(client=MobileApplicationClient(client_id=client_id), scope=scopes) >>> authorization_url, state = oauth.authorization_url(auth_url) 2. Fetch an access token from the provider. .. code-block:: pycon >>> response = oauth.get(authorization_url) >>> oauth.token_from_fragment(response.url) .. _legacy-application-flow: Legacy Application Flow ----------------------- The steps below outline how to use the Resource Owner Password Credentials Grant Type flow to obtain an access token. 0. You will need the following settings. ``client_secret`` is optional depending on the provider. .. code-block:: pycon >>> client_id = 'your_client_id' >>> client_secret = 'your_client_secret' >>> username = 'your_username' >>> password = 'your_password' 1. Fetch an access token from the provider. .. code-block:: pycon >>> from oauthlib.oauth2 import LegacyApplicationClient >>> from requests_oauthlib import OAuth2Session >>> oauth = OAuth2Session(client=LegacyApplicationClient(client_id=client_id)) >>> token = oauth.fetch_token(token_url='https://somesite.com/oauth2/token', username=username, password=password, client_id=client_id, client_secret=client_secret) .. _backend-application-flow: Backend Application Flow ------------------------ The steps below outline how to use the Resource Owner Client Credentials Grant Type flow to obtain an access token. 0. Obtain credentials from your OAuth provider. At minimum you will need a ``client_id`` and ``client_secret``. .. code-block:: pycon >>> client_id = 'your_client_id' >>> client_secret = 'your_client_secret' 1. Fetch an access token from the provider. .. code-block:: pycon >>> from oauthlib.oauth2 import BackendApplicationClient >>> client = BackendApplicationClient(client_id=client_id) >>> oauth = OAuth2Session(client=client) >>> token = oauth.fetch_token(token_url='https://provider.com/oauth2/token', client_id=client_id, client_secret=client_secret) If your provider requires that you pass auth credentials in a Basic Auth header, you can do this instead: .. code-block:: pycon >>> from oauthlib.oauth2 import BackendApplicationClient >>> from requests.auth import HTTPBasicAuth >>> auth = HTTPBasicAuth(client_id, client_secret) >>> client = BackendApplicationClient(client_id=client_id) >>> oauth = OAuth2Session(client=client) >>> token = oauth.fetch_token(token_url='https://provider.com/oauth2/token', auth=auth) Refreshing tokens ----------------- Certain providers will give you a ``refresh_token`` along with the ``access_token``. These can be used to directly fetch new access tokens without going through the normal OAuth workflow. ``requests-oauthlib`` provides three methods of obtaining refresh tokens. All of these are dependant on you specifying an accurate ``expires_in`` in the token. ``expires_in`` is a credential given with the access and refresh token indiciating in how many seconds from now the access token expires. Commonly, access tokens expire after an hour an the ``expires_in`` would be ``3600``. Without this it is impossible for ``requests-oauthlib`` to know when a token is expired as the status code of a request failing due to token expiration is not defined. If you are not interested in token refreshing, always pass in a positive value for ``expires_in`` or omit it entirely. (ALL) Define the token, token saver and needed credentials ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: pycon >>> token = { ... 'access_token': 'eswfld123kjhn1v5423', ... 'refresh_token': 'asdfkljh23490sdf', ... 'token_type': 'Bearer', ... 'expires_in': '-30', # initially 3600, need to be updated by you ... } >>> client_id = r'foo' >>> refresh_url = 'https://provider.com/token' >>> protected_url = 'https://provider.com/secret' >>> # most providers will ask you for extra credentials to be passed along >>> # when refreshing tokens, usually for authentication purposes. >>> extra = { ... 'client_id': client_id, ... 'client_secret': r'potato', ... } >>> # After updating the token you will most likely want to save it. >>> def token_saver(token): ... # save token in database / session (First) Define Try-Catch TokenExpiredError on each request ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This is the most basic version in which an error is raised when refresh is necessary but refreshing is done manually. .. code-block:: pycon >>> from requests_oauthlib import OAuth2Session >>> from oauthlib.oauth2 import TokenExpiredError >>> try: ... client = OAuth2Session(client_id, token=token) ... r = client.get(protected_url) >>> except TokenExpiredError as e: ... token = client.refresh_token(refresh_url, **extra) ... token_saver(token) >>> client = OAuth2Session(client_id, token=token) >>> r = client.get(protected_url) (Second) Define automatic token refresh automatic but update manually ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This is the, arguably awkward, middle between the basic and convenient refresh methods in which a token is automatically refreshed, but saving the new token is done manually. .. code-block:: pycon >>> from requests_oauthlib import OAuth2Session, TokenUpdated >>> try: ... client = OAuth2Session(client_id, token=token, ... auto_refresh_kwargs=extra, auto_refresh_url=refresh_url) ... r = client.get(protected_url) >>> except TokenUpdated as e: ... token_saver(e.token) (Third, Recommended) Define automatic token refresh and update ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The third and recommended method will automatically fetch refresh tokens and save them. It requires no exception catching and results in clean code. Remember however that you still need to update ``expires_in`` to trigger the refresh. .. code-block:: pycon >>> from requests_oauthlib import OAuth2Session >>> client = OAuth2Session(client_id, token=token, auto_refresh_url=refresh_url, ... auto_refresh_kwargs=extra, token_updater=token_saver) >>> r = client.get(protected_url) .. _write this section: https://github.com/requests/requests-oauthlib/issues/48 requests-oauthlib-1.0.0/docs/api.rst0000644000076500000240000000062612726270216021617 0ustar singingwolfboystaff00000000000000.. _api: Developer Interface =================== .. module:: requests_oauthlib OAuth 1.0 --------- .. autoclass:: OAuth1 :members: OAuth 1.0 Session ----------------- .. autoclass:: OAuth1Session :members: OAuth 2.0 --------- .. autoclass:: OAuth2 :members: .. autoclass:: TokenUpdated :members: OAuth 2.0 Session ----------------- .. autoclass:: OAuth2Session :members: requests-oauthlib-1.0.0/setup.py0000644000076500000240000000357213277061160021077 0ustar singingwolfboystaff00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- import os import sys import re from setuptools import setup # Get the version version_regex = r'__version__ = ["\']([^"\']*)["\']' with open('requests_oauthlib/__init__.py', 'r') as f: text = f.read() match = re.search(version_regex, text) if match: VERSION = match.group(1) else: raise RuntimeError("No version number found!") APP_NAME = 'requests-oauthlib' # Publish Helper. if sys.argv[-1] == 'publish': os.system('python setup.py sdist upload') sys.exit() def readall(path): with open(path) as fp: return fp.read() setup( name=APP_NAME, version=VERSION, description='OAuthlib authentication support for Requests.', long_description=readall('README.rst') + '\n\n' + readall('HISTORY.rst'), author='Kenneth Reitz', author_email='me@kennethreitz.com', url='https://github.com/requests/requests-oauthlib', packages=['requests_oauthlib', 'requests_oauthlib.compliance_fixes'], python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", install_requires=['oauthlib>=0.6.2', 'requests>=2.0.0'], extras_require={'rsa': ['oauthlib[rsa]>=0.6.2', 'requests>=2.0.0']}, license='ISC', classifiers=( 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'Natural Language :: English', 'License :: OSI Approved :: BSD License', 'Programming Language :: Python', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', ), zip_safe=False, tests_require=[ 'mock', 'requests-mock', ], test_suite='tests' ) requests-oauthlib-1.0.0/HISTORY.rst0000644000076500000240000001100413305200776021245 0ustar singingwolfboystaff00000000000000History ------- UNRELEASED ++++++++++ nothing yet v1.0.0 (4 June 2018) ++++++++++++++++++++ - **Removed support for Python 2.6 and Python 3.3.** This project now supports Python 2.7, and Python 3.4 and above. - Added several examples to the documentation. - Added plentymarkets compliance fix. - Added a ``token`` property to OAuth1Session, to match the corresponding ``token`` property on OAuth2Session. v0.8.0 (14 February 2017) +++++++++++++++++++++++++ - Added Fitbit compliance fix. - Fixed an issue where newlines in the response body for the access token request would cause errors when trying to extract the token. - Fixed an issue introduced in v0.7.0 where users passing ``auth`` to several methods would encounter conflicts with the ``client_id`` and ``client_secret``-derived auth. The user-supplied ``auth`` argument is now used in preference to those options. v0.7.0 (22 September 2016) ++++++++++++++++++++++++++ - Allowed ``OAuth2Session.request`` to take the ``client_id`` and ``client_secret`` parameters for the purposes of automatic token refresh, which may need them. v0.6.2 (12 July 2016) +++++++++++++++++++++ - Use ``client_id`` and ``client_secret`` for the Authorization header if provided. - Allow explicit bypass of the Authorization header by setting ``auth=False``. - Pass through the ``proxies`` kwarg when refreshing tokens. - Miscellaneous cleanups. v0.6.1 (19 February 2016) +++++++++++++++++++++++++ - Fixed a bug when sending authorization in headers with no username and password present. - Make sure we clear the session token before obtaining a new one. - Some improvements to the Slack compliance fix. - Avoid timing problems around token refresh. - Allow passing arbitrary arguments to requests when calling ``fetch_request_token`` and ``fetch_access_token``. v0.6.0 (14 December 2015) +++++++++++++++++++++++++ - Add compliance fix for Slack. - Add compliance fix for Mailchimp. - ``TokenRequestDenied`` exceptions now carry the entire response, not just the status code. - Pass through keyword arguments when refreshing tokens automatically. - Send authorization in headers, not just body, to maximize compatibility. - More getters/setters available for OAuth2 session client values. - Allow sending custom headers when refreshing tokens, and set some defaults. v0.5.0 (4 May 2015) +++++++++++++++++++ - Fix ``TypeError`` being raised instead of ``TokenMissing`` error. - Raise requests exceptions on 4XX and 5XX responses in the OAuth2 flow. - Avoid ``AttributeError`` when initializing the ``OAuth2Session`` class without complete client information. v0.4.2 (16 October 2014) ++++++++++++++++++++++++ - New ``authorized`` property on OAuth1Session and OAuth2Session, which allows you to easily determine if the session is already authorized with OAuth tokens or not. - New ``TokenMissing`` and ``VerifierMissing`` exception classes for OAuth1Session: this will make it easier to catch and identify these exceptions. v0.4.1 (6 June 2014) ++++++++++++++++++++ - New install target ``[rsa]`` for people using OAuth1 RSA-SHA1 signature method. - Fixed bug in OAuth2 where supplied state param was not used in auth url. - OAuth2 HTTPS checking can be disabled by setting environment variable ``OAUTHLIB_INSECURE_TRANSPORT``. - OAuth1 now re-authorize upon redirects. - OAuth1 token fetching now raise a detailed error message when the response body is incorrectly encoded or the request was denied. - Added support for custom OAuth1 clients. - OAuth2 compliance fix for Sina Weibo. - Multiple fixes to facebook compliance fix. - Compliance fixes now re-encode body properly as bytes in Python 3. - Logging now properly done under ``requests_oauthlib`` namespace instead of piggybacking on oauthlib namespace. - Logging introduced for OAuth1 auth and session. v0.4.0 (29 September 2013) ++++++++++++++++++++++++++ - OAuth1Session methods only return unicode strings. #55. - Renamed requests_oauthlib.core to requests_oauthlib.oauth1_auth for consistency. #79. - Added Facebook compliance fix and access_token_response hook to OAuth2Session. #63. - Added LinkedIn compliance fix. - Added refresh_token_response compliance hook, invoked before parsing the refresh token. - Correctly limit compliance hooks to running only once! - Content type guessing should only be done when no content type is given - OAuth1 now updates r.headers instead of replacing it with non case insensitive dict - Remove last use of Response.content (in OAuth1Session). #44. - State param can now be supplied in OAuth2Session.authorize_url requests-oauthlib-1.0.0/AUTHORS.rst0000644000076500000240000000127512726270216021244 0ustar singingwolfboystaff00000000000000Requests-oauthlib is written and maintained by Kenneth Reitz and various contributors: Development Lead ---------------- - Kenneth Reitz Patches and Suggestions ----------------------- - Cory Benfield - Ib Lundgren - Devin Sevilla - Imad Mouhtassem - Johan Euphrosine - Johannes Spielmann - Martin Trigaux - Matt McClure - Mikhail Sobolev - Paul Bonser - Vinay Raikar - kracekumar - David Baumgold requests-oauthlib-1.0.0/setup.cfg0000644000076500000240000000014613305201162021166 0ustar singingwolfboystaff00000000000000[bdist_wheel] universal = 1 [metadata] license_file = LICENSE [egg_info] tag_build = tag_date = 0 requests-oauthlib-1.0.0/README.rst0000644000076500000240000000472313305200330021035 0ustar singingwolfboystaff00000000000000Requests-OAuthlib |build-status| |coverage-status| |docs| ========================================================= This project provides first-class OAuth library support for `Requests `_. The OAuth 1 workflow -------------------- OAuth 1 can seem overly complicated and it sure has its quirks. Luckily, requests_oauthlib hides most of these and let you focus at the task at hand. Accessing protected resources using requests_oauthlib is as simple as: .. code-block:: pycon >>> from requests_oauthlib import OAuth1Session >>> twitter = OAuth1Session('client_key', client_secret='client_secret', resource_owner_key='resource_owner_key', resource_owner_secret='resource_owner_secret') >>> url = 'https://api.twitter.com/1/account/settings.json' >>> r = twitter.get(url) Before accessing resources you will need to obtain a few credentials from your provider (e.g. Twitter) and authorization from the user for whom you wish to retrieve resources for. You can read all about this in the full `OAuth 1 workflow guide on RTD `_. The OAuth 2 workflow -------------------- OAuth 2 is generally simpler than OAuth 1 but comes in more flavours. The most common being the Authorization Code Grant, also known as the WebApplication flow. Fetching a protected resource after obtaining an access token can be extremely simple. However, before accessing resources you will need to obtain a few credentials from your provider (e.g. Google) and authorization from the user for whom you wish to retrieve resources for. You can read all about this in the full `OAuth 2 workflow guide on RTD `_. Installation ------------- To install requests and requests_oauthlib you can use pip: .. code-block:: bash $ pip install requests requests_oauthlib .. |build-status| image:: https://travis-ci.org/requests/requests-oauthlib.svg?branch=master :target: https://travis-ci.org/requests/requests-oauthlib .. |coverage-status| image:: https://img.shields.io/coveralls/requests/requests-oauthlib.svg :target: https://coveralls.io/r/requests/requests-oauthlib .. |docs| image:: https://readthedocs.org/projects/requests-oauthlib/badge/ :alt: Documentation Status :scale: 100% :target: https://requests-oauthlib.readthedocs.io/ requests-oauthlib-1.0.0/requests_oauthlib.egg-info/0000755000076500000240000000000013305201162024600 5ustar singingwolfboystaff00000000000000requests-oauthlib-1.0.0/requests_oauthlib.egg-info/PKG-INFO0000644000076500000240000002227413305201162025704 0ustar singingwolfboystaff00000000000000Metadata-Version: 2.1 Name: requests-oauthlib Version: 1.0.0 Summary: OAuthlib authentication support for Requests. Home-page: https://github.com/requests/requests-oauthlib Author: Kenneth Reitz Author-email: me@kennethreitz.com License: ISC Description: Requests-OAuthlib |build-status| |coverage-status| |docs| ========================================================= This project provides first-class OAuth library support for `Requests `_. The OAuth 1 workflow -------------------- OAuth 1 can seem overly complicated and it sure has its quirks. Luckily, requests_oauthlib hides most of these and let you focus at the task at hand. Accessing protected resources using requests_oauthlib is as simple as: .. code-block:: pycon >>> from requests_oauthlib import OAuth1Session >>> twitter = OAuth1Session('client_key', client_secret='client_secret', resource_owner_key='resource_owner_key', resource_owner_secret='resource_owner_secret') >>> url = 'https://api.twitter.com/1/account/settings.json' >>> r = twitter.get(url) Before accessing resources you will need to obtain a few credentials from your provider (e.g. Twitter) and authorization from the user for whom you wish to retrieve resources for. You can read all about this in the full `OAuth 1 workflow guide on RTD `_. The OAuth 2 workflow -------------------- OAuth 2 is generally simpler than OAuth 1 but comes in more flavours. The most common being the Authorization Code Grant, also known as the WebApplication flow. Fetching a protected resource after obtaining an access token can be extremely simple. However, before accessing resources you will need to obtain a few credentials from your provider (e.g. Google) and authorization from the user for whom you wish to retrieve resources for. You can read all about this in the full `OAuth 2 workflow guide on RTD `_. Installation ------------- To install requests and requests_oauthlib you can use pip: .. code-block:: bash $ pip install requests requests_oauthlib .. |build-status| image:: https://travis-ci.org/requests/requests-oauthlib.svg?branch=master :target: https://travis-ci.org/requests/requests-oauthlib .. |coverage-status| image:: https://img.shields.io/coveralls/requests/requests-oauthlib.svg :target: https://coveralls.io/r/requests/requests-oauthlib .. |docs| image:: https://readthedocs.org/projects/requests-oauthlib/badge/ :alt: Documentation Status :scale: 100% :target: https://requests-oauthlib.readthedocs.io/ History ------- UNRELEASED ++++++++++ nothing yet v1.0.0 (4 June 2018) ++++++++++++++++++++ - **Removed support for Python 2.6 and Python 3.3.** This project now supports Python 2.7, and Python 3.4 and above. - Added several examples to the documentation. - Added plentymarkets compliance fix. - Added a ``token`` property to OAuth1Session, to match the corresponding ``token`` property on OAuth2Session. v0.8.0 (14 February 2017) +++++++++++++++++++++++++ - Added Fitbit compliance fix. - Fixed an issue where newlines in the response body for the access token request would cause errors when trying to extract the token. - Fixed an issue introduced in v0.7.0 where users passing ``auth`` to several methods would encounter conflicts with the ``client_id`` and ``client_secret``-derived auth. The user-supplied ``auth`` argument is now used in preference to those options. v0.7.0 (22 September 2016) ++++++++++++++++++++++++++ - Allowed ``OAuth2Session.request`` to take the ``client_id`` and ``client_secret`` parameters for the purposes of automatic token refresh, which may need them. v0.6.2 (12 July 2016) +++++++++++++++++++++ - Use ``client_id`` and ``client_secret`` for the Authorization header if provided. - Allow explicit bypass of the Authorization header by setting ``auth=False``. - Pass through the ``proxies`` kwarg when refreshing tokens. - Miscellaneous cleanups. v0.6.1 (19 February 2016) +++++++++++++++++++++++++ - Fixed a bug when sending authorization in headers with no username and password present. - Make sure we clear the session token before obtaining a new one. - Some improvements to the Slack compliance fix. - Avoid timing problems around token refresh. - Allow passing arbitrary arguments to requests when calling ``fetch_request_token`` and ``fetch_access_token``. v0.6.0 (14 December 2015) +++++++++++++++++++++++++ - Add compliance fix for Slack. - Add compliance fix for Mailchimp. - ``TokenRequestDenied`` exceptions now carry the entire response, not just the status code. - Pass through keyword arguments when refreshing tokens automatically. - Send authorization in headers, not just body, to maximize compatibility. - More getters/setters available for OAuth2 session client values. - Allow sending custom headers when refreshing tokens, and set some defaults. v0.5.0 (4 May 2015) +++++++++++++++++++ - Fix ``TypeError`` being raised instead of ``TokenMissing`` error. - Raise requests exceptions on 4XX and 5XX responses in the OAuth2 flow. - Avoid ``AttributeError`` when initializing the ``OAuth2Session`` class without complete client information. v0.4.2 (16 October 2014) ++++++++++++++++++++++++ - New ``authorized`` property on OAuth1Session and OAuth2Session, which allows you to easily determine if the session is already authorized with OAuth tokens or not. - New ``TokenMissing`` and ``VerifierMissing`` exception classes for OAuth1Session: this will make it easier to catch and identify these exceptions. v0.4.1 (6 June 2014) ++++++++++++++++++++ - New install target ``[rsa]`` for people using OAuth1 RSA-SHA1 signature method. - Fixed bug in OAuth2 where supplied state param was not used in auth url. - OAuth2 HTTPS checking can be disabled by setting environment variable ``OAUTHLIB_INSECURE_TRANSPORT``. - OAuth1 now re-authorize upon redirects. - OAuth1 token fetching now raise a detailed error message when the response body is incorrectly encoded or the request was denied. - Added support for custom OAuth1 clients. - OAuth2 compliance fix for Sina Weibo. - Multiple fixes to facebook compliance fix. - Compliance fixes now re-encode body properly as bytes in Python 3. - Logging now properly done under ``requests_oauthlib`` namespace instead of piggybacking on oauthlib namespace. - Logging introduced for OAuth1 auth and session. v0.4.0 (29 September 2013) ++++++++++++++++++++++++++ - OAuth1Session methods only return unicode strings. #55. - Renamed requests_oauthlib.core to requests_oauthlib.oauth1_auth for consistency. #79. - Added Facebook compliance fix and access_token_response hook to OAuth2Session. #63. - Added LinkedIn compliance fix. - Added refresh_token_response compliance hook, invoked before parsing the refresh token. - Correctly limit compliance hooks to running only once! - Content type guessing should only be done when no content type is given - OAuth1 now updates r.headers instead of replacing it with non case insensitive dict - Remove last use of Response.content (in OAuth1Session). #44. - State param can now be supplied in OAuth2Session.authorize_url Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: Natural Language :: English Classifier: License :: OSI Approved :: BSD License Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* Provides-Extra: rsa requests-oauthlib-1.0.0/requests_oauthlib.egg-info/not-zip-safe0000644000076500000240000000000113305201162027026 0ustar singingwolfboystaff00000000000000 requests-oauthlib-1.0.0/requests_oauthlib.egg-info/SOURCES.txt0000644000076500000240000000402513305201162026465 0ustar singingwolfboystaff00000000000000AUTHORS.rst HISTORY.rst LICENSE MANIFEST.in README.rst requirements.txt setup.cfg setup.py docs/Makefile docs/api.rst docs/conf.py docs/index.rst docs/make.bat docs/oauth1_workflow.rst docs/oauth2_workflow.rst docs/examples/bitbucket.rst docs/examples/examples.rst docs/examples/facebook.rst docs/examples/fitbit.rst docs/examples/github.rst docs/examples/google.rst docs/examples/linkedin.rst docs/examples/mediawiki.rst docs/examples/outlook.rst docs/examples/real_world_example.rst docs/examples/real_world_example_with_refresh.rst docs/examples/tumblr.rst docs/examples/wso2.rst requests_oauthlib/__init__.py requests_oauthlib/oauth1_auth.py requests_oauthlib/oauth1_session.py requests_oauthlib/oauth2_auth.py requests_oauthlib/oauth2_session.py requests_oauthlib.egg-info/PKG-INFO requests_oauthlib.egg-info/SOURCES.txt requests_oauthlib.egg-info/dependency_links.txt requests_oauthlib.egg-info/not-zip-safe requests_oauthlib.egg-info/requires.txt requests_oauthlib.egg-info/top_level.txt requests_oauthlib/compliance_fixes/__init__.py requests_oauthlib/compliance_fixes/douban.py requests_oauthlib/compliance_fixes/facebook.py requests_oauthlib/compliance_fixes/fitbit.py requests_oauthlib/compliance_fixes/linkedin.py requests_oauthlib/compliance_fixes/mailchimp.py requests_oauthlib/compliance_fixes/plentymarkets.py requests_oauthlib/compliance_fixes/slack.py requests_oauthlib/compliance_fixes/weibo.py tests/__init__.py tests/__init__.pyc tests/test.bin tests/test_compliance_fixes.py tests/test_compliance_fixes.pyc tests/test_core.py tests/test_core.pyc tests/test_oauth1_session.py tests/test_oauth1_session.pyc tests/test_oauth2_auth.py tests/test_oauth2_auth.pyc tests/test_oauth2_session.py tests/test_oauth2_session.pyc tests/__pycache__/__init__.cpython-36.pyc tests/__pycache__/test_compliance_fixes.cpython-36-PYTEST.pyc tests/__pycache__/test_core.cpython-36-PYTEST.pyc tests/__pycache__/test_oauth1_session.cpython-36-PYTEST.pyc tests/__pycache__/test_oauth2_auth.cpython-36-PYTEST.pyc tests/__pycache__/test_oauth2_session.cpython-36-PYTEST.pycrequests-oauthlib-1.0.0/requests_oauthlib.egg-info/requires.txt0000644000076500000240000000011413305201162027174 0ustar singingwolfboystaff00000000000000oauthlib>=0.6.2 requests>=2.0.0 [rsa] oauthlib[rsa]>=0.6.2 requests>=2.0.0 requests-oauthlib-1.0.0/requests_oauthlib.egg-info/top_level.txt0000644000076500000240000000002213305201162027324 0ustar singingwolfboystaff00000000000000requests_oauthlib requests-oauthlib-1.0.0/requests_oauthlib.egg-info/dependency_links.txt0000644000076500000240000000000113305201162030646 0ustar singingwolfboystaff00000000000000