11import ssl
22import urllib .parse
33import urllib .request
4+ import logging
45from typing import Dict , Any , Optional , Tuple , Union
56
67from urllib3 import HTTPConnectionPool , HTTPSConnectionPool , ProxyManager
910from databricks .sql .auth .retry import DatabricksRetryPolicy
1011from databricks .sql .types import SSLOptions
1112
13+ logger = logging .getLogger (__name__ )
14+
1215
1316def detect_and_parse_proxy (
14- scheme : str , host : str = None , skip_bypass : bool = False
17+ scheme : str ,
18+ host : str = None ,
19+ skip_bypass : bool = False ,
20+ proxy_auth_method : Optional [str ] = None ,
1521) -> Tuple [Optional [str ], Optional [Dict [str , str ]]]:
1622 """
1723 Detect system proxy and return proxy URI and headers using standardized logic.
@@ -20,6 +26,7 @@ def detect_and_parse_proxy(
2026 scheme: URL scheme (http/https)
2127 host: Target hostname (optional, only needed for bypass checking)
2228 skip_bypass: If True, skip proxy bypass checking and return proxy config if found
29+ proxy_auth_method: Authentication method ('basic', 'negotiate', or None)
2330
2431 Returns:
2532 Tuple of (proxy_uri, proxy_headers) or (None, None) if no proxy
@@ -40,10 +47,41 @@ def detect_and_parse_proxy(
4047 return None , None
4148
4249 parsed_proxy = urllib .parse .urlparse (proxy )
43- proxy_headers = create_basic_proxy_auth_headers (parsed_proxy )
50+
51+ # Generate appropriate auth headers based on method
52+ if proxy_auth_method == "negotiate" :
53+ proxy_headers = _generate_negotiate_headers (parsed_proxy .hostname )
54+ elif proxy_auth_method == "basic" or proxy_auth_method is None :
55+ # Default to basic if method not specified (backward compatibility)
56+ proxy_headers = create_basic_proxy_auth_headers (parsed_proxy )
57+ else :
58+ raise ValueError (f"Unsupported proxy_auth_method: { proxy_auth_method } " )
59+
4460 return proxy , proxy_headers
4561
4662
63+ def _generate_negotiate_headers (proxy_hostname : str ) -> Optional [Dict [str , str ]]:
64+ """Generate Kerberos/SPNEGO authentication headers"""
65+ try :
66+ from requests_kerberos import HTTPKerberosAuth
67+
68+ logger .debug (
69+ f"Attempting to generate Kerberos SPNEGO token for proxy: { proxy_hostname } "
70+ )
71+ auth = HTTPKerberosAuth ()
72+ negotiate_details = auth .generate_request_header (
73+ None , proxy_hostname , is_preemptive = True
74+ )
75+ if negotiate_details :
76+ return {"proxy-authorization" : negotiate_details }
77+ else :
78+ logger .debug ("Unable to generate kerberos proxy auth headers" )
79+ except Exception as e :
80+ logger .error (f"Error generating Kerberos proxy auth headers: { e } " )
81+
82+ return None
83+
84+
4785def create_basic_proxy_auth_headers (parsed_proxy ) -> Optional [Dict [str , str ]]:
4886 """
4987 Create basic auth headers for proxy if credentials are provided.
0 commit comments