Exemplo n.º 1
0
 def test_single_value_lists_are_not_flattened(self):
     d = parse_qs("a=1&a=2&a=3&b=c")
     for n, v in d.items():
         self.assertTrue(is_bytes(n),
                         "Dictionary key is not bytes.")
         self.assertTrue(isinstance(v, list),
                         "Dictionary value is not a list.")
Exemplo n.º 2
0
    def _parse_credentials_response(self, response):
        """
        Parses the entity-body of the OAuth server response to an OAuth
        credential request.

        :param response:
            An instance of :class:`pyoauth.http.ResponseProxy`.
        :returns:
            A tuple of the form::

                (parameter dictionary, pyoauth.oauth1.Credentials instance)
        """
        if not response.status_code:
            raise InvalidHttpResponseError("Invalid status code: `%r`" % (response.status_code, ))
        if not response.status:
            raise InvalidHttpResponseError("Invalid status message: `%r`" % (response.status, ))
        if not response.payload:
            raise InvalidHttpResponseError("Body is invalid or empty: `%r`" % (response.payload, ))
        if not response.headers:
            raise InvalidHttpResponseError("Headers are invalid or not specified: `%r`" % (response.headers, ))

        if response.error:
            raise HttpError("Could not fetch credentials: HTTP %d - %s" % (response.status_code, response.status,))
        # The response body must be URL encoded.
        if not response.is_body_form_urlencoded():
            raise InvalidContentTypeError("OAuth credentials server response must have Content-Type: `%s`" % (CONTENT_TYPE_FORM_URLENCODED, ))

        params = parse_qs(response.payload)
        return params, Credentials(identifier=params["oauth_token"][0],
                                   shared_secret=params["oauth_token_secret"][0])
Exemplo n.º 3
0
 def test_ignores_prefixed_question_mark_character_if_included(self):
     qs = '?b5=%3D%253D&a3=a&c%40=&a2=r%20b&c2&a3=2+q'
     q = parse_qs(qs)
     self.assertDictEqual(q,
             {b('a2'): [b('r b')],
              b('a3'): [b('a'), b('2 q')],
              b('b5'): [b('=%3D')],
              b('c@'): [b('')],
              b('c2'): [b('')]})
Exemplo n.º 4
0
 def test_names_and_values_are_percent_decoded(self):
     qs = 'b5=%3D%253D&a3=a&c%40=&a2=r%20b&c2&a3=2+q'
     q = parse_qs(qs)
     self.assertDictEqual(q,
             {b('a2'): [b('r b')],
              b('a3'): [b('a'), b('2 q')],
              b('b5'): [b('=%3D')],
              b('c@'): [b('')],
              b('c2'): [b('')]})
Exemplo n.º 5
0
    def _parse_credentials_response(cls, response, strict=True):
        """
        Parses the entity-body of the OAuth server response to an OAuth
        credential request.

        :param response:
            An instance of :class:`pyoauth.http.ResponseAdapter`.
        :param strict:
            ``True`` (default) for string response parsing; ``False`` to be a
            bit lenient. Some non-compliant OAuth servers return credentials
            without setting the content-type.

            Setting this to ``False`` will not raise an error, but will
            still warn you that the response content-type is not valid.
        :returns:
            A tuple of the form::

                (pyoauth.oauth1.Credentials instance, other parameters)
        """
        if not response.status:
            raise InvalidHttpResponseError(
                "Invalid status code: `%r`" % response.status)
        if not response.reason:
            raise InvalidHttpResponseError(
                "Invalid status message: `%r`" % response.reason)
        if not response.body:
            raise InvalidHttpResponseError(
                "Body is invalid or empty: `%r`" % response.body)
        if not response.headers:
            raise InvalidHttpResponseError(
                "Headers are invalid or not specified: `%r`" % \
                response.headers)

        if response.error:
            raise HttpError("Could not fetch credentials: HTTP %d - %s" \
            % (response.status, response.reason,))

        # The response body must be form URL-encoded.
        if not response.is_body_form_urlencoded():
            if strict:
                raise InvalidContentTypeError(
                    "OAuth credentials server response must " \
                    "have Content-Type: `%s`; got %r" %
                    (CONTENT_TYPE_FORM_URLENCODED, response.content_type))
            else:
                logging.warning(
                    "Response parsing strict-mode disabled -- " \
                    "OAuth server credentials response specifies invalid " \
                    "Content-Type: expected %r; got %r",
                    CONTENT_TYPE_FORM_URLENCODED, response.content_type)

        params = parse_qs(response.body)
        # Ensure the keys to this dictionary are unicode strings in Python 3.x.
        params = map_dict(lambda k, v: (utf8_decode_if_bytes(k), v), params)
        credentials = Credentials(identifier=params[OAUTH_PARAM_TOKEN][0],
                            shared_secret=params[OAUTH_PARAM_TOKEN_SECRET][0])
        return credentials, params
