Procházet zdrojové kódy

[backend] Fix HTTP client adapter selection when TLS is disabled

- Add conditional logic to use standard HTTPAdapter when create_http_ssl_context() returns None
- Prevent unnecessary TLS processing overhead when TLS 1.2/1.3 are both disabled
- Move SSL verification configuration to TLS-enabled path only
- Mount standard adapter to specific URL instead of protocol prefixes when TLS is off
Prakash Ranade před 1 měsícem
rodič
revize
40f6ffc117

+ 6 - 0
desktop/conf.dist/hue.ini

@@ -116,6 +116,12 @@ http_500_debug_mode=false
 # the client is always receiving the latest version of the resource.
 ## custom_cache_control=true
 
+# Enable TLS 1.3 support when available. Requires OpenSSL 1.1.1+ and Python 3.7+
+## ssl_tls13_enabled=true
+
+# Enable TLS 1.2 support when available. This is the default behavior.
+## ssl_tls12_enabled=true
+
 # Filename of SSL Certificate
 ## ssl_certificate=
 

+ 6 - 0
desktop/conf/pseudo-distributed.ini.tmpl

@@ -121,6 +121,12 @@
   # that the client is always receiving the latest version of the resource.
   ## custom_cache_control=true
 
+  # Enable TLS 1.3 support when available. Requires OpenSSL 1.1.1+ and Python 3.7+
+  ## ssl_tls13_enabled=true
+
+  # Enable TLS 1.2 support when available. This is the default behavior.
+  ## ssl_tls12_enabled=true
+
   # Filename of SSL Certificate
   ## ssl_certificate=
 

+ 2 - 2
desktop/core/src/desktop/conf.py

@@ -331,7 +331,7 @@ def has_tls13_support():
   """Check if TLS 1.3 is supported by the current Python/OpenSSL version."""
   try:
     import ssl
-    return hasattr(ssl, 'HAS_TLSv1_3') and ssl.HAS_TLSv1_3
+    return hasattr(ssl, 'HAS_TLSv1_3') and ssl.HAS_TLSv1_3 and is_https_enabled()
   except ImportError:
     return False
 
@@ -346,7 +346,7 @@ SSL_TLS12_ENABLED = Config(
   key="ssl_tls12_enabled",
   help=_("Enable TLS 1.2 support when available. This is the default behavior."),
   type=coerce_bool,
-  default=True)
+  dynamic_default=is_https_enabled)
 
 
 def has_ssl_no_renegotiation():

+ 3 - 1
desktop/core/src/desktop/lib/gunicorn_server_utils.py

@@ -333,7 +333,6 @@ def create_gunicorn_options(options):
     'reload_engine': None,
     'sendfile': True,
     'spew': None,
-    'ssl_context': gunicorn_ssl_context,
     'statsd_host': None,
     'statsd_prefix': None,
     'suppress_ragged_eofs': None,      # Suppress ragged EOFs (see stdlib ssl module)
@@ -354,6 +353,9 @@ def create_gunicorn_options(options):
     'worker_int': worker_int
   }
 
+  if tls_settings:
+    gunicorn_options.update({'ssl_context': gunicorn_ssl_context})
+
   return gunicorn_options
 
 

+ 25 - 18
desktop/core/src/desktop/lib/rest/http_client.py

@@ -90,24 +90,31 @@ def get_request_session(url, logger):
       CACHE_SESSION[url] = requests.Session()
       logger.debug("Setting request Session")
 
