[py] Fix proxy basic auth handling special characters (#16105)
Co-authored-by: Navin Chandra <navinchandra772@gmail.com>
NOKEYCHECK=True
GitOrigin-RevId: 26fc1bbd001f002f0d48620c6d439e2a6a555d82
diff --git a/selenium/webdriver/remote/remote_connection.py b/selenium/webdriver/remote/remote_connection.py
index 59b278b..031481c 100644
--- a/selenium/webdriver/remote/remote_connection.py
+++ b/selenium/webdriver/remote/remote_connection.py
@@ -22,7 +22,7 @@
from base64 import b64encode
from typing import Optional
from urllib import parse
-from urllib.parse import urlparse
+from urllib.parse import unquote, urlparse
import urllib3
@@ -298,7 +298,9 @@
return SOCKSProxyManager(self._proxy_url, **pool_manager_init_args)
if self._identify_http_proxy_auth():
self._proxy_url, self._basic_proxy_auth = self._separate_http_proxy_auth()
- pool_manager_init_args["proxy_headers"] = urllib3.make_headers(proxy_basic_auth=self._basic_proxy_auth)
+ pool_manager_init_args["proxy_headers"] = urllib3.make_headers(
+ proxy_basic_auth=unquote(self._basic_proxy_auth)
+ )
return urllib3.ProxyManager(self._proxy_url, **pool_manager_init_args)
return urllib3.PoolManager(**pool_manager_init_args)
diff --git a/test/unit/selenium/webdriver/remote/remote_connection_tests.py b/test/unit/selenium/webdriver/remote/remote_connection_tests.py
index d4a353c..e2efccd 100644
--- a/test/unit/selenium/webdriver/remote/remote_connection_tests.py
+++ b/test/unit/selenium/webdriver/remote/remote_connection_tests.py
@@ -15,6 +15,7 @@
# specific language governing permissions and limitations
# under the License.
+import base64
import os
from unittest.mock import patch
from urllib import parse
@@ -544,3 +545,58 @@
assert isinstance(conn, PoolManager)
assert conn.connection_pool_kw["retries"] == retries
assert conn.connection_pool_kw["timeout"] == timeout
+
+
+def test_proxy_auth_with_special_characters_url_encoded():
+ proxy_url = "http://user:passw%23rd@proxy.example.com:8080"
+ client_config = ClientConfig(
+ remote_server_addr="http://localhost:4444",
+ keep_alive=False,
+ proxy=Proxy({"proxyType": ProxyType.MANUAL, "httpProxy": proxy_url}),
+ )
+ remote_connection = RemoteConnection(client_config=client_config)
+
+ proxy_without_auth, basic_auth = remote_connection._separate_http_proxy_auth()
+
+ assert proxy_without_auth == "http://proxy.example.com:8080"
+ assert basic_auth == "user:passw%23rd" # Still URL-encoded
+
+ conn = remote_connection._get_connection_manager()
+ assert isinstance(conn, ProxyManager)
+
+ expected_auth = base64.b64encode("user:passw#rd".encode()).decode() # Decoded password
+ expected_headers = make_headers(proxy_basic_auth="user:passw#rd") # Unquoted password
+
+ assert conn.proxy_headers == expected_headers
+ assert conn.proxy_headers["proxy-authorization"] == f"Basic {expected_auth}"
+
+
+def test_proxy_auth_with_multiple_special_characters():
+ test_cases = [
+ ("passw%23rd", "passw#rd"), # # character
+ ("passw%40rd", "passw@rd"), # @ character
+ ("passw%26rd", "passw&rd"), # & character
+ ("passw%3Drd", "passw=rd"), # = character
+ ("passw%2Brd", "passw+rd"), # + character
+ ("passw%20rd", "passw rd"), # space character
+ ("passw%21%40%23%24", "passw!@#$"), # Multiple special chars
+ ]
+
+ for encoded_password, decoded_password in test_cases:
+ proxy_url = f"http://testuser:{encoded_password}@proxy.example.com:8080"
+ client_config = ClientConfig(
+ remote_server_addr="http://localhost:4444",
+ keep_alive=False,
+ proxy=Proxy({"proxyType": ProxyType.MANUAL, "httpProxy": proxy_url}),
+ )
+ remote_connection = RemoteConnection(client_config=client_config)
+
+ proxy_without_auth, basic_auth = remote_connection._separate_http_proxy_auth()
+ assert basic_auth == f"testuser:{encoded_password}"
+
+ conn = remote_connection._get_connection_manager()
+ expected_auth = base64.b64encode(f"testuser:{decoded_password}".encode()).decode()
+ expected_headers = make_headers(proxy_basic_auth=f"testuser:{decoded_password}")
+
+ assert conn.proxy_headers == expected_headers
+ assert conn.proxy_headers["proxy-authorization"] == f"Basic {expected_auth}"