mcp-proxy-adapter 4.1.1__py3-none-any.whl → 6.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. mcp_proxy_adapter/__main__.py +12 -0
  2. mcp_proxy_adapter/api/app.py +254 -33
  3. mcp_proxy_adapter/api/handlers.py +32 -6
  4. mcp_proxy_adapter/api/middleware/__init__.py +36 -30
  5. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +148 -0
  6. mcp_proxy_adapter/api/middleware/error_handling.py +9 -0
  7. mcp_proxy_adapter/api/middleware/factory.py +243 -0
  8. mcp_proxy_adapter/api/middleware/logging.py +32 -6
  9. mcp_proxy_adapter/api/middleware/protocol_middleware.py +135 -0
  10. mcp_proxy_adapter/api/middleware/transport_middleware.py +122 -0
  11. mcp_proxy_adapter/api/middleware/unified_security.py +152 -0
  12. mcp_proxy_adapter/api/middleware/user_info_middleware.py +83 -0
  13. mcp_proxy_adapter/commands/__init__.py +19 -4
  14. mcp_proxy_adapter/commands/auth_validation_command.py +408 -0
  15. mcp_proxy_adapter/commands/base.py +66 -32
  16. mcp_proxy_adapter/commands/builtin_commands.py +95 -0
  17. mcp_proxy_adapter/commands/catalog_manager.py +838 -0
  18. mcp_proxy_adapter/commands/cert_monitor_command.py +620 -0
  19. mcp_proxy_adapter/commands/certificate_management_command.py +608 -0
  20. mcp_proxy_adapter/commands/command_registry.py +711 -354
  21. mcp_proxy_adapter/commands/dependency_manager.py +245 -0
  22. mcp_proxy_adapter/commands/echo_command.py +81 -0
  23. mcp_proxy_adapter/commands/health_command.py +7 -0
  24. mcp_proxy_adapter/commands/help_command.py +21 -14
  25. mcp_proxy_adapter/commands/hooks.py +200 -167
  26. mcp_proxy_adapter/commands/key_management_command.py +506 -0
  27. mcp_proxy_adapter/commands/load_command.py +176 -0
  28. mcp_proxy_adapter/commands/plugins_command.py +235 -0
  29. mcp_proxy_adapter/commands/protocol_management_command.py +232 -0
  30. mcp_proxy_adapter/commands/proxy_registration_command.py +409 -0
  31. mcp_proxy_adapter/commands/reload_command.py +48 -50
  32. mcp_proxy_adapter/commands/result.py +1 -0
  33. mcp_proxy_adapter/commands/role_test_command.py +141 -0
  34. mcp_proxy_adapter/commands/roles_management_command.py +697 -0
  35. mcp_proxy_adapter/commands/security_command.py +488 -0
  36. mcp_proxy_adapter/commands/ssl_setup_command.py +483 -0
  37. mcp_proxy_adapter/commands/token_management_command.py +529 -0
  38. mcp_proxy_adapter/commands/transport_management_command.py +144 -0
  39. mcp_proxy_adapter/commands/unload_command.py +158 -0
  40. mcp_proxy_adapter/config.py +159 -2
  41. mcp_proxy_adapter/core/app_factory.py +326 -0
  42. mcp_proxy_adapter/core/auth_validator.py +606 -0
  43. mcp_proxy_adapter/core/certificate_utils.py +827 -0
  44. mcp_proxy_adapter/core/client_security.py +384 -0
  45. mcp_proxy_adapter/core/config_converter.py +405 -0
  46. mcp_proxy_adapter/core/config_validator.py +218 -0
  47. mcp_proxy_adapter/core/logging.py +19 -3
  48. mcp_proxy_adapter/core/mtls_asgi.py +156 -0
  49. mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
  50. mcp_proxy_adapter/core/protocol_manager.py +235 -0
  51. mcp_proxy_adapter/core/proxy_client.py +602 -0
  52. mcp_proxy_adapter/core/proxy_registration.py +522 -0
  53. mcp_proxy_adapter/core/role_utils.py +426 -0
  54. mcp_proxy_adapter/core/security_adapter.py +370 -0
  55. mcp_proxy_adapter/core/security_factory.py +239 -0
  56. mcp_proxy_adapter/core/security_integration.py +277 -0
  57. mcp_proxy_adapter/core/server_adapter.py +345 -0
  58. mcp_proxy_adapter/core/server_engine.py +364 -0
  59. mcp_proxy_adapter/core/settings.py +1 -0
  60. mcp_proxy_adapter/core/ssl_utils.py +233 -0
  61. mcp_proxy_adapter/core/transport_manager.py +292 -0
  62. mcp_proxy_adapter/core/unified_config_adapter.py +579 -0
  63. mcp_proxy_adapter/custom_openapi.py +22 -11
  64. mcp_proxy_adapter/examples/README.md +230 -97
  65. mcp_proxy_adapter/examples/README_EN.md +258 -0
  66. mcp_proxy_adapter/examples/SECURITY_TESTING.md +455 -0
  67. mcp_proxy_adapter/examples/__pycache__/security_configurations.cpython-312.pyc +0 -0
  68. mcp_proxy_adapter/examples/__pycache__/security_test_client.cpython-312.pyc +0 -0
  69. mcp_proxy_adapter/examples/basic_framework/configs/http_auth.json +37 -0
  70. mcp_proxy_adapter/examples/basic_framework/configs/http_simple.json +23 -0
  71. mcp_proxy_adapter/examples/basic_framework/configs/https_auth.json +39 -0
  72. mcp_proxy_adapter/examples/basic_framework/configs/https_simple.json +25 -0
  73. mcp_proxy_adapter/examples/basic_framework/configs/mtls_no_roles.json +39 -0
  74. mcp_proxy_adapter/examples/basic_framework/configs/mtls_with_roles.json +45 -0
  75. mcp_proxy_adapter/examples/basic_framework/main.py +63 -0
  76. mcp_proxy_adapter/examples/basic_framework/roles.json +21 -0
  77. mcp_proxy_adapter/examples/cert_config.json +9 -0
  78. mcp_proxy_adapter/examples/certs/admin.crt +32 -0
  79. mcp_proxy_adapter/examples/certs/admin.key +52 -0
  80. mcp_proxy_adapter/examples/certs/admin_cert.pem +21 -0
  81. mcp_proxy_adapter/examples/certs/admin_key.pem +28 -0
  82. mcp_proxy_adapter/examples/certs/ca_cert.pem +23 -0
  83. mcp_proxy_adapter/examples/certs/ca_cert.srl +1 -0
  84. mcp_proxy_adapter/examples/certs/ca_key.pem +28 -0
  85. mcp_proxy_adapter/examples/certs/cert_config.json +9 -0
  86. mcp_proxy_adapter/examples/certs/client.crt +32 -0
  87. mcp_proxy_adapter/examples/certs/client.key +52 -0
  88. mcp_proxy_adapter/examples/certs/client_admin.crt +32 -0
  89. mcp_proxy_adapter/examples/certs/client_admin.key +52 -0
  90. mcp_proxy_adapter/examples/certs/client_user.crt +32 -0
  91. mcp_proxy_adapter/examples/certs/client_user.key +52 -0
  92. mcp_proxy_adapter/examples/certs/guest_cert.pem +21 -0
  93. mcp_proxy_adapter/examples/certs/guest_key.pem +28 -0
  94. mcp_proxy_adapter/examples/certs/mcp_proxy_adapter_ca_ca.crt +23 -0
  95. mcp_proxy_adapter/examples/certs/proxy_cert.pem +21 -0
  96. mcp_proxy_adapter/examples/certs/proxy_key.pem +28 -0
  97. mcp_proxy_adapter/examples/certs/readonly.crt +32 -0
  98. mcp_proxy_adapter/examples/certs/readonly.key +52 -0
  99. mcp_proxy_adapter/examples/certs/readonly_cert.pem +21 -0
  100. mcp_proxy_adapter/examples/certs/readonly_key.pem +28 -0
  101. mcp_proxy_adapter/examples/certs/server.crt +32 -0
  102. mcp_proxy_adapter/examples/certs/server.key +52 -0
  103. mcp_proxy_adapter/examples/certs/server_cert.pem +32 -0
  104. mcp_proxy_adapter/examples/certs/server_key.pem +52 -0
  105. mcp_proxy_adapter/examples/certs/test_ca_ca.crt +20 -0
  106. mcp_proxy_adapter/examples/certs/user.crt +32 -0
  107. mcp_proxy_adapter/examples/certs/user.key +52 -0
  108. mcp_proxy_adapter/examples/certs/user_cert.pem +21 -0
  109. mcp_proxy_adapter/examples/certs/user_key.pem +28 -0
  110. mcp_proxy_adapter/examples/client_configs/api_key_client.json +13 -0
  111. mcp_proxy_adapter/examples/client_configs/basic_auth_client.json +13 -0
  112. mcp_proxy_adapter/examples/client_configs/certificate_client.json +22 -0
  113. mcp_proxy_adapter/examples/client_configs/jwt_client.json +15 -0
  114. mcp_proxy_adapter/examples/client_configs/no_auth_client.json +9 -0
  115. mcp_proxy_adapter/examples/commands/__init__.py +1 -0
  116. mcp_proxy_adapter/examples/create_certificates_simple.py +307 -0
  117. mcp_proxy_adapter/examples/debug_request_state.py +144 -0
  118. mcp_proxy_adapter/examples/debug_role_chain.py +205 -0
  119. mcp_proxy_adapter/examples/demo_client.py +341 -0
  120. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +99 -0
  121. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +106 -0
  122. mcp_proxy_adapter/examples/full_application/configs/http_auth.json +37 -0
  123. mcp_proxy_adapter/examples/full_application/configs/http_simple.json +23 -0
  124. mcp_proxy_adapter/examples/full_application/configs/https_auth.json +39 -0
  125. mcp_proxy_adapter/examples/full_application/configs/https_simple.json +25 -0
  126. mcp_proxy_adapter/examples/full_application/configs/mtls_no_roles.json +39 -0
  127. mcp_proxy_adapter/examples/full_application/configs/mtls_with_roles.json +45 -0
  128. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +97 -0
  129. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +95 -0
  130. mcp_proxy_adapter/examples/full_application/main.py +138 -0
  131. mcp_proxy_adapter/examples/full_application/roles.json +21 -0
  132. mcp_proxy_adapter/examples/generate_all_certificates.py +429 -0
  133. mcp_proxy_adapter/examples/generate_certificates.py +121 -0
  134. mcp_proxy_adapter/examples/keys/ca_key.pem +28 -0
  135. mcp_proxy_adapter/examples/keys/mcp_proxy_adapter_ca_ca.key +28 -0
  136. mcp_proxy_adapter/examples/keys/test_ca_ca.key +28 -0
  137. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log +220 -0
  138. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.1 +1 -0
  139. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.2 +1 -0
  140. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.3 +1 -0
  141. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.4 +1 -0
  142. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.5 +1 -0
  143. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log +220 -0
  144. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.1 +1 -0
  145. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.2 +1 -0
  146. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.3 +1 -0
  147. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.4 +1 -0
  148. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.5 +1 -0
  149. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log +2 -0
  150. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.1 +1 -0
  151. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.2 +1 -0
  152. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.3 +1 -0
  153. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.4 +1 -0
  154. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.5 +1 -0
  155. mcp_proxy_adapter/examples/proxy_registration_example.py +401 -0
  156. mcp_proxy_adapter/examples/roles.json +38 -0
  157. mcp_proxy_adapter/examples/run_example.py +81 -0
  158. mcp_proxy_adapter/examples/run_security_tests.py +326 -0
  159. mcp_proxy_adapter/examples/run_security_tests_fixed.py +300 -0
  160. mcp_proxy_adapter/examples/security_test_client.py +743 -0
  161. mcp_proxy_adapter/examples/server_configs/config_basic_http.json +204 -0
  162. mcp_proxy_adapter/examples/server_configs/config_http_token.json +238 -0
  163. mcp_proxy_adapter/examples/server_configs/config_https.json +215 -0
  164. mcp_proxy_adapter/examples/server_configs/config_https_token.json +231 -0
  165. mcp_proxy_adapter/examples/server_configs/config_mtls.json +215 -0
  166. mcp_proxy_adapter/examples/server_configs/config_proxy_registration.json +250 -0
  167. mcp_proxy_adapter/examples/server_configs/config_simple.json +46 -0
  168. mcp_proxy_adapter/examples/server_configs/roles.json +38 -0
  169. mcp_proxy_adapter/examples/test_examples.py +344 -0
  170. mcp_proxy_adapter/examples/universal_client.py +628 -0
  171. mcp_proxy_adapter/main.py +186 -0
  172. mcp_proxy_adapter/utils/config_generator.py +639 -0
  173. mcp_proxy_adapter/version.py +2 -1
  174. mcp_proxy_adapter-6.1.0.dist-info/METADATA +205 -0
  175. mcp_proxy_adapter-6.1.0.dist-info/RECORD +193 -0
  176. mcp_proxy_adapter-6.1.0.dist-info/entry_points.txt +2 -0
  177. {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.1.0.dist-info}/licenses/LICENSE +2 -2
  178. mcp_proxy_adapter/api/middleware/auth.py +0 -146
  179. mcp_proxy_adapter/api/middleware/rate_limit.py +0 -152
  180. mcp_proxy_adapter/commands/reload_settings_command.py +0 -125
  181. mcp_proxy_adapter/examples/__init__.py +0 -7
  182. mcp_proxy_adapter/examples/basic_server/README.md +0 -60
  183. mcp_proxy_adapter/examples/basic_server/__init__.py +0 -7
  184. mcp_proxy_adapter/examples/basic_server/basic_custom_settings.json +0 -39
  185. mcp_proxy_adapter/examples/basic_server/config.json +0 -35
  186. mcp_proxy_adapter/examples/basic_server/custom_settings_example.py +0 -238
  187. mcp_proxy_adapter/examples/basic_server/server.py +0 -103
  188. mcp_proxy_adapter/examples/custom_commands/README.md +0 -127
  189. mcp_proxy_adapter/examples/custom_commands/__init__.py +0 -27
  190. mcp_proxy_adapter/examples/custom_commands/advanced_hooks.py +0 -250
  191. mcp_proxy_adapter/examples/custom_commands/auto_commands/__init__.py +0 -6
  192. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_echo_command.py +0 -103
  193. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_info_command.py +0 -111
  194. mcp_proxy_adapter/examples/custom_commands/config.json +0 -35
  195. mcp_proxy_adapter/examples/custom_commands/custom_health_command.py +0 -169
  196. mcp_proxy_adapter/examples/custom_commands/custom_help_command.py +0 -215
  197. mcp_proxy_adapter/examples/custom_commands/custom_openapi_generator.py +0 -76
  198. mcp_proxy_adapter/examples/custom_commands/custom_settings.json +0 -96
  199. mcp_proxy_adapter/examples/custom_commands/custom_settings_manager.py +0 -241
  200. mcp_proxy_adapter/examples/custom_commands/data_transform_command.py +0 -135
  201. mcp_proxy_adapter/examples/custom_commands/echo_command.py +0 -122
  202. mcp_proxy_adapter/examples/custom_commands/hooks.py +0 -230
  203. mcp_proxy_adapter/examples/custom_commands/intercept_command.py +0 -123
  204. mcp_proxy_adapter/examples/custom_commands/manual_echo_command.py +0 -103
  205. mcp_proxy_adapter/examples/custom_commands/server.py +0 -228
  206. mcp_proxy_adapter/examples/custom_commands/test_hooks.py +0 -176
  207. mcp_proxy_adapter/examples/deployment/README.md +0 -49
  208. mcp_proxy_adapter/examples/deployment/__init__.py +0 -7
  209. mcp_proxy_adapter/examples/deployment/config.development.json +0 -8
  210. mcp_proxy_adapter/examples/deployment/config.json +0 -29
  211. mcp_proxy_adapter/examples/deployment/config.production.json +0 -12
  212. mcp_proxy_adapter/examples/deployment/config.staging.json +0 -11
  213. mcp_proxy_adapter/examples/deployment/docker-compose.yml +0 -31
  214. mcp_proxy_adapter/examples/deployment/run.sh +0 -43
  215. mcp_proxy_adapter/examples/deployment/run_docker.sh +0 -84
  216. mcp_proxy_adapter/schemas/base_schema.json +0 -114
  217. mcp_proxy_adapter/schemas/openapi_schema.json +0 -314
  218. mcp_proxy_adapter/tests/__init__.py +0 -0
  219. mcp_proxy_adapter/tests/api/__init__.py +0 -3
  220. mcp_proxy_adapter/tests/api/test_cmd_endpoint.py +0 -115
  221. mcp_proxy_adapter/tests/api/test_custom_openapi.py +0 -617
  222. mcp_proxy_adapter/tests/api/test_handlers.py +0 -522
  223. mcp_proxy_adapter/tests/api/test_middleware.py +0 -340
  224. mcp_proxy_adapter/tests/api/test_schemas.py +0 -546
  225. mcp_proxy_adapter/tests/api/test_tool_integration.py +0 -531
  226. mcp_proxy_adapter/tests/commands/__init__.py +0 -3
  227. mcp_proxy_adapter/tests/commands/test_config_command.py +0 -211
  228. mcp_proxy_adapter/tests/commands/test_echo_command.py +0 -127
  229. mcp_proxy_adapter/tests/commands/test_help_command.py +0 -136
  230. mcp_proxy_adapter/tests/conftest.py +0 -131
  231. mcp_proxy_adapter/tests/functional/__init__.py +0 -3
  232. mcp_proxy_adapter/tests/functional/test_api.py +0 -253
  233. mcp_proxy_adapter/tests/integration/__init__.py +0 -3
  234. mcp_proxy_adapter/tests/integration/test_cmd_integration.py +0 -129
  235. mcp_proxy_adapter/tests/integration/test_integration.py +0 -255
  236. mcp_proxy_adapter/tests/performance/__init__.py +0 -3
  237. mcp_proxy_adapter/tests/performance/test_performance.py +0 -189
  238. mcp_proxy_adapter/tests/stubs/__init__.py +0 -10
  239. mcp_proxy_adapter/tests/stubs/echo_command.py +0 -104
  240. mcp_proxy_adapter/tests/test_api_endpoints.py +0 -271
  241. mcp_proxy_adapter/tests/test_api_handlers.py +0 -289
  242. mcp_proxy_adapter/tests/test_base_command.py +0 -123
  243. mcp_proxy_adapter/tests/test_batch_requests.py +0 -117
  244. mcp_proxy_adapter/tests/test_command_registry.py +0 -281
  245. mcp_proxy_adapter/tests/test_config.py +0 -127
  246. mcp_proxy_adapter/tests/test_utils.py +0 -65
  247. mcp_proxy_adapter/tests/unit/__init__.py +0 -3
  248. mcp_proxy_adapter/tests/unit/test_base_command.py +0 -436
  249. mcp_proxy_adapter/tests/unit/test_config.py +0 -217
  250. mcp_proxy_adapter-4.1.1.dist-info/METADATA +0 -200
  251. mcp_proxy_adapter-4.1.1.dist-info/RECORD +0 -110
  252. {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.1.0.dist-info}/WHEEL +0 -0
  253. {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.1.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,384 @@
1
+ """
2
+ Client Security Module
3
+
4
+ This module provides client-side security integration for MCP Proxy Adapter,
5
+ using mcp_security_framework utilities for secure connections to servers.
6
+
7
+ Author: Vasiliy Zdanovskiy
8
+ email: vasilyvz@gmail.com
9
+ """
10
+
11
+ import logging
12
+ import ssl
13
+ from typing import Dict, Any, Optional, List, Tuple
14
+ from pathlib import Path
15
+
16
+ # Import framework utilities
17
+ try:
18
+ from mcp_security_framework.utils.crypto_utils import (
19
+ generate_api_key, create_jwt_token, verify_jwt_token
20
+ )
21
+ from mcp_security_framework.utils.cert_utils import (
22
+ parse_certificate, extract_roles_from_certificate,
23
+ validate_certificate_chain, validate_certificate_format
24
+ )
25
+ from mcp_security_framework.core.ssl_manager import SSLManager
26
+ from mcp_security_framework.schemas.config import SSLConfig, AuthConfig
27
+ from mcp_security_framework.schemas.models import AuthResult, ValidationResult
28
+ SECURITY_FRAMEWORK_AVAILABLE = True
29
+ except ImportError:
30
+ SECURITY_FRAMEWORK_AVAILABLE = False
31
+ SSLManager = None
32
+ SSLConfig = None
33
+ AuthConfig = None
34
+ AuthResult = None
35
+ ValidationResult = None
36
+
37
+ from mcp_proxy_adapter.core.logging import logger
38
+
39
+
40
+ class ClientSecurityManager:
41
+ """
42
+ Client-side security manager for MCP Proxy Adapter.
43
+
44
+ Provides secure client connections using mcp_security_framework utilities.
45
+ Handles authentication, certificate management, and SSL/TLS for client connections.
46
+ """
47
+
48
+ def __init__(self, config: Dict[str, Any]):
49
+ """
50
+ Initialize client security manager.
51
+
52
+ Args:
53
+ config: Security configuration
54
+ """
55
+ if not SECURITY_FRAMEWORK_AVAILABLE:
56
+ raise ImportError("mcp_security_framework is not available")
57
+
58
+ self.config = config
59
+ self.security_config = config.get("security", {})
60
+
61
+ # Initialize SSL manager if needed
62
+ self.ssl_manager = None
63
+ if self.security_config.get("ssl", {}).get("enabled", False):
64
+ ssl_config = self._create_ssl_config()
65
+ self.ssl_manager = SSLManager(ssl_config)
66
+
67
+ logger.info("Client security manager initialized")
68
+
69
+ def _create_ssl_config(self) -> SSLConfig:
70
+ """Create SSL configuration for client connections."""
71
+ ssl_section = self.security_config.get("ssl", {})
72
+
73
+ return SSLConfig(
74
+ enabled=ssl_section.get("enabled", False),
75
+ cert_file=ssl_section.get("client_cert_file"),
76
+ key_file=ssl_section.get("client_key_file"),
77
+ ca_cert_file=ssl_section.get("ca_cert_file"),
78
+ verify_mode=ssl_section.get("verify_mode", "CERT_REQUIRED"),
79
+ min_tls_version=ssl_section.get("min_tls_version", "TLSv1.2"),
80
+ check_hostname=ssl_section.get("check_hostname", True),
81
+ check_expiry=ssl_section.get("check_expiry", True)
82
+ )
83
+
84
+ def create_client_ssl_context(self, server_hostname: Optional[str] = None) -> Optional[ssl.SSLContext]:
85
+ """
86
+ Create SSL context for client connections.
87
+
88
+ Args:
89
+ server_hostname: Server hostname for SNI
90
+
91
+ Returns:
92
+ SSL context or None if SSL not enabled
93
+ """
94
+ if not self.ssl_manager:
95
+ return None
96
+
97
+ try:
98
+ # Create client SSL context
99
+ context = self.ssl_manager.create_client_context()
100
+
101
+ if server_hostname:
102
+ # Set server hostname for SNI
103
+ context.check_hostname = True
104
+ context.verify_mode = ssl.CERT_REQUIRED
105
+
106
+ logger.info(f"Client SSL context created for {server_hostname or 'unknown server'}")
107
+ return context
108
+
109
+ except Exception as e:
110
+ logger.error(f"Failed to create client SSL context: {e}")
111
+ return None
112
+
113
+ def generate_client_api_key(self, user_id: str, prefix: str = "mcp_proxy") -> str:
114
+ """
115
+ Generate API key for client authentication.
116
+
117
+ Args:
118
+ user_id: User identifier
119
+ prefix: Key prefix
120
+
121
+ Returns:
122
+ Generated API key
123
+ """
124
+ try:
125
+ api_key = generate_api_key(prefix=prefix)
126
+ logger.info(f"Generated API key for user: {user_id}")
127
+ return api_key
128
+ except Exception as e:
129
+ logger.error(f"Failed to generate API key: {e}")
130
+ raise
131
+
132
+ def create_client_jwt_token(self, user_id: str, roles: List[str],
133
+ secret: str, algorithm: str = "HS256",
134
+ expiry_hours: int = 24) -> str:
135
+ """
136
+ Create JWT token for client authentication.
137
+
138
+ Args:
139
+ user_id: User identifier
140
+ roles: User roles
141
+ secret: JWT secret
142
+ algorithm: JWT algorithm
143
+ expiry_hours: Token expiry in hours
144
+
145
+ Returns:
146
+ JWT token
147
+ """
148
+ try:
149
+ payload = {
150
+ "user_id": user_id,
151
+ "roles": roles,
152
+ "type": "client_proxy"
153
+ }
154
+
155
+ token = create_jwt_token(
156
+ payload=payload,
157
+ secret=secret,
158
+ algorithm=algorithm,
159
+ expiry_hours=expiry_hours
160
+ )
161
+
162
+ logger.info(f"Created JWT token for user: {user_id}")
163
+ return token
164
+
165
+ except Exception as e:
166
+ logger.error(f"Failed to create JWT token: {e}")
167
+ raise
168
+
169
+ def validate_server_certificate(self, cert_path: str, ca_cert_path: Optional[str] = None) -> bool:
170
+ """
171
+ Validate server certificate before connection.
172
+
173
+ Args:
174
+ cert_path: Path to server certificate
175
+ ca_cert_path: Path to CA certificate
176
+
177
+ Returns:
178
+ True if certificate is valid
179
+ """
180
+ try:
181
+ # Validate certificate format
182
+ if not validate_certificate_format(cert_path):
183
+ logger.error(f"Invalid certificate format: {cert_path}")
184
+ return False
185
+
186
+ # Validate certificate chain if CA provided
187
+ if ca_cert_path:
188
+ if not validate_certificate_chain(cert_path, ca_cert_path):
189
+ logger.error(f"Invalid certificate chain: {cert_path}")
190
+ return False
191
+
192
+ # Parse certificate and check basic properties
193
+ cert_info = parse_certificate(cert_path)
194
+ if not cert_info:
195
+ logger.error(f"Failed to parse certificate: {cert_path}")
196
+ return False
197
+
198
+ logger.info(f"Server certificate validated: {cert_path}")
199
+ return True
200
+
201
+ except Exception as e:
202
+ logger.error(f"Failed to validate server certificate: {e}")
203
+ return False
204
+
205
+ def extract_server_roles(self, cert_path: str) -> List[str]:
206
+ """
207
+ Extract roles from server certificate.
208
+
209
+ Args:
210
+ cert_path: Path to server certificate
211
+
212
+ Returns:
213
+ List of roles extracted from certificate
214
+ """
215
+ try:
216
+ roles = extract_roles_from_certificate(cert_path)
217
+ logger.info(f"Extracted roles from server certificate: {roles}")
218
+ return roles
219
+ except Exception as e:
220
+ logger.error(f"Failed to extract roles from certificate: {e}")
221
+ return []
222
+
223
+ def get_client_auth_headers(self, auth_method: str = "api_key", **kwargs) -> Dict[str, str]:
224
+ """
225
+ Get authentication headers for client requests.
226
+
227
+ Args:
228
+ auth_method: Authentication method (api_key, jwt, certificate)
229
+ **kwargs: Additional parameters
230
+
231
+ Returns:
232
+ Dictionary of authentication headers
233
+ """
234
+ headers = {}
235
+
236
+ try:
237
+ if auth_method == "api_key":
238
+ api_key = kwargs.get("api_key")
239
+ if api_key:
240
+ headers["X-API-Key"] = api_key
241
+ headers["Authorization"] = f"Bearer {api_key}"
242
+
243
+ elif auth_method == "jwt":
244
+ token = kwargs.get("token")
245
+ if token:
246
+ headers["Authorization"] = f"Bearer {token}"
247
+
248
+ elif auth_method == "certificate":
249
+ # Certificate authentication is handled at SSL level
250
+ headers["X-Auth-Method"] = "certificate"
251
+
252
+ # Add common proxy headers
253
+ headers["X-Proxy-Type"] = "mcp_proxy_adapter"
254
+ headers["X-Client-Type"] = "proxy_client"
255
+
256
+ logger.debug(f"Created auth headers for method: {auth_method}")
257
+ return headers
258
+
259
+ except Exception as e:
260
+ logger.error(f"Failed to create auth headers: {e}")
261
+ return {}
262
+
263
+ def prepare_client_connection(self, server_config: Dict[str, Any]) -> Tuple[Optional[ssl.SSLContext], Dict[str, str]]:
264
+ """
265
+ Prepare secure client connection to server.
266
+
267
+ Args:
268
+ server_config: Server connection configuration
269
+
270
+ Returns:
271
+ Tuple of (SSL context, auth headers)
272
+ """
273
+ ssl_context = None
274
+ auth_headers = {}
275
+
276
+ try:
277
+ # Create SSL context if needed
278
+ if server_config.get("ssl", False):
279
+ server_hostname = server_config.get("hostname")
280
+ ssl_context = self.create_client_ssl_context(server_hostname)
281
+
282
+ # Create authentication headers
283
+ auth_method = server_config.get("auth_method", "api_key")
284
+ auth_headers = self.get_client_auth_headers(
285
+ auth_method=auth_method,
286
+ api_key=server_config.get("api_key"),
287
+ token=server_config.get("token")
288
+ )
289
+
290
+ logger.info(f"Prepared client connection for {server_config.get('hostname', 'unknown')}")
291
+ return ssl_context, auth_headers
292
+
293
+ except Exception as e:
294
+ logger.error(f"Failed to prepare client connection: {e}")
295
+ return None, {}
296
+
297
+ def validate_server_response(self, response_headers: Dict[str, str]) -> bool:
298
+ """
299
+ Validate server response for security compliance.
300
+
301
+ Args:
302
+ response_headers: Server response headers
303
+
304
+ Returns:
305
+ True if response is valid
306
+ """
307
+ try:
308
+ # Check for required security headers
309
+ required_headers = ["Content-Type"]
310
+ for header in required_headers:
311
+ if header not in response_headers:
312
+ logger.warning(f"Missing required header: {header}")
313
+
314
+ # Check for security headers
315
+ security_headers = ["X-Frame-Options", "X-Content-Type-Options"]
316
+ for header in security_headers:
317
+ if header in response_headers:
318
+ logger.debug(f"Found security header: {header}")
319
+
320
+ # Validate content type
321
+ content_type = response_headers.get("Content-Type", "")
322
+ if "application/json" not in content_type:
323
+ logger.warning(f"Unexpected content type: {content_type}")
324
+
325
+ return True
326
+
327
+ except Exception as e:
328
+ logger.error(f"Failed to validate server response: {e}")
329
+ return False
330
+
331
+ def get_client_certificate_info(self) -> Optional[Dict[str, Any]]:
332
+ """
333
+ Get information about client certificate.
334
+
335
+ Returns:
336
+ Certificate information or None
337
+ """
338
+ try:
339
+ ssl_config = self.security_config.get("ssl", {})
340
+ cert_path = ssl_config.get("client_cert_file")
341
+
342
+ if not cert_path or not Path(cert_path).exists():
343
+ return None
344
+
345
+ cert_info = parse_certificate(cert_path)
346
+ if cert_info:
347
+ roles = extract_roles_from_certificate(cert_path)
348
+ cert_info["roles"] = roles
349
+ return cert_info
350
+
351
+ return None
352
+
353
+ except Exception as e:
354
+ logger.error(f"Failed to get client certificate info: {e}")
355
+ return None
356
+
357
+ def is_ssl_enabled(self) -> bool:
358
+ """Check if SSL is enabled for client connections."""
359
+ return self.security_config.get("ssl", {}).get("enabled", False)
360
+
361
+ def get_supported_auth_methods(self) -> List[str]:
362
+ """Get list of supported authentication methods."""
363
+ return ["api_key", "jwt", "certificate"]
364
+
365
+
366
+ # Factory function for easy integration
367
+ def create_client_security_manager(config: Dict[str, Any]) -> Optional[ClientSecurityManager]:
368
+ """
369
+ Create client security manager instance.
370
+
371
+ Args:
372
+ config: Configuration dictionary
373
+
374
+ Returns:
375
+ ClientSecurityManager instance or None if framework not available
376
+ """
377
+ try:
378
+ return ClientSecurityManager(config)
379
+ except ImportError:
380
+ logger.warning("mcp_security_framework not available, client security disabled")
381
+ return None
382
+ except Exception as e:
383
+ logger.error(f"Failed to create client security manager: {e}")
384
+ return None