-      # Use TLS 1.3 supporting adapter
-      tls13_adapter = TLS13HTTPAdapter(
-        pool_connections=conf.CHERRYPY_SERVER_THREADS.get(),
-        pool_maxsize=conf.CHERRYPY_SERVER_THREADS.get()
-      )
-
-      # Mount the adapter for both HTTP and HTTPS
-      CACHE_SESSION[url].mount('https://', tls13_adapter)
-      CACHE_SESSION[url].mount('http://', tls13_adapter)
-
-      # Configure SSL verification
-      CACHE_SESSION[url].verify = conf.SSL_VALIDATE.get()
-
-      # Set CA certificates if configured
-      if conf.SSL_CACERTS.get() and conf.SSL_VALIDATE.get():
-        CACHE_SESSION[url].verify = conf.SSL_CACERTS.get()
-
-      logger.debug(f"Configured HTTP session with TLS 1.3 support for {url}")
+      # Check if TLS is enabled by testing SSL context creation
+      ssl_context = create_http_ssl_context()
+      if ssl_context is not None:
+        # Use TLS 1.3 supporting adapter when TLS is enabled
+        tls13_adapter = TLS13HTTPAdapter(
+          pool_connections=conf.CHERRYPY_SERVER_THREADS.get(),
+          pool_maxsize=conf.CHERRYPY_SERVER_THREADS.get()
+        )
+
+        # Mount the adapter for both HTTP and HTTPS
+        CACHE_SESSION[url].mount('https://', tls13_adapter)
+        CACHE_SESSION[url].mount('http://', tls13_adapter)
+        # Configure SSL verification
+        CACHE_SESSION[url].verify = conf.SSL_VALIDATE.get()
+
+        # Set CA certificates if configured
+        if conf.SSL_CACERTS.get() and conf.SSL_VALIDATE.get():
+          CACHE_SESSION[url].verify = conf.SSL_CACERTS.get()
+      else:
+        # Fall back to standard HTTP adapter when TLS is disabled
+        standard_adapter = HTTPAdapter(
+          pool_connections=conf.CHERRYPY_SERVER_THREADS.get(),
+          pool_maxsize=conf.CHERRYPY_SERVER_THREADS.get()
+        )
+        CACHE_SESSION[url].mount(url, standard_adapter)
 
   return CACHE_SESSION
 

+ 21 - 8
desktop/core/src/desktop/lib/tls_utils.py

@@ -40,14 +40,18 @@ def get_tls_settings():
   """
   from desktop import conf
 
+  # Check for both TLS 1.3 and TLS 1.2
+  tls13_enabled = conf.SSL_TLS13_ENABLED.get()
+  tls12_enabled = conf.SSL_TLS12_ENABLED.get()
+
+  if not tls13_enabled and not tls12_enabled:
+    LOG.warning("TLS 1.3 and TLS 1.2 are disabled, returning empty TLS settings")
+    return None
+
   tls_settings = {}
   try:
     import ssl
 
-    # Check for both TLS 1.3 and TLS 1.2
-    tls13_enabled = conf.SSL_TLS13_ENABLED.get()
-    tls12_enabled = conf.SSL_TLS12_ENABLED.get()
-
     # Set default values for minimum and maximum versions
     min_version = "TLSv1.2"
     max_version = "TLSv1.2"
@@ -91,12 +95,14 @@ def create_ssl_context(validate=True, ca_certs=None, keyfile=None, certfile=None
   Returns:
     ssl.SSLContext: Configured SSL context or None if creation failed
   """
+  # Get TLS settings from centralized configuration
+  tls_settings = get_tls_settings()
+  if not tls_settings:
+    return None
+
   try:
     import ssl
 
-    # Get TLS settings from centralized configuration
-    tls_settings = get_tls_settings()
-
     # Check for errors in TLS settings
     if "error" in tls_settings:
       LOG.error(f"TLS configuration error: {tls_settings['error']}")
@@ -234,6 +240,8 @@ def create_thrift_ssl_context(validate=True, ca_certs=None, keyfile=None, certfi
     ssl.SSLContext configured for Thrift connections or None if creation failed
   """
   context = create_ssl_context(validate, ca_certs, keyfile, certfile)
+  if context is None:
+    return None
 
   if context and validate:
     # Thrift handles hostname validation separately
@@ -251,7 +259,12 @@ def create_http_ssl_context():
   """
   from desktop import conf
 
-  return create_ssl_context(
+  context = create_ssl_context(
     validate=conf.SSL_VALIDATE.get(),
     ca_certs=conf.SSL_CACERTS.get() if conf.SSL_VALIDATE.get() else None
   )
+  if context is None:
+    LOG.warning("HTTP SSL context is not available, returning None")
+    return None
+
+  return context