From: Kenneth Reitz Date: Tue, 27 Nov 2012 19:47:17 +0000 (-0800) Subject: no more oauth X-Git-Tag: v1.0.0~101 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4d06e4019f3a30a38fbdc3f59156f08f74d6c76e;p=services%2Fpython-requests.git no more oauth --- diff --git a/requests/_oauth.py b/requests/_oauth.py deleted file mode 100644 index 055154d..0000000 --- a/requests/_oauth.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -requests._oauth -~~~~~~~~~~~~~~~ - -This module contains the path hack necessary for oauthlib to be vendored into -requests while allowing upstream changes. -""" - -import os -import sys - -try: - from oauthlib.oauth1 import rfc5849 - from oauthlib.common import extract_params - from oauthlib.oauth1.rfc5849 import (Client, SIGNATURE_HMAC, SIGNATURE_TYPE_AUTH_HEADER) -except ImportError: - from .packages import oauthlib - sys.modules['oauthlib'] = oauthlib - from oauthlib.oauth1 import rfc5849 - from oauthlib.common import extract_params - from oauthlib.oauth1.rfc5849 import (Client, SIGNATURE_HMAC, SIGNATURE_TYPE_AUTH_HEADER) diff --git a/requests/packages/oauthlib/__init__.py b/requests/packages/oauthlib/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/requests/packages/oauthlib/common.py b/requests/packages/oauthlib/common.py deleted file mode 100644 index 70fb6a0..0000000 --- a/requests/packages/oauthlib/common.py +++ /dev/null @@ -1,229 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import - -""" -oauthlib.common -~~~~~~~~~~~~~~ - -This module provides data structures and utilities common -to all implementations of OAuth. -""" - -import random -import re -import string -import time -import urllib -import urlparse - -UNICODE_ASCII_CHARACTER_SET = (string.ascii_letters.decode('ascii') + - string.digits.decode('ascii')) - -always_safe = (u'ABCDEFGHIJKLMNOPQRSTUVWXYZ' - u'abcdefghijklmnopqrstuvwxyz' - u'0123456789' u'_.-') - - -def quote(s, safe=u'/'): - encoded = s.encode("utf-8") - quoted = urllib.quote(encoded, safe) - return quoted.decode("utf-8") - - -def unquote(s): - encoded = s.encode("utf-8") - unquoted = urllib.unquote(encoded) - return unquoted.decode("utf-8") - - -def urlencode(params): - utf8_params = encode_params_utf8(params) - urlencoded = urllib.urlencode(utf8_params) - return urlencoded.decode("utf-8") - - -def encode_params_utf8(params): - """Ensures that all parameters in a list of 2-element tuples are encoded to - bytestrings using UTF-8 - """ - encoded = [] - for k, v in params: - encoded.append(( - k.encode('utf-8') if isinstance(k, unicode) else k, - v.encode('utf-8') if isinstance(v, unicode) else v)) - return encoded - - -def decode_params_utf8(params): - """Ensures that all parameters in a list of 2-element tuples are decoded to - unicode using UTF-8. - """ - decoded = [] - for k, v in params: - decoded.append(( - k.decode('utf-8') if isinstance(k, str) else k, - v.decode('utf-8') if isinstance(v, str) else v)) - return decoded - - -urlencoded = set(always_safe) | set(u'=&;%+~') - - -def urldecode(query): - """Decode a query string in x-www-form-urlencoded format into a sequence - of two-element tuples. - - Unlike urlparse.parse_qsl(..., strict_parsing=True) urldecode will enforce - correct formatting of the query string by validation. If validation fails - a ValueError will be raised. urllib.parse_qsl will only raise errors if - any of name-value pairs omits the equals sign. - """ - # Check if query contains invalid characters - if query and not set(query) <= urlencoded: - raise ValueError('Invalid characters in query string.') - - # Check for correctly hex encoded values using a regular expression - # All encoded values begin with % followed by two hex characters - # correct = %00, %A0, %0A, %FF - # invalid = %G0, %5H, %PO - invalid_hex = u'%[^0-9A-Fa-f]|%[0-9A-Fa-f][^0-9A-Fa-f]' - if len(re.findall(invalid_hex, query)): - raise ValueError('Invalid hex encoding in query string.') - - query = query.decode('utf-8') if isinstance(query, str) else query - # We want to allow queries such as "c2" whereas urlparse.parse_qsl - # with the strict_parsing flag will not. - params = urlparse.parse_qsl(query, keep_blank_values=True) - - # unicode all the things - return decode_params_utf8(params) - - -def extract_params(raw): - """Extract parameters and return them as a list of 2-tuples. - - Will successfully extract parameters from urlencoded query strings, - dicts, or lists of 2-tuples. Empty strings/dicts/lists will return an - empty list of parameters. Any other input will result in a return - value of None. - """ - if isinstance(raw, basestring): - try: - params = urldecode(raw) - except ValueError: - params = None - elif hasattr(raw, '__iter__'): - try: - dict(raw) - except ValueError: - params = None - except TypeError: - params = None - else: - params = list(raw.items() if isinstance(raw, dict) else raw) - params = decode_params_utf8(params) - else: - params = None - - return params - - -def generate_nonce(): - """Generate pseudorandom nonce that is unlikely to repeat. - - Per `section 3.3`_ of the OAuth 1 RFC 5849 spec. - Per `section 3.2.1`_ of the MAC Access Authentication spec. - - A random 64-bit number is appended to the epoch timestamp for both - randomness and to decrease the likelihood of collisions. - - .. _`section 3.2.1`: http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01#section-3.2.1 - .. _`section 3.3`: http://tools.ietf.org/html/rfc5849#section-3.3 - """ - return unicode(unicode(random.getrandbits(64)) + generate_timestamp()) - - -def generate_timestamp(): - """Get seconds since epoch (UTC). - - Per `section 3.3`_ of the OAuth 1 RFC 5849 spec. - Per `section 3.2.1`_ of the MAC Access Authentication spec. - - .. _`section 3.2.1`: http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01#section-3.2.1 - .. _`section 3.3`: http://tools.ietf.org/html/rfc5849#section-3.3 - """ - return unicode(int(time.time())) - - -def generate_token(length=30, chars=UNICODE_ASCII_CHARACTER_SET): - """Generates a non-guessable OAuth token - - OAuth (1 and 2) does not specify the format of tokens except that they - should be strings of random characters. Tokens should not be guessable - and entropy when generating the random characters is important. Which is - why SystemRandom is used instead of the default random.choice method. - """ - rand = random.SystemRandom() - return u''.join(rand.choice(chars) for x in range(length)) - - -def add_params_to_qs(query, params): - """Extend a query with a list of two-tuples.""" - queryparams = urlparse.parse_qsl(query, keep_blank_values=True) - queryparams.extend(params) - return urlencode(queryparams) - - -def add_params_to_uri(uri, params): - """Add a list of two-tuples to the uri query components.""" - sch, net, path, par, query, fra = urlparse.urlparse(uri) - query = add_params_to_qs(query, params) - return urlparse.urlunparse((sch, net, path, par, query, fra)) - -def safe_string_equals(a, b): - """ Near-constant time string comparison. - - Used in order to avoid timing attacks on sensitive information such - as secret keys during request verification (`rootLabs`_). - - .. _`rootLabs`: http://rdist.root.org/2010/01/07/timing-independent-array-comparison/ - - """ - if len(a) != len(b): - return False - - result = 0 - for x, y in zip(a, b): - result |= ord(x) ^ ord(y) - return result == 0 - -class Request(object): - """A malleable representation of a signable HTTP request. - - Body argument may contain any data, but parameters will only be decoded if - they are one of: - - * urlencoded query string - * dict - * list of 2-tuples - - Anything else will be treated as raw body data to be passed through - unmolested. - """ - - def __init__(self, uri, http_method=u'GET', body=None, headers=None): - self.uri = uri - self.http_method = http_method - self.headers = headers or {} - self.body = body - self.decoded_body = extract_params(body) - self.oauth_params = [] - - @property - def uri_query(self): - return urlparse.urlparse(self.uri).query - - @property - def uri_query_params(self): - return urlparse.parse_qsl(self.uri_query, keep_blank_values=True, - strict_parsing=True) diff --git a/requests/packages/oauthlib/oauth1/__init__.py b/requests/packages/oauthlib/oauth1/__init__.py deleted file mode 100644 index ef692b5..0000000 --- a/requests/packages/oauthlib/oauth1/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import - -""" -oauthlib.oauth1 -~~~~~~~~~~~~~~ - -This module is a wrapper for the most recent implementation of OAuth 1.0 Client -and Server classes. -""" - -from .rfc5849 import Client, Server - diff --git a/requests/packages/oauthlib/oauth1/rfc5849/__init__.py b/requests/packages/oauthlib/oauth1/rfc5849/__init__.py deleted file mode 100644 index da3988d..0000000 --- a/requests/packages/oauthlib/oauth1/rfc5849/__init__.py +++ /dev/null @@ -1,889 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import - -""" -oauthlib.oauth1.rfc5849 -~~~~~~~~~~~~~~ - -This module is an implementation of various logic needed -for signing and checking OAuth 1.0 RFC 5849 requests. -""" - -import logging -import time -import urlparse - -from oauthlib.common import Request, urlencode, generate_nonce -from oauthlib.common import generate_timestamp -from . import parameters, signature, utils - -logger = logging.getLogger(__name__) - -SIGNATURE_HMAC = u"HMAC-SHA1" -SIGNATURE_RSA = u"RSA-SHA1" -SIGNATURE_PLAINTEXT = u"PLAINTEXT" -SIGNATURE_METHODS = (SIGNATURE_HMAC, SIGNATURE_RSA, SIGNATURE_PLAINTEXT) - -SIGNATURE_TYPE_AUTH_HEADER = u'AUTH_HEADER' -SIGNATURE_TYPE_QUERY = u'QUERY' -SIGNATURE_TYPE_BODY = u'BODY' - -CONTENT_TYPE_FORM_URLENCODED = u'application/x-www-form-urlencoded' - - -class Client(object): - """A client used to sign OAuth 1.0 RFC 5849 requests""" - 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): - self.client_key = client_key - self.client_secret = client_secret - self.resource_owner_key = resource_owner_key - self.resource_owner_secret = resource_owner_secret - self.signature_method = signature_method - self.signature_type = signature_type - self.callback_uri = callback_uri - self.rsa_key = rsa_key - self.verifier = verifier - - if self.signature_method == SIGNATURE_RSA and self.rsa_key is None: - raise ValueError('rsa_key is required when using RSA signature method.') - - def get_oauth_signature(self, request): - """Get an OAuth signature to be used in signing a request - """ - if self.signature_method == SIGNATURE_PLAINTEXT: - # fast-path - return signature.sign_plaintext(self.client_secret, - self.resource_owner_secret) - - uri, headers, body = self._render(request) - - collected_params = signature.collect_parameters( - uri_query=urlparse.urlparse(uri).query, - body=body, - headers=headers) - logger.debug("Collected params: {0}".format(collected_params)) - - normalized_params = signature.normalize_parameters(collected_params) - normalized_uri = signature.normalize_base_string_uri(request.uri) - logger.debug("Normalized params: {0}".format(normalized_params)) - logger.debug("Normalized URI: {0}".format(normalized_uri)) - - base_string = signature.construct_base_string(request.http_method, - normalized_uri, normalized_params) - - logger.debug("Base signing string: {0}".format(base_string)) - - if self.signature_method == SIGNATURE_HMAC: - sig = signature.sign_hmac_sha1(base_string, self.client_secret, - self.resource_owner_secret) - elif self.signature_method == SIGNATURE_RSA: - sig = signature.sign_rsa_sha1(base_string, self.rsa_key) - else: - sig = signature.sign_plaintext(self.client_secret, - self.resource_owner_secret) - - logger.debug("Signature: {0}".format(sig)) - return sig - - def get_oauth_params(self): - """Get the basic OAuth parameters to be used in generating a signature. - """ - params = [ - (u'oauth_nonce', generate_nonce()), - (u'oauth_timestamp', generate_timestamp()), - (u'oauth_version', u'1.0'), - (u'oauth_signature_method', self.signature_method), - (u'oauth_consumer_key', self.client_key), - ] - if self.resource_owner_key: - params.append((u'oauth_token', self.resource_owner_key)) - if self.callback_uri: - params.append((u'oauth_callback', self.callback_uri)) - if self.verifier: - params.append((u'oauth_verifier', self.verifier)) - - return params - - def _render(self, request, formencode=False): - """Render a signed request according to signature type - - Returns a 3-tuple containing the request URI, headers, and body. - - If the formencode argument is True and the body contains parameters, it - is escaped and returned as a valid formencoded string. - """ - # TODO what if there are body params on a header-type auth? - # TODO what if there are query params on a body-type auth? - - uri, headers, body = request.uri, request.headers, request.body - - # TODO: right now these prepare_* methods are very narrow in scope--they - # only affect their little thing. In some cases (for example, with - # header auth) it might be advantageous to allow these methods to touch - # other parts of the request, like the headers—so the prepare_headers - # method could also set the Content-Type header to x-www-form-urlencoded - # like the spec requires. This would be a fundamental change though, and - # I'm not sure how I feel about it. - if self.signature_type == SIGNATURE_TYPE_AUTH_HEADER: - headers = parameters.prepare_headers(request.oauth_params, request.headers) - elif self.signature_type == SIGNATURE_TYPE_BODY and request.decoded_body is not None: - body = parameters.prepare_form_encoded_body(request.oauth_params, request.decoded_body) - if formencode: - body = urlencode(body) - headers['Content-Type'] = u'application/x-www-form-urlencoded' - elif self.signature_type == SIGNATURE_TYPE_QUERY: - uri = parameters.prepare_request_uri_query(request.oauth_params, request.uri) - else: - raise ValueError('Unknown signature type specified.') - - return uri, headers, body - - def sign(self, uri, http_method=u'GET', body=None, headers=None): - """Sign a request - - Signs an HTTP request with the specified parts. - - Returns a 3-tuple of the signed request's URI, headers, and body. - Note that http_method is not returned as it is unaffected by the OAuth - signing process. - - The body argument may be a dict, a list of 2-tuples, or a formencoded - string. The Content-Type header must be 'application/x-www-form-urlencoded' - if it is present. - - If the body argument is not one of the above, it will be returned - verbatim as it is unaffected by the OAuth signing process. Attempting to - sign a request with non-formencoded data using the OAuth body signature - type is invalid and will raise an exception. - - If the body does contain parameters, it will be returned as a properly- - formatted formencoded string. - - All string data MUST be unicode. This includes strings inside body - dicts, for example. - """ - # normalize request data - request = Request(uri, http_method, body, headers) - - # sanity check - content_type = request.headers.get('Content-Type', None) - multipart = content_type and content_type.startswith('multipart/') - should_have_params = content_type == CONTENT_TYPE_FORM_URLENCODED - has_params = request.decoded_body is not None - # 3.4.1.3.1. Parameter Sources - # [Parameters are collected from the HTTP request entity-body, but only - # if [...]: - # * The entity-body is single-part. - if multipart and has_params: - raise ValueError("Headers indicate a multipart body but body contains parameters.") - # * The entity-body follows the encoding requirements of the - # "application/x-www-form-urlencoded" content-type as defined by - # [W3C.REC-html40-19980424]. - elif should_have_params and not has_params: - raise ValueError("Headers indicate a formencoded body but body was not decodable.") - # * The HTTP request entity-header includes the "Content-Type" - # header field set to "application/x-www-form-urlencoded". - elif not should_have_params and has_params: - raise ValueError("Body contains parameters but Content-Type header was not set.") - - # 3.5.2. Form-Encoded Body - # Protocol parameters can be transmitted in the HTTP request entity- - # body, but only if the following REQUIRED conditions are met: - # o The entity-body is single-part. - # o The entity-body follows the encoding requirements of the - # "application/x-www-form-urlencoded" content-type as defined by - # [W3C.REC-html40-19980424]. - # o The HTTP request entity-header includes the "Content-Type" header - # field set to "application/x-www-form-urlencoded". - elif self.signature_type == SIGNATURE_TYPE_BODY and not ( - should_have_params and has_params and not multipart): - raise ValueError('Body signatures may only be used with form-urlencoded content') - - # generate the basic OAuth parameters - request.oauth_params = self.get_oauth_params() - - # generate the signature - request.oauth_params.append((u'oauth_signature', self.get_oauth_signature(request))) - - # render the signed request and return it - return self._render(request, formencode=True) - - -class Server(object): - """A server base class used to verify OAuth 1.0 RFC 5849 requests - - OAuth providers should inherit from Server and implement the methods - and properties outlined below. Further details are provided in the - documentation for each method and property. - - Methods used to check the format of input parameters. Common tests include - length, character set, membership, range or pattern. These tests are - referred to as `whitelisting or blacklisting`_. Whitelisting is better - but blacklisting can be usefull to spot malicious activity. - The following have methods a default implementation: - - - check_client_key - - check_request_token - - check_access_token - - check_nonce - - check_verifier - - check_realm - - The methods above default to whitelist input parameters, checking that they - are alphanumerical and between a minimum and maximum length. Rather than - overloading the methods a few properties can be used to configure these - methods. - - @ safe_characters -> (character set) - @ client_key_length -> (min, max) - @ request_token_length -> (min, max) - @ access_token_length -> (min, max) - @ nonce_length -> (min, max) - @ verifier_length -> (min, max) - @ realms -> [list, of, realms] - - Methods used to validate input parameters. These checks usually hit either - persistent or temporary storage such as databases or the filesystem. See - each methods documentation for detailed usage. - The following methods must be implemented: - - - validate_client - - validate_request_token - - validate_access_token - - validate_nonce_and_timestamp - - validate_redirect_uri - - validate_requested_realm - - validate_realm - - validate_verifier - - Method used to retrieve sensitive information from storage. - The following methods must be implemented: - - - get_client_secret - - get_request_token_secret - - get_access_token_secret - - get_rsa_key - - To prevent timing attacks it is necessary to not exit early even if the - client key or resource owner key is invalid. Instead dummy values should - be used during the remaining verification process. It is very important - that the dummy client and token are valid input parameters to the methods - get_client_secret, get_rsa_key and get_(access/request)_token_secret and - that the running time of those methods when given a dummy value remain - equivalent to the running time when given a valid client/resource owner. - The following properties must be implemented: - - @ dummy_client - @ dummy_request_token - @ dummy_access_token - - .. _`whitelisting or blacklisting`: http://www.schneier.com/blog/archives/2011/01/whitelisting_vs.html - """ - - def __init__(self): - pass - - @property - def allowed_signature_methods(self): - return SIGNATURE_METHODS - - @property - def safe_characters(self): - return set(utils.UNICODE_ASCII_CHARACTER_SET) - - @property - def client_key_length(self): - return 20, 30 - - @property - def request_token_length(self): - return 20, 30 - - @property - def access_token_length(self): - return 20, 30 - - @property - def timestamp_lifetime(self): - return 600 - - @property - def nonce_length(self): - return 20, 30 - - @property - def verifier_length(self): - return 20, 30 - - @property - def realms(self): - return [] - - @property - def enforce_ssl(self): - return True - - def check_client_key(self, client_key): - """Check that the client key only contains safe characters - and is no shorter than lower and no longer than upper. - """ - lower, upper = self.client_key_length - return (set(client_key) <= self.safe_characters and - lower <= len(client_key) <= upper) - - def check_request_token(self, request_token): - """Checks that the request token contains only safe characters - and is no shorter than lower and no longer than upper. - """ - lower, upper = self.request_token_length - return (set(request_token) <= self.safe_characters and - lower <= len(request_token) <= upper) - - def check_access_token(self, request_token): - """Checks that the token contains only safe characters - and is no shorter than lower and no longer than upper. - """ - lower, upper = self.access_token_length - return (set(request_token) <= self.safe_characters and - lower <= len(request_token) <= upper) - - def check_nonce(self, nonce): - """Checks that the nonce only contains only safe characters - and is no shorter than lower and no longer than upper. - """ - lower, upper = self.nonce_length - return (set(nonce) <= self.safe_characters and - lower <= len(nonce) <= upper) - - def check_verifier(self, verifier): - """Checks that the verifier contains only safe characters - and is no shorter than lower and no longer than upper. - """ - lower, upper = self.verifier_length - return (set(verifier) <= self.safe_characters and - lower <= len(verifier) <= upper) - - def check_realm(self, realm): - """Check that the realm is one of a set allowed realms. - """ - return realm in self.realms - - def get_client_secret(self, client_key): - """Retrieves the client secret associated with the client key. - - This method must allow the use of a dummy client_key value. - Fetching the secret using the dummy key must take the same amount of - time as fetching a secret for a valid client. - - Note that the returned key must be in plaintext. - """ - raise NotImplementedError("Subclasses must implement this function.") - - @property - def dummy_client(self): - """Dummy client used when an invalid client key is supplied. - - The dummy client should be associated with either a client secret, - a rsa key or both depending on which signature methods are supported. - Providers should make sure that - - get_client_secret(dummy_client) - get_rsa_key(dummy_client) - - return a valid secret or key for the dummy client. - """ - raise NotImplementedError("Subclasses must implement this function.") - - def get_request_token_secret(self, client_key, request_token): - """Retrieves the shared secret associated with the request token. - - This method must allow the use of a dummy values and the running time - must be roughly equivalent to that of the running time of valid values. - - Note that the returned key must be in plaintext. - """ - raise NotImplementedError("Subclasses must implement this function.") - - def get_access_token_secret(self, client_key, access_token): - """Retrieves the shared secret associated with the access token. - - This method must allow the use of a dummy values and the running time - must be roughly equivalent to that of the running time of valid values. - - Note that the returned key must be in plaintext. - """ - raise NotImplementedError("Subclasses must implement this function.") - - @property - def dummy_request_token(self): - """Dummy request token used when an invalid token was supplied. - - The dummy request token should be associated with a request token - secret such that get_request_token_secret(.., dummy_request_token) - returns a valid secret. - """ - raise NotImplementedError("Subclasses must implement this function.") - - @property - def dummy_access_token(self): - """Dummy access token used when an invalid token was supplied. - - The dummy access token should be associated with an access token - secret such that get_access_token_secret(.., dummy_access_token) - returns a valid secret. - """ - raise NotImplementedError("Subclasses must implement this function.") - - def get_rsa_key(self, client_key): - """Retrieves a previously stored client provided RSA key. - - This method must allow the use of a dummy client_key value. Fetching - the rsa key using the dummy key must take the same aount of time - as fetching a key for a valid client. - - Note that the key must be returned in plaintext. - """ - raise NotImplementedError("Subclasses must implement this function.") - - def get_signature_type_and_params(self, request): - """Extracts parameters from query, headers and body. Signature type - is set to the source in which parameters were found. - """ - header_params = signature.collect_parameters(headers=request.headers, - exclude_oauth_signature=False) - body_params = signature.collect_parameters(body=request.body, - exclude_oauth_signature=False) - query_params = signature.collect_parameters(uri_query=request.uri_query, - exclude_oauth_signature=False) - - params = [] - params.extend(header_params) - params.extend(body_params) - params.extend(query_params) - signature_types_with_oauth_params = filter(lambda s: s[2], ( - (SIGNATURE_TYPE_AUTH_HEADER, params, - utils.filter_oauth_params(header_params)), - (SIGNATURE_TYPE_BODY, params, - utils.filter_oauth_params(body_params)), - (SIGNATURE_TYPE_QUERY, params, - utils.filter_oauth_params(query_params)) - )) - - if len(signature_types_with_oauth_params) > 1: - raise ValueError('oauth_ params must come from only 1 signature type but were found in %s' % ', '.join( - [s[0] for s in signature_types_with_oauth_params])) - try: - signature_type, params, oauth_params = signature_types_with_oauth_params[0] - except IndexError: - raise ValueError('oauth_ params are missing. Could not determine signature type.') - - return signature_type, params, oauth_params - - def validate_client_key(self, client_key): - """Validates that supplied client key is a registered and valid client. - - Note that if the dummy client is supplied it should validate in same - or nearly the same amount of time as a valid one. - - Bad: - - if client_key == self.dummy_client: - return False - else: - return storage.has_client(client_key) - - Good: - - return storage.has_client(client_key) and client_key != self.dummy_client - """ - raise NotImplementedError("Subclasses must implement this function.") - - def validate_request_token(self, client_key, request_token): - """Validates that supplied request token is registered and valid. - - Note that if the dummy request_token is supplied it should validate in - the same nearly the same amount of time as a valid one. - - Bad: - - if request_token == self.dummy_request_token: - return False - else: - return storage.has_request_token(request_token) - - Good: - - return (storage.has_request_token(request_token) and - request_token != self.dummy_request_token) - """ - raise NotImplementedError("Subclasses must implement this function.") - - def validate_access_token(self, client_key, access_token): - """Validates that supplied access token is registered and valid. - - Note that if the dummy access token is supplied it should validate in - the same or nearly the same amount of time as a valid one. - - Bad: - - if access_token == self.dummy_access_token: - return False - else: - return storage.has_access_token(access_token) - - Good: - - return (storage.has_access_token(access_token) and - access_token != self.dummy_access_token) - """ - raise NotImplementedError("Subclasses must implement this function.") - - def validate_timestamp_and_nonce(self, client_key, timestamp, nonce, - request_token=None, access_token=None): - """Validates that the nonce has not been used before. - - Per `Section 3.3`_ of the spec. - - "A nonce is a random string, uniquely generated by the client to allow - the server to verify that a request has never been made before and - helps prevent replay attacks when requests are made over a non-secure - channel. The nonce value MUST be unique across all requests with the - same timestamp, client credentials, and token combinations." - - .. _`Section 3.3`: http://tools.ietf.org/html/rfc5849#section-3.3 - - """ - raise NotImplementedError("Subclasses must implement this function.") - - def validate_redirect_uri(self, client_key, redirect_uri): - """Validates the client supplied redirection URI. - - It is highly recommended that OAuth providers require their clients - to register all redirection URIs prior to using them in requests and - register them as absolute URIs. See `CWE-601`_ for more information - about open redirection attacks. - - By requiring registration of all redirection URIs it should be - straightforward for the provider to verify whether the supplied - redirect_uri is valid or not. - - .. _`CWE-601`: http://cwe.mitre.org/top25/index.html#CWE-601 - """ - raise NotImplementedError("Subclasses must implement this function.") - - - def validate_requested_realm(self, client_key, realm): - """Validates that the client may request access to the realm. - - This method is invoked when obtaining a request token and should - tie a realm to the request token and after user authorization - this realm restriction should transfer to the access token. - """ - raise NotImplementedError("Subclasses must implement this function.") - - def validate_realm(self, client_key, access_token, uri=None, - required_realm=None): - """Validates access to the request realm. - - How providers choose to use the realm parameter is outside the OAuth - specification but it is commonly used to restrict access to a subset - of protected resources such as "photos". - - required_realm is a convenience parameter which can be used to provide - a per view method pre-defined list of allowed realms. - """ - raise NotImplementedError("Subclasses must implement this function.") - - def validate_verifier(self, client_key, request_token, verifier): - """Validates a verification code. - - OAuth providers issue a verification code to clients after the - resource owner authorizes access. This code is used by the client to - obtain token credentials and the provider must verify that the - verifier is valid and associated with the client as well as the - resource owner. - """ - raise NotImplementedError("Subclasses must implement this function.") - - def verify_request(self, uri, http_method=u'GET', body=None, - headers=None, require_resource_owner=True, require_verifier=False, - require_realm=False, required_realm=None): - """Verifies a request ensuring that the following is true: - - Per `section 3.2`_ of the spec. - - - all mandated OAuth parameters are supplied - - parameters are only supplied in one source which may be the URI - query, the Authorization header or the body - - all parameters are checked and validated, see comments and the - methods and properties of this class for further details. - - the supplied signature is verified against a recalculated one - - A ValueError will be raised if any parameter is missing, - supplied twice or invalid. A HTTP 400 Response should be returned - upon catching an exception. - - A HTTP 401 Response should be returned if verify_request returns False. - - `Timing attacks`_ are prevented through the use of dummy credentials to - create near constant time verification even if an invalid credential - is used. Early exit on invalid credentials would enable attackers - to perform `enumeration attacks`_. Near constant time string comparison - is used to prevent secret key guessing. Note that timing attacks can - only be prevented through near constant time execution, not by adding - a random delay which would only require more samples to be gathered. - - .. _`section 3.2`: http://tools.ietf.org/html/rfc5849#section-3.2 - .. _`Timing attacks`: http://rdist.root.org/2010/07/19/exploiting-remote-timing-attacks/ - .. _`enumeration attacks`: http://www.sans.edu/research/security-laboratory/article/attacks-browsing - """ - # Only include body data from x-www-form-urlencoded requests - headers = headers or {} - if (u"Content-Type" in headers and - headers[u"Content-Type"] == CONTENT_TYPE_FORM_URLENCODED): - request = Request(uri, http_method, body, headers) - else: - request = Request(uri, http_method, u'', headers) - - if self.enforce_ssl and not request.uri.lower().startswith("https://"): - raise ValueError("Insecure transport, only HTTPS is allowed.") - - signature_type, params, oauth_params = self.get_signature_type_and_params(request) - - # The server SHOULD return a 400 (Bad Request) status code when - # receiving a request with duplicated protocol parameters. - if len(dict(oauth_params)) != len(oauth_params): - raise ValueError("Duplicate OAuth entries.") - - oauth_params = dict(oauth_params) - request_signature = oauth_params.get(u'oauth_signature') - client_key = oauth_params.get(u'oauth_consumer_key') - resource_owner_key = oauth_params.get(u'oauth_token') - nonce = oauth_params.get(u'oauth_nonce') - timestamp = oauth_params.get(u'oauth_timestamp') - callback_uri = oauth_params.get(u'oauth_callback') - verifier = oauth_params.get(u'oauth_verifier') - signature_method = oauth_params.get(u'oauth_signature_method') - realm = dict(params).get(u'realm') - - # The server SHOULD return a 400 (Bad Request) status code when - # receiving a request with missing parameters. - if not all((request_signature, client_key, nonce, - timestamp, signature_method)): - raise ValueError("Missing OAuth parameters.") - - # OAuth does not mandate a particular signature method, as each - # implementation can have its own unique requirements. Servers are - # free to implement and document their own custom methods. - # Recommending any particular method is beyond the scope of this - # specification. Implementers should review the Security - # Considerations section (`Section 4`_) before deciding on which - # method to support. - # .. _`Section 4`: http://tools.ietf.org/html/rfc5849#section-4 - if not signature_method in self.allowed_signature_methods: - raise ValueError("Invalid signature method.") - - # Servers receiving an authenticated request MUST validate it by: - # If the "oauth_version" parameter is present, ensuring its value is - # "1.0". - if u'oauth_version' in oauth_params and oauth_params[u'oauth_version'] != u'1.0': - raise ValueError("Invalid OAuth version.") - - # The timestamp value MUST be a positive integer. Unless otherwise - # specified by the server's documentation, the timestamp is expressed - # in the number of seconds since January 1, 1970 00:00:00 GMT. - if len(timestamp) != 10: - raise ValueError("Invalid timestamp size") - try: - ts = int(timestamp) - - except ValueError: - raise ValueError("Timestamp must be an integer") - - else: - # To avoid the need to retain an infinite number of nonce values for - # future checks, servers MAY choose to restrict the time period after - # which a request with an old timestamp is rejected. - if time.time() - ts > self.timestamp_lifetime: - raise ValueError("Request too old, over 10 minutes.") - - # Provider specific validation of parameters, used to enforce - # restrictions such as character set and length. - if not self.check_client_key(client_key): - raise ValueError("Invalid client key.") - - if not resource_owner_key and require_resource_owner: - raise ValueError("Missing resource owner.") - - if (require_resource_owner and not require_verifier and - not self.check_access_token(resource_owner_key)): - raise ValueError("Invalid resource owner key.") - - if (require_resource_owner and require_verifier and - not self.check_request_token(resource_owner_key)): - raise ValueError("Invalid resource owner key.") - - if not self.check_nonce(nonce): - raise ValueError("Invalid nonce.") - - if realm and not self.check_realm(realm): - raise ValueError("Invalid realm. Allowed are %s" % self.realms) - - if not verifier and require_verifier: - raise ValueError("Missing verifier.") - - if require_verifier and not self.check_verifier(verifier): - raise ValueError("Invalid verifier.") - - # Servers receiving an authenticated request MUST validate it by: - # If using the "HMAC-SHA1" or "RSA-SHA1" signature methods, ensuring - # that the combination of nonce/timestamp/token (if present) - # received from the client has not been used before in a previous - # request (the server MAY reject requests with stale timestamps as - # described in `Section 3.3`_). - # .._`Section 3.3`: http://tools.ietf.org/html/rfc5849#section-3.3 - # - # We check this before validating client and resource owner for - # increased security and performance, both gained by doing less work. - if require_verifier: - token = {"request_token": resource_owner_key} - else: - token = {"access_token": resource_owner_key} - if not self.validate_timestamp_and_nonce(client_key, timestamp, - nonce, **token): - return False - - # The server SHOULD return a 401 (Unauthorized) status code when - # receiving a request with invalid client credentials. - # Note: This is postponed in order to avoid timing attacks, instead - # a dummy client is assigned and used to maintain near constant - # time request verification. - # - # Note that early exit would enable client enumeration - valid_client = self.validate_client_key(client_key) - if not valid_client: - client_key = self.dummy_client - - # Ensure a valid redirection uri is used - valid_redirect = self.validate_redirect_uri(client_key, callback_uri) - - # The server SHOULD return a 401 (Unauthorized) status code when - # receiving a request with invalid or expired token. - # Note: This is postponed in order to avoid timing attacks, instead - # a dummy token is assigned and used to maintain near constant - # time request verification. - # - # Note that early exit would enable resource owner enumeration - if resource_owner_key: - if require_verifier: - valid_resource_owner = self.validate_request_token( - client_key, resource_owner_key) - else: - valid_resource_owner = self.validate_access_token( - client_key, resource_owner_key) - if not valid_resource_owner: - resource_owner_key = self.dummy_resource_owner - else: - valid_resource_owner = True - - # Note that `realm`_ is only used in authorization headers and how - # it should be interepreted is not included in the OAuth spec. - # However they could be seen as a scope or realm to which the - # client has access and as such every client should be checked - # to ensure it is authorized access to that scope or realm. - # .. _`realm`: http://tools.ietf.org/html/rfc2617#section-1.2 - # - # Note that early exit would enable client realm access enumeration. - # - # The require_realm indicates this is the first step in the OAuth - # workflow where a client requests access to a specific realm. - # - # Clients obtaining an access token will not supply a realm and it will - # not be checked. Instead the previously requested realm should be - # transferred from the request token to the access token. - # - # Access to protected resources will always validate the realm but note - # that the realm is now tied to the access token and not provided by - # the client. - if require_realm and not resource_owner_key: - valid_realm = self.validate_requested_realm(client_key, realm) - elif require_verifier: - valid_realm = True - else: - valid_realm = self.validate_realm(client_key, resource_owner_key, - uri=request.uri, required_realm=required_realm) - - # The server MUST verify (Section 3.2) the validity of the request, - # ensure that the resource owner has authorized the provisioning of - # token credentials to the client, and ensure that the temporary - # credentials have not expired or been used before. The server MUST - # also verify the verification code received from the client. - # .. _`Section 3.2`: http://tools.ietf.org/html/rfc5849#section-3.2 - # - # Note that early exit would enable resource owner authorization - # verifier enumertion. - if verifier: - valid_verifier = self.validate_verifier(client_key, - resource_owner_key, verifier) - else: - valid_verifier = True - - # Parameters to Client depend on signature method which may vary - # for each request. Note that HMAC-SHA1 and PLAINTEXT share parameters - - request.params = filter(lambda x: x[0] != "oauth_signature", params) - request.signature = request_signature - - # ---- RSA Signature verification ---- - if signature_method == SIGNATURE_RSA: - # The server verifies the signature per `[RFC3447] section 8.2.2`_ - # .. _`[RFC3447] section 8.2.2`: http://tools.ietf.org/html/rfc3447#section-8.2.1 - rsa_key = self.get_rsa_key(client_key) - valid_signature = signature.verify_rsa_sha1(request, rsa_key) - - # ---- HMAC or Plaintext Signature verification ---- - else: - # Servers receiving an authenticated request MUST validate it by: - # Recalculating the request signature independently as described in - # `Section 3.4`_ and comparing it to the value received from the - # client via the "oauth_signature" parameter. - # .. _`Section 3.4`: http://tools.ietf.org/html/rfc5849#section-3.4 - client_secret = self.get_client_secret(client_key) - if require_verifier: - resource_owner_secret = self.get_request_token_secret( - client_key, resource_owner_key) - else: - resource_owner_secret = self.get_access_token_secret( - client_key, resource_owner_key) - - if signature_method == SIGNATURE_HMAC: - valid_signature = signature.verify_hmac_sha1(request, - client_secret, resource_owner_secret) - else: - valid_signature = signature.verify_plaintext(request, - client_secret, resource_owner_secret) - - # We delay checking validity until the very end, using dummy values for - # calculations and fetching secrets/keys to ensure the flow of every - # request remains almost identical regardless of whether valid values - # have been supplied. This ensures near constant time execution and - # prevents malicious users from guessing sensitive information - v = all((valid_client, valid_resource_owner, valid_realm, - valid_redirect, valid_verifier, valid_signature)) - logger = logging.getLogger("oauthlib") - if not v: - logger.info("[Failure] OAuthLib request verification failed.") - logger.info("Valid client:\t%s" % valid_client) - logger.info("Valid token:\t%s\t(Required: %s" % (valid_resource_owner, require_resource_owner)) - logger.info("Valid realm:\t%s\t(Required: %s)" % (valid_realm, require_realm)) - logger.info("Valid callback:\t%s" % valid_redirect) - logger.info("Valid verifier:\t%s\t(Required: %s)" % (valid_verifier, require_verifier)) - logger.info("Valid signature:\t%s" % valid_signature) - return v diff --git a/requests/packages/oauthlib/oauth1/rfc5849/parameters.py b/requests/packages/oauthlib/oauth1/rfc5849/parameters.py deleted file mode 100644 index dee23a4..0000000 --- a/requests/packages/oauthlib/oauth1/rfc5849/parameters.py +++ /dev/null @@ -1,134 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import - -""" -oauthlib.parameters -~~~~~~~~~~~~~~~~~~~ - -This module contains methods related to `section 3.5`_ of the OAuth 1.0a spec. - -.. _`section 3.5`: http://tools.ietf.org/html/rfc5849#section-3.5 -""" - -from urlparse import urlparse, urlunparse -from . import utils -from oauthlib.common import extract_params, urlencode - - -# TODO: do we need filter_params now that oauth_params are handled by Request? -# We can easily pass in just oauth protocol params. -@utils.filter_params -def prepare_headers(oauth_params, headers=None, realm=None): - """**Prepare the Authorization header.** - Per `section 3.5.1`_ of the spec. - - Protocol parameters can be transmitted using the HTTP "Authorization" - header field as defined by `RFC2617`_ with the auth-scheme name set to - "OAuth" (case insensitive). - - For example:: - - Authorization: OAuth realm="Example", - oauth_consumer_key="0685bd9184jfhq22", - oauth_token="ad180jjd733klru7", - oauth_signature_method="HMAC-SHA1", - oauth_signature="wOJIO9A2W5mFwDgiDvZbTSMK%2FPY%3D", - oauth_timestamp="137131200", - oauth_nonce="4572616e48616d6d65724c61686176", - oauth_version="1.0" - - - .. _`section 3.5.1`: http://tools.ietf.org/html/rfc5849#section-3.5.1 - .. _`RFC2617`: http://tools.ietf.org/html/rfc2617 - """ - headers = headers or {} - - # Protocol parameters SHALL be included in the "Authorization" header - # field as follows: - authorization_header_parameters_parts = [] - for oauth_parameter_name, value in oauth_params: - # 1. Parameter names and values are encoded per Parameter Encoding - # (`Section 3.6`_) - # - # .. _`Section 3.6`: http://tools.ietf.org/html/rfc5849#section-3.6 - escaped_name = utils.escape(oauth_parameter_name) - escaped_value = utils.escape(value) - - # 2. Each parameter's name is immediately followed by an "=" character - # (ASCII code 61), a """ character (ASCII code 34), the parameter - # value (MAY be empty), and another """ character (ASCII code 34). - part = u'{0}="{1}"'.format(escaped_name, escaped_value) - - authorization_header_parameters_parts.append(part) - - # 3. Parameters are separated by a "," character (ASCII code 44) and - # OPTIONAL linear whitespace per `RFC2617`_. - # - # .. _`RFC2617`: http://tools.ietf.org/html/rfc2617 - authorization_header_parameters = ', '.join( - authorization_header_parameters_parts) - - # 4. The OPTIONAL "realm" parameter MAY be added and interpreted per - # `RFC2617 section 1.2`_. - # - # .. _`RFC2617 section 1.2`: http://tools.ietf.org/html/rfc2617#section-1.2 - if realm: - # NOTE: realm should *not* be escaped - authorization_header_parameters = (u'realm="%s", ' % realm + - authorization_header_parameters) - - # the auth-scheme name set to "OAuth" (case insensitive). - authorization_header = u'OAuth %s' % authorization_header_parameters - - # contribute the Authorization header to the given headers - full_headers = {} - full_headers.update(headers) - full_headers[u'Authorization'] = authorization_header - return full_headers - - -def _append_params(oauth_params, params): - """Append OAuth params to an existing set of parameters. - - Both params and oauth_params is must be lists of 2-tuples. - - Per `section 3.5.2`_ and `3.5.3`_ of the spec. - - .. _`section 3.5.2`: http://tools.ietf.org/html/rfc5849#section-3.5.2 - .. _`3.5.3`: http://tools.ietf.org/html/rfc5849#section-3.5.3 - - """ - merged = list(params) - merged.extend(oauth_params) - # The request URI / entity-body MAY include other request-specific - # parameters, in which case, the protocol parameters SHOULD be appended - # following the request-specific parameters, properly separated by an "&" - # character (ASCII code 38) - merged.sort(key=lambda i: i[0].startswith('oauth_')) - return merged - - -def prepare_form_encoded_body(oauth_params, body): - """Prepare the Form-Encoded Body. - - Per `section 3.5.2`_ of the spec. - - .. _`section 3.5.2`: http://tools.ietf.org/html/rfc5849#section-3.5.2 - - """ - # append OAuth params to the existing body - return _append_params(oauth_params, body) - - -def prepare_request_uri_query(oauth_params, uri): - """Prepare the Request URI Query. - - Per `section 3.5.3`_ of the spec. - - .. _`section 3.5.3`: http://tools.ietf.org/html/rfc5849#section-3.5.3 - - """ - # append OAuth params to the existing set of query components - sch, net, path, par, query, fra = urlparse(uri) - query = urlencode(_append_params(oauth_params, extract_params(query) or [])) - return urlunparse((sch, net, path, par, query, fra)) diff --git a/requests/packages/oauthlib/oauth1/rfc5849/signature.py b/requests/packages/oauthlib/oauth1/rfc5849/signature.py deleted file mode 100644 index dbd43aa..0000000 --- a/requests/packages/oauthlib/oauth1/rfc5849/signature.py +++ /dev/null @@ -1,551 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import -""" -oauthlib.oauth1.rfc5849.signature -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This module represents a direct implementation of `section 3.4`_ of the spec. - -Terminology: - * Client: software interfacing with an OAuth API - * Server: the API provider - * Resource Owner: the user who is granting authorization to the client - -Steps for signing a request: - -1. Collect parameters from the uri query, auth header, & body -2. Normalize those parameters -3. Normalize the uri -4. Pass the normalized uri, normalized parameters, and http method to - construct the base string -5. Pass the base string and any keys needed to a signing function - -.. _`section 3.4`: http://tools.ietf.org/html/rfc5849#section-3.4 -""" -import binascii -import hashlib -import hmac -import urlparse -from . import utils -from oauthlib.common import extract_params, safe_string_equals - - -def construct_base_string(http_method, base_string_uri, - normalized_encoded_request_parameters): - """**String Construction** - Per `section 3.4.1.1`_ of the spec. - - For example, the HTTP request:: - - POST /request?b5=%3D%253D&a3=a&c%40=&a2=r%20b HTTP/1.1 - Host: example.com - Content-Type: application/x-www-form-urlencoded - Authorization: OAuth realm="Example", - oauth_consumer_key="9djdj82h48djs9d2", - oauth_token="kkk9d7dh3k39sjv7", - oauth_signature_method="HMAC-SHA1", - oauth_timestamp="137131201", - oauth_nonce="7d8f3e4a", - oauth_signature="bYT5CMsGcbgUdFHObYMEfcx6bsw%3D" - - c2&a3=2+q - - is represented by the following signature base string (line breaks - are for display purposes only):: - - POST&http%3A%2F%2Fexample.com%2Frequest&a2%3Dr%2520b%26a3%3D2%2520q - %26a3%3Da%26b5%3D%253D%25253D%26c%2540%3D%26c2%3D%26oauth_consumer_ - key%3D9djdj82h48djs9d2%26oauth_nonce%3D7d8f3e4a%26oauth_signature_m - ethod%3DHMAC-SHA1%26oauth_timestamp%3D137131201%26oauth_token%3Dkkk - 9d7dh3k39sjv7 - - .. _`section 3.4.1.1`: http://tools.ietf.org/html/rfc5849#section-3.4.1.1 - """ - - # The signature base string is constructed by concatenating together, - # in order, the following HTTP request elements: - - # 1. The HTTP request method in uppercase. For example: "HEAD", - # "GET", "POST", etc. If the request uses a custom HTTP method, it - # MUST be encoded (`Section 3.6`_). - # - # .. _`Section 3.6`: http://tools.ietf.org/html/rfc5849#section-3.6 - base_string = utils.escape(http_method.upper()) - - # 2. An "&" character (ASCII code 38). - base_string += u'&' - - # 3. The base string URI from `Section 3.4.1.2`_, after being encoded - # (`Section 3.6`_). - # - # .. _`Section 3.4.1.2`: http://tools.ietf.org/html/rfc5849#section-3.4.1.2 - # .. _`Section 3.4.6`: http://tools.ietf.org/html/rfc5849#section-3.4.6 - base_string += utils.escape(base_string_uri) - - # 4. An "&" character (ASCII code 38). - base_string += u'&' - - # 5. The request parameters as normalized in `Section 3.4.1.3.2`_, after - # being encoded (`Section 3.6`). - # - # .. _`Section 3.4.1.3.2`: http://tools.ietf.org/html/rfc5849#section-3.4.1.3.2 - # .. _`Section 3.4.6`: http://tools.ietf.org/html/rfc5849#section-3.4.6 - base_string += utils.escape(normalized_encoded_request_parameters) - - return base_string - - -def normalize_base_string_uri(uri): - """**Base String URI** - Per `section 3.4.1.2`_ of the spec. - - For example, the HTTP request:: - - GET /r%20v/X?id=123 HTTP/1.1 - Host: EXAMPLE.COM:80 - - is represented by the base string URI: "http://example.com/r%20v/X". - - In another example, the HTTPS request:: - - GET /?q=1 HTTP/1.1 - Host: www.example.net:8080 - - is represented by the base string URI: "https://www.example.net:8080/". - - .. _`section 3.4.1.2`: http://tools.ietf.org/html/rfc5849#section-3.4.1.2 - """ - if not isinstance(uri, unicode): - raise ValueError('uri must be a unicode object.') - - # FIXME: urlparse does not support unicode - scheme, netloc, path, params, query, fragment = urlparse.urlparse(uri) - - # The scheme, authority, and path of the request resource URI `RFC3986` - # are included by constructing an "http" or "https" URI representing - # the request resource (without the query or fragment) as follows: - # - # .. _`RFC2616`: http://tools.ietf.org/html/rfc3986 - - # 1. The scheme and host MUST be in lowercase. - scheme = scheme.lower() - netloc = netloc.lower() - - # 2. The host and port values MUST match the content of the HTTP - # request "Host" header field. - # TODO: enforce this constraint - - # 3. The port MUST be included if it is not the default port for the - # scheme, and MUST be excluded if it is the default. Specifically, - # the port MUST be excluded when making an HTTP request `RFC2616`_ - # to port 80 or when making an HTTPS request `RFC2818`_ to port 443. - # All other non-default port numbers MUST be included. - # - # .. _`RFC2616`: http://tools.ietf.org/html/rfc2616 - # .. _`RFC2818`: http://tools.ietf.org/html/rfc2818 - default_ports = ( - (u'http', u'80'), - (u'https', u'443'), - ) - if u':' in netloc: - host, port = netloc.split(u':', 1) - if (scheme, port) in default_ports: - netloc = host - - return urlparse.urlunparse((scheme, netloc, path, u'', u'', u'')) - - -# ** Request Parameters ** -# -# Per `section 3.4.1.3`_ of the spec. -# -# In order to guarantee a consistent and reproducible representation of -# the request parameters, the parameters are collected and decoded to -# their original decoded form. They are then sorted and encoded in a -# particular manner that is often different from their original -# encoding scheme, and concatenated into a single string. -# -# .. _`section 3.4.1.3`: http://tools.ietf.org/html/rfc5849#section-3.4.1.3 - -def collect_parameters(uri_query='', body=[], headers=None, - exclude_oauth_signature=True): - """**Parameter Sources** - - Parameters starting with `oauth_` will be unescaped. - - Body parameters must be supplied as a dict, a list of 2-tuples, or a - formencoded query string. - - Headers must be supplied as a dict. - - Per `section 3.4.1.3.1`_ of the spec. - - For example, the HTTP request:: - - POST /request?b5=%3D%253D&a3=a&c%40=&a2=r%20b HTTP/1.1 - Host: example.com - Content-Type: application/x-www-form-urlencoded - Authorization: OAuth realm="Example", - oauth_consumer_key="9djdj82h48djs9d2", - oauth_token="kkk9d7dh3k39sjv7", - oauth_signature_method="HMAC-SHA1", - oauth_timestamp="137131201", - oauth_nonce="7d8f3e4a", - oauth_signature="djosJKDKJSD8743243%2Fjdk33klY%3D" - - c2&a3=2+q - - contains the following (fully decoded) parameters used in the - signature base sting:: - - +------------------------+------------------+ - | Name | Value | - +------------------------+------------------+ - | b5 | =%3D | - | a3 | a | - | c@ | | - | a2 | r b | - | oauth_consumer_key | 9djdj82h48djs9d2 | - | oauth_token | kkk9d7dh3k39sjv7 | - | oauth_signature_method | HMAC-SHA1 | - | oauth_timestamp | 137131201 | - | oauth_nonce | 7d8f3e4a | - | c2 | | - | a3 | 2 q | - +------------------------+------------------+ - - Note that the value of "b5" is "=%3D" and not "==". Both "c@" and - "c2" have empty values. While the encoding rules specified in this - specification for the purpose of constructing the signature base - string exclude the use of a "+" character (ASCII code 43) to - represent an encoded space character (ASCII code 32), this practice - is widely used in "application/x-www-form-urlencoded" encoded values, - and MUST be properly decoded, as demonstrated by one of the "a3" - parameter instances (the "a3" parameter is used twice in this - request). - - .. _`section 3.4.1.3.1`: http://tools.ietf.org/html/rfc5849#section-3.4.1.3.1 - """ - headers = headers or {} - params = [] - - # The parameters from the following sources are collected into a single - # list of name/value pairs: - - # * The query component of the HTTP request URI as defined by - # `RFC3986, Section 3.4`_. The query component is parsed into a list - # of name/value pairs by treating it as an - # "application/x-www-form-urlencoded" string, separating the names - # and values and decoding them as defined by - # `W3C.REC-html40-19980424`_, Section 17.13.4. - # - # .. _`RFC3986, Section 3.4`: http://tools.ietf.org/html/rfc3986#section-3.4 - # .. _`W3C.REC-html40-19980424`: http://tools.ietf.org/html/rfc5849#ref-W3C.REC-html40-19980424 - if uri_query: - params.extend(urlparse.parse_qsl(uri_query, keep_blank_values=True)) - - # * The OAuth HTTP "Authorization" header field (`Section 3.5.1`_) if - # present. The header's content is parsed into a list of name/value - # pairs excluding the "realm" parameter if present. The parameter - # values are decoded as defined by `Section 3.5.1`_. - # - # .. _`Section 3.5.1`: http://tools.ietf.org/html/rfc5849#section-3.5.1 - if headers: - headers_lower = dict((k.lower(), v) for k, v in headers.items()) - authorization_header = headers_lower.get(u'authorization') - if authorization_header is not None: - params.extend([i for i in utils.parse_authorization_header( - authorization_header) if i[0] != u'realm']) - - # * The HTTP request entity-body, but only if all of the following - # conditions are met: - # * The entity-body is single-part. - # - # * The entity-body follows the encoding requirements of the - # "application/x-www-form-urlencoded" content-type as defined by - # `W3C.REC-html40-19980424`_. - - # * The HTTP request entity-header includes the "Content-Type" - # header field set to "application/x-www-form-urlencoded". - # - # .._`W3C.REC-html40-19980424`: http://tools.ietf.org/html/rfc5849#ref-W3C.REC-html40-19980424 - - # TODO: enforce header param inclusion conditions - bodyparams = extract_params(body) or [] - params.extend(bodyparams) - - # ensure all oauth params are unescaped - unescaped_params = [] - for k, v in params: - if k.startswith(u'oauth_'): - v = utils.unescape(v) - unescaped_params.append((k, v)) - - # The "oauth_signature" parameter MUST be excluded from the signature - # base string if present. - if exclude_oauth_signature: - unescaped_params = filter(lambda i: i[0] != u'oauth_signature', - unescaped_params) - - return unescaped_params - - -def normalize_parameters(params): - """**Parameters Normalization** - Per `section 3.4.1.3.2`_ of the spec. - - For example, the list of parameters from the previous section would - be normalized as follows: - - Encoded:: - - +------------------------+------------------+ - | Name | Value | - +------------------------+------------------+ - | b5 | %3D%253D | - | a3 | a | - | c%40 | | - | a2 | r%20b | - | oauth_consumer_key | 9djdj82h48djs9d2 | - | oauth_token | kkk9d7dh3k39sjv7 | - | oauth_signature_method | HMAC-SHA1 | - | oauth_timestamp | 137131201 | - | oauth_nonce | 7d8f3e4a | - | c2 | | - | a3 | 2%20q | - +------------------------+------------------+ - - Sorted:: - - +------------------------+------------------+ - | Name | Value | - +------------------------+------------------+ - | a2 | r%20b | - | a3 | 2%20q | - | a3 | a | - | b5 | %3D%253D | - | c%40 | | - | c2 | | - | oauth_consumer_key | 9djdj82h48djs9d2 | - | oauth_nonce | 7d8f3e4a | - | oauth_signature_method | HMAC-SHA1 | - | oauth_timestamp | 137131201 | - | oauth_token | kkk9d7dh3k39sjv7 | - +------------------------+------------------+ - - Concatenated Pairs:: - - +-------------------------------------+ - | Name=Value | - +-------------------------------------+ - | a2=r%20b | - | a3=2%20q | - | a3=a | - | b5=%3D%253D | - | c%40= | - | c2= | - | oauth_consumer_key=9djdj82h48djs9d2 | - | oauth_nonce=7d8f3e4a | - | oauth_signature_method=HMAC-SHA1 | - | oauth_timestamp=137131201 | - | oauth_token=kkk9d7dh3k39sjv7 | - +-------------------------------------+ - - and concatenated together into a single string (line breaks are for - display purposes only):: - - a2=r%20b&a3=2%20q&a3=a&b5=%3D%253D&c%40=&c2=&oauth_consumer_key=9dj - dj82h48djs9d2&oauth_nonce=7d8f3e4a&oauth_signature_method=HMAC-SHA1 - &oauth_timestamp=137131201&oauth_token=kkk9d7dh3k39sjv7 - - .. _`section 3.4.1.3.2`: http://tools.ietf.org/html/rfc5849#section-3.4.1.3.2 - """ - - # The parameters collected in `Section 3.4.1.3`_ are normalized into a - # single string as follows: - # - # .. _`Section 3.4.1.3`: http://tools.ietf.org/html/rfc5849#section-3.4.1.3 - - # 1. First, the name and value of each parameter are encoded - # (`Section 3.6`_). - # - # .. _`Section 3.6`: http://tools.ietf.org/html/rfc5849#section-3.6 - key_values = [(utils.escape(k), utils.escape(v)) for k, v in params] - - # 2. The parameters are sorted by name, using ascending byte value - # ordering. If two or more parameters share the same name, they - # are sorted by their value. - key_values.sort() - - # 3. The name of each parameter is concatenated to its corresponding - # value using an "=" character (ASCII code 61) as a separator, even - # if the value is empty. - parameter_parts = [u'{0}={1}'.format(k, v) for k, v in key_values] - - # 4. The sorted name/value pairs are concatenated together into a - # single string by using an "&" character (ASCII code 38) as - # separator. - return u'&'.join(parameter_parts) - - -def sign_hmac_sha1(base_string, client_secret, resource_owner_secret): - """**HMAC-SHA1** - - The "HMAC-SHA1" signature method uses the HMAC-SHA1 signature - algorithm as defined in `RFC2104`_:: - - digest = HMAC-SHA1 (key, text) - - Per `section 3.4.2`_ of the spec. - - .. _`RFC2104`: http://tools.ietf.org/html/rfc2104 - .. _`section 3.4.2`: http://tools.ietf.org/html/rfc5849#section-3.4.2 - """ - - # The HMAC-SHA1 function variables are used in following way: - - # text is set to the value of the signature base string from - # `Section 3.4.1.1`_. - # - # .. _`Section 3.4.1.1`: http://tools.ietf.org/html/rfc5849#section-3.4.1.1 - text = base_string - - # key is set to the concatenated values of: - # 1. The client shared-secret, after being encoded (`Section 3.6`_). - # - # .. _`Section 3.6`: http://tools.ietf.org/html/rfc5849#section-3.6 - key = utils.escape(client_secret or u'') - - # 2. An "&" character (ASCII code 38), which MUST be included - # even when either secret is empty. - key += u'&' - - # 3. The token shared-secret, after being encoded (`Section 3.6`_). - # - # .. _`Section 3.6`: http://tools.ietf.org/html/rfc5849#section-3.6 - key += utils.escape(resource_owner_secret or u'') - - # FIXME: HMAC does not support unicode! - key_utf8 = key.encode('utf-8') - text_utf8 = text.encode('utf-8') - signature = hmac.new(key_utf8, text_utf8, hashlib.sha1) - - # digest is used to set the value of the "oauth_signature" protocol - # parameter, after the result octet string is base64-encoded - # per `RFC2045, Section 6.8`. - # - # .. _`RFC2045, Section 6.8`: http://tools.ietf.org/html/rfc2045#section-6.8 - return binascii.b2a_base64(signature.digest())[:-1].decode('utf-8') - - -def sign_rsa_sha1(base_string, rsa_private_key): - """**RSA-SHA1** - - Per `section 3.4.3`_ of the spec. - - The "RSA-SHA1" signature method uses the RSASSA-PKCS1-v1_5 signature - algorithm as defined in `RFC3447, Section 8.2`_ (also known as - PKCS#1), using SHA-1 as the hash function for EMSA-PKCS1-v1_5. To - use this method, the client MUST have established client credentials - with the server that included its RSA public key (in a manner that is - beyond the scope of this specification). - - NOTE: this method requires the python-rsa library. - - .. _`section 3.4.3`: http://tools.ietf.org/html/rfc5849#section-3.4.3 - .. _`RFC3447, Section 8.2`: http://tools.ietf.org/html/rfc3447#section-8.2 - - """ - # TODO: finish RSA documentation - from Crypto.PublicKey import RSA - from Crypto.Signature import PKCS1_v1_5 - from Crypto.Hash import SHA - key = RSA.importKey(rsa_private_key) - h = SHA.new(base_string) - p = PKCS1_v1_5.new(key) - return binascii.b2a_base64(p.sign(h))[:-1].decode('utf-8') - - -def sign_plaintext(client_secret, resource_owner_secret): - """Sign a request using plaintext. - - Per `section 3.4.4`_ of the spec. - - The "PLAINTEXT" method does not employ a signature algorithm. It - MUST be used with a transport-layer mechanism such as TLS or SSL (or - sent over a secure channel with equivalent protections). It does not - utilize the signature base string or the "oauth_timestamp" and - "oauth_nonce" parameters. - - .. _`section 3.4.4`: http://tools.ietf.org/html/rfc5849#section-3.4.4 - - """ - - # The "oauth_signature" protocol parameter is set to the concatenated - # value of: - - # 1. The client shared-secret, after being encoded (`Section 3.6`_). - # - # .. _`Section 3.6`: http://tools.ietf.org/html/rfc5849#section-3.6 - signature = utils.escape(client_secret or u'') - - # 2. An "&" character (ASCII code 38), which MUST be included even - # when either secret is empty. - signature += u'&' - - # 3. The token shared-secret, after being encoded (`Section 3.6`_). - # - # .. _`Section 3.6`: http://tools.ietf.org/html/rfc5849#section-3.6 - signature += utils.escape(resource_owner_secret or u'') - - return signature - - -def verify_hmac_sha1(request, client_secret=None, - resource_owner_secret=None): - """Verify a HMAC-SHA1 signature. - - Per `section 3.4`_ of the spec. - - .. _`section 3.4`: http://tools.ietf.org/html/rfc5849#section-3.4 - """ - norm_params = normalize_parameters(request.params) - uri = normalize_base_string_uri(request.uri) - base_string = construct_base_string(request.http_method, uri, norm_params) - signature = sign_hmac_sha1(base_string, client_secret, - resource_owner_secret) - return safe_string_equals(signature, request.signature) - - -def verify_rsa_sha1(request, rsa_public_key): - """Verify a RSASSA-PKCS #1 v1.5 base64 encoded signature. - - Per `section 3.4.3`_ of the spec. - - Note this method requires the PyCrypto library. - - .. _`section 3.4.3`: http://tools.ietf.org/html/rfc5849#section-3.4.3 - - """ - from Crypto.PublicKey import RSA - from Crypto.Signature import PKCS1_v1_5 - from Crypto.Hash import SHA - key = RSA.importKey(rsa_public_key) - norm_params = normalize_parameters(request.params) - uri = normalize_base_string_uri(request.uri) - message = construct_base_string(request.http_method, uri, norm_params) - h = SHA.new(message) - p = PKCS1_v1_5.new(key) - sig = binascii.a2b_base64(request.signature) - return p.verify(h, sig) - - -def verify_plaintext(request, client_secret=None, resource_owner_secret=None): - """Verify a PLAINTEXT signature. - - Per `section 3.4`_ of the spec. - - .. _`section 3.4`: http://tools.ietf.org/html/rfc5849#section-3.4 - """ - signature = sign_plaintext(client_secret, resource_owner_secret) - return safe_string_equals(signature, request.signature) diff --git a/requests/packages/oauthlib/oauth1/rfc5849/utils.py b/requests/packages/oauthlib/oauth1/rfc5849/utils.py deleted file mode 100644 index 8fb0e77..0000000 --- a/requests/packages/oauthlib/oauth1/rfc5849/utils.py +++ /dev/null @@ -1,99 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -oauthlib.utils -~~~~~~~~~~~~~~ - -This module contains utility methods used by various parts of the OAuth -spec. -""" - -import string -import urllib2 - -from oauthlib.common import quote, unquote - -UNICODE_ASCII_CHARACTER_SET = (string.ascii_letters.decode('ascii') + - string.digits.decode('ascii')) - - -def filter_params(target): - """Decorator which filters params to remove non-oauth_* parameters - - Assumes the decorated method takes a params dict or list of tuples as its - first argument. - """ - def wrapper(params, *args, **kwargs): - params = filter_oauth_params(params) - return target(params, *args, **kwargs) - - wrapper.__doc__ = target.__doc__ - return wrapper - - -def filter_oauth_params(params): - """Removes all non oauth parameters from a dict or a list of params.""" - is_oauth = lambda kv: kv[0].startswith(u"oauth_") - if isinstance(params, dict): - return filter(is_oauth, params.items()) - else: - return filter(is_oauth, params) - - -def escape(u): - """Escape a unicode string in an OAuth-compatible fashion. - - Per `section 3.6`_ of the spec. - - .. _`section 3.6`: http://tools.ietf.org/html/rfc5849#section-3.6 - - """ - if not isinstance(u, unicode): - raise ValueError('Only unicode objects are escapable.') - # Letters, digits, and the characters '_.-' are already treated as safe - # by urllib.quote(). We need to add '~' to fully support rfc5849. - return quote(u, safe='~') - - -def unescape(u): - if not isinstance(u, unicode): - raise ValueError('Only unicode objects are unescapable.') - return unquote(u) - - -def urlencode(query): - """Encode a sequence of two-element tuples or dictionary into a URL query string. - - Operates using an OAuth-safe escape() method, in contrast to urllib.urlencode. - """ - # Convert dictionaries to list of tuples - if isinstance(query, dict): - query = query.items() - return u"&".join([u'='.join([escape(k), escape(v)]) for k, v in query]) - - -def parse_keqv_list(l): - """A unicode-safe version of urllib2.parse_keqv_list""" - encoded_list = [u.encode('utf-8') for u in l] - encoded_parsed = urllib2.parse_keqv_list(encoded_list) - return dict((k.decode('utf-8'), - v.decode('utf-8')) for k, v in encoded_parsed.items()) - - -def parse_http_list(u): - """A unicode-safe version of urllib2.parse_http_list""" - encoded_str = u.encode('utf-8') - encoded_list = urllib2.parse_http_list(encoded_str) - return [s.decode('utf-8') for s in encoded_list] - - -def parse_authorization_header(authorization_header): - """Parse an OAuth authorization header into a list of 2-tuples""" - auth_scheme = u'OAuth ' - if authorization_header.startswith(auth_scheme): - authorization_header = authorization_header.replace(auth_scheme, u'', 1) - items = parse_http_list(authorization_header) - try: - return parse_keqv_list(items).items() - except ValueError: - raise ValueError('Malformed authorization header') diff --git a/requests/packages/oauthlib/oauth2/__init__.py b/requests/packages/oauthlib/oauth2/__init__.py deleted file mode 100644 index 0e8933c..0000000 --- a/requests/packages/oauthlib/oauth2/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import - -""" -oauthlib.oauth2 -~~~~~~~~~~~~~~ - -This module is a wrapper for the most recent implementation of OAuth 2.0 Client -and Server classes. -""" - -from .draft25 import Client, Server - diff --git a/requests/packages/oauthlib/oauth2/draft25/__init__.py b/requests/packages/oauthlib/oauth2/draft25/__init__.py deleted file mode 100644 index 7c90573..0000000 --- a/requests/packages/oauthlib/oauth2/draft25/__init__.py +++ /dev/null @@ -1,497 +0,0 @@ -""" -oauthlib.oauth2.draft_25 -~~~~~~~~~~~~~~ - -This module is an implementation of various logic needed -for signing and checking OAuth 2.0 draft 25 requests. -""" -from tokens import prepare_bearer_uri, prepare_bearer_headers -from tokens import prepare_bearer_body, prepare_mac_header -from parameters import prepare_grant_uri, prepare_token_request -from parameters import parse_authorization_code_response -from parameters import parse_implicit_response, parse_token_response - - -AUTH_HEADER = u'auth_header' -URI_QUERY = u'query' -BODY = u'body' - - -class Client(object): - - def __init__(self, client_id, - default_redirect_uri=None, - token_type=None, - access_token=None, - refresh_token=None): - """Initialize a client with commonly used attributes.""" - - self.client_id = client_id - self.default_redirect_uri = default_redirect_uri - self.token_type = token_type - self.access_token = access_token - self.refresh_token = refresh_token - self.token_types = { - u'bearer': self._add_bearer_token, - u'mac': self._add_mac_token - } - - def add_token(self, uri, http_method=u'GET', body=None, headers=None, - token_placement=AUTH_HEADER): - """Add token to the request uri, body or authorization header. - - The access token type provides the client with the information - required to successfully utilize the access token to make a protected - resource request (along with type-specific attributes). The client - MUST NOT use an access token if it does not understand the token - type. - - For example, the "bearer" token type defined in - [I-D.ietf-oauth-v2-bearer] is utilized by simply including the access - token string in the request: - - GET /resource/1 HTTP/1.1 - Host: example.com - Authorization: Bearer mF_9.B5f-4.1JqM - - while the "mac" token type defined in [I-D.ietf-oauth-v2-http-mac] is - utilized by issuing a MAC key together with the access token which is - used to sign certain components of the HTTP requests: - - GET /resource/1 HTTP/1.1 - Host: example.com - Authorization: MAC id="h480djs93hd8", - nonce="274312:dj83hs9s", - mac="kDZvddkndxvhGRXZhvuDjEWhGeE=" - - .. _`I-D.ietf-oauth-v2-bearer`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#ref-I-D.ietf-oauth-v2-bearer - .. _`I-D.ietf-oauth-v2-http-mac`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#ref-I-D.ietf-oauth-v2-http-mac - """ - return self.token_types[self.token_type](uri, http_method, body, - headers, token_placement) - - def prepare_refresh_body(self, body=u'', refresh_token=None, scope=None): - """Prepare an access token request, using a refresh token. - - If the authorization server issued a refresh token to the client, the - client makes a refresh request to the token endpoint by adding the - following parameters using the "application/x-www-form-urlencoded" - format in the HTTP request entity-body: - - grant_type - REQUIRED. Value MUST be set to "refresh_token". - refresh_token - REQUIRED. The refresh token issued to the client. - scope - OPTIONAL. The scope of the access request as described by - Section 3.3. The requested scope MUST NOT include any scope - not originally granted by the resource owner, and if omitted is - treated as equal to the scope originally granted by the - resource owner. - """ - refresh_token = refresh_token or self.refresh_token - return prepare_token_request(u'refresh_token', body=body, scope=scope, - refresh_token=refresh_token) - - def _add_bearer_token(self, uri, http_method=u'GET', body=None, - headers=None, token_placement=AUTH_HEADER): - """Add a bearer token to the request uri, body or authorization header.""" - if token_placement == AUTH_HEADER: - headers = prepare_bearer_headers(self.token, headers) - - if token_placement == URI_QUERY: - uri = prepare_bearer_uri(self.token, uri) - - if token_placement == BODY: - body = prepare_bearer_body(self.token, body) - - return uri, headers, body - - def _add_mac_token(self, uri, http_method=u'GET', body=None, - headers=None, token_placement=AUTH_HEADER): - """Add a MAC token to the request authorization header.""" - headers = prepare_mac_header(self.token, uri, self.key, http_method, - headers=headers, body=body, ext=self.ext, - hash_algorithm=self.hash_algorithm) - return uri, headers, body - - def _populate_attributes(self, response): - """Add commonly used values such as access_token to self.""" - - if u'access_token' in response: - self.access_token = response.get(u'access_token') - - if u'refresh_token' in response: - self.refresh_token = response.get(u'refresh_token') - - if u'token_type' in response: - self.token_type = response.get(u'token_type') - - if u'expires_in' in response: - self.expires_in = response.get(u'expires_in') - - if u'code' in response: - self.code = response.get(u'code') - - def prepare_request_uri(self, *args, **kwargs): - """Abstract method used to create request URIs.""" - raise NotImplementedError("Must be implemented by inheriting classes.") - - def prepare_request_body(self, *args, **kwargs): - """Abstract method used to create request bodies.""" - raise NotImplementedError("Must be implemented by inheriting classes.") - - def parse_request_uri_response(self, *args, **kwargs): - """Abstract method used to parse redirection responses.""" - - def parse_request_body_response(self, *args, **kwargs): - """Abstract method used to parse JSON responses.""" - - -class WebApplicationClient(Client): - """A client utilizing the authorization code grant workflow. - - A web application is a confidential client running on a web - server. Resource owners access the client via an HTML user - interface rendered in a user-agent on the device used by the - resource owner. The client credentials as well as any access - token issued to the client are stored on the web server and are - not exposed to or accessible by the resource owner. - - The authorization code grant type is used to obtain both access - tokens and refresh tokens and is optimized for confidential clients. - As a redirection-based flow, the client must be capable of - interacting with the resource owner's user-agent (typically a web - browser) and capable of receiving incoming requests (via redirection) - from the authorization server. - """ - - def prepare_request_uri(self, uri, redirect_uri=None, scope=None, - state=None, **kwargs): - """Prepare the authorization code request URI - - The client constructs the request URI by adding the following - parameters to the query component of the authorization endpoint URI - using the "application/x-www-form-urlencoded" format as defined by - [`W3C.REC-html401-19991224`_]: - - response_type - REQUIRED. Value MUST be set to "code". - client_id - REQUIRED. The client identifier as described in `Section 2.2`_. - redirect_uri - OPTIONAL. As described in `Section 3.1.2`_. - scope - OPTIONAL. The scope of the access request as described by - `Section 3.3`_. - state - RECOMMENDED. An opaque value used by the client to maintain - state between the request and callback. The authorization - server includes this value when redirecting the user-agent back - to the client. The parameter SHOULD be used for preventing - cross-site request forgery as described in `Section 10.12`_. - - .. _`W3C.REC-html401-19991224`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#ref-W3C.REC-html401-19991224 - .. _`Section 2.2`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-2.2 - .. _`Section 3.1.2`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-3.1.2 - .. _`Section 3.3`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-3.3 - .. _`Section 10.12`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-10.12 - """ - redirect_uri = redirect_uri or self.default_redirect_uri - return prepare_grant_uri(uri, self.client_id, u'code', - redirect_uri=redirect_uri, scope=scope, state=state, **kwargs) - - def prepare_request_body(self, code, body=u'', redirect_uri=None, **kwargs): - """Prepare the access token request body. - - The client makes a request to the token endpoint by adding the - following parameters using the "application/x-www-form-urlencoded" - format in the HTTP request entity-body: - - grant_type - REQUIRED. Value MUST be set to "authorization_code". - code - REQUIRED. The authorization code received from the - authorization server. - redirect_uri - REQUIRED, if the "redirect_uri" parameter was included in the - authorization request as described in Section 4.1.1, and their - values MUST be identical. - - .. _`Section 4.1.1`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-4.1.1 - """ - redirect_uri = redirect_uri or self.default_redirect_uri - code = code or self.code - return prepare_token_request(u'authorization_code', code=code, body=body, - redirect_uri=redirect_uri, **kwargs) - - def parse_request_uri_response(self, uri, state=None): - """Parse the URI query for code and state. - - If the resource owner grants the access request, the authorization - server issues an authorization code and delivers it to the client by - adding the following parameters to the query component of the - redirection URI using the "application/x-www-form-urlencoded" format: - - code - REQUIRED. The authorization code generated by the - authorization server. The authorization code MUST expire - shortly after it is issued to mitigate the risk of leaks. A - maximum authorization code lifetime of 10 minutes is - RECOMMENDED. The client MUST NOT use the authorization code - more than once. If an authorization code is used more than - once, the authorization server MUST deny the request and SHOULD - revoke (when possible) all tokens previously issued based on - that authorization code. The authorization code is bound to - the client identifier and redirection URI. - state - REQUIRED if the "state" parameter was present in the client - authorization request. The exact value received from the - client. - """ - response = parse_authorization_code_response(uri, state=state) - self._populate_attributes(response) - return response - - def parse_request_body_response(self, body, scope=None): - """Parse the JSON response body. - - If the access token request is valid and authorized, the - authorization server issues an access token and optional refresh - token as described in `Section 5.1`_. If the request client - authentication failed or is invalid, the authorization server returns - an error response as described in `Section 5.2`_. - - .. `Section 5.1`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-5.1 - .. `Section 5.2`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-5.2 - """ - response = parse_token_response(body, scope=scope) - self._populate_attributes(response) - return response - - -class UserAgentClient(Client): - """A public client utilizing the implicit code grant workflow. - - A user-agent-based application is a public client in which the - client code is downloaded from a web server and executes within a - user-agent (e.g. web browser) on the device used by the resource - owner. Protocol data and credentials are easily accessible (and - often visible) to the resource owner. Since such applications - reside within the user-agent, they can make seamless use of the - user-agent capabilities when requesting authorization. - - The implicit grant type is used to obtain access tokens (it does not - support the issuance of refresh tokens) and is optimized for public - clients known to operate a particular redirection URI. These clients - are typically implemented in a browser using a scripting language - such as JavaScript. - - As a redirection-based flow, the client must be capable of - interacting with the resource owner's user-agent (typically a web - browser) and capable of receiving incoming requests (via redirection) - from the authorization server. - - Unlike the authorization code grant type in which the client makes - separate requests for authorization and access token, the client - receives the access token as the result of the authorization request. - - The implicit grant type does not include client authentication, and - relies on the presence of the resource owner and the registration of - the redirection URI. Because the access token is encoded into the - redirection URI, it may be exposed to the resource owner and other - applications residing on the same device. - """ - - def prepare_request_uri(self, uri, redirect_uri=None, scope=None, - state=None, **kwargs): - """Prepare the implicit grant request URI. - - The client constructs the request URI by adding the following - parameters to the query component of the authorization endpoint URI - using the "application/x-www-form-urlencoded" format: - - response_type - REQUIRED. Value MUST be set to "token". - client_id - REQUIRED. The client identifier as described in Section 2.2. - redirect_uri - OPTIONAL. As described in Section 3.1.2. - scope - OPTIONAL. The scope of the access request as described by - Section 3.3. - state - RECOMMENDED. An opaque value used by the client to maintain - state between the request and callback. The authorization - server includes this value when redirecting the user-agent back - to the client. The parameter SHOULD be used for preventing - cross-site request forgery as described in Section 10.12. - """ - redirect_uri = redirect_uri or self.default_redirect_uri - return prepare_grant_uri(uri, self.client_id, u'token', - redirect_uri=redirect_uri, state=state, scope=scope, **kwargs) - - def parse_request_uri_response(self, uri, state=None, scope=None): - """Parse the response URI fragment. - - If the resource owner grants the access request, the authorization - server issues an access token and delivers it to the client by adding - the following parameters to the fragment component of the redirection - URI using the "application/x-www-form-urlencoded" format: - - access_token - REQUIRED. The access token issued by the authorization server. - token_type - REQUIRED. The type of the token issued as described in - `Section 7.1`_. Value is case insensitive. - expires_in - RECOMMENDED. The lifetime in seconds of the access token. For - example, the value "3600" denotes that the access token will - expire in one hour from the time the response was generated. - If omitted, the authorization server SHOULD provide the - expiration time via other means or document the default value. - scope - OPTIONAL, if identical to the scope requested by the client, - otherwise REQUIRED. The scope of the access token as described - by `Section 3.3`_. - state - REQUIRED if the "state" parameter was present in the client - authorization request. The exact value received from the - client. - - .. _`Section 7.1`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-7.1 - .. _`Section 3.3`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-3.3 - """ - response = parse_implicit_response(uri, state=state, scope=scope) - self._populate_attributes(response) - return response - - -class NativeApplicationClient(Client): - """A public client utilizing the client credentials grant workflow. - - A native application is a public client installed and executed on - the device used by the resource owner. Protocol data and - credentials are accessible to the resource owner. It is assumed - that any client authentication credentials included in the - application can be extracted. On the other hand, dynamically - issued credentials such as access tokens or refresh tokens can - receive an acceptable level of protection. At a minimum, these - credentials are protected from hostile servers with which the - application may interact with. On some platforms these - credentials might be protected from other applications residing on - the same device. - - The client can request an access token using only its client - credentials (or other supported means of authentication) when the - client is requesting access to the protected resources under its - control, or those of another resource owner which has been previously - arranged with the authorization server (the method of which is beyond - the scope of this specification). - - The client credentials grant type MUST only be used by confidential - clients. - - Since the client authentication is used as the authorization grant, - no additional authorization request is needed. - """ - - def prepare_request_body(self, body=u'', scope=None, **kwargs): - """Add the client credentials to the request body. - - The client makes a request to the token endpoint by adding the - following parameters using the "application/x-www-form-urlencoded" - format in the HTTP request entity-body: - - grant_type - REQUIRED. Value MUST be set to "client_credentials". - scope - OPTIONAL. The scope of the access request as described by - `Section 3.3`_. - - .. _`Section 3.3`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-3.3 - """ - return prepare_token_request(u'client_credentials', body=body, - scope=scope, **kwargs) - - def parse_request_body_response(self, body, scope=None): - """Parse the JSON response body. - - If the access token request is valid and authorized, the - authorization server issues an access token as described in - `Section 5.1`_. A refresh token SHOULD NOT be included. If the request - failed client authentication or is invalid, the authorization server - returns an error response as described in `Section 5.2`_. - - .. `Section 5.1`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-5.1 - .. `Section 5.2`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-5.2 - """ - response = parse_token_response(body, scope=scope) - self._populate_attributes(response) - return response - - -class PasswordCredentialsClient(Client): - """A public client using the resource owner password and username directly. - - The resource owner password credentials grant type is suitable in - cases where the resource owner has a trust relationship with the - client, such as the device operating system or a highly privileged - application. The authorization server should take special care when - enabling this grant type, and only allow it when other flows are not - viable. - - The grant type is suitable for clients capable of obtaining the - resource owner's credentials (username and password, typically using - an interactive form). It is also used to migrate existing clients - using direct authentication schemes such as HTTP Basic or Digest - authentication to OAuth by converting the stored credentials to an - access token. - - The method through which the client obtains the resource owner - credentials is beyond the scope of this specification. The client - MUST discard the credentials once an access token has been obtained. - """ - - def prepare_request_body(self, username, password, body=u'', scope=None, - **kwargs): - """Add the resource owner password and username to the request body. - - The client makes a request to the token endpoint by adding the - following parameters using the "application/x-www-form-urlencoded" - format in the HTTP request entity-body: - - grant_type - REQUIRED. Value MUST be set to "password". - username - REQUIRED. The resource owner username. - password - REQUIRED. The resource owner password. - scope - OPTIONAL. The scope of the access request as described by - `Section 3.3`_. - - .. _`Section 3.3`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-3.3 - """ - return prepare_token_request(u'password', body=body, username=username, - password=password, scope=scope, **kwargs) - - def parse_request_body_response(self, body, scope=None): - """Parse the JSON response body. - - If the access token request is valid and authorized, the - authorization server issues an access token and optional refresh - token as described in `Section 5.1`_. If the request failed client - authentication or is invalid, the authorization server returns an - error response as described in `Section 5.2`_. - - .. `Section 5.1`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-5.1 - .. `Section 5.2`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-5.2 - """ - response = parse_token_response(body, scope=scope) - self._populate_attributes(response) - return response - - -class Server(object): - pass diff --git a/requests/packages/oauthlib/oauth2/draft25/parameters.py b/requests/packages/oauthlib/oauth2/draft25/parameters.py deleted file mode 100644 index ecc9f63..0000000 --- a/requests/packages/oauthlib/oauth2/draft25/parameters.py +++ /dev/null @@ -1,256 +0,0 @@ -""" -oauthlib.oauth2_draft28.parameters -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This module contains methods related to `Section 4`_ of the OAuth 2 draft. - -.. _`Section 4`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-4 -""" - -import json -import urlparse -from oauthlib.common import add_params_to_uri, add_params_to_qs - - -def prepare_grant_uri(uri, client_id, response_type, redirect_uri=None, - scope=None, state=None, **kwargs): - """Prepare the authorization grant request URI. - - The client constructs the request URI by adding the following - parameters to the query component of the authorization endpoint URI - using the "application/x-www-form-urlencoded" format as defined by - [W3C.REC-html401-19991224]: - - response_type - REQUIRED. Value MUST be set to "code". - client_id - REQUIRED. The client identifier as described in `Section 2.2`_. - redirect_uri - OPTIONAL. As described in `Section 3.1.2`_. - scope - OPTIONAL. The scope of the access request as described by - `Section 3.3`_. - state - RECOMMENDED. An opaque value used by the client to maintain - state between the request and callback. The authorization - server includes this value when redirecting the user-agent back - to the client. The parameter SHOULD be used for preventing - cross-site request forgery as described in `Section 10.12`_. - - GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz - &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1 - Host: server.example.com - - .. _`W3C.REC-html401-19991224`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#ref-W3C.REC-html401-19991224 - .. _`Section 2.2`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-2.2 - .. _`Section 3.1.2`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-3.1.2 - .. _`Section 3.3`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-3.3 - .. _`section 10.12`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-10.12 - """ - params = [((u'response_type', response_type)), - ((u'client_id', client_id))] - - if redirect_uri: - params.append((u'redirect_uri', redirect_uri)) - if scope: - params.append((u'scope', scope)) - if state: - params.append((u'state', state)) - - for k in kwargs: - params.append((unicode(k), kwargs[k])) - - return add_params_to_uri(uri, params) - - -def prepare_token_request(grant_type, body=u'', **kwargs): - """Prepare the access token request. - - The client makes a request to the token endpoint by adding the - following parameters using the "application/x-www-form-urlencoded" - format in the HTTP request entity-body: - - grant_type - REQUIRED. Value MUST be set to "authorization_code". - code - REQUIRED. The authorization code received from the - authorization server. - redirect_uri - REQUIRED, if the "redirect_uri" parameter was included in the - authorization request as described in `Section 4.1.1`_, and their - values MUST be identical. - - grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA - &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb - - .. _`Section 4.1.1`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-4.1.1 - """ - params = [(u'grant_type', grant_type)] - for k in kwargs: - params.append((unicode(k), kwargs[k])) - - return add_params_to_qs(body, params) - - -def parse_authorization_code_response(uri, state=None): - """Parse authorization grant response URI into a dict. - - If the resource owner grants the access request, the authorization - server issues an authorization code and delivers it to the client by - adding the following parameters to the query component of the - redirection URI using the "application/x-www-form-urlencoded" format: - - code - REQUIRED. The authorization code generated by the - authorization server. The authorization code MUST expire - shortly after it is issued to mitigate the risk of leaks. A - maximum authorization code lifetime of 10 minutes is - RECOMMENDED. The client MUST NOT use the authorization code - more than once. If an authorization code is used more than - once, the authorization server MUST deny the request and SHOULD - revoke (when possible) all tokens previously issued based on - that authorization code. The authorization code is bound to - the client identifier and redirection URI. - state - REQUIRED if the "state" parameter was present in the client - authorization request. The exact value received from the - client. - - For example, the authorization server redirects the user-agent by - sending the following HTTP response: - - HTTP/1.1 302 Found - Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA - &state=xyz - - """ - query = urlparse.urlparse(uri).query - params = dict(urlparse.parse_qsl(query)) - - if not u'code' in params: - raise KeyError("Missing code parameter in response.") - - if state and params.get(u'state', None) != state: - raise ValueError("Mismatching or missing state in response.") - - return params - - -def parse_implicit_response(uri, state=None, scope=None): - """Parse the implicit token response URI into a dict. - - If the resource owner grants the access request, the authorization - server issues an access token and delivers it to the client by adding - the following parameters to the fragment component of the redirection - URI using the "application/x-www-form-urlencoded" format: - - access_token - REQUIRED. The access token issued by the authorization server. - token_type - REQUIRED. The type of the token issued as described in - Section 7.1. Value is case insensitive. - expires_in - RECOMMENDED. The lifetime in seconds of the access token. For - example, the value "3600" denotes that the access token will - expire in one hour from the time the response was generated. - If omitted, the authorization server SHOULD provide the - expiration time via other means or document the default value. - scope - OPTIONAL, if identical to the scope requested by the client, - otherwise REQUIRED. The scope of the access token as described - by Section 3.3. - state - REQUIRED if the "state" parameter was present in the client - authorization request. The exact value received from the - client. - - HTTP/1.1 302 Found - Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA - &state=xyz&token_type=example&expires_in=3600 - """ - fragment = urlparse.urlparse(uri).fragment - params = dict(urlparse.parse_qsl(fragment, keep_blank_values=True)) - validate_token_parameters(params, scope) - - if state and params.get(u'state', None) != state: - raise ValueError("Mismatching or missing state in params.") - - return params - - -def parse_token_response(body, scope=None): - """Parse the JSON token response body into a dict. - - The authorization server issues an access token and optional refresh - token, and constructs the response by adding the following parameters - to the entity body of the HTTP response with a 200 (OK) status code: - - access_token - REQUIRED. The access token issued by the authorization server. - token_type - REQUIRED. The type of the token issued as described in - `Section 7.1`_. Value is case insensitive. - expires_in - RECOMMENDED. The lifetime in seconds of the access token. For - example, the value "3600" denotes that the access token will - expire in one hour from the time the response was generated. - If omitted, the authorization server SHOULD provide the - expiration time via other means or document the default value. - refresh_token - OPTIONAL. The refresh token which can be used to obtain new - access tokens using the same authorization grant as described - in `Section 6`_. - scope - OPTIONAL, if identical to the scope requested by the client, - otherwise REQUIRED. The scope of the access token as described - by `Section 3.3`_. - - The parameters are included in the entity body of the HTTP response - using the "application/json" media type as defined by [`RFC4627`_]. The - parameters are serialized into a JSON structure by adding each - parameter at the highest structure level. Parameter names and string - values are included as JSON strings. Numerical values are included - as JSON numbers. The order of parameters does not matter and can - vary. - - For example: - - HTTP/1.1 200 OK - Content-Type: application/json;charset=UTF-8 - Cache-Control: no-store - Pragma: no-cache - - { - "access_token":"2YotnFZFEjr1zCsicMWpAA", - "token_type":"example", - "expires_in":3600, - "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", - "example_parameter":"example_value" - } - - .. _`Section 7.1`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-7.1 - .. _`Section 6`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-6 - .. _`Section 3.3`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-3.3 - .. _`RFC4627`: http://tools.ietf.org/html/rfc4627 - """ - params = json.loads(body) - validate_token_parameters(params, scope) - return params - - -def validate_token_parameters(params, scope=None): - """Ensures token precence, token type, expiration and scope in params.""" - - if not u'access_token' in params: - raise KeyError("Missing access token parameter.") - - if not u'token_type' in params: - raise KeyError("Missing token type parameter.") - - # If the issued access token scope is different from the one requested by - # the client, the authorization server MUST include the "scope" response - # parameter to inform the client of the actual scope granted. - # http://tools.ietf.org/html/draft-ietf-oauth-v2-25#section-3.3 - new_scope = params.get(u'scope', None) - if scope and new_scope and scope != new_scope: - raise Warning("Scope has changed to %s." % new_scope) diff --git a/requests/packages/oauthlib/oauth2/draft25/tokens.py b/requests/packages/oauthlib/oauth2/draft25/tokens.py deleted file mode 100644 index 74491fb..0000000 --- a/requests/packages/oauthlib/oauth2/draft25/tokens.py +++ /dev/null @@ -1,132 +0,0 @@ -from __future__ import absolute_import -""" -oauthlib.oauth2.draft25.tokens -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This module contains methods for adding two types of access tokens to requests. - -- Bearer http://tools.ietf.org/html/draft-ietf-oauth-saml2-bearer-08 -- MAC http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-00 - -""" -from binascii import b2a_base64 -import hashlib -import hmac -from urlparse import urlparse - -from oauthlib.common import add_params_to_uri, add_params_to_qs -from . import utils - - -def prepare_mac_header(token, uri, key, http_method, nonce=None, headers=None, - body=None, ext=u'', hash_algorithm=u'hmac-sha-1'): - """Add an `MAC Access Authentication`_ signature to headers. - - Unlike OAuth 1, this HMAC signature does not require inclusion of the request - payload/body, neither does it use a combination of client_secret and - token_secret but rather a mac_key provided together with the access token. - - Currently two algorithms are supported, "hmac-sha-1" and "hmac-sha-256", - `extension algorithms`_ are not supported. - - Example MAC Authorization header, linebreaks added for clarity - - Authorization: MAC id="h480djs93hd8", - nonce="1336363200:dj83hs9s", - mac="bhCQXTVyfj5cmA9uKkPFx1zeOXM=" - - .. _`MAC Access Authentication`: http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01 - .. _`extension algorithms`: http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01#section-7.1 - - :param uri: Request URI. - :param headers: Request headers as a dictionary. - :param http_method: HTTP Request method. - :param key: MAC given provided by token endpoint. - :param algorithm: HMAC algorithm provided by token endpoint. - :return: headers dictionary with the authorization field added. - """ - http_method = http_method.upper() - host, port = utils.host_from_uri(uri) - - if hash_algorithm.lower() == u'hmac-sha-1': - h = hashlib.sha1 - else: - h = hashlib.sha256 - - nonce = nonce or u'{0}:{1}'.format(utils.generate_nonce(), utils.generate_timestamp()) - sch, net, path, par, query, fra = urlparse(uri) - - if query: - request_uri = path + u'?' + query - else: - request_uri = path - - # Hash the body/payload - if body is not None: - bodyhash = b2a_base64(h(body).digest())[:-1].decode('utf-8') - else: - bodyhash = u'' - - # Create the normalized base string - base = [] - base.append(nonce) - base.append(http_method.upper()) - base.append(request_uri) - base.append(host) - base.append(port) - base.append(bodyhash) - base.append(ext) - base_string = '\n'.join(base) + u'\n' - - # hmac struggles with unicode strings - http://bugs.python.org/issue5285 - if isinstance(key, unicode): - key = key.encode('utf-8') - sign = hmac.new(key, base_string, h) - sign = b2a_base64(sign.digest())[:-1].decode('utf-8') - - header = [] - header.append(u'MAC id="%s"' % token) - header.append(u'nonce="%s"' % nonce) - if bodyhash: - header.append(u'bodyhash="%s"' % bodyhash) - if ext: - header.append(u'ext="%s"' % ext) - header.append(u'mac="%s"' % sign) - - headers = headers or {} - headers[u'Authorization'] = u', '.join(header) - return headers - - -def prepare_bearer_uri(token, uri): - """Add a `Bearer Token`_ to the request URI. - Not recommended, use only if client can't use authorization header or body. - - http://www.example.com/path?access_token=h480djs93hd8 - - .. _`Bearer Token`: http://tools.ietf.org/html/draft-ietf-oauth-v2-bearer-18 - """ - return add_params_to_uri(uri, [((u'access_token', token))]) - - -def prepare_bearer_headers(token, headers=None): - """Add a `Bearer Token`_ to the request URI. - Recommended method of passing bearer tokens. - - Authorization: Bearer h480djs93hd8 - - .. _`Bearer Token`: http://tools.ietf.org/html/draft-ietf-oauth-v2-bearer-18 - """ - headers = headers or {} - headers[u'Authorization'] = u'Bearer %s' % token - return headers - - -def prepare_bearer_body(token, body=u''): - """Add a `Bearer Token`_ to the request body. - - access_token=h480djs93hd8 - - .. _`Bearer Token`: http://tools.ietf.org/html/draft-ietf-oauth-v2-bearer-18 - """ - return add_params_to_qs(body, [((u'access_token', token))]) diff --git a/requests/packages/oauthlib/oauth2/draft25/utils.py b/requests/packages/oauthlib/oauth2/draft25/utils.py deleted file mode 100644 index 75d5fcc..0000000 --- a/requests/packages/oauthlib/oauth2/draft25/utils.py +++ /dev/null @@ -1,39 +0,0 @@ -""" -oauthlib.utils -~~~~~~~~~~~~~~ - -This module contains utility methods used by various parts of the OAuth 2 spec. -""" - -import urllib -import urlparse - - -def host_from_uri(uri): - """Extract hostname and port from URI. - - Will use default port for HTTP and HTTPS if none is present in the URI. - """ - default_ports = { - u'HTTP': u'80', - u'HTTPS': u'443', - } - - sch, netloc, path, par, query, fra = urlparse.urlparse(uri) - if u':' in netloc: - netloc, port = netloc.split(u':', 1) - else: - port = default_ports.get(sch.upper()) - - return netloc, port - - -def escape(u): - """Escape a string in an OAuth-compatible fashion. - - TODO: verify whether this can in fact be used for OAuth 2 - - """ - if not isinstance(u, unicode): - raise ValueError('Only unicode objects are escapable.') - return urllib.quote(u.encode('utf-8'), safe='~')