Exemplo n.º 6
0
def _url_equals(url1, url2):
    """
    Compares two URLs and determines whether they are the equal.

    :param url1:
        First URL.
    :param url2:
        Second URL.
    :returns:
        ``True`` if equal; ``False`` otherwise.

    Usage::

        >>> _url_equals("http://www.google.com/a", "http://www.google.com/a")
        True
        >>> _url_equals("https://www.google.com/a", "http://www.google.com/a")
        False
        >>> _url_equals("http://www.google.com/", "http://www.example.com/")
        False
        >>> _url_equals("http://example.com:80/", "http://example.com:8000/")
        False
        >>> _url_equals("http://[email protected]/", "http://[email protected]/")
        False
        >>> _url_equals("http://[email protected]/request?a=b&b=c&b=d#fragment", "http://[email protected]/request?b=c&b=d&a=b#fragment")
        True
        >>> _url_equals("http://[email protected]/request?a=b&b=c&b=d#fragment", "http://[email protected]/request?b=c&b=d&a=b#fragment2")
        False
        >>> _url_equals("http://www.google.com/request?a=b", "http://www.google.com/request?b=c")
        False
    """
    u1 = urlparse(url1)
    u2 = urlparse(url2)
    return u1.scheme == u2.scheme and \
        u1.path == u2.path and \
        u1.params == u2.params and \
        u1.netloc == u2.netloc and \
        u1.fragment == u2.fragment and \
        parse_qs(u1.query, keep_blank_values=True) == \
            parse_qs(u2.query, keep_blank_values=True)
Exemplo n.º 7
0
 def test_percent_decoding_treats_plus_as_space(self):
     self.assertDictEqual(parse_qs('a=2+q'), {b('a'): [b('2 q')]})
Exemplo n.º 8
0
 def test_are_multiple_values_obtained(self):
     self.assertDictEqual(parse_qs("a=1&a=2&a=3&b=c"),
             {b("a"): [b("1"), b("2"), b("3")], b("b"): [b("c")]})
Exemplo n.º 9
0
 def test_are_blank_values_preserved(self):
     self.assertDictEqual(parse_qs("a="), {b("a"): [b("")]})
     self.assertDictEqual(parse_qs("a"), {b("a"): [b("")]})
Exemplo n.º 10
0
    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
            )
Exemplo n.º 11
0
 def test_percent_decoding_treats_plus_as_space(self):
     assert_dict_equal(parse_qs('a=2+q'), {'a': ['2 q']})
Exemplo n.º 12
0
 def test_names_and_values_are_percent_decoded(self):
     qs = 'b5=%3D%253D&a3=a&c%40=&a2=r%20b' + '&' + 'c2&a3=2+q'
     q = parse_qs(qs)
     assert_dict_equal(q,
             {'a2': ['r b'], 'a3': ['a', '2 q'], 'b5': ['=%3D'], 'c@': [''],
              'c2': ['']})
Exemplo n.º 13
0
 def test_single_value_lists_are_not_flattened(self):
     d = parse_qs("a=1&a=2&a=3&b=c")
     for n, v in d.items():
         assert_true(isinstance(n, str), "Dictionary key is not a string.")
         assert_true(isinstance(v, list), "Dictionary value is not a list.")
Exemplo n.º 14
0
 def test_are_multiple_values_obtained(self):
     assert_dict_equal(parse_qs("a=1&a=2&a=3&b=c"),
             {"a": ["1", "2", "3"], "b": ["c"]})
Exemplo n.º 15
0
 def test_are_blank_values_preserved(self):
     assert_dict_equal(parse_qs("a="), {"a": [""]})
     assert_dict_equal(parse_qs("a"), {"a": [""]})
Exemplo n.º 16
0
 def test_ignores_prefixed_question_mark_character_if_included(self):
     qs = '?b5=%3D%253D&a3=a&c%40=&a2=r%20b' + '&' + 'c2&a3=2+q'
     q = parse_qs(qs)
     assert_dict_equal(q,
             {'a2': ['r b'], 'a3': ['a', '2 q'], 'b5': ['=%3D'], 'c@': [''],
              'c2': ['']})