def test_alphabets_are_not_encoded(self):
     lowercase_alphabets = [chr(x) for x in range(ord('a'), ord('z') + 1)]
     uppercase_alphabers = [chr(x) for x in range(ord('A'), ord('Z') + 1)]
     alphabets = lowercase_alphabets + uppercase_alphabers
     for alphabet in alphabets:
         self.assertEqual(percent_encode(alphabet), alphabet.encode("ascii"),
                      "Alphabets should not be encoded.")
 def test_character_encoding_is_uppercase(self):
     for char in self._unsafe_characters:
         for c in percent_encode(char):
             if isinstance(c, int):
                 c = chr(c)
             if c.isalpha():
                 self.assertTrue(
                     c.isupper(),
                     "Percent-encoding is not uppercase: %r for char: %r" \
                     % (c, char))
 def test_oauth_test_cases(self):
     # http://wiki.oauth.net/w/page/12238556/TestCases
     ex = [
         ('abcABC123', 'abcABC123'),
         ('-._~', '-._~'),
         ('%', '%25'),
         ('+', '%2B'),
         ('&=*', '%26%3D%2A'),
         (u'\u000A', '%0A'),
         (u'\u0020', '%20'),
         (u'\u007F', '%7F'),
         (u'\u0080', '%C2%80'),
         (u'\u3001', '%E3%80%81'),
     ]
     for k, v in ex:
         assert_equal(percent_encode(k), v)
Exemple #4
0
def _generate_plaintext_signature(client_shared_secret,
                             token_or_temporary_shared_secret=None):
    """
    Calculates the PLAINTEXT signature.

    :param client_shared_secret:
        Client (consumer) shared secret.
    :param token_or_temporary_shared_secret:
        Token/temporary credentials shared secret if available.
    :returns:
        PLAINTEXT signature.
    """
    client_shared_secret = client_shared_secret or ""
    token_or_temporary_shared_secret = token_or_temporary_shared_secret or ""
    return "&".join([
        percent_encode(a) for a in [
            client_shared_secret, token_or_temporary_shared_secret]])
Exemple #5
0
def generate_signature_base_string(method, url, oauth_params):
    """
    Calculates a signature base string based on the URL, method, and
    oauth parameters.

    Any query parameter by the name "oauth_signature" will be excluded
    from the base string.

    :see: Signature base string (http://tools.ietf.org/html/rfc5849#section-3.4.1)

    :param method:
        HTTP request method.
    :param url:
        The URL. If this includes a query string, query parameters are first
        extracted and encoded as well. All protocol-specific parameters
        will be ignored from the query string.
    :param oauth_params:
        Protocol-specific parameters must be specified in this dictionary.
        All non-protocol parameters will be ignored.
    :returns:
        Base string.
    """
    allowed_methods = ("POST", "GET", "PUT", "DELETE",
                       "OPTIONS", "TRACE", "HEAD", "CONNECT",
                       "PATCH")
    method_normalized = method.upper()
    if method_normalized not in allowed_methods:
        raise InvalidHttpMethodError("Method must be one of the HTTP methods %s: got `%s` instead" % (allowed_methods, method))
    if not url:
        raise InvalidUrlError("URL must be specified: got `%r`" % (url, ))
    if not isinstance(oauth_params, dict):
        raise InvalidOAuthParametersError("Dictionary required: got `%r`" % (oauth_params, ))

    scheme, netloc, path, matrix_params, query, fragment = urlparse_normalized(url)
    query_string = _generate_signature_base_string_query(query, oauth_params)
    normalized_url = urlunparse((scheme, netloc, path, matrix_params, None, None))
    return "&".join([
        percent_encode(e) for e in [
            method_normalized, normalized_url, query_string]])
 def test_unsafe_characters_are_encoded(self):
     for char in self._unsafe_characters:
         self.assertNotEqual(percent_encode(char), char)
 def test_unicode_utf8_encoded(self):
     assert_equal(percent_encode(self.uni_unicode_object), "%C2%AE")
 def test_space_is_not_encoded_as_plus(self):
     self.assertNotEqual(percent_encode(" "), b("+"))
     self.assertEqual(percent_encode(" "), b("%20"))
 def test_safe_symbols_are_not_encoded(self):
     safe_symbols = ["-", ".", "_", "~"]
     for symbol in safe_symbols:
         self.assertEqual(percent_encode(symbol), symbol.encode("ascii"),
                      "Symbol %s should not be encoded." % (symbol,))
 def test_digits_are_not_encoded(self):
     digits = [str(x) for x in range(10)]
     for digit in digits:
         self.assertEqual(percent_encode(digit), digit.encode("ascii"),
                      "Digits should not be encoded.")
