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 = { "a2": ["r b"], "b5": ["=%3D"], "a3": ["a", "2 q"], "c@": [""], "c2": [""], } expected_result = urlencode_s(expected_params) assert_equal(urlencode_s(query_params_sanitize(params)), expected_result) assert_equal(urlencode_s(query_params_sanitize(query_string)), expected_result)
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 get_authorization_url(self, temporary_credentials, **query_params): """ Calculates the authorization URL to which the user will be (re)directed. :param temporary_credentials: Temporary credentials obtained after parsing the response to the temporary credentials request. :param query_params: Additional query parameters that you would like to include into the authorization URL. Parameters beginning with the ``oauth_`` prefix will be ignored. """ url = self._resource_owner_authorization_uri if query_params: query_params = query_params_sanitize(query_params) url = url_append_query(url, query_params) # So that the "oauth_token" appears LAST. return url_append_query(url, { "oauth_token": temporary_credentials.identifier, })
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)