This commit is contained in:
Timothy Jaeryang Baek
2026-06-19 15:34:43 +02:00
parent 8b9e28b503
commit a54878b14f
2 changed files with 75 additions and 3 deletions
+69 -2
View File
@@ -498,6 +498,65 @@ else:
WEBSOCKET_EVENT_CALLER_TIMEOUT = 300
import ssl as _ssl
# Dedicated env var for a custom CA bundle file path. When set, this is
# used as the default CA bundle for all outbound HTTPS connections that
# have SSL verification enabled (i.e. when their per-connection SSL env
# var is ``"True"``). Per-connection overrides (setting the SSL env var
# to a path directly) take precedence over this global fallback.
#
# This follows the industry convention of ``SSL_CERT_FILE`` / ``REQUESTS_CA_BUNDLE``
# but is scoped to Open WebUI to avoid interfering with system-level settings.
AIOHTTP_CLIENT_SSL_CERT_FILE = os.getenv('AIOHTTP_CLIENT_SSL_CERT_FILE', '').strip()
def _build_ssl_context_from_file(path: str) -> '_ssl.SSLContext | None':
"""Create an SSLContext from a CA bundle file, or None if invalid."""
if not path:
return None
if not os.path.isfile(path):
log.warning(
'SSL CA bundle path does not exist: %r, ignoring',
path,
)
return None
ctx = _ssl.create_default_context(cafile=path)
log.info('Using custom SSL CA bundle: %s', path)
return ctx
# Pre-built SSLContext from the dedicated env var (cached once at startup).
_GLOBAL_SSL_CONTEXT = _build_ssl_context_from_file(AIOHTTP_CLIENT_SSL_CERT_FILE)
def _parse_ssl_env(value: str) -> 'bool | _ssl.SSLContext':
"""Parse an SSL env var into a bool or SSLContext.
- ``"true"`` → uses ``AIOHTTP_CLIENT_SSL_CERT_FILE`` context if set,
otherwise ``True`` (default SSL verification via certifi)
- ``"false"`` → ``False`` (no verification)
- ``"/path/to/ca-bundle.crt"`` → ``SSLContext`` loading that CA file
(takes precedence over ``AIOHTTP_CLIENT_SSL_CERT_FILE``)
This allows users with corporate or internal CAs to point Open WebUI
at a custom CA bundle without disabling verification entirely.
"""
lower = value.strip().lower()
if lower == 'true':
# Use the global dedicated CA bundle if configured, otherwise default
return _GLOBAL_SSL_CONTEXT if _GLOBAL_SSL_CONTEXT is not None else True
if lower == 'false':
return False
# Treat as a file path to a CA bundle (per-connection override)
ctx = _build_ssl_context_from_file(value.strip())
if ctx is not None:
return ctx
# Path was invalid — fall back to default
return _GLOBAL_SSL_CONTEXT if _GLOBAL_SSL_CONTEXT is not None else True
REQUESTS_VERIFY = os.getenv('REQUESTS_VERIFY', 'True').lower() == 'true'
_aiohttp_timeout_raw = os.getenv('AIOHTTP_CLIENT_TIMEOUT', '')
@@ -507,7 +566,10 @@ except (ValueError, TypeError):
AIOHTTP_CLIENT_TIMEOUT = 300
AIOHTTP_CLIENT_SESSION_SSL = os.getenv('AIOHTTP_CLIENT_SESSION_SSL', 'True').lower() == 'true'
# SSL verification for general outbound requests (OpenAI, OAuth, etc.).
# Accepts "True", "False", or a path to a CA bundle file.
# When "True", falls back to AIOHTTP_CLIENT_SSL_CERT_FILE if set.
AIOHTTP_CLIENT_SESSION_SSL = _parse_ssl_env(os.getenv('AIOHTTP_CLIENT_SESSION_SSL', 'True'))
# When False (default), outbound HTTP requests do not follow 3xx redirects.
AIOHTTP_CLIENT_ALLOW_REDIRECTS = os.getenv('AIOHTTP_CLIENT_ALLOW_REDIRECTS', 'False').lower() == 'true'
@@ -533,7 +595,12 @@ except (ValueError, TypeError):
AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA = 10
AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL = os.getenv('AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL', 'True').lower() == 'true'
# SSL verification for tool server connections specifically.
# Accepts "True", "False", or a path to a CA bundle file.
# When "True", falls back to AIOHTTP_CLIENT_SSL_CERT_FILE if set.
AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL = _parse_ssl_env(
os.getenv('AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL', 'True')
)
AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER = os.getenv('AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER', '')
+6 -1
View File
@@ -44,7 +44,12 @@ def _build_httpx_client(headers=None, timeout=None, auth=None, verify=True):
def create_httpx_client(headers=None, timeout=None, auth=None):
return _build_httpx_client(headers=headers, timeout=timeout, auth=auth, verify=True)
# AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL may be True, False, or an
# ssl.SSLContext (when a custom CA bundle path is configured).
# httpx's verify= accepts bool | str | ssl.SSLContext, so all three work.
ssl_setting = AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL
verify = ssl_setting if ssl_setting is not True else True
return _build_httpx_client(headers=headers, timeout=timeout, auth=auth, verify=verify)
def create_insecure_httpx_client(headers=None, timeout=None, auth=None):