@@ -105,9 +105,9 @@ def construct_base_string(http_method, base_string_uri,
105105 return base_string
106106
107107
108- def normalize_base_string_uri (uri , host = None ):
108+ def base_string_uri (uri , host = None ):
109109 """**Base String URI**
110- Per `section 3.4.1.2`_ of the spec .
110+ Per `section 3.4.1.2`_ of RFC 5849 .
111111
112112 For example, the HTTP request::
113113
@@ -177,7 +177,31 @@ def normalize_base_string_uri(uri, host=None):
177177 if (scheme , port ) in default_ports :
178178 netloc = host
179179
180- return urlparse .urlunparse ((scheme , netloc , path , params , '' , '' ))
180+ v = urlparse .urlunparse ((scheme , netloc , path , params , '' , '' ))
181+
182+ # RFC 5849 does not specify which characters are encoded in the
183+ # "base string URI", nor how they are encoded - which is very bad, since
184+ # the signatures won't match if there are any differences. Fortunately,
185+ # most URIs only use characters that are clearly not encoded (e.g. digits
186+ # and A-Z, a-z), so have avoided any differences between implementations.
187+ #
188+ # The example from its section 3.4.1.2 illustrates that spaces in
189+ # the path are percent encoded. But it provides no guidance as to what other
190+ # characters (if any) must be encoded (nor how); nor if characters in the
191+ # other components are to be encoded or not.
192+ #
193+ # This implementation **assumes** that **only** the space is percent-encoded
194+ # and it is done to the entire value (not just to spaces in the path).
195+ #
196+ # This code may need to be changed if it is discovered that other characters
197+ # are expected to be encoded.
198+ #
199+ # Note: the "base string URI" returned by this function will be encoded
200+ # again before being concatenated into the "signature base string". So any
201+ # spaces in the URI will actually appear in the "signature base string"
202+ # as "%2520" (the "%20" further encoded according to section 3.6).
203+
204+ return v .replace (' ' , '%20' )
181205
182206
183207# ** Request Parameters **
@@ -624,8 +648,8 @@ def verify_hmac_sha1(request, client_secret=None,
624648
625649 """
626650 norm_params = normalize_parameters (request .params )
627- uri = normalize_base_string_uri (request .uri )
628- base_string = construct_base_string (request .http_method , uri , norm_params )
651+ bs_uri = base_string_uri (request .uri )
652+ base_string = construct_base_string (request .http_method , bs_uri , norm_params )
629653 signature = sign_hmac_sha1 (base_string , client_secret ,
630654 resource_owner_secret )
631655 match = safe_string_equals (signature , request .signature )
@@ -657,8 +681,8 @@ def verify_rsa_sha1(request, rsa_public_key):
657681 .. _`RFC2616 section 5.2`: https://tools.ietf.org/html/rfc2616#section-5.2
658682 """
659683 norm_params = normalize_parameters (request .params )
660- uri = normalize_base_string_uri (request .uri )
661- message = construct_base_string (request .http_method , uri , norm_params ).encode ('utf-8' )
684+ bs_uri = base_string_uri (request .uri )
685+ message = construct_base_string (request .http_method , bs_uri , norm_params ).encode ('utf-8' )
662686 sig = binascii .a2b_base64 (request .signature .encode ('utf-8' ))
663687
664688 alg = _jwt_rs1_signing_algorithm ()
0 commit comments