Blame SOURCES/0004-IPV6-parsing-signature.patch

8f73b7
From 49294a6a7cb6e9ece1c1814d629e2d9e497180fa Mon Sep 17 00:00:00 2001
8f73b7
From: Dariusz Smigiel <dsmigiel@redhat.com>
8f73b7
Date: Thu, 19 May 2022 09:41:59 -0700
8f73b7
Subject: [PATCH 1/4] OAuth1: Allow IPv6 addresses being parsed by signature
8f73b7
8f73b7
This PR addresses issue with incorrectly parsing IPv6 address,
8f73b7
described here: https://github.com/oauthlib/oauthlib/issues/817
8f73b7
---
8f73b7
 oauthlib/oauth1/rfc5849/signature.py | 2 +-
8f73b7
 1 file changed, 1 insertion(+), 1 deletion(-)
8f73b7
8f73b7
diff --git a/oauthlib/oauth1/rfc5849/signature.py b/oauthlib/oauth1/rfc5849/signature.py
8f73b7
index a370ccd6..424393b6 100644
8f73b7
--- a/oauthlib/oauth1/rfc5849/signature.py
8f73b7
+++ b/oauthlib/oauth1/rfc5849/signature.py
8f73b7
@@ -173,7 +173,7 @@ def base_string_uri(uri: str, host: str = None) -> str:
8f73b7
     if ':' in netloc:
8f73b7
         # Contains a colon ":", so try to parse as "host:port"
8f73b7
 
8f73b7
-        hostname, port_str = netloc.split(':', 1)
8f73b7
+        hostname, port_str = netloc.rsplit(':', 1)
8f73b7
 
8f73b7
         if len(hostname) == 0:
8f73b7
             raise ValueError('missing host')  # error: netloc was ":port" or ":"
8f73b7
8f73b7
From d05c388078b45285ac4a012c568a5e2d56556a34 Mon Sep 17 00:00:00 2001
8f73b7
From: Dariusz Smigiel <dsmigiel@redhat.com>
8f73b7
Date: Wed, 15 Jun 2022 09:26:20 -0700
8f73b7
Subject: [PATCH 2/4] Removed dependency on split
8f73b7
8f73b7
---
8f73b7
 oauthlib/oauth1/rfc5849/signature.py    | 68 +++++++++++++++----------
8f73b7
 tests/oauth1/rfc5849/test_signatures.py | 21 +++++++-
8f73b7
 2 files changed, 60 insertions(+), 29 deletions(-)
8f73b7
8f73b7
diff --git a/oauthlib/oauth1/rfc5849/signature.py b/oauthlib/oauth1/rfc5849/signature.py
8f73b7
index 424393b6..70447852 100644
8f73b7
--- a/oauthlib/oauth1/rfc5849/signature.py
8f73b7
+++ b/oauthlib/oauth1/rfc5849/signature.py
8f73b7
@@ -37,6 +37,7 @@
8f73b7
 import binascii
8f73b7
 import hashlib
8f73b7
 import hmac
8f73b7
+import ipaddress
8f73b7
 import logging
8f73b7
 import warnings
8f73b7
 
8f73b7
@@ -131,7 +132,14 @@ def base_string_uri(uri: str, host: str = None) -> str:
8f73b7
         raise ValueError('uri must be a string.')
8f73b7
 
8f73b7
     # FIXME: urlparse does not support unicode
8f73b7
-    scheme, netloc, path, params, query, fragment = urlparse.urlparse(uri)
8f73b7
+    output = urlparse.urlparse(uri)
8f73b7
+    scheme = output.scheme
8f73b7
+    hostname = output.hostname
8f73b7
+    port = output.port
8f73b7
+    path = output.path
8f73b7
+    params = output.params
8f73b7
+    query = output.query
8f73b7
+    fragment = output.fragment
8f73b7
 
8f73b7
     # The scheme, authority, and path of the request resource URI `RFC3986`
8f73b7
     # are included by constructing an "http" or "https" URI representing
8f73b7
@@ -153,13 +161,22 @@ def base_string_uri(uri: str, host: str = None) -> str:
8f73b7
 
8f73b7
     # 1.  The scheme and host MUST be in lowercase.
8f73b7
     scheme = scheme.lower()
8f73b7
-    netloc = netloc.lower()
8f73b7
     # Note: if ``host`` is used, it will be converted to lowercase below
8f73b7
+    if hostname is not None:
8f73b7
+        hostname = hostname.lower()
8f73b7
 
8f73b7
     # 2.  The host and port values MUST match the content of the HTTP
8f73b7
     #     request "Host" header field.
8f73b7
     if host is not None:
8f73b7
-        netloc = host.lower()  # override value in uri with provided host
8f73b7
+        # NOTE: override value in uri with provided host
8f73b7
+        # Host argument is equal to netloc. It means it's missing scheme.
8f73b7
+        # Add it back, before parsing.
8f73b7
+
8f73b7
+        host = host.lower()
8f73b7
+        host = f"{scheme}://{host}"
8f73b7
+        output = urlparse.urlparse(host)
8f73b7
+        hostname = output.hostname
8f73b7
+        port = output.port
8f73b7
 
