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,277 @@
1
+ """
2
+ Direct Security Framework Integration
3
+
4
+ This module provides direct integration with mcp_security_framework,
5
+ replacing all project security methods with framework calls.
6
+
7
+ Author: Vasiliy Zdanovskiy
8
+ email: vasilyvz@gmail.com
9
+ """
10
+
11
+ import logging
12
+ from typing import Dict, Any, Optional, List
13
+ from pathlib import Path
14
+
15
+ # Direct imports from framework
16
+ try:
17
+ from mcp_security_framework import (
18
+ SecurityManager, AuthManager, CertificateManager,
19
+ PermissionManager, RateLimiter
20
+ )
21
+ from mcp_security_framework.schemas.config import (
22
+ SecurityConfig, AuthConfig, SSLConfig, PermissionConfig,
23
+ RateLimitConfig, CertificateConfig, LoggingConfig
24
+ )
25
+ from mcp_security_framework.schemas.models import (
26
+ AuthResult, ValidationResult, CertificateInfo, CertificatePair
27
+ )
28
+ from mcp_security_framework.middleware.fastapi_middleware import FastAPISecurityMiddleware
29
+ SECURITY_FRAMEWORK_AVAILABLE = True
30
+ except ImportError:
31
+ SECURITY_FRAMEWORK_AVAILABLE = False
32
+ SecurityManager = None
33
+ SecurityConfig = None
34
+ AuthManager = None
35
+ CertificateManager = None
36
+ PermissionManager = None
37
+ RateLimiter = None
38
+ FastAPISecurityMiddleware = None
39
+
40
+ from mcp_proxy_adapter.core.logging import logger
41
+
42
+
43
+ class SecurityIntegration:
44
+ """
45
+ Direct integration with mcp_security_framework.
46
+
47
+ This class replaces all project security methods with direct calls
48
+ to the security framework components.
49
+ """
50
+
51
+ def __init__(self, config: Dict[str, Any]):
52
+ """
53
+ Initialize security integration.
54
+
55
+ Args:
56
+ config: Configuration dictionary
57
+ """
58
+ if not SECURITY_FRAMEWORK_AVAILABLE:
59
+ raise ImportError("mcp_security_framework is not available")
60
+
61
+ self.config = config
62
+ self.security_config = self._create_security_config()
63
+
64
+ # Initialize framework components
65
+ self.security_manager = SecurityManager(self.security_config)
66
+ self.permission_manager = PermissionManager(self.security_config.permissions)
67
+ self.auth_manager = AuthManager(self.security_config.auth, self.permission_manager)
68
+ self.certificate_manager = CertificateManager(self.security_config.certificates)
69
+ self.rate_limiter = RateLimiter(self.security_config.rate_limit)
70
+
71
+ logger.info("Security integration initialized with mcp_security_framework")
72
+
73
+ def _create_security_config(self) -> SecurityConfig:
74
+ """Create SecurityConfig from project configuration."""
75
+ security_section = self.config.get("security", {})
76
+
77
+ # Create SSL config
78
+ ssl_config = SSLConfig(
79
+ enabled=security_section.get("ssl", {}).get("enabled", False),
80
+ cert_file=security_section.get("ssl", {}).get("cert_file"),
81
+ key_file=security_section.get("ssl", {}).get("key_file"),
82
+ ca_cert_file=security_section.get("ssl", {}).get("ca_cert_file"),
83
+ client_cert_file=security_section.get("ssl", {}).get("client_cert_file"),
84
+ client_key_file=security_section.get("ssl", {}).get("client_key_file"),
85
+ verify_mode=security_section.get("ssl", {}).get("verify_mode", "CERT_REQUIRED"),
86
+ min_tls_version=security_section.get("ssl", {}).get("min_tls_version", "TLSv1.2"),
87
+ check_hostname=security_section.get("ssl", {}).get("check_hostname", True),
88
+ check_expiry=security_section.get("ssl", {}).get("check_expiry", True),
89
+ expiry_warning_days=security_section.get("ssl", {}).get("expiry_warning_days", 30)
90
+ )
91
+
92
+ # Create auth config
93
+ auth_config = AuthConfig(
94
+ enabled=security_section.get("auth", {}).get("enabled", True),
95
+ methods=security_section.get("auth", {}).get("methods", ["api_key"]),
96
+ api_keys=security_section.get("auth", {}).get("api_keys", {}),
97
+ user_roles=security_section.get("auth", {}).get("user_roles", {}),
98
+ jwt_secret=security_section.get("auth", {}).get("jwt_secret"),
99
+ jwt_algorithm=security_section.get("auth", {}).get("jwt_algorithm", "HS256"),
100
+ jwt_expiry_hours=security_section.get("auth", {}).get("jwt_expiry_hours", 24),
101
+ certificate_auth=security_section.get("auth", {}).get("certificate_auth", False),
102
+ public_paths=security_section.get("auth", {}).get("public_paths", [])
103
+ )
104
+
105
+ # Create permission config
106
+ permission_config = PermissionConfig(
107
+ enabled=security_section.get("permissions", {}).get("enabled", True),
108
+ roles_file=security_section.get("permissions", {}).get("roles_file"),
109
+ default_role=security_section.get("permissions", {}).get("default_role", "guest"),
110
+ admin_role=security_section.get("permissions", {}).get("admin_role", "admin"),
111
+ role_hierarchy=security_section.get("permissions", {}).get("role_hierarchy", {}),
112
+ permission_cache_enabled=security_section.get("permissions", {}).get("permission_cache_enabled", True),
113
+ permission_cache_ttl=security_section.get("permissions", {}).get("permission_cache_ttl", 300),
114
+ wildcard_permissions=security_section.get("permissions", {}).get("wildcard_permissions", False),
115
+ strict_mode=security_section.get("permissions", {}).get("strict_mode", True),
116
+ roles=security_section.get("permissions", {}).get("roles")
117
+ )
118
+
119
+ # Create rate limit config
120
+ rate_limit_config = RateLimitConfig(
121
+ enabled=security_section.get("rate_limit", {}).get("enabled", True),
122
+ default_requests_per_minute=security_section.get("rate_limit", {}).get("default_requests_per_minute", 60),
123
+ default_requests_per_hour=security_section.get("rate_limit", {}).get("default_requests_per_hour", 1000),
124
+ burst_limit=security_section.get("rate_limit", {}).get("burst_limit", 2),
125
+ window_size_seconds=security_section.get("rate_limit", {}).get("window_size_seconds", 60),
126
+ storage_backend=security_section.get("rate_limit", {}).get("storage_backend", "memory"),
127
+ exempt_paths=security_section.get("rate_limit", {}).get("exempt_paths", []),
128
+ exempt_roles=security_section.get("rate_limit", {}).get("exempt_roles", [])
129
+ )
130
+
131
+ # Create certificate config
132
+ certificate_config = CertificateConfig(
133
+ enabled=security_section.get("certificates", {}).get("enabled", False),
134
+ ca_cert_path=security_section.get("certificates", {}).get("ca_cert_path"),
135
+ ca_key_path=security_section.get("certificates", {}).get("ca_key_path"),
136
+ cert_storage_path=security_section.get("certificates", {}).get("cert_storage_path", "./certs"),
137
+ key_storage_path=security_section.get("certificates", {}).get("key_storage_path", "./keys"),
138
+ default_validity_days=security_section.get("certificates", {}).get("default_validity_days", 365),
139
+ key_size=security_section.get("certificates", {}).get("key_size", 2048),
140
+ hash_algorithm=security_section.get("certificates", {}).get("hash_algorithm", "sha256")
141
+ )
142
+
143
+ # Create logging config
144
+ logging_config = LoggingConfig(
145
+ enabled=security_section.get("logging", {}).get("enabled", True),
146
+ level=security_section.get("logging", {}).get("level", "INFO"),
147
+ format=security_section.get("logging", {}).get("format"),
148
+ console_output=security_section.get("logging", {}).get("console_output", True),
149
+ file_path=security_section.get("logging", {}).get("file_path")
150
+ )
151
+
152
+ # Create main security config
153
+ return SecurityConfig(
154
+ ssl=ssl_config,
155
+ auth=auth_config,
156
+ permissions=permission_config,
157
+ rate_limit=rate_limit_config,
158
+ certificates=certificate_config,
159
+ logging=logging_config,
160
+ debug=security_section.get("debug", False),
161
+ environment=security_section.get("environment", "dev"),
162
+ version=security_section.get("version", "1.0.0")
163
+ )
164
+
165
+ # Authentication methods - direct calls to AuthManager
166
+ async def authenticate_api_key(self, api_key: str) -> AuthResult:
167
+ """Authenticate using API key."""
168
+ return await self.auth_manager.authenticate_api_key(api_key)
169
+
170
+ async def authenticate_jwt(self, token: str) -> AuthResult:
171
+ """Authenticate using JWT token."""
172
+ return await self.auth_manager.authenticate_jwt(token)
173
+
174
+ async def authenticate_certificate(self, cert_data: bytes) -> AuthResult:
175
+ """Authenticate using certificate."""
176
+ return await self.auth_manager.authenticate_certificate(cert_data)
177
+
178
+ async def validate_request(self, request_data: Dict[str, Any]) -> ValidationResult:
179
+ """Validate request using security manager."""
180
+ return await self.security_manager.validate_request(request_data)
181
+
182
+ # Certificate methods - direct calls to CertificateManager
183
+ async def create_ca_certificate(self, common_name: str, **kwargs) -> CertificatePair:
184
+ """Create CA certificate."""
185
+ return await self.certificate_manager.create_ca_certificate(common_name, **kwargs)
186
+
187
+ async def create_client_certificate(self, common_name: str, **kwargs) -> CertificatePair:
188
+ """Create client certificate."""
189
+ return await self.certificate_manager.create_client_certificate(common_name, **kwargs)
190
+
191
+ async def create_server_certificate(self, common_name: str, **kwargs) -> CertificatePair:
192
+ """Create server certificate."""
193
+ return await self.certificate_manager.create_server_certificate(common_name, **kwargs)
194
+
195
+ async def validate_certificate(self, cert_path: str) -> bool:
196
+ """Validate certificate."""
197
+ return await self.certificate_manager.validate_certificate(cert_path)
198
+
199
+ async def extract_roles_from_certificate(self, cert_path: str) -> List[str]:
200
+ """Extract roles from certificate."""
201
+ return await self.certificate_manager.extract_roles_from_certificate(cert_path)
202
+
203
+ async def revoke_certificate(self, cert_path: str) -> bool:
204
+ """Revoke certificate."""
205
+ return await self.certificate_manager.revoke_certificate(cert_path)
206
+
207
+ # Permission methods - direct calls to PermissionManager
208
+ async def check_permission(self, user_id: str, permission: str) -> bool:
209
+ """Check user permission."""
210
+ return await self.permission_manager.check_permission(user_id, permission)
211
+
212
+ async def get_user_roles(self, user_id: str) -> List[str]:
213
+ """Get user roles."""
214
+ return await self.permission_manager.get_user_roles(user_id)
215
+
216
+ async def add_user_role(self, user_id: str, role: str) -> bool:
217
+ """Add role to user."""
218
+ return await self.permission_manager.add_user_role(user_id, role)
219
+
220
+ async def remove_user_role(self, user_id: str, role: str) -> bool:
221
+ """Remove role from user."""
222
+ return await self.permission_manager.remove_user_role(user_id, role)
223
+
224
+ # Rate limiting methods - direct calls to RateLimiter
225
+ async def check_rate_limit(self, identifier: str, limit_type: str = "per_minute") -> bool:
226
+ """Check rate limit."""
227
+ return await self.rate_limiter.check_rate_limit(identifier, limit_type)
228
+
229
+ async def increment_rate_limit(self, identifier: str) -> None:
230
+ """Increment rate limit counter."""
231
+ await self.rate_limiter.increment_rate_limit(identifier)
232
+
233
+ async def get_rate_limit_info(self, identifier: str) -> Dict[str, Any]:
234
+ """Get rate limit information."""
235
+ return await self.rate_limiter.get_rate_limit_info(identifier)
236
+
237
+ # Middleware creation - direct use of framework middleware
238
+ def create_fastapi_middleware(self, app) -> FastAPISecurityMiddleware:
239
+ """Create FastAPI security middleware."""
240
+ return FastAPISecurityMiddleware(app, self.security_config)
241
+
242
+ # Utility methods
243
+ def is_security_enabled(self) -> bool:
244
+ """Check if security is enabled."""
245
+ return self.security_config.auth.enabled or self.security_config.ssl.enabled
246
+
247
+ def get_public_paths(self) -> List[str]:
248
+ """Get public paths that bypass authentication."""
249
+ return self.security_config.auth.public_paths
250
+
251
+ def get_security_config(self) -> SecurityConfig:
252
+ """Get security configuration."""
253
+ return self.security_config
254
+
255
+
256
+ # Factory function for easy integration
257
+ def create_security_integration(config: Dict[str, Any]) -> SecurityIntegration:
258
+ """
259
+ Create security integration instance.
260
+
261
+ Args:
262
+ config: Configuration dictionary
263
+
264
+ Returns:
265
+ SecurityIntegration instance
266
+
267
+ Raises:
268
+ RuntimeError: If security integration cannot be created
269
+ """
270
+ try:
271
+ return SecurityIntegration(config)
272
+ except ImportError as e:
273
+ logger.error(f"mcp_security_framework not available: {e}")
274
+ raise RuntimeError("Security framework is required but not available") from e
275
+ except Exception as e:
276
+ logger.error(f"Failed to create security integration: {e}")
277
+ raise RuntimeError(f"Security integration failed: {e}") from e
@@ -0,0 +1,345 @@
1
+ """
2
+ Server Configuration Adapter
3
+
4
+ This module provides adapters for converting configuration between different
5
+ server engines and handling SSL configuration mapping.
6
+
7
+ Author: Vasiliy Zdanovskiy
8
+ email: vasilyvz@gmail.com
9
+ """
10
+
11
+ import logging
12
+ from typing import Dict, Any, Optional
13
+ from pathlib import Path
14
+
15
+ from .server_engine import ServerEngineFactory, ServerEngine
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ class ServerConfigAdapter:
21
+ """
22
+ Adapter for converting server configurations between different engines.
23
+
24
+ This class handles the mapping of configuration parameters between
25
+ different server engines and provides unified configuration management.
26
+ """
27
+
28
+ @staticmethod
29
+ def convert_ssl_config_for_engine(
30
+ ssl_config: Dict[str, Any],
31
+ target_engine: str
32
+ ) -> Dict[str, Any]:
33
+ """
34
+ Convert SSL configuration for a specific server engine.
35
+
36
+ Args:
37
+ ssl_config: Source SSL configuration
38
+ target_engine: Target engine name (uvicorn, hypercorn, etc.)
39
+
40
+ Returns:
41
+ Converted SSL configuration for the target engine
42
+ """
43
+ engine = ServerEngineFactory.get_engine(target_engine)
44
+ if not engine:
45
+ logger.error(f"Unknown server engine: {target_engine}")
46
+ return {}
47
+
48
+ if target_engine == "uvicorn":
49
+ return ServerConfigAdapter._convert_to_uvicorn_ssl(ssl_config)
50
+ elif target_engine == "hypercorn":
51
+ return ServerConfigAdapter._convert_to_hypercorn_ssl(ssl_config)
52
+ else:
53
+ logger.warning(f"No SSL conversion available for engine: {target_engine}")
54
+ return {}
55
+
56
+ @staticmethod
57
+ def _convert_to_uvicorn_ssl(ssl_config: Dict[str, Any]) -> Dict[str, Any]:
58
+ """Convert SSL configuration to uvicorn format."""
59
+ uvicorn_ssl = {}
60
+
61
+ # Map SSL parameters
62
+ if ssl_config.get("cert_file"):
63
+ uvicorn_ssl["ssl_certfile"] = ssl_config["cert_file"]
64
+ if ssl_config.get("key_file"):
65
+ uvicorn_ssl["ssl_keyfile"] = ssl_config["key_file"]
66
+ if ssl_config.get("ca_cert"):
67
+ uvicorn_ssl["ssl_ca_certs"] = ssl_config["ca_cert"]
68
+
69
+ # Map verification mode
70
+ if ssl_config.get("verify_client", False):
71
+ import ssl
72
+ uvicorn_ssl["ssl_cert_reqs"] = ssl.CERT_REQUIRED
73
+
74
+ logger.debug(f"Converted SSL config to uvicorn: {uvicorn_ssl}")
75
+ return uvicorn_ssl
76
+
77
+ @staticmethod
78
+ def _convert_to_hypercorn_ssl(ssl_config: Dict[str, Any]) -> Dict[str, Any]:
79
+ """Convert SSL configuration to hypercorn format."""
80
+ hypercorn_ssl = {}
81
+
82
+ # Map SSL parameters
83
+ if ssl_config.get("cert_file"):
84
+ hypercorn_ssl["certfile"] = ssl_config["cert_file"]
85
+ if ssl_config.get("key_file"):
86
+ hypercorn_ssl["keyfile"] = ssl_config["key_file"]
87
+ if ssl_config.get("ca_cert"):
88
+ hypercorn_ssl["ca_certs"] = ssl_config["ca_cert"]
89
+
90
+ # Map verification mode
91
+ if ssl_config.get("verify_client", False):
92
+ hypercorn_ssl["verify_mode"] = "CERT_REQUIRED"
93
+
94
+ logger.debug(f"Converted SSL config to hypercorn: {hypercorn_ssl}")
95
+ return hypercorn_ssl
96
+
97
+ @staticmethod
98
+ def get_optimal_engine_for_config(config: Dict[str, Any]) -> Optional[str]:
99
+ """
100
+ Determine the optimal server engine for a given configuration.
101
+
102
+ Args:
103
+ config: Server configuration
104
+
105
+ Returns:
106
+ Name of the optimal engine or None if no suitable engine found
107
+ """
108
+ # Check if mTLS is required
109
+ ssl_config = config.get("ssl", {})
110
+ if not ssl_config:
111
+ # Try to get SSL config from security section
112
+ ssl_config = config.get("security", {}).get("ssl", {})
113
+
114
+ # Prefer hypercorn for all SSL/TLS scenarios due to better mTLS support
115
+ if ssl_config.get("enabled", False):
116
+ engine = ServerEngineFactory.get_engine("hypercorn")
117
+ if engine:
118
+ logger.info("Selected hypercorn for SSL/TLS support (better mTLS capabilities)")
119
+ return engine.get_name()
120
+ else:
121
+ logger.warning("SSL enabled but hypercorn not available")
122
+
123
+ # For mTLS client verification, hypercorn is required
124
+ if ssl_config.get("verify_client", False) or ssl_config.get("client_cert_required", False):
125
+ engine = ServerEngineFactory.get_engine_with_feature("mtls_client_certs")
126
+ if engine:
127
+ logger.info(f"Selected {engine.get_name()} for mTLS support")
128
+ return engine.get_name()
129
+ else:
130
+ logger.warning("mTLS required but no suitable engine available")
131
+ return None
132
+
133
+ # Default to hypercorn for better async support, fallback to uvicorn
134
+ engine = ServerEngineFactory.get_engine("hypercorn")
135
+ if engine:
136
+ logger.info("Selected hypercorn as default engine (better async support)")
137
+ return engine.get_name()
138
+
139
+ engine = ServerEngineFactory.get_engine("uvicorn")
140
+ if engine:
141
+ logger.info("Selected uvicorn as fallback engine")
142
+ return "uvicorn"
143
+
144
+ return None
145
+
146
+ @staticmethod
147
+ def validate_engine_compatibility(
148
+ config: Dict[str, Any],
149
+ engine_name: str
150
+ ) -> bool:
151
+ """
152
+ Validate if a configuration is compatible with a specific engine.
153
+
154
+ Args:
155
+ config: Server configuration
156
+ engine_name: Name of the server engine
157
+
158
+ Returns:
159
+ True if compatible, False otherwise
160
+ """
161
+ engine = ServerEngineFactory.get_engine(engine_name)
162
+ if not engine:
163
+ logger.error(f"Unknown engine: {engine_name}")
164
+ return False
165
+
166
+ # Check SSL requirements
167
+ ssl_config = config.get("ssl", {})
168
+ if not ssl_config:
169
+ # Try to get SSL config from security section
170
+ ssl_config = config.get("security", {}).get("ssl", {})
171
+
172
+ if ssl_config.get("verify_client", False):
173
+ if not engine.get_supported_features().get("mtls_client_certs", False):
174
+ logger.error(f"Engine {engine_name} doesn't support mTLS client certificates")
175
+ return False
176
+
177
+ # Validate engine-specific configuration
178
+ return engine.validate_config(config)
179
+
180
+ @staticmethod
181
+ def get_engine_capabilities(engine_name: str) -> Dict[str, Any]:
182
+ """
183
+ Get capabilities of a specific server engine.
184
+
185
+ Args:
186
+ engine_name: Name of the server engine
187
+
188
+ Returns:
189
+ Dictionary of engine capabilities
190
+ """
191
+ engine = ServerEngineFactory.get_engine(engine_name)
192
+ if not engine:
193
+ return {}
194
+
195
+ return {
196
+ "name": engine.get_name(),
197
+ "features": engine.get_supported_features(),
198
+ "config_schema": engine.get_config_schema()
199
+ }
200
+
201
+
202
+ class UnifiedServerRunner:
203
+ """
204
+ Unified server runner that abstracts the choice of server engine.
205
+
206
+ This class provides a unified interface for running servers regardless
207
+ of the underlying engine, automatically selecting the best engine
208
+ for the given configuration.
209
+ """
210
+
211
+ def __init__(self, default_engine: str = "uvicorn"):
212
+ """
213
+ Initialize the unified server runner.
214
+
215
+ Args:
216
+ default_engine: Default engine to use if no specific requirements
217
+ """
218
+ self.default_engine = default_engine
219
+ self.available_engines = ServerEngineFactory.get_available_engines()
220
+
221
+ logger.info(f"Available engines: {list(self.available_engines.keys())}")
222
+ logger.info(f"Default engine: {default_engine}")
223
+
224
+ def run_server(
225
+ self,
226
+ app: Any,
227
+ config: Dict[str, Any],
228
+ engine_name: Optional[str] = None
229
+ ) -> None:
230
+ """
231
+ Run server with the specified or optimal engine.
232
+
233
+ Args:
234
+ app: ASGI application
235
+ config: Server configuration
236
+ engine_name: Specific engine to use (optional)
237
+ """
238
+ # Determine which engine to use
239
+ if engine_name:
240
+ selected_engine = engine_name
241
+ logger.info(f"Using specified engine: {selected_engine}")
242
+ else:
243
+ selected_engine = ServerConfigAdapter.get_optimal_engine_for_config(config)
244
+ if not selected_engine:
245
+ selected_engine = self.default_engine
246
+ logger.info(f"Using default engine: {selected_engine}")
247
+
248
+ # Validate compatibility
249
+ if not ServerConfigAdapter.validate_engine_compatibility(config, selected_engine):
250
+ raise ValueError(f"Configuration not compatible with engine: {selected_engine}")
251
+
252
+ # Get engine instance
253
+ engine = ServerEngineFactory.get_engine(selected_engine)
254
+ if not engine:
255
+ raise ValueError(f"Engine not available: {selected_engine}")
256
+
257
+ # Convert configuration if needed
258
+ converted_config = self._prepare_config_for_engine(config, selected_engine)
259
+
260
+ # Run server
261
+ logger.info(f"Starting server with {selected_engine} engine")
262
+ engine.run_server(app, converted_config)
263
+
264
+ def _prepare_config_for_engine(
265
+ self,
266
+ config: Dict[str, Any],
267
+ engine_name: str
268
+ ) -> Dict[str, Any]:
269
+ logger.info(f"🔍 Debug: _prepare_config_for_engine called with config keys: {list(config.keys())}")
270
+ logger.info(f"🔍 Debug: SSL config in input: {config.get('ssl', 'NOT_FOUND')}")
271
+ """
272
+ Prepare configuration for a specific engine.
273
+
274
+ Args:
275
+ config: Original configuration
276
+ engine_name: Target engine name
277
+
278
+ Returns:
279
+ Engine-specific configuration
280
+ """
281
+ # Start with basic config
282
+ engine_config = {
283
+ "host": config.get("host", "127.0.0.1"),
284
+ "port": config.get("port", 8000),
285
+ "log_level": config.get("log_level", "info"),
286
+ "reload": config.get("reload", False)
287
+ }
288
+
289
+ # Add SSL configuration if present
290
+ # First check for direct SSL parameters (from app_factory.py)
291
+ if "certfile" in config or "keyfile" in config or "ca_certs" in config or "verify_mode" in config:
292
+ logger.info(f"🔍 DEBUG: Direct SSL parameters found in config")
293
+ if "certfile" in config:
294
+ engine_config["certfile"] = config["certfile"]
295
+ if "keyfile" in config:
296
+ engine_config["keyfile"] = config["keyfile"]
297
+ if "ca_certs" in config:
298
+ engine_config["ca_certs"] = config["ca_certs"]
299
+ if "verify_mode" in config:
300
+ engine_config["verify_mode"] = config["verify_mode"]
301
+ else:
302
+ # Try to get SSL config from ssl section
303
+ ssl_config = config.get("ssl", {})
304
+ if not ssl_config:
305
+ # Try to get SSL config from security section
306
+ ssl_config = config.get("security", {}).get("ssl", {})
307
+
308
+ if ssl_config:
309
+ converted_ssl = ServerConfigAdapter.convert_ssl_config_for_engine(
310
+ ssl_config, engine_name
311
+ )
312
+ engine_config.update(converted_ssl)
313
+
314
+ # Add engine-specific configuration
315
+ if "workers" in config:
316
+ engine_config["workers"] = config["workers"]
317
+
318
+ return engine_config
319
+
320
+ def get_engine_info(self, engine_name: str) -> Dict[str, Any]:
321
+ """
322
+ Get information about a specific engine.
323
+
324
+ Args:
325
+ engine_name: Name of the engine
326
+
327
+ Returns:
328
+ Engine information dictionary
329
+ """
330
+ return ServerConfigAdapter.get_engine_capabilities(engine_name)
331
+
332
+ def list_available_engines(self) -> Dict[str, Dict[str, Any]]:
333
+ """
334
+ List all available engines with their capabilities.
335
+
336
+ Returns:
337
+ Dictionary mapping engine names to their capabilities
338
+ """
339
+ engines_info = {}
340
+ for name, engine in self.available_engines.items():
341
+ engines_info[name] = {
342
+ "features": engine.get_supported_features(),
343
+ "config_schema": engine.get_config_schema()
344
+ }
345
+ return engines_info