summaryrefslogtreecommitdiff
path: root/requests-0.14.0/requests/packages/oauthlib/oauth1
diff options
context:
space:
mode:
Diffstat (limited to 'requests-0.14.0/requests/packages/oauthlib/oauth1')
-rw-r--r--requests-0.14.0/requests/packages/oauthlib/oauth1/__init__.py13
-rw-r--r--requests-0.14.0/requests/packages/oauthlib/oauth1/rfc5849/__init__.py889
-rw-r--r--requests-0.14.0/requests/packages/oauthlib/oauth1/rfc5849/parameters.py134
-rw-r--r--requests-0.14.0/requests/packages/oauthlib/oauth1/rfc5849/signature.py551
-rw-r--r--requests-0.14.0/requests/packages/oauthlib/oauth1/rfc5849/utils.py99
5 files changed, 1686 insertions, 0 deletions
diff --git a/requests-0.14.0/requests/packages/oauthlib/oauth1/__init__.py b/requests-0.14.0/requests/packages/oauthlib/oauth1/__init__.py
new file mode 100644
index 0000000..ef692b5
--- /dev/null
+++ b/requests-0.14.0/requests/packages/oauthlib/oauth1/__init__.py
@@ -0,0 +1,13 @@
+# -*- 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-0.14.0/requests/packages/oauthlib/oauth1/rfc5849/__init__.py b/requests-0.14.0/requests/packages/oauthlib/oauth1/rfc5849/__init__.py
new file mode 100644
index 0000000..da3988d
--- /dev/null
+++ b/requests-0.14.0/requests/packages/oauthlib/oauth1/rfc5849/__init__.py
@@ -0,0 +1,889 @@
+# -*- 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-0.14.0/requests/packages/oauthlib/oauth1/rfc5849/parameters.py b/requests-0.14.0/requests/packages/oauthlib/oauth1/rfc5849/parameters.py
new file mode 100644
index 0000000..dee23a4
--- /dev/null
+++ b/requests-0.14.0/requests/packages/oauthlib/oauth1/rfc5849/parameters.py
@@ -0,0 +1,134 @@
+# -*- 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-0.14.0/requests/packages/oauthlib/oauth1/rfc5849/signature.py b/requests-0.14.0/requests/packages/oauthlib/oauth1/rfc5849/signature.py
new file mode 100644
index 0000000..dbd43aa
--- /dev/null
+++ b/requests-0.14.0/requests/packages/oauthlib/oauth1/rfc5849/signature.py
@@ -0,0 +1,551 @@
+# -*- 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-0.14.0/requests/packages/oauthlib/oauth1/rfc5849/utils.py b/requests-0.14.0/requests/packages/oauthlib/oauth1/rfc5849/utils.py
new file mode 100644
index 0000000..8fb0e77
--- /dev/null
+++ b/requests-0.14.0/requests/packages/oauthlib/oauth1/rfc5849/utils.py
@@ -0,0 +1,99 @@
+# -*- 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')