def test_filter(self): params = { "a2": ["r b"], "b5": ["=%3D"], "a3": ["a", "2 q"], "c@": [""], "c2": [""], "oauth_consumer_key": ["9djdj82h48djs9d2"], "oauth_token": ["kkk9d7dh3k39sjv7"], "oauth_signature_method": ["HMAC-SHA1"], "oauth_timestamp": ["137131201"], "oauth_nonce": ["7d8f3e4a"], } query_string = "?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" expected_params = { "oauth_consumer_key": ["9djdj82h48djs9d2"], "oauth_token": ["kkk9d7dh3k39sjv7"], "oauth_signature_method": ["HMAC-SHA1"], "oauth_timestamp": ["137131201"], "oauth_nonce": ["7d8f3e4a"], } expected_result = urlencode_s(expected_params) assert_equal(urlencode_s(request_protocol_params_sanitize(params)), expected_result) assert_equal(urlencode_s(request_protocol_params_sanitize(query_string)), expected_result)
def test_ignores_prefixed_question_mark_character_if_included(self): query_string = """\ ?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""" expected_params = { "a2": ["r b"], "b5": ["=%3D"], "a3": ["a", "2 q"], "c@": [""], "c2": [""], OAUTH_PARAM_CONSUMER_KEY: ["9djdj82h48djs9d2"], OAUTH_PARAM_TOKEN: ["kkk9d7dh3k39sjv7"], OAUTH_PARAM_SIGNATURE_METHOD: ["HMAC-SHA1"], OAUTH_PARAM_TIMESTAMP: ["137131201"], OAUTH_PARAM_NONCE: ["7d8f3e4a"], } self.assertEqual(urlencode_s(query_unflatten(query_string)), urlencode_s(expected_params))
def test_ignores_prefixed_question_mark_character_if_included(self): query_string = "?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" expected_params = { "a2": ["r b"], "b5": ["=%3D"], "a3": ["a", "2 q"], "c@": [""], "c2": [""], "oauth_consumer_key": ["9djdj82h48djs9d2"], "oauth_token": ["kkk9d7dh3k39sjv7"], "oauth_signature_method": ["HMAC-SHA1"], "oauth_timestamp": ["137131201"], "oauth_nonce": ["7d8f3e4a"], } assert_equal(urlencode_s(query_unflatten(query_string)), urlencode_s(expected_params))
def fetch_access_token(self, code, redirect_uri, error=None, method="POST", payload_params=None, async_callback=None): """ Fetches an access token and a refresh token. :param code: The code returned by the OAuth 2.0 server to your callback URI. Set to ``None`` if an error occurred. :param redirect_uri: The URL to which the OAuth 2.0 server should redirect. :param error: Set this to the error query parameter from your callback handler if available. (Default ``None``.) :param method: (Default POST). The HTTP method to use. :param payload_params: Additional params to he URL-encoded into the body. (Existing parameters may be overridden). :param async_callback: (Optional) Asynchronous callback handler that will be called with the received token. If none is specified, this function returns the token instead. :returns: Access token and refresh token (if ``async_callback`` is unspecified). If ``async_callback`` is specified, ``None`` will be returned. """ # TODO: Add async_callback signature and example in documentation. if error: raise OAuthError(error) if not code: raise ValueError("argument ``code`` not specified") params = { "code": code, "client_id": self._client_credentials.identifier, "client_secret": self._client_credentials.shared_secret, "redirect_uri": redirect_uri, "grant_type": "authorization_code", } if payload_params: params.update(payload_params) body = urlencode_s(params) headers = { HEADER_CONTENT_TYPE: CONTENT_TYPE_FORM_URLENCODED, } response = self._http_client.fetch( RequestAdapter(method=method, url=self._token_uri, body=body, headers=headers)) if response.error: raise HttpError( "[fetch access token] OAuth 2.0 server response " \ "error: %d - %s" % (response.status, response.reason)) logging.info(response.content_type) token = json_decode(response.content) logging.info(token) return token
def test_adds_query_params_properly(self): params1 = { b("a2"): b("r b"), b("b5"): b("=%3D"), b("a3"): [b("a")], b("c2"): [b("")], } params2 = { b("a3"): [b("2 q")], b("c@"): b(""), } params3 = b("""oauth_nonce=7d8f3e4a\ &oauth_timestamp=137131201\ &oauth_signature_method=HMAC-SHA1\ &oauth_consumer_key=9djdj82h48djs9d2\ &oauth_token=kkk9d7dh3k39sjv7\ """) resulting_query_string = b("""\ 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""") self.assertEqual(urlencode_s(query_add(params1, params2, params3)), resulting_query_string)
def test_valid_query_string(self): params = { "a2": "r b", "b5": "=%3D", "a3": ["a", "2 q"], "c@": [""], "c2": "", OAUTH_PARAM_CONSUMER_KEY: "9djdj82h48djs9d2", OAUTH_PARAM_TOKEN: "kkk9d7dh3k39sjv7", OAUTH_PARAM_SIGNATURE_METHOD: "HMAC-SHA1", OAUTH_PARAM_TIMESTAMP: ["137131201"], OAUTH_PARAM_NONCE: "7d8f3e4a", } valid_query_string = b("""\ 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""") self.assertEqual(urlencode_s(params), valid_query_string)
def _generate_signature_base_string_query(url_query_params, oauth_params): """ Serializes URL query parameters and OAuth protocol parameters into a valid OAuth base string URI query string. :see: Parameter Normalization (http://tools.ietf.org/html/rfc5849#section-3.4.1.3.2) :param url_query_params: A dictionary or string of URL query parameters. Any parameters starting with ``oauth_`` will be ignored. :param oauth_params: A dictionary or string of protocol-specific query parameters. Any parameter names that do not begin with ``oauth_`` will be excluded from the normalized query string. ``oauth_signature``, ``oauth_consumer_secret``, and ``oauth_token_secret`` are also specifically excluded. :returns: Normalized string of query parameters. """ url_query_params = query_params_sanitize(url_query_params) oauth_params = request_protocol_params_sanitize(oauth_params) query_params = {} query_params.update(url_query_params) query_params.update(oauth_params) # Now encode the parameters, while ignoring 'oauth_signature' and obviously, # the secrets from the entire list of parameters. def allow_func(name, value): return name not in ("oauth_signature", #"oauth_consumer_secret", # Already filtered by protocol parameter sanitization above. #"oauth_token_secret", # Already filtered by protocol parameter sanitization above. ) query = urlencode_s(query_params, allow_func=allow_func) return query
def test_sanitization_force_secure_default_and_removes_fragment(self): url = "https://www.EXAMPLE.com/request?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#fragment" expected_params = { "a2": ["r b"], "b5": ["=%3D"], "a3": ["a", "2 q"], "c@": [""], "c2": [""], } expected_result = "https://www.example.com/request?" + urlencode_s(expected_params) # Fragment ignored. assert_equal(oauth_url_sanitize(url), expected_result)
def test_filter(self): params = { "a2": ["r b"], "b5": ["=%3D"], "a3": ["a", "2 q"], "c@": [""], "c2": [""], OAUTH_PARAM_CONSUMER_KEY: ["9djdj82h48djs9d2"], OAUTH_PARAM_TOKEN: ["kkk9d7dh3k39sjv7"], OAUTH_PARAM_SIGNATURE_METHOD: ["HMAC-SHA1"], OAUTH_PARAM_TIMESTAMP: ["137131201"], OAUTH_PARAM_NONCE: ["7d8f3e4a"], } query_string = """\ ?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""" expected_params = { OAUTH_PARAM_CONSUMER_KEY: ["9djdj82h48djs9d2"], OAUTH_PARAM_TOKEN: ["kkk9d7dh3k39sjv7"], OAUTH_PARAM_SIGNATURE_METHOD: ["HMAC-SHA1"], OAUTH_PARAM_TIMESTAMP: ["137131201"], OAUTH_PARAM_NONCE: ["7d8f3e4a"], } expected_result = urlencode_s(expected_params) self.assertEqual(urlencode_s(request_query_remove_non_oauth(params)), expected_result) self.assertEqual( urlencode_s(request_query_remove_non_oauth(query_string)), expected_result)
def test_valid_query_string(self): params = { "a2": "r b", "b5": "=%3D", "a3": ["a", "2 q"], "c@": [""], "c2": "", "oauth_consumer_key": "9djdj82h48djs9d2", "oauth_token": "kkk9d7dh3k39sjv7", "oauth_signature_method": "HMAC-SHA1", "oauth_timestamp": ["137131201"], "oauth_nonce": "7d8f3e4a", } valid_query_string = "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" assert_equal(urlencode_s(params), valid_query_string)
def generate_base_string_query(url_query, oauth_params): """ Serializes URL query parameters and OAuth protocol parameters into a valid OAuth base string URI query string. :see: Parameter Normalization (http://tools.ietf.org/html/rfc5849#section-3.4.1.3.2) :param url_query: A dictionary or string of URL query parameters. Any parameters starting with ``oauth_`` will be ignored. :param oauth_params: A dictionary or string of protocol-specific query parameters. Any parameter names that do not begin with ``oauth_`` will be excluded from the normalized query string. ``oauth_signature``, ``oauth_consumer_secret``, and ``oauth_token_secret`` are also specifically excluded. :returns: Normalized string of query parameters. """ url_query = query_remove_oauth(url_query) oauth_params = request_query_remove_non_oauth(oauth_params) query_d = {} query_d.update(url_query) query_d.update(oauth_params) # Now encode the parameters, while ignoring 'oauth_signature' and obviously, # the secrets from the entire list of parameters. def allow_func(name, _): """Allows only protocol parameters that must be included into the signature. :param name: The name of the parameter. :returns: ``True`` if the parameter can be included; ``False`` otherwise. """ return name not in (OAUTH_PARAM_SIGNATURE, #OAUTH_PARAM_CONSUMER_SECRET, # Sanitized above. #OAUTH_PARAM_TOKEN_SECRET, # Sanitized above. ) query = urlencode_s(query_d, allow_func) return query
def test_adds_query_params_properly(self): params1 = { "a2": "r b", "b5": "=%3D", "a3": ["a"], "c2": [""], } params2 = { "a3": ["2 q"], "c@": "", } params3 = """oauth_nonce=7d8f3e4a\ &oauth_timestamp=137131201\ &oauth_signature_method=HMAC-SHA1\ &oauth_consumer_key=9djdj82h48djs9d2\ &oauth_token=kkk9d7dh3k39sjv7\ """ resulting_query_string = "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" assert_equal(urlencode_s(query_add(params1, params2, params3)), resulting_query_string)
def fetch_refreshed_access_token(self, refresh_token, method="POST", payload_params=None): """ Fetches a refreshed access token from the OAuth 2.0 server. :param refresh_token: The previously-obtained refresh token. :param method: (Default POST) The HTTP method to use for the request. :param payload_params: (Default ``None``) Additional payload parameters to be URL-encoded and added into the request body. :returns: Refreshed access token. """ # TODO: Add async_callback. params = { "client_id": self._client_credentials.identifier, "client_secret": self._client_credentials.shared_secret, "refresh_token": refresh_token, "grant_type": "refresh_token", } if payload_params: params.update(payload_params) body = urlencode_s(params) headers = { HEADER_CONTENT_TYPE: CONTENT_TYPE_FORM_URLENCODED, } response = self._http_client.fetch(RequestAdapter(method=method, url=self._token_uri, body=body, headers=headers)) if response.error: raise HttpError( "[refresh access token] OAuth 2.0 server response " \ "error: %d - %s" % (response.status, response.reason)) logging.info(response.content_type) token = json_decode(response.content) logging.info(token) return token
def test_do_seq_removes_blank_lists(self): params = dict(a=[], c="something") self.assertEqual(urlencode_s(params), b("c=something"))
def test_do_seq_dicts(self): # Behaves like doseq=1 params = dict(a=dict(a='b'), c="something") self.assertEqual(urlencode_s(params), b('a=a&c=something'))