8f73b7
     # 3.  The port MUST be included if it is not the default port for the
8f73b7
     #     scheme, and MUST be excluded if it is the default.  Specifically,
8f73b7
@@ -170,33 +187,28 @@ def base_string_uri(uri: str, host: str = None) -> str:
8f73b7
     # .. _`RFC2616`: https://tools.ietf.org/html/rfc2616
8f73b7
     # .. _`RFC2818`: https://tools.ietf.org/html/rfc2818
8f73b7
 
8f73b7
-    if ':' in netloc:
8f73b7
-        # Contains a colon ":", so try to parse as "host:port"
8f73b7
-
8f73b7
-        hostname, port_str = netloc.rsplit(':', 1)
8f73b7
-
8f73b7
-        if len(hostname) == 0:
8f73b7
-            raise ValueError('missing host')  # error: netloc was ":port" or ":"
8f73b7
+    if hostname is None:
8f73b7
+        raise ValueError('missing host')
8f73b7
 
8f73b7
-        if len(port_str) == 0:
8f73b7
-            netloc = hostname  # was "host:", so just use the host part
8f73b7
-        else:
8f73b7
-            try:
8f73b7
-                port_num = int(port_str)  # try to parse into an integer number
8f73b7
-            except ValueError:
8f73b7
-                raise ValueError('port is not an integer')
8f73b7
-
8f73b7
-            if port_num <= 0 or 65535 < port_num:
8f73b7
-                raise ValueError('port out of range')  # 16-bit unsigned ints
8f73b7
-            if (scheme, port_num) in (('http', 80), ('https', 443)):
8f73b7
-                netloc = hostname  # default port for scheme: exclude port num
8f73b7
-            else:
8f73b7
-                netloc = hostname + ':' + str(port_num)  # use hostname:port
8f73b7
+    # NOTE: Try guessing if we're dealing with IP or hostname
8f73b7
+    try:
8f73b7
+        hostname = ipaddress.ip_address(hostname)
8f73b7
+    except ValueError:
8f73b7
+        pass
8f73b7
+
8f73b7
+    if isinstance(hostname, ipaddress.IPv6Address):
8f73b7
+        hostname = f"[{hostname}]"
8f73b7
+    elif isinstance(hostname, ipaddress.IPv4Address):
8f73b7
+        hostname = f"{hostname}"
8f73b7
+
8f73b7
+    if port is not None and not (0 <= port <= 65535):
8f73b7
+        raise ValueError('port out of range')  # 16-bit unsigned ints
8f73b7
+    if (scheme, port) in (('http', 80), ('https', 443)):
8f73b7
+        netloc = hostname  # default port for scheme: exclude port num
8f73b7
+    elif port:
8f73b7
+        netloc = f"{hostname}:{port}"  # use hostname:port
8f73b7
     else:
8f73b7
-        # Does not contain a colon, so entire value must be the hostname
8f73b7
-
8f73b7
-        if len(netloc) == 0:
8f73b7
-            raise ValueError('missing host')  # error: netloc was empty string
8f73b7
+        netloc = hostname
8f73b7
 
8f73b7
     v = urlparse.urlunparse((scheme, netloc, path, params, '', ''))
8f73b7
 
8f73b7
diff --git a/tests/oauth1/rfc5849/test_signatures.py b/tests/oauth1/rfc5849/test_signatures.py
8f73b7
index 3e84f24b..e737e68b 100644
8f73b7
--- a/tests/oauth1/rfc5849/test_signatures.py
8f73b7
+++ b/tests/oauth1/rfc5849/test_signatures.py
8f73b7
@@ -239,6 +239,26 @@ def test_base_string_uri(self):
8f73b7
             'http://override.example.com/path',
8f73b7
             base_string_uri('http:///path', 'OVERRIDE.example.com'))
8f73b7
 
8f73b7
+        # ----------------
8f73b7
+        # Host: valid host allows for IPv4 and IPv6
8f73b7
+
8f73b7
+        self.assertEqual(
8f73b7
+            'https://192.168.0.1/',
8f73b7
+            base_string_uri('https://192.168.0.1')
8f73b7
+        )
8f73b7
+        self.assertEqual(
8f73b7
+            'https://192.168.0.1:13000/',
8f73b7
+            base_string_uri('https://192.168.0.1:13000')
8f73b7
+        )
8f73b7
+        self.assertEqual(
8f73b7
+            'https://[123:db8:fd00:1000::5]:13000/',
8f73b7
+            base_string_uri('https://[123:db8:fd00:1000::5]:13000')
8f73b7
+        )
8f73b7
+        self.assertEqual(
8f73b7
+            'https://[123:db8:fd00:1000::5]/',
8f73b7
+            base_string_uri('https://[123:db8:fd00:1000::5]')
8f73b7
+        )
8f73b7
+
8f73b7
         # ----------------
