Skip to main content
Glama
http_security.py5.47 kB
# # Copyright (C) 2024 Billy Bryant # Portions copyright (C) 2024 Sergey Parfenyuk (original MIT-licensed author) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. # # MIT License attribution: Portions of this file were originally licensed # under the MIT License by Sergey Parfenyuk (2024). # """Secure HTTP client configuration for OAuth operations.""" from typing import Any import httpx from .config import OAUTH_USER_AGENT # Security-hardened timeout configuration DEFAULT_TIMEOUT = httpx.Timeout( connect=10.0, # Connection timeout read=30.0, # Read timeout write=10.0, # Write timeout pool=5.0, # Pool acquisition timeout ) # Connection limits to prevent resource exhaustion DEFAULT_LIMITS = httpx.Limits(max_keepalive_connections=10, max_connections=100, keepalive_expiry=30.0) # Default security headers DEFAULT_HEADERS = { "User-Agent": OAUTH_USER_AGENT, # Prevent MIME type sniffing "X-Content-Type-Options": "nosniff", # Prevent cross-site scripting "X-XSS-Protection": "1; mode=block", # Prevent framing "X-Frame-Options": "DENY", } def create_secure_client(follow_redirects: bool = True) -> httpx.Client: """Create a security-hardened synchronous HTTP client. Args: follow_redirects: Whether to automatically follow redirects (default: True for OAuth compatibility) Returns: httpx.Client configured with security best practices """ return httpx.Client( timeout=DEFAULT_TIMEOUT, limits=DEFAULT_LIMITS, headers=DEFAULT_HEADERS, verify=True, # Always verify SSL certificates trust_env=False, # Don't trust environment proxy settings follow_redirects=follow_redirects, # Configurable redirect handling http2=True, # Enable HTTP/2 support ) def create_secure_async_client(follow_redirects: bool = True) -> httpx.AsyncClient: """Create a security-hardened asynchronous HTTP client. Args: follow_redirects: Whether to automatically follow redirects (default: True for OAuth compatibility) Returns: httpx.AsyncClient configured with security best practices """ return httpx.AsyncClient( timeout=DEFAULT_TIMEOUT, limits=DEFAULT_LIMITS, headers=DEFAULT_HEADERS, verify=True, # Always verify SSL certificates trust_env=False, # Don't trust environment proxy settings follow_redirects=follow_redirects, # Configurable redirect handling http2=True, # Enable HTTP/2 support ) def create_localhost_client(follow_redirects: bool = True) -> httpx.AsyncClient: """Create an HTTP client for localhost requests without SSL verification. This client is specifically for localhost HTTP (not HTTPS) requests where SSL verification would fail. Should only be used for internal coordination. Args: follow_redirects: Whether to automatically follow redirects (default: True) Returns: httpx.AsyncClient configured for localhost HTTP requests """ return httpx.AsyncClient( timeout=DEFAULT_TIMEOUT, limits=DEFAULT_LIMITS, headers=DEFAULT_HEADERS, verify=False, # noqa: S501 - Intentionally disabled for localhost HTTP; snyk:ignore:python/SSLVerificationBypass trust_env=False, # Don't trust environment proxy settings follow_redirects=follow_redirects, # Configurable redirect handling http2=False, # Disable HTTP/2 for localhost to avoid negotiation issues with uvicorn ) def secure_get(url: str, **kwargs: Any) -> httpx.Response: """Make a secure GET request with hardened defaults. Args: url: URL to request **kwargs: Additional httpx parameters Returns: httpx.Response object """ # Ensure security defaults kwargs.setdefault("verify", True) kwargs.setdefault("timeout", 10.0) kwargs.setdefault("follow_redirects", True) # Enable redirects for OAuth compatibility # Merge headers securely headers = DEFAULT_HEADERS.copy() if "headers" in kwargs: headers.update(kwargs["headers"]) kwargs["headers"] = headers return httpx.get(url, **kwargs) def secure_post(url: str, **kwargs: Any) -> httpx.Response: """Make a secure POST request with hardened defaults. Args: url: URL to request **kwargs: Additional httpx parameters Returns: httpx.Response object """ # Ensure security defaults kwargs.setdefault("verify", True) kwargs.setdefault("timeout", 10.0) kwargs.setdefault("follow_redirects", True) # Enable redirects for OAuth compatibility # Merge headers securely headers = DEFAULT_HEADERS.copy() if "headers" in kwargs: headers.update(kwargs["headers"]) kwargs["headers"] = headers return httpx.post(url, **kwargs)

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/billyjbryant/mcp-foxxy-bridge'

If you have feedback or need assistance with the MCP directory API, please join our Discord server