def test_when_neither_secret_present(self): base_string = generate_base_string( HTTP_POST, b("http://example.com/"), self.oauth_params) self.assertEqual(generate_plaintext_signature( base_string, b(""), None ), b("&"))
def test_when_token_secret_present(self): base_string = generate_base_string( HTTP_POST, b("http://example.com/"), self.oauth_params) self.assertEqual(generate_plaintext_signature( base_string, b(""), self.oauth_token_secret ), b("&token%20test%20secret"))
def test_base_string_preserves_matrix_params_and_drops_default_ports(self): url = b("http://social.yahooapis.com:80/v1/user/6677/connections" ";start=0;count=20?format=json#fragment") decoded_base_string = "POST&" \ "http://social.yahooapis.com/v1/user/6677/connections" \ ";start=0;count=20&format=json" self.assertEqual( percent_decode(generate_base_string(HTTP_POST, url, dict())), decoded_base_string )
def test_base_string_does_not_contain_oauth_signature(self): # Ensure both are present in the query parameters as well as the URL. oauth_params = { OAUTH_PARAM_REALM: b("example.com"), } oauth_params.update(self.oauth_params) url = b("http://example.com/request?" "oauth_signature=foobar&realm=something") base_string = generate_base_string(HTTP_POST, url, oauth_params) self.assertTrue(b("oauth_signature%3D") not in base_string) self.assertTrue(b("realm%3Dexample.com") not in base_string) self.assertTrue(b("realm%3Dsomething") in base_string)
def test_signature_is_valid(self): for example in self._examples: client_shared_secret = example[OAUTH_PARAM_CONSUMER_SECRET] token_shared_secret = example[OAUTH_PARAM_TOKEN_SECRET] url = example["url"] method = example["method"] oauth_params = example["oauth_params"] expected_signature = example[OAUTH_PARAM_SIGNATURE] base_string = generate_base_string(method, url, oauth_params) self.assertEqual(expected_signature, generate_hmac_sha1_signature( base_string, client_shared_secret, token_shared_secret ))
def test_valid_base_string(self): base_string = generate_base_string(HTTP_POST, b("http://example.com/request?"\ "b5=%3D%253D&a3=a&c%40=&a2=r%20b&c2&a3=2+q"), self.oauth_params) self.assertEqual(base_string, b("POST&"\ "http%3A%2F%2Fexample.com%2Frequest&"\ "a2%3Dr%2520b%26"\ "a3%3D2%2520q%26a3%3Da%26"\ "b5%3D%253D%25253D%26"\ "c%2540%3D%26"\ "c2%3D%26"\ "oauth_consumer_key%3D9djdj82h48djs9d2%26"\ "oauth_nonce%3D7d8f3e4a%26"\ "oauth_signature_method%3DHMAC-SHA1%26"\ "oauth_timestamp%3D137131201%26"\ "oauth_token%3Dkkk9d7dh3k39sjv7"))
def test_valid_signature(self): for example in self._examples: client_shared_secret = example["private_key"] client_certificate = example["certificate"] public_key = example["public_key"] url = example["url"] method = example["method"] oauth_params = example["oauth_params"] expected_signature = example[OAUTH_PARAM_SIGNATURE] # Using the RSA private key. base_string = generate_base_string(method, url, oauth_params) self.assertEqual(expected_signature, generate_rsa_sha1_signature(base_string, client_shared_secret)) # Using the X.509 certificate. self.assertTrue(verify_rsa_sha1_signature( expected_signature, base_string, client_certificate)) # Using the RSA public key. self.assertTrue(verify_rsa_sha1_signature( expected_signature, base_string, public_key))
def _generate_signature(cls, method, url, params, body, headers, oauth_consumer_secret, oauth_token_secret, oauth_params): """ Given the base string parameters, secrets, and protocol parameters, calculates a signature for the request. :param method: HTTP method. :param url: Request URL. :param params: Additional query/payload parameters. :param body: Payload if any. :param headers: HTTP headers as a dictionary. :param oauth_consumer_secret: OAuth client shared secret (consumer secret). :param oauth_token_secret: OAuth token/temporary shared secret if obtained from the OAuth server. :param oauth_params: OAuth parameters generated by :func:`OAuthClient._generate_oauth_params`. :returns: Request signature. """ # Take parameters from the body if the Content-Type is specified # as ``application/x-www-form-urlencoded``. # http://tools.ietf.org/html/rfc5849#section-3.4.1.3.1 if body: try: try: content_type = headers[HEADER_CONTENT_TYPE] except KeyError: content_type = headers[HEADER_CONTENT_TYPE_CAPS] if content_type == CONTENT_TYPE_FORM_URLENCODED: # These parameters must also be included in the signature. # Ignore OAuth-specific parameters. They must be specified # separately. body_params = query_remove_oauth(parse_qs(body)) params = query_add(params, body_params) else: logging.info( "Entity-body specified but `content-type` header " \ "value is not %r: entity-body parameters if " \ "present will not be signed: got body %r" % \ (CONTENT_TYPE_FORM_URLENCODED, body) ) except KeyError: logging.warning( "Entity-body specified but `content-type` is missing " ) # Make oauth params and sign the request. signature_url = url_add_query(url, query_remove_oauth(params)) # NOTE: We're not explicitly cleaning up because this method # expects oauth params generated by _generate_oauth_params. base_string = generate_base_string(method, signature_url, oauth_params) signature_method = oauth_params[OAUTH_PARAM_SIGNATURE_METHOD] cls.check_signature_method(signature_method) try: sign_func = SIGNATURE_METHOD_MAP[signature_method] return sign_func(base_string, oauth_consumer_secret, oauth_token_secret) except KeyError: raise InvalidSignatureMethodError( "unsupported signature method: %r" % signature_method )