Exemplo n.º 1
0
    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)
Exemplo n.º 2
0
def generate_normalized_authorization_header_value(oauth_params,
                                              realm=None,
                                              param_delimiter=","):
    """
    Builds the Authorization header value.

    Please note that the generated authorization header value MUST be
    on a SINGLE line.

    :see: Authorization Header http://tools.ietf.org/html/rfc5849#section-3.5.1
    :param oauth_params:
        Protocol-specific parameters excluding the ``realm`` parameter.
    :param realm:
        If specified, the realm is included into the Authorization header.
        The realm is never percent-encoded according to the OAuth spec.
    :param param_delimiter:
        The delimiter used to separate header value parameters.
        According to the Specification, this must be a comma ",". However,
        certain services like Yahoo! use "&" instead. Comma is default.

        See https://github.com/oauth/oauth-ruby/pull/12
    :returns:
        A properly formatted Authorization header value.
    """
    if realm:
        s = 'OAuth realm="' + unicode_to_utf8(realm) + '"' + param_delimiter
    else:
        s = 'OAuth '
    oauth_params = request_protocol_params_sanitize(oauth_params)
    normalized_param_pairs = urlencode_sl(oauth_params)
    s += param_delimiter.join([k + '="' + v + '"' for k, v in normalized_param_pairs])
    return s
Exemplo n.º 3
0
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
Exemplo n.º 4
0
def parse_authorization_header_value(header_value, param_delimiter=",", strict=True):
    """
    Parses the OAuth Authorization header.

    :see: Authorization Header http://tools.ietf.org/html/rfc5849#section-3.5.1
    :param header_value:
        Header value.
    :param param_delimiter:
        The delimiter used to separate header value parameters.
        According to the Specification, this must be a comma ",". However,
        certain services like Yahoo! use "&" instead. Comma is default.

        If you want to use another delimiter character, the ``strict``
        argument to this function must also be set to ``False``.
        See https://github.com/oauth/oauth-ruby/pull/12
    :param strict:
        When ``True``, more strict checking will be performed.
        The authorization header value must be on a single line.
        The param delimiter MUST be a comma.
        When ``False``, the parser is a bit lenient.
    :returns:
        Dictionary of parameter name value pairs.
    """
    d = {}
    param_list, realm = \
        _parse_authorization_header_value_l(header_value,
                                            param_delimiter=param_delimiter,
                                            strict=strict)
    for name, value in param_list:
        #d[name] = [value]
        # We do keep track of multiple values because they will be
        # detected by the sanitization below and flagged as an error
        # in the Authorization header value.
        if name in d:
            d[name].append(value)
        else:
            d[name] = [value]
    d = request_protocol_params_sanitize(d)
    return d, realm
