From 5bedf76da0f76ab2d489972055a5d62066013427 Mon Sep 17 00:00:00 2001
From: Ian Stapleton Cordasco <graffatcolmingov@gmail.com>
Date: Sun, 3 Mar 2024 07:00:49 -0600
Subject: [PATCH] Use TLS settings in selecting connection pool

Previously, if someone made a request with `verify=False` then made a
request where they expected verification to be enabled to the same host,
they would potentially reuse a connection where TLS had not been
verified.

This fixes that issue.

Upstream-Status: Backport
[https://github.com/psf/requests/commit/a58d7f2ffb4d00b46dca2d70a3932a0b37e22fac]

CVE: CVE-2024-35195

Signed-off-by: Jiaying Song <jiaying.song.cn@windriver.com>
---
 requests/adapters.py | 58 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 57 insertions(+), 1 deletion(-)

diff --git a/requests/adapters.py b/requests/adapters.py
index fe22ff4..7ff6998 100644
--- a/requests/adapters.py
+++ b/requests/adapters.py
@@ -10,6 +10,7 @@ and maintain connections.
 
 import os.path
 import socket
+import typing
 
 from urllib3.poolmanager import PoolManager, proxy_from_url
 from urllib3.response import HTTPResponse
@@ -47,12 +48,38 @@ except ImportError:
     def SOCKSProxyManager(*args, **kwargs):
         raise InvalidSchema("Missing dependencies for SOCKS support.")
 
+if typing.TYPE_CHECKING:
+    from .models import PreparedRequest
+
+
 DEFAULT_POOLBLOCK = False
 DEFAULT_POOLSIZE = 10
 DEFAULT_RETRIES = 0
 DEFAULT_POOL_TIMEOUT = None
 
 
+def _urllib3_request_context(
+    request: "PreparedRequest", verify: "bool | str | None"
+) -> "(typing.Dict[str, typing.Any], typing.Dict[str, typing.Any])":
+    host_params = {}
+    pool_kwargs = {}
+    parsed_request_url = urlparse(request.url)
+    scheme = parsed_request_url.scheme.lower()
+    port = parsed_request_url.port
+    cert_reqs = "CERT_REQUIRED"
+    if verify is False:
+        cert_reqs = "CERT_NONE"
+    if isinstance(verify, str):
+        pool_kwargs["ca_certs"] = verify
+    pool_kwargs["cert_reqs"] = cert_reqs
+    host_params = {
+        "scheme": scheme,
+        "host": parsed_request_url.hostname,
+        "port": port,
+    }
+    return host_params, pool_kwargs
+
+
 class BaseAdapter(object):
     """The Base Transport Adapter"""
 
@@ -290,6 +317,35 @@ class HTTPAdapter(BaseAdapter):
 
         return response
 
+    def _get_connection(self, request, verify, proxies=None):
+        # Replace the existing get_connection without breaking things and
+        # ensure that TLS settings are considered when we interact with
+        # urllib3 HTTP Pools
+        proxy = select_proxy(request.url, proxies)
+        try:
+            host_params, pool_kwargs = _urllib3_request_context(request, verify)
+        except ValueError as e:
+            raise InvalidURL(e, request=request)
+        if proxy:
+            proxy = prepend_scheme_if_needed(proxy, "http")
+            proxy_url = parse_url(proxy)
+            if not proxy_url.host:
+                raise InvalidProxyURL(
+                    "Please check proxy URL. It is malformed "
+                    "and could be missing the host."
+                )
+            proxy_manager = self.proxy_manager_for(proxy)
+            conn = proxy_manager.connection_from_host(
+                **host_params, pool_kwargs=pool_kwargs
+            )
+        else:
+            # Only scheme should be lower case
+            conn = self.poolmanager.connection_from_host(
+                **host_params, pool_kwargs=pool_kwargs
+            )
+
+        return conn
+
     def get_connection(self, url, proxies=None):
         """Returns a urllib3 connection for the given URL. This should not be
         called from user code, and is only exposed for use when subclassing the
@@ -410,7 +466,7 @@ class HTTPAdapter(BaseAdapter):
         """
 
         try:
-            conn = self.get_connection(request.url, proxies)
+            conn = self._get_connection(request, verify, proxies)
         except LocationValueError as e:
             raise InvalidURL(e, request=request)
 
-- 
2.25.1