Exemple #11
0
 def test_utf8_bytestring_left_as_is(self):
     assert_equal(percent_encode(self.uni_utf8_bytes), "%C2%AE")
 def test_unicode_utf8_encoded(self):
     self.assertEqual(percent_encode(self.uni_unicode_object), b("%C2%AE"))
 def test_non_string_values_are_stringified(self):
     self.assertEqual(percent_encode(True), b("True"))
     self.assertEqual(percent_encode(5), b("5"))
Exemple #14
0
 def test_digits_are_not_encoded(self):
     digits = [str(x) for x in range(10)]
     for digit in digits:
         assert_equal(percent_encode(digit), digit,
                      "Digits should not be encoded.")
Exemple #15
0
 def test_space_is_not_encoded_as_plus(self):
     assert_not_equal(percent_encode(" "), "+")
     assert_equal(percent_encode(" "), "%20")
Exemple #16
0
 def test_non_string_values_are_stringified(self):
     assert_equal(percent_encode(True), "True")
     assert_equal(percent_encode(5), "5")
Exemple #17
0
 def test_character_encoding_is_uppercase(self):
     for char in self._unsafe_characters:
         for c in percent_encode(char):
             if c.isalpha():
                 assert_true(c.isupper(), "Percent-encoding is not uppercase: %r for char: %r" % (c, char))
 def test_percent_encoded(self):
     for char in self._unsafe_characters:
         self.assertEqual(
             percent_encode(char)[0], b("%")[0],
             "Character not percent-encoded.")
 def test_oauth_test_cases(self):
     # http://wiki.oauth.net/w/page/12238556/TestCases
     ex = constants.percent_encode_test_cases
     for k, v in ex:
         self.assertEqual(percent_encode(k), v)
Exemple #20
0
def verify_hmac_sha1_signature(signature,
                               base_string,
                               client_shared_secret,
                               token_shared_secret=None,
                               debug=False):
    """
    Verifies an HMAC-SHA1 signature for a base string.

    :see: HMAC-SHA1 (http://tools.ietf.org/html/rfc5849#section-3.4.2)
    :param signature:
        The signature to verify.
    :param base_string:
        The base string.
    :param client_shared_secret:
        Client (consumer) shared secret.
    :param token_shared_secret:
        Token/temporary credentials shared secret if available.
    :param debug:
        Default ``False``.

        ``True`` to turn on debugging mode, which attempts to find out
        why signature verification fails, if it does; ``False`` otherwise.
    :returns:
        A tuple of
            (whether signature matches (boolean),
            error message (None if it succeeded)).
    """
    key = _generate_plaintext_signature(client_shared_secret,
                                        token_shared_secret)
    check_ok = (signature == hmac_sha1_base64_digest(key, base_string))
    if check_ok:
        err = None
    else:
        err = "Invalid signature"

    if not check_ok and debug:
        # Try to find out why it didn't match.
        # We need to help the poor human souls on the other
        # side of this mess who are trying to debug their OAuth clients.
        # This is not going to detect 100% of the cases, because it is
        # too easy to screw up on the client side. Anything could be wrong.
        # We're just trying to find out some common problems.

        # Assume correct base string but detect incorrect signature encoding.
        key = _generate_plaintext_signature(client_shared_secret,
                                            token_shared_secret,
                                            _percent_encode=False)
        if signature == hmac_sha1_base64_digest(key, base_string):
            return check_ok, "Invalid signature: signature elements " \
                       "are not percent-encoded properly"

        # Assume correct base string but detect missing ampersands in signature.
        if client_shared_secret and not token_shared_secret:
            key = percent_encode(client_shared_secret) + SYMBOL_AMPERSAND
            if signature == hmac_sha1_base64_digest(key, base_string):
                return check_ok, "Invalid signature: missing ampersand `&` " \
                           "after client shared secret in signature"
        elif not client_shared_secret and token_shared_secret:
            key = SYMBOL_AMPERSAND + percent_encode(token_shared_secret)
            if signature == hmac_sha1_base64_digest(key, base_string):
                return check_ok, "Invalid signature: missing ampersand `&` "\
                           "before token secret in signature"
        elif not client_shared_secret and not token_shared_secret:
            key = SYMBOL_AMPERSAND
            if signature == hmac_sha1_base64_digest(key, base_string):
                return check_ok, "Invalid signature: missing ampersand `&` "\
                           "without secrets in signature"
        elif client_shared_secret and token_shared_secret:
            key = percent_encode(client_shared_secret) + \
                  SYMBOL_AMPERSAND + percent_encode(token_shared_secret)
            if signature == hmac_sha1_base64_digest(key, base_string):
                return check_ok, "Invalid signature: missing ampersand `&` "\
                           "between signature secrets"

        # Assume incorrect base string
        return check_ok, "Invalid signature: check base string?"

    return check_ok, err
 def test_utf8_bytestring_left_as_is(self):
     self.assertEqual(percent_encode(self.uni_utf8_bytes), b("%C2%AE"))