Exemplo n.º 5
0
    def _build_request(self,
                      method,
                      url,
                      payload_params=None,
                      headers=None,
                      token_or_temporary_credentials=None,
                      realm=None,
                      oauth_signature_method=SIGNATURE_METHOD_HMAC_SHA1,
                      **extra_oauth_params):
        """
        Builds an OAuth request.

        :param method:
            HTTP request method.
        :param url:
            The OAuth request URI.
        :param payload_params:
            A dictionary of payload parameters. These will be serialized
            into the URL or the entity-body depending on the HTTP request method.
            These must not include any parameters starting with ``oauth_``. Any
            of these parameters with names starting with the ``oauth_`` prefix
            will be ignored.
        :param headers:
            A dictionary of headers that will be passed along with the request.
            Must not include the "Authorization" header.
        :param realm:
            The value to use for the realm parameter in the Authorization HTTP
            header. It will be excluded from the request signature.
        :param oauth_signature_method:
            One of:
            1. :attr:`pyoauth.oauth1.SIGNATURE_METHOD_HMAC_SHA1`
            2. :attr:`pyoauth.oauth1.SIGNATURE_METHOD_RSA_SHA1`
            3. :attr:`pyoauth.oauth1.SIGNATURE_METHOD_PLAINTEXT`
        :param extra_oauth_params:
            Any additional oauth parameters you would like to include.
            The parameter names must begin with ``oauth_``. Any other parameters
            with names that do not begin with this prefix will be ignored.
        :returns:
            An instance of :class:`pyoauth.http.Request`.
        """
        method = method.upper()
        headers = headers or {}
        realm = realm or ""

        if oauth_signature_method not in SIGNATURE_METHOD_MAP:
            raise InvalidSignatureMethodError("Invalid signature method specified: `%r`" % (oauth_signature_method,))

        # Required OAuth protocol parameters.
        # See Making Requests (http://tools.ietf.org/html/rfc5849#section-3.1)
        oauth_params = dict(
            oauth_consumer_key=self._client_credentials.identifier,
            oauth_signature_method=oauth_signature_method,
            oauth_timestamp=generate_timestamp(),
            oauth_nonce=generate_nonce(),
            oauth_version=self.oauth_version,
        )
        if token_or_temporary_credentials:
            oauth_params["oauth_token"] = token_or_temporary_credentials.identifier

        if "_test_force_exclude_oauth_version" in extra_oauth_params:
            del oauth_params["oauth_version"]

        # Filter and add additional OAuth parameters.
        _force_override_reserved_oauth_params_for_tests = "_test_force_override_reserved_oauth_params" in extra_oauth_params
        extra_oauth_params = request_protocol_params_sanitize(extra_oauth_params)
        reserved_oauth_params = (
            "oauth_signature",     # Calculated from given parameters.
            "oauth_nonce",         # System-generated.
            "oauth_timestamp",     # System-generated.
            "oauth_consumer_key",  # Provided when creating the client instance.
            "oauth_version",       # Optional but MUST be set to "1.0" according to spec.
            "oauth_token",         # Determined from the token or temporary credentials.
        )
        for k, v in extra_oauth_params.items():
            if not _force_override_reserved_oauth_params_for_tests and k in reserved_oauth_params:
                # Don't override these required system-generated protocol parameters.
                raise IllegalArgumentError("Cannot override system-generated protocol parameter `%r`." % k)
            else:
                if k in oauth_params:
                    # Warn when an existing protocol parameter is being
                    # overridden.
                    logging.warning("Overriding existing protocol parameter `%r`=`%r` with `%r`=`%r`",
                                    k, oauth_params[k], k, v[0])
                oauth_params[k] = v[0]

        # Filter payload parameters for the request.
        payload_params = query_params_sanitize(payload_params)

        # I was not entirely certain about whether PUT payload
        # params should be included in the signature or not.
        # Here is why:
        #
        #    http://groups.google.com/group/oauth/browse_thread/thread/fdc0b11f2c4a8dc3/
        #
        # http://tools.ietf.org/html/rfc5849#appendix-A
        # However, Appendix A in the RFC specification clarifies this point.
        # form URL encoded entity bodies in a request using any HTTP verb
        # must be part of the base string used for the signature.
        # Therefore, do NOT exclude payload params from the signature URL
        # when the PUT HTTP method is used.
        #
        #if method == "PUT":
        #     signature_url = url
        #else:
        signature_url = url_add_query(url, payload_params)

        # Determine the request's OAuth signature.
        oauth_params["oauth_signature"] = self._sign_request_data(oauth_signature_method,
                                                                  method, signature_url, oauth_params,
                                                                  token_or_temporary_credentials)

        # Build request data now.
        # OAuth parameters and any parameters starting with the ``oauth_``
        # must be included only in ONE of these three locations:
        #
        # 1. Authorization header.
        # 2. Request URI query string.
        # 3. Request entity body.
        #
        # See Parameter Transmission (http://tools.ietf.org/html/rfc5849#section-3.6)
        if "Authorization" in headers:
            raise InvalidAuthorizationHeaderError("Authorization field is already present in headers: `%r`" % (headers, ))
        if self._use_authorization_header:
            auth_header_value = \
                generate_normalized_authorization_header_value(oauth_params,
                                                          realm=realm,
                                                          param_delimiter=self._authorization_header_param_delimiter)
            headers["Authorization"] = auth_header_value
            # Empty the params if using authorization so that they are not
            # included multiple times in a request below.
            oauth_params = None

        if method == "GET":
            request_url = url_add_query(url, payload_params)
            request_url = url_append_query(request_url, oauth_params)
            payload = ""
        else:
            # The payload params are not appended to the OAuth request URL
            # in this case but added to the payload instead.
            request_url = url
            headers["Content-Type"] = CONTENT_TYPE_FORM_URLENCODED
            payload = query_append(payload_params, oauth_params)

        return RequestProxy(method,
                            url=request_url,
                            body=payload,
                            headers=headers)