From 7879395d06272ce8e5b92fafe6a7cdbc56fc8430 Mon Sep 17 00:00:00 2001 From: Shubham-Padkonde Date: Thu, 24 Sep 2026 03:32:17 +0000 Subject: [PATCH] fix: is_same_host returns False for bare hostnames (no scheme) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit urlparse treats a string with no scheme as an opaque path, so urlparse("host.example.com").netloc is "" while urlparse("https://host.example.com").netloc is "host.example.com". is_same_host therefore returned False whenever one of its arguments lacked a scheme — for example a JWT iss claim stored as a bare hostname vs. self.hostname which is always normalized with https://. Fix: extract a nested helper _extract_host that re-parses with a dummy "https://" prefix when the initial parse yields an empty netloc, recovering the actual hostname in the bare-hostname case. Also normalises extracted hosts to lowercase for a consistent comparison. Add four new parametrize cases to test_is_same_host covering the previously failing mixed-scheme and bare-vs-bare comparisons. --- src/databricks/sql/auth/auth_utils.py | 18 ++++++++++++------ tests/unit/test_token_federation.py | 6 ++++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/databricks/sql/auth/auth_utils.py b/src/databricks/sql/auth/auth_utils.py index a21ce843b..ea41cf36b 100644 --- a/src/databricks/sql/auth/auth_utils.py +++ b/src/databricks/sql/auth/auth_utils.py @@ -36,12 +36,18 @@ def is_same_host(url1: str, url2: str) -> bool: True if hosts are the same, False otherwise """ try: - host1 = urlparse(url1).netloc - host2 = urlparse(url2).netloc - # Handle port differences (e.g., example.com vs example.com:443) - host1_without_port = host1.split(":")[0] - host2_without_port = host2.split(":")[0] - return host1_without_port == host2_without_port + def _extract_host(url: str) -> str: + parsed = urlparse(url) + netloc = parsed.netloc + if not netloc: + # Bare hostname with no scheme: urlparse puts the host in the + # path component and leaves netloc empty. Add a dummy scheme so + # the parser can identify the netloc correctly. + netloc = urlparse(f"https://{url}").netloc + # Strip port (e.g. example.com:443 -> example.com) + return netloc.split(":")[0].lower() + + return _extract_host(url1) == _extract_host(url2) except Exception as e: logger.debug("Failed to parse URLs: %s", e) return False diff --git a/tests/unit/test_token_federation.py b/tests/unit/test_token_federation.py index 9c209e894..08ce6ffbd 100644 --- a/tests/unit/test_token_federation.py +++ b/tests/unit/test_token_federation.py @@ -322,6 +322,12 @@ def test_normalize_hostname(self, input_hostname, expected): ("https://test.databricks.com", "https://test.databricks.com:443", True), ("https://test1.databricks.com", "https://test2.databricks.com", False), ("https://login.microsoftonline.com", "https://test.databricks.com", False), + # Bare hostname (no scheme) — regression: urlparse("host").netloc == "" + # caused these to incorrectly return False + ("test.databricks.com", "https://test.databricks.com", True), + ("https://test.databricks.com", "test.databricks.com", True), + ("test.databricks.com", "test.databricks.com", True), + ("other.example.com", "test.databricks.com", False), ], ) def test_is_same_host(self, url1, url2, expected):