8f73b7
         # Port: default ports always excluded; non-default ports always included
8f73b7
 
8f73b7
@@ -339,7 +359,6 @@ def test_base_string_uri(self):
8f73b7
         self.assertRaises(ValueError, base_string_uri, 'http://:8080')
8f73b7
 
8f73b7
         # Port is not a valid TCP/IP port number
8f73b7
-        self.assertRaises(ValueError, base_string_uri, 'http://eg.com:0')
8f73b7
         self.assertRaises(ValueError, base_string_uri, 'http://eg.com:-1')
8f73b7
         self.assertRaises(ValueError, base_string_uri, 'http://eg.com:65536')
8f73b7
         self.assertRaises(ValueError, base_string_uri, 'http://eg.com:3.14')
8f73b7
8f73b7
From ed0cb63945c4a5940b185823809693b7f97989ad Mon Sep 17 00:00:00 2001
8f73b7
From: Dariusz Smigiel <dsmigiel@redhat.com>
8f73b7
Date: Wed, 15 Jun 2022 10:20:29 -0700
8f73b7
Subject: [PATCH 3/4] Removed unused query and fragment
8f73b7
8f73b7
---
8f73b7
 oauthlib/oauth1/rfc5849/signature.py | 2 --
8f73b7
 1 file changed, 2 deletions(-)
8f73b7
8f73b7
diff --git a/oauthlib/oauth1/rfc5849/signature.py b/oauthlib/oauth1/rfc5849/signature.py
8f73b7
index 70447852..7e8044a9 100644
8f73b7
--- a/oauthlib/oauth1/rfc5849/signature.py
8f73b7
+++ b/oauthlib/oauth1/rfc5849/signature.py
8f73b7
@@ -138,8 +138,6 @@ def base_string_uri(uri: str, host: str = None) -> str:
8f73b7
     port = output.port
8f73b7
     path = output.path
8f73b7
     params = output.params
8f73b7
-    query = output.query
8f73b7
-    fragment = output.fragment
8f73b7
 
8f73b7
     # The scheme, authority, and path of the request resource URI `RFC3986`
8f73b7
     # are included by constructing an "http" or "https" URI representing
8f73b7
8f73b7
From 9aa45aaff0cdeab258d18c025cf66e9bdba529c0 Mon Sep 17 00:00:00 2001
8f73b7
From: Dariusz Smigiel <dsmigiel@redhat.com>
8f73b7
Date: Mon, 27 Jun 2022 07:20:06 -0700
8f73b7
Subject: [PATCH 4/4] Restored test for port 0.
8f73b7
8f73b7
---
8f73b7
 oauthlib/oauth1/rfc5849/signature.py    | 2 +-
8f73b7
 tests/oauth1/rfc5849/test_signatures.py | 1 +
8f73b7
 2 files changed, 2 insertions(+), 1 deletion(-)
8f73b7
8f73b7
diff --git a/oauthlib/oauth1/rfc5849/signature.py b/oauthlib/oauth1/rfc5849/signature.py
8f73b7
index 862c3f3c..9cb1a517 100644
8f73b7
--- a/oauthlib/oauth1/rfc5849/signature.py
8f73b7
+++ b/oauthlib/oauth1/rfc5849/signature.py
8f73b7
@@ -198,7 +198,7 @@ def base_string_uri(uri: str, host: str = None) -> str:
8f73b7
     elif isinstance(hostname, ipaddress.IPv4Address):
8f73b7
         hostname = f"{hostname}"
8f73b7
 
8f73b7
-    if port is not None and not (0 <= port <= 65535):
8f73b7
+    if port is not None and not (0 < port <= 65535):
8f73b7
         raise ValueError('port out of range')  # 16-bit unsigned ints
8f73b7
     if (scheme, port) in (('http', 80), ('https', 443)):
8f73b7
         netloc = hostname  # default port for scheme: exclude port num
8f73b7
diff --git a/tests/oauth1/rfc5849/test_signatures.py b/tests/oauth1/rfc5849/test_signatures.py
8f73b7
index f0e18093..2d4735ea 100644
8f73b7
--- a/tests/oauth1/rfc5849/test_signatures.py
8f73b7
+++ b/tests/oauth1/rfc5849/test_signatures.py
8f73b7
@@ -348,6 +348,7 @@ def test_base_string_uri(self):
8f73b7
         self.assertRaises(ValueError, base_string_uri, 'http://:8080')
8f73b7
 
8f73b7
         # Port is not a valid TCP/IP port number
8f73b7
+        self.assertRaises(ValueError, base_string_uri, 'http://eg.com:0')
8f73b7
         self.assertRaises(ValueError, base_string_uri, 'http://eg.com:-1')
8f73b7
         self.assertRaises(ValueError, base_string_uri, 'http://eg.com:65536')
8f73b7
         self.assertRaises(ValueError, base_string_uri, 'http://eg.com:3.14')