mcp-proxy-adapter 6.0.0__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 (259) hide show
  1. mcp_proxy_adapter/api/app.py +174 -80
  2. mcp_proxy_adapter/api/handlers.py +16 -5
  3. mcp_proxy_adapter/api/middleware/__init__.py +7 -2
  4. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +148 -0
  5. mcp_proxy_adapter/api/middleware/factory.py +36 -12
  6. mcp_proxy_adapter/api/middleware/unified_security.py +152 -0
  7. mcp_proxy_adapter/api/middleware/user_info_middleware.py +83 -0
  8. mcp_proxy_adapter/commands/__init__.py +7 -1
  9. mcp_proxy_adapter/commands/base.py +7 -4
  10. mcp_proxy_adapter/commands/builtin_commands.py +8 -2
  11. mcp_proxy_adapter/commands/command_registry.py +8 -0
  12. mcp_proxy_adapter/commands/echo_command.py +81 -0
  13. mcp_proxy_adapter/commands/help_command.py +21 -14
  14. mcp_proxy_adapter/commands/proxy_registration_command.py +326 -185
  15. mcp_proxy_adapter/commands/role_test_command.py +141 -0
  16. mcp_proxy_adapter/commands/security_command.py +488 -0
  17. mcp_proxy_adapter/commands/ssl_setup_command.py +2 -2
  18. mcp_proxy_adapter/commands/token_management_command.py +1 -1
  19. mcp_proxy_adapter/config.py +81 -21
  20. mcp_proxy_adapter/core/app_factory.py +326 -0
  21. mcp_proxy_adapter/core/client_security.py +384 -0
  22. mcp_proxy_adapter/core/logging.py +8 -3
  23. mcp_proxy_adapter/core/mtls_asgi.py +156 -0
  24. mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
  25. mcp_proxy_adapter/core/protocol_manager.py +9 -0
  26. mcp_proxy_adapter/core/proxy_client.py +602 -0
  27. mcp_proxy_adapter/core/proxy_registration.py +299 -47
  28. mcp_proxy_adapter/core/security_adapter.py +12 -15
  29. mcp_proxy_adapter/core/security_integration.py +277 -0
  30. mcp_proxy_adapter/core/server_adapter.py +345 -0
  31. mcp_proxy_adapter/core/server_engine.py +364 -0
  32. mcp_proxy_adapter/core/unified_config_adapter.py +579 -0
  33. mcp_proxy_adapter/examples/README.md +230 -97
  34. mcp_proxy_adapter/examples/README_EN.md +258 -0
  35. mcp_proxy_adapter/examples/SECURITY_TESTING.md +455 -0
  36. mcp_proxy_adapter/examples/__pycache__/security_configurations.cpython-312.pyc +0 -0
  37. mcp_proxy_adapter/examples/__pycache__/security_test_client.cpython-312.pyc +0 -0
  38. mcp_proxy_adapter/examples/basic_framework/configs/http_auth.json +37 -0
  39. mcp_proxy_adapter/examples/basic_framework/configs/http_simple.json +23 -0
  40. mcp_proxy_adapter/examples/basic_framework/configs/https_auth.json +39 -0
  41. mcp_proxy_adapter/examples/basic_framework/configs/https_simple.json +25 -0
  42. mcp_proxy_adapter/examples/basic_framework/configs/mtls_no_roles.json +39 -0
  43. mcp_proxy_adapter/examples/basic_framework/configs/mtls_with_roles.json +45 -0
  44. mcp_proxy_adapter/examples/basic_framework/main.py +63 -0
  45. mcp_proxy_adapter/examples/basic_framework/roles.json +21 -0
  46. mcp_proxy_adapter/examples/cert_config.json +9 -0
  47. mcp_proxy_adapter/examples/certs/admin.crt +32 -0
  48. mcp_proxy_adapter/examples/certs/admin.key +52 -0
  49. mcp_proxy_adapter/examples/certs/admin_cert.pem +21 -0
  50. mcp_proxy_adapter/examples/certs/admin_key.pem +28 -0
  51. mcp_proxy_adapter/examples/certs/ca_cert.pem +23 -0
  52. mcp_proxy_adapter/examples/certs/ca_cert.srl +1 -0
  53. mcp_proxy_adapter/examples/certs/ca_key.pem +28 -0
  54. mcp_proxy_adapter/examples/certs/cert_config.json +9 -0
  55. mcp_proxy_adapter/examples/certs/client.crt +32 -0
  56. mcp_proxy_adapter/examples/certs/client.key +52 -0
  57. mcp_proxy_adapter/examples/certs/client_admin.crt +32 -0
  58. mcp_proxy_adapter/examples/certs/client_admin.key +52 -0
  59. mcp_proxy_adapter/examples/certs/client_user.crt +32 -0
  60. mcp_proxy_adapter/examples/certs/client_user.key +52 -0
  61. mcp_proxy_adapter/examples/certs/guest_cert.pem +21 -0
  62. mcp_proxy_adapter/examples/certs/guest_key.pem +28 -0
  63. mcp_proxy_adapter/examples/certs/mcp_proxy_adapter_ca_ca.crt +23 -0
  64. mcp_proxy_adapter/examples/certs/proxy_cert.pem +21 -0
  65. mcp_proxy_adapter/examples/certs/proxy_key.pem +28 -0
  66. mcp_proxy_adapter/examples/certs/readonly.crt +32 -0
  67. mcp_proxy_adapter/examples/certs/readonly.key +52 -0
  68. mcp_proxy_adapter/examples/certs/readonly_cert.pem +21 -0
  69. mcp_proxy_adapter/examples/certs/readonly_key.pem +28 -0
  70. mcp_proxy_adapter/examples/certs/server.crt +32 -0
  71. mcp_proxy_adapter/examples/certs/server.key +52 -0
  72. mcp_proxy_adapter/examples/certs/server_cert.pem +32 -0
  73. mcp_proxy_adapter/examples/certs/server_key.pem +52 -0
  74. mcp_proxy_adapter/examples/certs/test_ca_ca.crt +20 -0
  75. mcp_proxy_adapter/examples/certs/user.crt +32 -0
  76. mcp_proxy_adapter/examples/certs/user.key +52 -0
  77. mcp_proxy_adapter/examples/certs/user_cert.pem +21 -0
  78. mcp_proxy_adapter/examples/certs/user_key.pem +28 -0
  79. mcp_proxy_adapter/examples/client_configs/api_key_client.json +13 -0
  80. mcp_proxy_adapter/examples/client_configs/basic_auth_client.json +13 -0
  81. mcp_proxy_adapter/examples/client_configs/certificate_client.json +22 -0
  82. mcp_proxy_adapter/examples/client_configs/jwt_client.json +15 -0
  83. mcp_proxy_adapter/examples/client_configs/no_auth_client.json +9 -0
  84. mcp_proxy_adapter/examples/commands/__init__.py +1 -0
  85. mcp_proxy_adapter/examples/create_certificates_simple.py +307 -0
  86. mcp_proxy_adapter/examples/debug_request_state.py +144 -0
  87. mcp_proxy_adapter/examples/debug_role_chain.py +205 -0
  88. mcp_proxy_adapter/examples/demo_client.py +341 -0
  89. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +99 -0
  90. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +106 -0
  91. mcp_proxy_adapter/examples/full_application/configs/http_auth.json +37 -0
  92. mcp_proxy_adapter/examples/full_application/configs/http_simple.json +23 -0
  93. mcp_proxy_adapter/examples/full_application/configs/https_auth.json +39 -0
  94. mcp_proxy_adapter/examples/full_application/configs/https_simple.json +25 -0
  95. mcp_proxy_adapter/examples/full_application/configs/mtls_no_roles.json +39 -0
  96. mcp_proxy_adapter/examples/full_application/configs/mtls_with_roles.json +45 -0
  97. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +97 -0
  98. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +95 -0
  99. mcp_proxy_adapter/examples/full_application/main.py +138 -0
  100. mcp_proxy_adapter/examples/full_application/roles.json +21 -0
  101. mcp_proxy_adapter/examples/generate_all_certificates.py +429 -0
  102. mcp_proxy_adapter/examples/generate_certificates.py +121 -0
  103. mcp_proxy_adapter/examples/keys/ca_key.pem +28 -0
  104. mcp_proxy_adapter/examples/keys/mcp_proxy_adapter_ca_ca.key +28 -0
  105. mcp_proxy_adapter/examples/keys/test_ca_ca.key +28 -0
  106. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log +220 -0
  107. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.1 +1 -0
  108. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.2 +1 -0
  109. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.3 +1 -0
  110. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.4 +1 -0
  111. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.5 +1 -0
  112. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log +220 -0
  113. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.1 +1 -0
  114. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.2 +1 -0
  115. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.3 +1 -0
  116. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.4 +1 -0
  117. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.5 +1 -0
  118. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log +2 -0
  119. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.1 +1 -0
  120. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.2 +1 -0
  121. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.3 +1 -0
  122. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.4 +1 -0
  123. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.5 +1 -0
  124. mcp_proxy_adapter/examples/proxy_registration_example.py +401 -0
  125. mcp_proxy_adapter/examples/roles.json +38 -0
  126. mcp_proxy_adapter/examples/run_example.py +81 -0
  127. mcp_proxy_adapter/examples/run_security_tests.py +326 -0
  128. mcp_proxy_adapter/examples/run_security_tests_fixed.py +300 -0
  129. mcp_proxy_adapter/examples/security_test_client.py +743 -0
  130. mcp_proxy_adapter/examples/server_configs/config_basic_http.json +204 -0
  131. mcp_proxy_adapter/examples/server_configs/config_http_token.json +238 -0
  132. mcp_proxy_adapter/examples/server_configs/config_https.json +215 -0
  133. mcp_proxy_adapter/examples/server_configs/config_https_token.json +231 -0
  134. mcp_proxy_adapter/examples/server_configs/config_mtls.json +215 -0
  135. mcp_proxy_adapter/examples/server_configs/config_proxy_registration.json +250 -0
  136. mcp_proxy_adapter/examples/server_configs/config_simple.json +46 -0
  137. mcp_proxy_adapter/examples/server_configs/roles.json +38 -0
  138. mcp_proxy_adapter/examples/test_examples.py +344 -0
  139. mcp_proxy_adapter/examples/universal_client.py +628 -0
  140. mcp_proxy_adapter/main.py +21 -10
  141. mcp_proxy_adapter/utils/config_generator.py +639 -0
  142. mcp_proxy_adapter/version.py +2 -1
  143. mcp_proxy_adapter-6.1.0.dist-info/METADATA +205 -0
  144. mcp_proxy_adapter-6.1.0.dist-info/RECORD +193 -0
  145. mcp_proxy_adapter-6.1.0.dist-info/entry_points.txt +2 -0
  146. {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.1.0.dist-info}/licenses/LICENSE +2 -2
  147. mcp_proxy_adapter/api/middleware/auth.py +0 -146
  148. mcp_proxy_adapter/api/middleware/auth_adapter.py +0 -235
  149. mcp_proxy_adapter/api/middleware/mtls_adapter.py +0 -305
  150. mcp_proxy_adapter/api/middleware/mtls_middleware.py +0 -296
  151. mcp_proxy_adapter/api/middleware/rate_limit.py +0 -152
  152. mcp_proxy_adapter/api/middleware/rate_limit_adapter.py +0 -241
  153. mcp_proxy_adapter/api/middleware/roles_adapter.py +0 -365
  154. mcp_proxy_adapter/api/middleware/roles_middleware.py +0 -381
  155. mcp_proxy_adapter/api/middleware/security.py +0 -376
  156. mcp_proxy_adapter/api/middleware/token_auth_middleware.py +0 -261
  157. mcp_proxy_adapter/examples/__init__.py +0 -7
  158. mcp_proxy_adapter/examples/basic_server/README.md +0 -60
  159. mcp_proxy_adapter/examples/basic_server/__init__.py +0 -7
  160. mcp_proxy_adapter/examples/basic_server/basic_custom_settings.json +0 -39
  161. mcp_proxy_adapter/examples/basic_server/config.json +0 -70
  162. mcp_proxy_adapter/examples/basic_server/config_all_protocols.json +0 -54
  163. mcp_proxy_adapter/examples/basic_server/config_http.json +0 -70
  164. mcp_proxy_adapter/examples/basic_server/config_http_only.json +0 -52
  165. mcp_proxy_adapter/examples/basic_server/config_https.json +0 -58
  166. mcp_proxy_adapter/examples/basic_server/config_mtls.json +0 -58
  167. mcp_proxy_adapter/examples/basic_server/config_ssl.json +0 -46
  168. mcp_proxy_adapter/examples/basic_server/custom_settings_example.py +0 -238
  169. mcp_proxy_adapter/examples/basic_server/server.py +0 -114
  170. mcp_proxy_adapter/examples/custom_commands/README.md +0 -127
  171. mcp_proxy_adapter/examples/custom_commands/__init__.py +0 -27
  172. mcp_proxy_adapter/examples/custom_commands/advanced_hooks.py +0 -566
  173. mcp_proxy_adapter/examples/custom_commands/auto_commands/__init__.py +0 -6
  174. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_echo_command.py +0 -103
  175. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_info_command.py +0 -111
  176. mcp_proxy_adapter/examples/custom_commands/auto_commands/test_command.py +0 -105
  177. mcp_proxy_adapter/examples/custom_commands/catalog/commands/test_command.py +0 -129
  178. mcp_proxy_adapter/examples/custom_commands/config.json +0 -118
  179. mcp_proxy_adapter/examples/custom_commands/config_all_protocols.json +0 -46
  180. mcp_proxy_adapter/examples/custom_commands/config_https_only.json +0 -46
  181. mcp_proxy_adapter/examples/custom_commands/config_https_transport.json +0 -33
  182. mcp_proxy_adapter/examples/custom_commands/config_mtls_only.json +0 -46
  183. mcp_proxy_adapter/examples/custom_commands/config_mtls_transport.json +0 -33
  184. mcp_proxy_adapter/examples/custom_commands/config_single_transport.json +0 -33
  185. mcp_proxy_adapter/examples/custom_commands/custom_health_command.py +0 -169
  186. mcp_proxy_adapter/examples/custom_commands/custom_help_command.py +0 -215
  187. mcp_proxy_adapter/examples/custom_commands/custom_openapi_generator.py +0 -76
  188. mcp_proxy_adapter/examples/custom_commands/custom_settings.json +0 -96
  189. mcp_proxy_adapter/examples/custom_commands/custom_settings_manager.py +0 -241
  190. mcp_proxy_adapter/examples/custom_commands/data_transform_command.py +0 -135
  191. mcp_proxy_adapter/examples/custom_commands/echo_command.py +0 -122
  192. mcp_proxy_adapter/examples/custom_commands/full_help_response.json +0 -1
  193. mcp_proxy_adapter/examples/custom_commands/generated_openapi.json +0 -629
  194. mcp_proxy_adapter/examples/custom_commands/get_openapi.py +0 -103
  195. mcp_proxy_adapter/examples/custom_commands/hooks.py +0 -230
  196. mcp_proxy_adapter/examples/custom_commands/intercept_command.py +0 -123
  197. mcp_proxy_adapter/examples/custom_commands/loadable_commands/test_ignored.py +0 -129
  198. mcp_proxy_adapter/examples/custom_commands/manual_echo_command.py +0 -103
  199. mcp_proxy_adapter/examples/custom_commands/proxy_connection_manager.py +0 -278
  200. mcp_proxy_adapter/examples/custom_commands/server.py +0 -252
  201. mcp_proxy_adapter/examples/custom_commands/simple_openapi_server.py +0 -75
  202. mcp_proxy_adapter/examples/custom_commands/start_server_with_proxy_manager.py +0 -299
  203. mcp_proxy_adapter/examples/custom_commands/start_server_with_registration.py +0 -278
  204. mcp_proxy_adapter/examples/custom_commands/test_hooks.py +0 -176
  205. mcp_proxy_adapter/examples/custom_commands/test_openapi.py +0 -27
  206. mcp_proxy_adapter/examples/custom_commands/test_registry.py +0 -23
  207. mcp_proxy_adapter/examples/custom_commands/test_simple.py +0 -19
  208. mcp_proxy_adapter/examples/custom_project_example/README.md +0 -103
  209. mcp_proxy_adapter/examples/custom_project_example/README_EN.md +0 -103
  210. mcp_proxy_adapter/examples/deployment/README.md +0 -49
  211. mcp_proxy_adapter/examples/deployment/__init__.py +0 -7
  212. mcp_proxy_adapter/examples/deployment/config.development.json +0 -8
  213. mcp_proxy_adapter/examples/deployment/config.json +0 -29
  214. mcp_proxy_adapter/examples/deployment/config.production.json +0 -12
  215. mcp_proxy_adapter/examples/deployment/config.staging.json +0 -11
  216. mcp_proxy_adapter/examples/deployment/docker-compose.yml +0 -31
  217. mcp_proxy_adapter/examples/deployment/run.sh +0 -43
  218. mcp_proxy_adapter/examples/deployment/run_docker.sh +0 -84
  219. mcp_proxy_adapter/examples/simple_custom_commands/README.md +0 -149
  220. mcp_proxy_adapter/examples/simple_custom_commands/README_EN.md +0 -149
  221. mcp_proxy_adapter/schemas/base_schema.json +0 -114
  222. mcp_proxy_adapter/schemas/openapi_schema.json +0 -314
  223. mcp_proxy_adapter/schemas/roles_schema.json +0 -162
  224. mcp_proxy_adapter/tests/__init__.py +0 -0
  225. mcp_proxy_adapter/tests/api/__init__.py +0 -3
  226. mcp_proxy_adapter/tests/api/test_cmd_endpoint.py +0 -115
  227. mcp_proxy_adapter/tests/api/test_custom_openapi.py +0 -617
  228. mcp_proxy_adapter/tests/api/test_handlers.py +0 -522
  229. mcp_proxy_adapter/tests/api/test_middleware.py +0 -340
  230. mcp_proxy_adapter/tests/api/test_schemas.py +0 -546
  231. mcp_proxy_adapter/tests/api/test_tool_integration.py +0 -531
  232. mcp_proxy_adapter/tests/commands/__init__.py +0 -3
  233. mcp_proxy_adapter/tests/commands/test_config_command.py +0 -211
  234. mcp_proxy_adapter/tests/commands/test_echo_command.py +0 -127
  235. mcp_proxy_adapter/tests/commands/test_help_command.py +0 -136
  236. mcp_proxy_adapter/tests/conftest.py +0 -131
  237. mcp_proxy_adapter/tests/functional/__init__.py +0 -3
  238. mcp_proxy_adapter/tests/functional/test_api.py +0 -253
  239. mcp_proxy_adapter/tests/integration/__init__.py +0 -3
  240. mcp_proxy_adapter/tests/integration/test_cmd_integration.py +0 -129
  241. mcp_proxy_adapter/tests/integration/test_integration.py +0 -255
  242. mcp_proxy_adapter/tests/performance/__init__.py +0 -3
  243. mcp_proxy_adapter/tests/performance/test_performance.py +0 -189
  244. mcp_proxy_adapter/tests/stubs/__init__.py +0 -10
  245. mcp_proxy_adapter/tests/stubs/echo_command.py +0 -104
  246. mcp_proxy_adapter/tests/test_api_endpoints.py +0 -271
  247. mcp_proxy_adapter/tests/test_api_handlers.py +0 -289
  248. mcp_proxy_adapter/tests/test_base_command.py +0 -123
  249. mcp_proxy_adapter/tests/test_batch_requests.py +0 -117
  250. mcp_proxy_adapter/tests/test_command_registry.py +0 -281
  251. mcp_proxy_adapter/tests/test_config.py +0 -127
  252. mcp_proxy_adapter/tests/test_utils.py +0 -65
  253. mcp_proxy_adapter/tests/unit/__init__.py +0 -3
  254. mcp_proxy_adapter/tests/unit/test_base_command.py +0 -436
  255. mcp_proxy_adapter/tests/unit/test_config.py +0 -270
  256. mcp_proxy_adapter-6.0.0.dist-info/METADATA +0 -201
  257. mcp_proxy_adapter-6.0.0.dist-info/RECORD +0 -179
  258. {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.1.0.dist-info}/WHEEL +0 -0
  259. {mcp_proxy_adapter-6.0.0.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