mcp-proxy-adapter 6.0.0__py3-none-any.whl → 6.1.1__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 (264) 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 +9 -4
  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/protocol_middleware.py +32 -13
  7. mcp_proxy_adapter/api/middleware/unified_security.py +160 -0
  8. mcp_proxy_adapter/api/middleware/user_info_middleware.py +83 -0
  9. mcp_proxy_adapter/commands/__init__.py +7 -1
  10. mcp_proxy_adapter/commands/base.py +7 -4
  11. mcp_proxy_adapter/commands/builtin_commands.py +8 -2
  12. mcp_proxy_adapter/commands/command_registry.py +8 -0
  13. mcp_proxy_adapter/commands/echo_command.py +81 -0
  14. mcp_proxy_adapter/commands/help_command.py +21 -14
  15. mcp_proxy_adapter/commands/proxy_registration_command.py +326 -185
  16. mcp_proxy_adapter/commands/role_test_command.py +141 -0
  17. mcp_proxy_adapter/commands/security_command.py +488 -0
  18. mcp_proxy_adapter/commands/ssl_setup_command.py +2 -2
  19. mcp_proxy_adapter/commands/token_management_command.py +1 -1
  20. mcp_proxy_adapter/config.py +81 -21
  21. mcp_proxy_adapter/core/app_factory.py +326 -0
  22. mcp_proxy_adapter/core/client_security.py +384 -0
  23. mcp_proxy_adapter/core/logging.py +8 -3
  24. mcp_proxy_adapter/core/mtls_asgi.py +156 -0
  25. mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
  26. mcp_proxy_adapter/core/protocol_manager.py +139 -8
  27. mcp_proxy_adapter/core/proxy_client.py +602 -0
  28. mcp_proxy_adapter/core/proxy_registration.py +299 -47
  29. mcp_proxy_adapter/core/security_adapter.py +12 -15
  30. mcp_proxy_adapter/core/security_integration.py +285 -0
  31. mcp_proxy_adapter/core/server_adapter.py +345 -0
  32. mcp_proxy_adapter/core/server_engine.py +364 -0
  33. mcp_proxy_adapter/core/unified_config_adapter.py +579 -0
  34. mcp_proxy_adapter/docs/EN/TROUBLESHOOTING.md +285 -0
  35. mcp_proxy_adapter/docs/RU/TROUBLESHOOTING.md +285 -0
  36. mcp_proxy_adapter/examples/README.md +230 -97
  37. mcp_proxy_adapter/examples/README_EN.md +258 -0
  38. mcp_proxy_adapter/examples/SECURITY_TESTING.md +455 -0
  39. mcp_proxy_adapter/examples/basic_framework/configs/http_auth.json +37 -0
  40. mcp_proxy_adapter/examples/basic_framework/configs/http_simple.json +23 -0
  41. mcp_proxy_adapter/examples/basic_framework/configs/https_auth.json +43 -0
  42. mcp_proxy_adapter/examples/basic_framework/configs/https_no_protocol_middleware.json +36 -0
  43. mcp_proxy_adapter/examples/basic_framework/configs/https_simple.json +29 -0
  44. mcp_proxy_adapter/examples/basic_framework/configs/mtls_no_protocol_middleware.json +34 -0
  45. mcp_proxy_adapter/examples/basic_framework/configs/mtls_no_roles.json +39 -0
  46. mcp_proxy_adapter/examples/basic_framework/configs/mtls_simple.json +35 -0
  47. mcp_proxy_adapter/examples/basic_framework/configs/mtls_with_roles.json +45 -0
  48. mcp_proxy_adapter/examples/basic_framework/main.py +63 -0
  49. mcp_proxy_adapter/examples/basic_framework/roles.json +21 -0
  50. mcp_proxy_adapter/examples/cert_config.json +9 -0
  51. mcp_proxy_adapter/examples/certs/admin.crt +32 -0
  52. mcp_proxy_adapter/examples/certs/admin.key +52 -0
  53. mcp_proxy_adapter/examples/certs/admin_cert.pem +21 -0
  54. mcp_proxy_adapter/examples/certs/admin_key.pem +28 -0
  55. mcp_proxy_adapter/examples/certs/ca_cert.pem +23 -0
  56. mcp_proxy_adapter/examples/certs/ca_cert.srl +1 -0
  57. mcp_proxy_adapter/examples/certs/ca_key.pem +28 -0
  58. mcp_proxy_adapter/examples/certs/cert_config.json +9 -0
  59. mcp_proxy_adapter/examples/certs/client.crt +32 -0
  60. mcp_proxy_adapter/examples/certs/client.key +52 -0
  61. mcp_proxy_adapter/examples/certs/client_admin.crt +32 -0
  62. mcp_proxy_adapter/examples/certs/client_admin.key +52 -0
  63. mcp_proxy_adapter/examples/certs/client_user.crt +32 -0
  64. mcp_proxy_adapter/examples/certs/client_user.key +52 -0
  65. mcp_proxy_adapter/examples/certs/guest_cert.pem +21 -0
  66. mcp_proxy_adapter/examples/certs/guest_key.pem +28 -0
  67. mcp_proxy_adapter/examples/certs/mcp_proxy_adapter_ca_ca.crt +23 -0
  68. mcp_proxy_adapter/examples/certs/proxy_cert.pem +21 -0
  69. mcp_proxy_adapter/examples/certs/proxy_key.pem +28 -0
  70. mcp_proxy_adapter/examples/certs/readonly.crt +32 -0
  71. mcp_proxy_adapter/examples/certs/readonly.key +52 -0
  72. mcp_proxy_adapter/examples/certs/readonly_cert.pem +21 -0
  73. mcp_proxy_adapter/examples/certs/readonly_key.pem +28 -0
  74. mcp_proxy_adapter/examples/certs/server.crt +32 -0
  75. mcp_proxy_adapter/examples/certs/server.key +52 -0
  76. mcp_proxy_adapter/examples/certs/server_cert.pem +32 -0
  77. mcp_proxy_adapter/examples/certs/server_key.pem +52 -0
  78. mcp_proxy_adapter/examples/certs/test_ca_ca.crt +20 -0
  79. mcp_proxy_adapter/examples/certs/user.crt +32 -0
  80. mcp_proxy_adapter/examples/certs/user.key +52 -0
  81. mcp_proxy_adapter/examples/certs/user_cert.pem +21 -0
  82. mcp_proxy_adapter/examples/certs/user_key.pem +28 -0
  83. mcp_proxy_adapter/examples/client_configs/api_key_client.json +13 -0
  84. mcp_proxy_adapter/examples/client_configs/basic_auth_client.json +13 -0
  85. mcp_proxy_adapter/examples/client_configs/certificate_client.json +22 -0
  86. mcp_proxy_adapter/examples/client_configs/jwt_client.json +15 -0
  87. mcp_proxy_adapter/examples/client_configs/no_auth_client.json +9 -0
  88. mcp_proxy_adapter/examples/commands/__init__.py +1 -0
  89. mcp_proxy_adapter/examples/create_certificates_simple.py +307 -0
  90. mcp_proxy_adapter/examples/debug_request_state.py +144 -0
  91. mcp_proxy_adapter/examples/debug_role_chain.py +205 -0
  92. mcp_proxy_adapter/examples/demo_client.py +341 -0
  93. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +99 -0
  94. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +106 -0
  95. mcp_proxy_adapter/examples/full_application/configs/http_auth.json +37 -0
  96. mcp_proxy_adapter/examples/full_application/configs/http_simple.json +23 -0
  97. mcp_proxy_adapter/examples/full_application/configs/https_auth.json +39 -0
  98. mcp_proxy_adapter/examples/full_application/configs/https_simple.json +25 -0
  99. mcp_proxy_adapter/examples/full_application/configs/mtls_no_roles.json +39 -0
  100. mcp_proxy_adapter/examples/full_application/configs/mtls_with_roles.json +45 -0
  101. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +97 -0
  102. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +95 -0
  103. mcp_proxy_adapter/examples/full_application/main.py +138 -0
  104. mcp_proxy_adapter/examples/full_application/roles.json +21 -0
  105. mcp_proxy_adapter/examples/generate_all_certificates.py +429 -0
  106. mcp_proxy_adapter/examples/generate_certificates.py +121 -0
  107. mcp_proxy_adapter/examples/keys/ca_key.pem +28 -0
  108. mcp_proxy_adapter/examples/keys/mcp_proxy_adapter_ca_ca.key +28 -0
  109. mcp_proxy_adapter/examples/keys/test_ca_ca.key +28 -0
  110. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log +220 -0
  111. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.1 +1 -0
  112. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.2 +1 -0
  113. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.3 +1 -0
  114. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.4 +1 -0
  115. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.5 +1 -0
  116. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log +220 -0
  117. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.1 +1 -0
  118. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.2 +1 -0
  119. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.3 +1 -0
  120. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.4 +1 -0
  121. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.5 +1 -0
  122. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log +2 -0
  123. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.1 +1 -0
  124. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.2 +1 -0
  125. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.3 +1 -0
  126. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.4 +1 -0
  127. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.5 +1 -0
  128. mcp_proxy_adapter/examples/proxy_registration_example.py +401 -0
  129. mcp_proxy_adapter/examples/roles.json +38 -0
  130. mcp_proxy_adapter/examples/run_example.py +81 -0
  131. mcp_proxy_adapter/examples/run_security_tests.py +326 -0
  132. mcp_proxy_adapter/examples/run_security_tests_fixed.py +300 -0
  133. mcp_proxy_adapter/examples/security_test_client.py +743 -0
  134. mcp_proxy_adapter/examples/server_configs/config_basic_http.json +204 -0
  135. mcp_proxy_adapter/examples/server_configs/config_http_token.json +238 -0
  136. mcp_proxy_adapter/examples/server_configs/config_https.json +215 -0
  137. mcp_proxy_adapter/examples/server_configs/config_https_token.json +231 -0
  138. mcp_proxy_adapter/examples/server_configs/config_mtls.json +215 -0
  139. mcp_proxy_adapter/examples/server_configs/config_proxy_registration.json +250 -0
  140. mcp_proxy_adapter/examples/server_configs/config_simple.json +46 -0
  141. mcp_proxy_adapter/examples/server_configs/roles.json +38 -0
  142. mcp_proxy_adapter/examples/test_config_generator.py +110 -0
  143. mcp_proxy_adapter/examples/test_examples.py +344 -0
  144. mcp_proxy_adapter/examples/universal_client.py +628 -0
  145. mcp_proxy_adapter/main.py +21 -10
  146. mcp_proxy_adapter/utils/config_generator.py +727 -0
  147. mcp_proxy_adapter/version.py +5 -2
  148. mcp_proxy_adapter-6.1.1.dist-info/METADATA +205 -0
  149. mcp_proxy_adapter-6.1.1.dist-info/RECORD +197 -0
  150. mcp_proxy_adapter-6.1.1.dist-info/entry_points.txt +2 -0
  151. {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.1.1.dist-info}/licenses/LICENSE +2 -2
  152. mcp_proxy_adapter/api/middleware/auth.py +0 -146
  153. mcp_proxy_adapter/api/middleware/auth_adapter.py +0 -235
  154. mcp_proxy_adapter/api/middleware/mtls_adapter.py +0 -305
  155. mcp_proxy_adapter/api/middleware/mtls_middleware.py +0 -296
  156. mcp_proxy_adapter/api/middleware/rate_limit.py +0 -152
  157. mcp_proxy_adapter/api/middleware/rate_limit_adapter.py +0 -241
  158. mcp_proxy_adapter/api/middleware/roles_adapter.py +0 -365
  159. mcp_proxy_adapter/api/middleware/roles_middleware.py +0 -381
  160. mcp_proxy_adapter/api/middleware/security.py +0 -376
  161. mcp_proxy_adapter/api/middleware/token_auth_middleware.py +0 -261
  162. mcp_proxy_adapter/examples/__init__.py +0 -7
  163. mcp_proxy_adapter/examples/basic_server/README.md +0 -60
  164. mcp_proxy_adapter/examples/basic_server/__init__.py +0 -7
  165. mcp_proxy_adapter/examples/basic_server/basic_custom_settings.json +0 -39
  166. mcp_proxy_adapter/examples/basic_server/config.json +0 -70
  167. mcp_proxy_adapter/examples/basic_server/config_all_protocols.json +0 -54
  168. mcp_proxy_adapter/examples/basic_server/config_http.json +0 -70
  169. mcp_proxy_adapter/examples/basic_server/config_http_only.json +0 -52
  170. mcp_proxy_adapter/examples/basic_server/config_https.json +0 -58
  171. mcp_proxy_adapter/examples/basic_server/config_mtls.json +0 -58
  172. mcp_proxy_adapter/examples/basic_server/config_ssl.json +0 -46
  173. mcp_proxy_adapter/examples/basic_server/custom_settings_example.py +0 -238
  174. mcp_proxy_adapter/examples/basic_server/server.py +0 -114
  175. mcp_proxy_adapter/examples/custom_commands/README.md +0 -127
  176. mcp_proxy_adapter/examples/custom_commands/__init__.py +0 -27
  177. mcp_proxy_adapter/examples/custom_commands/advanced_hooks.py +0 -566
  178. mcp_proxy_adapter/examples/custom_commands/auto_commands/__init__.py +0 -6
  179. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_echo_command.py +0 -103
  180. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_info_command.py +0 -111
  181. mcp_proxy_adapter/examples/custom_commands/auto_commands/test_command.py +0 -105
  182. mcp_proxy_adapter/examples/custom_commands/catalog/commands/test_command.py +0 -129
  183. mcp_proxy_adapter/examples/custom_commands/config.json +0 -118
  184. mcp_proxy_adapter/examples/custom_commands/config_all_protocols.json +0 -46
  185. mcp_proxy_adapter/examples/custom_commands/config_https_only.json +0 -46
  186. mcp_proxy_adapter/examples/custom_commands/config_https_transport.json +0 -33
  187. mcp_proxy_adapter/examples/custom_commands/config_mtls_only.json +0 -46
  188. mcp_proxy_adapter/examples/custom_commands/config_mtls_transport.json +0 -33
  189. mcp_proxy_adapter/examples/custom_commands/config_single_transport.json +0 -33
  190. mcp_proxy_adapter/examples/custom_commands/custom_health_command.py +0 -169
  191. mcp_proxy_adapter/examples/custom_commands/custom_help_command.py +0 -215
  192. mcp_proxy_adapter/examples/custom_commands/custom_openapi_generator.py +0 -76
  193. mcp_proxy_adapter/examples/custom_commands/custom_settings.json +0 -96
  194. mcp_proxy_adapter/examples/custom_commands/custom_settings_manager.py +0 -241
  195. mcp_proxy_adapter/examples/custom_commands/data_transform_command.py +0 -135
  196. mcp_proxy_adapter/examples/custom_commands/echo_command.py +0 -122
  197. mcp_proxy_adapter/examples/custom_commands/full_help_response.json +0 -1
  198. mcp_proxy_adapter/examples/custom_commands/generated_openapi.json +0 -629
  199. mcp_proxy_adapter/examples/custom_commands/get_openapi.py +0 -103
  200. mcp_proxy_adapter/examples/custom_commands/hooks.py +0 -230
  201. mcp_proxy_adapter/examples/custom_commands/intercept_command.py +0 -123
  202. mcp_proxy_adapter/examples/custom_commands/loadable_commands/test_ignored.py +0 -129
  203. mcp_proxy_adapter/examples/custom_commands/manual_echo_command.py +0 -103
  204. mcp_proxy_adapter/examples/custom_commands/proxy_connection_manager.py +0 -278
  205. mcp_proxy_adapter/examples/custom_commands/server.py +0 -252
  206. mcp_proxy_adapter/examples/custom_commands/simple_openapi_server.py +0 -75
  207. mcp_proxy_adapter/examples/custom_commands/start_server_with_proxy_manager.py +0 -299
  208. mcp_proxy_adapter/examples/custom_commands/start_server_with_registration.py +0 -278
  209. mcp_proxy_adapter/examples/custom_commands/test_hooks.py +0 -176
  210. mcp_proxy_adapter/examples/custom_commands/test_openapi.py +0 -27
  211. mcp_proxy_adapter/examples/custom_commands/test_registry.py +0 -23
  212. mcp_proxy_adapter/examples/custom_commands/test_simple.py +0 -19
  213. mcp_proxy_adapter/examples/custom_project_example/README.md +0 -103
  214. mcp_proxy_adapter/examples/custom_project_example/README_EN.md +0 -103
  215. mcp_proxy_adapter/examples/deployment/README.md +0 -49
  216. mcp_proxy_adapter/examples/deployment/__init__.py +0 -7
  217. mcp_proxy_adapter/examples/deployment/config.development.json +0 -8
  218. mcp_proxy_adapter/examples/deployment/config.json +0 -29
  219. mcp_proxy_adapter/examples/deployment/config.production.json +0 -12
  220. mcp_proxy_adapter/examples/deployment/config.staging.json +0 -11
  221. mcp_proxy_adapter/examples/deployment/docker-compose.yml +0 -31
  222. mcp_proxy_adapter/examples/deployment/run.sh +0 -43
  223. mcp_proxy_adapter/examples/deployment/run_docker.sh +0 -84
  224. mcp_proxy_adapter/examples/simple_custom_commands/README.md +0 -149
  225. mcp_proxy_adapter/examples/simple_custom_commands/README_EN.md +0 -149
  226. mcp_proxy_adapter/schemas/base_schema.json +0 -114
  227. mcp_proxy_adapter/schemas/openapi_schema.json +0 -314
  228. mcp_proxy_adapter/schemas/roles_schema.json +0 -162
  229. mcp_proxy_adapter/tests/__init__.py +0 -0
  230. mcp_proxy_adapter/tests/api/__init__.py +0 -3
  231. mcp_proxy_adapter/tests/api/test_cmd_endpoint.py +0 -115
  232. mcp_proxy_adapter/tests/api/test_custom_openapi.py +0 -617
  233. mcp_proxy_adapter/tests/api/test_handlers.py +0 -522
  234. mcp_proxy_adapter/tests/api/test_middleware.py +0 -340
  235. mcp_proxy_adapter/tests/api/test_schemas.py +0 -546
  236. mcp_proxy_adapter/tests/api/test_tool_integration.py +0 -531
  237. mcp_proxy_adapter/tests/commands/__init__.py +0 -3
  238. mcp_proxy_adapter/tests/commands/test_config_command.py +0 -211
  239. mcp_proxy_adapter/tests/commands/test_echo_command.py +0 -127
  240. mcp_proxy_adapter/tests/commands/test_help_command.py +0 -136
  241. mcp_proxy_adapter/tests/conftest.py +0 -131
  242. mcp_proxy_adapter/tests/functional/__init__.py +0 -3
  243. mcp_proxy_adapter/tests/functional/test_api.py +0 -253
  244. mcp_proxy_adapter/tests/integration/__init__.py +0 -3
  245. mcp_proxy_adapter/tests/integration/test_cmd_integration.py +0 -129
  246. mcp_proxy_adapter/tests/integration/test_integration.py +0 -255
  247. mcp_proxy_adapter/tests/performance/__init__.py +0 -3
  248. mcp_proxy_adapter/tests/performance/test_performance.py +0 -189
  249. mcp_proxy_adapter/tests/stubs/__init__.py +0 -10
  250. mcp_proxy_adapter/tests/stubs/echo_command.py +0 -104
  251. mcp_proxy_adapter/tests/test_api_endpoints.py +0 -271
  252. mcp_proxy_adapter/tests/test_api_handlers.py +0 -289
  253. mcp_proxy_adapter/tests/test_base_command.py +0 -123
  254. mcp_proxy_adapter/tests/test_batch_requests.py +0 -117
  255. mcp_proxy_adapter/tests/test_command_registry.py +0 -281
  256. mcp_proxy_adapter/tests/test_config.py +0 -127
  257. mcp_proxy_adapter/tests/test_utils.py +0 -65
  258. mcp_proxy_adapter/tests/unit/__init__.py +0 -3
  259. mcp_proxy_adapter/tests/unit/test_base_command.py +0 -436
  260. mcp_proxy_adapter/tests/unit/test_config.py +0 -270
  261. mcp_proxy_adapter-6.0.0.dist-info/METADATA +0 -201
  262. mcp_proxy_adapter-6.0.0.dist-info/RECORD +0 -179
  263. {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.1.1.dist-info}/WHEEL +0 -0
  264. {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.1.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,205 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Debug Role Chain - Анализ цепочки блокировки ролей
4
+
5
+ Этот скрипт анализирует всю цепочку от аутентификации до блокировки доступа.
6
+
7
+ Author: Vasiliy Zdanovskiy
8
+ email: vasilyvz@gmail.com
9
+ """
10
+
11
+ import asyncio
12
+ import json
13
+ import sys
14
+ from pathlib import Path
15
+
16
+ # Add project root to path
17
+ project_root = Path(__file__).parent.parent.parent
18
+ sys.path.insert(0, str(project_root))
19
+
20
+ from mcp_security_framework import SecurityManager, AuthManager, PermissionManager
21
+ from mcp_security_framework.schemas.config import SecurityConfig, AuthConfig, PermissionConfig
22
+
23
+
24
+ async def debug_role_chain():
25
+ """Debug the complete role chain from authentication to blocking."""
26
+
27
+ print("🔍 АНАЛИЗ ЦЕПОЧКИ БЛОКИРОВКИ РОЛЕЙ")
28
+ print("=" * 60)
29
+
30
+ # Load configuration
31
+ config_path = project_root / "mcp_proxy_adapter" / "examples" / "server_configs" / "config_http_token.json"
32
+
33
+ with open(config_path) as f:
34
+ config = json.load(f)
35
+
36
+ security_config = config.get("security", {})
37
+
38
+ print("📋 1. КОНФИГУРАЦИЯ API КЛЮЧЕЙ")
39
+ print("-" * 30)
40
+ api_keys = security_config.get("auth", {}).get("api_keys", {})
41
+ for key, value in api_keys.items():
42
+ print(f" {key}: {value}")
43
+
44
+ print("\n📋 2. КОНФИГУРАЦИЯ РОЛЕЙ")
45
+ print("-" * 30)
46
+ roles_config = security_config.get("permissions", {}).get("roles", {})
47
+ for role, permissions in roles_config.items():
48
+ print(f" {role}: {permissions}")
49
+
50
+ print("\n📋 3. СОЗДАНИЕ КОМПОНЕНТОВ БЕЗОПАСНОСТИ")
51
+ print("-" * 30)
52
+
53
+ # Create permission config
54
+ perm_config = PermissionConfig(
55
+ roles_file=str(project_root / "mcp_proxy_adapter" / "examples" / "server_configs" / "roles.json"),
56
+ default_role="guest",
57
+ admin_role="admin",
58
+ role_hierarchy=security_config.get("permissions", {}).get("role_hierarchy", {}),
59
+ permission_cache_enabled=True,
60
+ permission_cache_ttl=300,
61
+ wildcard_permissions=False,
62
+ strict_mode=True,
63
+ roles=roles_config
64
+ )
65
+
66
+ # Create auth config
67
+ auth_config = AuthConfig(
68
+ enabled=security_config.get("auth", {}).get("enabled", True),
69
+ methods=security_config.get("auth", {}).get("methods", ["api_key"]),
70
+ api_keys=api_keys,
71
+ user_roles=security_config.get("auth", {}).get("user_roles", {}),
72
+ jwt_secret=security_config.get("auth", {}).get("jwt_secret"),
73
+ jwt_algorithm=security_config.get("auth", {}).get("jwt_algorithm", "HS256"),
74
+ jwt_expiry_hours=security_config.get("auth", {}).get("jwt_expiry_hours", 24),
75
+ certificate_auth=security_config.get("auth", {}).get("certificate_auth", False),
76
+ certificate_roles_oid=security_config.get("auth", {}).get("certificate_roles_oid"),
77
+ certificate_permissions_oid=security_config.get("auth", {}).get("certificate_permissions_oid"),
78
+ basic_auth=security_config.get("auth", {}).get("basic_auth", False),
79
+ oauth2_config=security_config.get("auth", {}).get("oauth2_config"),
80
+ public_paths=security_config.get("auth", {}).get("public_paths", [])
81
+ )
82
+
83
+ # Create security config
84
+ security_config_obj = SecurityConfig(
85
+ auth=auth_config,
86
+ permissions=perm_config
87
+ )
88
+
89
+ print("✅ Конфигурации созданы")
90
+
91
+ print("\n📋 4. ИНИЦИАЛИЗАЦИЯ МЕНЕДЖЕРОВ")
92
+ print("-" * 30)
93
+
94
+ # Initialize managers
95
+ permission_manager = PermissionManager(perm_config)
96
+ auth_manager = AuthManager(auth_config, permission_manager)
97
+ security_manager = SecurityManager(security_config_obj)
98
+
99
+ print("✅ Менеджеры инициализированы")
100
+
101
+ print("\n📋 5. ТЕСТИРОВАНИЕ АУТЕНТИФИКАЦИИ")
102
+ print("-" * 30)
103
+
104
+ # Test authentication with different tokens
105
+ test_tokens = {
106
+ "admin": "test-token-123",
107
+ "user": "user-token-456",
108
+ "readonly": "readonly-token-123",
109
+ "invalid": "invalid-token-999"
110
+ }
111
+
112
+ auth_results = {}
113
+
114
+ for role, token in test_tokens.items():
115
+ print(f"\n🔐 Тестирование токена для роли '{role}': {token}")
116
+
117
+ try:
118
+ result = auth_manager.authenticate_api_key(token)
119
+ auth_results[role] = result
120
+
121
+ print(f" ✅ Аутентификация: {'УСПЕШНА' if result.is_valid else 'НЕУДАЧНА'}")
122
+ if result.is_valid:
123
+ print(f" 👤 Пользователь: {result.username}")
124
+ print(f" 🏷️ Роли: {result.roles}")
125
+ print(f" 🔑 Метод: {result.auth_method}")
126
+ else:
127
+ print(f" ❌ Ошибка: {result.error_message}")
128
+
129
+ except Exception as e:
130
+ print(f" ❌ Исключение: {e}")
131
+ auth_results[role] = None
132
+
133
+ print("\n📋 6. ТЕСТИРОВАНИЕ ПРАВ ДОСТУПА")
134
+ print("-" * 30)
135
+
136
+ # Test permissions for different actions
137
+ test_actions = ["read", "write", "manage", "delete"]
138
+
139
+ for role, auth_result in auth_results.items():
140
+ if auth_result and auth_result.is_valid:
141
+ print(f"\n🔒 Тестирование прав для роли '{role}' (роли: {auth_result.roles})")
142
+
143
+ for action in test_actions:
144
+ try:
145
+ # Check permissions using permission manager
146
+ validation_result = permission_manager.validate_access(
147
+ auth_result.roles,
148
+ [action]
149
+ )
150
+
151
+ status = "✅ РАЗРЕШЕНО" if validation_result.is_valid else "❌ ЗАБЛОКИРОВАНО"
152
+ print(f" {action}: {status}")
153
+
154
+ if not validation_result.is_valid:
155
+ print(f" 📝 Причина: {validation_result.error_message}")
156
+ print(f" 🎯 Эффективные права: {validation_result.effective_permissions}")
157
+ print(f" ❌ Отсутствующие права: {validation_result.missing_permissions}")
158
+
159
+ except Exception as e:
160
+ print(f" {action}: ❌ ОШИБКА - {e}")
161
+
162
+ print("\n📋 7. ТЕСТИРОВАНИЕ ПОЛНОЙ ЦЕПОЧКИ")
163
+ print("-" * 30)
164
+
165
+ # Test complete request validation
166
+ for role, token in test_tokens.items():
167
+ print(f"\n🔄 Полная цепочка для роли '{role}'")
168
+
169
+ request_data = {
170
+ "api_key": token,
171
+ "required_permissions": ["write"],
172
+ "client_ip": "127.0.0.1"
173
+ }
174
+
175
+ try:
176
+ result = security_manager.validate_request(request_data)
177
+
178
+ status = "✅ УСПЕШНО" if result.is_valid else "❌ ЗАБЛОКИРОВАНО"
179
+ print(f" Результат: {status}")
180
+
181
+ if not result.is_valid:
182
+ print(f" 📝 Причина: {result.error_message}")
183
+
184
+ except Exception as e:
185
+ print(f" ❌ ОШИБКА: {e}")
186
+
187
+ print("\n📋 8. АНАЛИЗ ПРОБЛЕМЫ")
188
+ print("-" * 30)
189
+
190
+ print("🔍 ПРОБЛЕМА: Readonly роль получает доступ к write операциям")
191
+ print("\n📋 ВОЗМОЖНЫЕ ПРИЧИНЫ:")
192
+ print("1. Middleware не передает информацию о пользователе в request.state")
193
+ print("2. Framework middleware не блокирует доступ на уровне middleware")
194
+ print("3. Команда role_test не получает правильный контекст пользователя")
195
+ print("4. Интеграция между middleware и командами не работает")
196
+
197
+ print("\n📋 РЕКОМЕНДАЦИИ:")
198
+ print("1. Проверить, как framework middleware устанавливает user info")
199
+ print("2. Добавить проверку прав на уровне middleware")
200
+ print("3. Убедиться, что request.state содержит user info")
201
+ print("4. Проверить интеграцию между middleware и командами")
202
+
203
+
204
+ if __name__ == "__main__":
205
+ asyncio.run(debug_role_chain())
@@ -0,0 +1,341 @@
1
+ """
2
+ Demo Client Script
3
+
4
+ This script demonstrates how to use the UniversalClient with different
5
+ authentication methods and connection types.
6
+
7
+ Author: Vasiliy Zdanovskiy
8
+ email: vasilyvz@gmail.com
9
+ """
10
+
11
+ import asyncio
12
+ import json
13
+ import sys
14
+ from pathlib import Path
15
+
16
+ # Add project root to path
17
+ sys.path.insert(0, str(Path(__file__).parent.parent))
18
+
19
+ from examples.universal_client import UniversalClient, create_client_config
20
+
21
+
22
+ async def demo_from_config_file(config_file: str):
23
+ """
24
+ Demo client using configuration from file.
25
+
26
+ Args:
27
+ config_file: Path to configuration file
28
+ """
29
+ print(f"🚀 Demo from config file: {config_file}")
30
+ print("=" * 50)
31
+
32
+ try:
33
+ # Load configuration
34
+ with open(config_file, 'r') as f:
35
+ config = json.load(f)
36
+
37
+ print(f"Configuration loaded: {config.get('security', {}).get('auth_method', 'none')} auth")
38
+
39
+ # Create and use client
40
+ async with UniversalClient(config) as client:
41
+ # Test connection
42
+ success = await client.test_connection()
43
+
44
+ if success:
45
+ print("✅ Connection successful!")
46
+
47
+ # Test security features
48
+ security_results = await client.test_security_features()
49
+ print("\nSecurity Features:")
50
+ for feature, status in security_results.items():
51
+ status_icon = "✅" if status else "❌"
52
+ print(f" {status_icon} {feature}: {status}")
53
+
54
+ # Make API calls
55
+ await demo_api_calls(client)
56
+ else:
57
+ print("❌ Connection failed")
58
+
59
+ except FileNotFoundError:
60
+ print(f"❌ Configuration file not found: {config_file}")
61
+ except json.JSONDecodeError:
62
+ print(f"❌ Invalid JSON in configuration file: {config_file}")
63
+ except Exception as e:
64
+ print(f"❌ Demo failed: {e}")
65
+
66
+
67
+ async def demo_api_calls(client: UniversalClient):
68
+ """Demonstrate various API calls."""
69
+ print("\n📡 API Calls Demo:")
70
+ print("-" * 30)
71
+
72
+ # Test health endpoint
73
+ try:
74
+ health = await client.get("/health")
75
+ print(f"Health: {health}")
76
+ except Exception as e:
77
+ print(f"Health check failed: {e}")
78
+
79
+ # Test status endpoint
80
+ try:
81
+ status = await client.get("/api/status")
82
+ print(f"Status: {status}")
83
+ except Exception as e:
84
+ print(f"Status check failed: {e}")
85
+
86
+ # Test JSON-RPC command
87
+ try:
88
+ command_data = {
89
+ "jsonrpc": "2.0",
90
+ "method": "test_command",
91
+ "params": {
92
+ "message": "Hello from universal client!",
93
+ "timestamp": "2024-01-01T00:00:00Z"
94
+ },
95
+ "id": 1
96
+ }
97
+
98
+ result = await client.post("/api/jsonrpc", command_data)
99
+ print(f"Command Result: {result}")
100
+ except Exception as e:
101
+ print(f"Command execution failed: {e}")
102
+
103
+ # Test security command if available
104
+ try:
105
+ security_data = {
106
+ "jsonrpc": "2.0",
107
+ "method": "security_command",
108
+ "params": {
109
+ "action": "get_status",
110
+ "include_certificates": True
111
+ },
112
+ "id": 2
113
+ }
114
+
115
+ result = await client.post("/api/jsonrpc", security_data)
116
+ print(f"Security Status: {result}")
117
+ except Exception as e:
118
+ print(f"Security command failed: {e}")
119
+
120
+
121
+ async def demo_all_configs():
122
+ """Demo all available client configurations."""
123
+ print("🚀 Demo All Client Configurations")
124
+ print("=" * 50)
125
+
126
+ config_dir = Path(__file__).parent / "client_configs"
127
+
128
+ if not config_dir.exists():
129
+ print(f"❌ Config directory not found: {config_dir}")
130
+ return
131
+
132
+ config_files = list(config_dir.glob("*.json"))
133
+
134
+ if not config_files:
135
+ print(f"❌ No configuration files found in {config_dir}")
136
+ return
137
+
138
+ print(f"Found {len(config_files)} configuration files:")
139
+ for config_file in config_files:
140
+ print(f" - {config_file.name}")
141
+
142
+ print("\n" + "=" * 50)
143
+
144
+ for config_file in config_files:
145
+ await demo_from_config_file(str(config_file))
146
+ print("\n" + "-" * 50)
147
+
148
+
149
+ async def demo_programmatic_config():
150
+ """Demo client with programmatically created configuration."""
151
+ print("🚀 Demo Programmatic Configuration")
152
+ print("=" * 50)
153
+
154
+ # Create different configurations programmatically
155
+ configs = [
156
+ {
157
+ "name": "API Key Client",
158
+ "config": create_client_config(
159
+ "http://localhost:8000",
160
+ "api_key",
161
+ api_key="demo_api_key_123"
162
+ )
163
+ },
164
+ {
165
+ "name": "JWT Client",
166
+ "config": create_client_config(
167
+ "http://localhost:8000",
168
+ "jwt",
169
+ username="demo_user",
170
+ password="demo_password",
171
+ secret="demo_jwt_secret"
172
+ )
173
+ },
174
+ {
175
+ "name": "Certificate Client",
176
+ "config": create_client_config(
177
+ "https://localhost:8443",
178
+ "certificate",
179
+ cert_file="./certs/client.crt",
180
+ key_file="./keys/client.key",
181
+ ca_cert_file="./certs/ca.crt"
182
+ )
183
+ },
184
+ {
185
+ "name": "Basic Auth Client",
186
+ "config": create_client_config(
187
+ "http://localhost:8000",
188
+ "basic",
189
+ username="demo_user",
190
+ password="demo_password"
191
+ )
192
+ }
193
+ ]
194
+
195
+ for config_info in configs:
196
+ print(f"\n📋 Testing: {config_info['name']}")
197
+ print("-" * 30)
198
+
199
+ try:
200
+ async with UniversalClient(config_info["config"]) as client:
201
+ success = await client.test_connection()
202
+
203
+ if success:
204
+ print("✅ Connection successful!")
205
+ await demo_api_calls(client)
206
+ else:
207
+ print("❌ Connection failed")
208
+
209
+ except Exception as e:
210
+ print(f"❌ Test failed: {e}")
211
+
212
+
213
+ async def interactive_demo():
214
+ """Interactive demo with user input."""
215
+ print("🚀 Interactive Client Demo")
216
+ print("=" * 50)
217
+
218
+ print("Available authentication methods:")
219
+ print("1. No authentication")
220
+ print("2. API Key")
221
+ print("3. JWT Token")
222
+ print("4. Certificate")
223
+ print("5. Basic Authentication")
224
+
225
+ try:
226
+ choice = input("\nSelect authentication method (1-5): ").strip()
227
+
228
+ auth_methods = {
229
+ "1": "none",
230
+ "2": "api_key",
231
+ "3": "jwt",
232
+ "4": "certificate",
233
+ "5": "basic"
234
+ }
235
+
236
+ if choice not in auth_methods:
237
+ print("❌ Invalid choice")
238
+ return
239
+
240
+ auth_method = auth_methods[choice]
241
+
242
+ # Get server URL
243
+ server_url = input("Enter server URL (default: http://localhost:8000): ").strip()
244
+ if not server_url:
245
+ server_url = "http://localhost:8000"
246
+
247
+ # Create configuration based on choice
248
+ config_kwargs = {}
249
+
250
+ if auth_method == "api_key":
251
+ api_key = input("Enter API key: ").strip()
252
+ if api_key:
253
+ config_kwargs["api_key"] = api_key
254
+
255
+ elif auth_method == "jwt":
256
+ username = input("Enter username: ").strip()
257
+ password = input("Enter password: ").strip()
258
+ secret = input("Enter JWT secret: ").strip()
259
+ if username and password and secret:
260
+ config_kwargs.update({
261
+ "username": username,
262
+ "password": password,
263
+ "secret": secret
264
+ })
265
+
266
+ elif auth_method == "certificate":
267
+ cert_file = input("Enter certificate file path: ").strip()
268
+ key_file = input("Enter key file path: ").strip()
269
+ ca_cert_file = input("Enter CA certificate file path: ").strip()
270
+ if cert_file and key_file:
271
+ config_kwargs.update({
272
+ "cert_file": cert_file,
273
+ "key_file": key_file,
274
+ "ca_cert_file": ca_cert_file
275
+ })
276
+
277
+ elif auth_method == "basic":
278
+ username = input("Enter username: ").strip()
279
+ password = input("Enter password: ").strip()
280
+ if username and password:
281
+ config_kwargs.update({
282
+ "username": username,
283
+ "password": password
284
+ })
285
+
286
+ # Create configuration
287
+ config = create_client_config(server_url, auth_method, **config_kwargs)
288
+
289
+ print(f"\nConfiguration created for {auth_method} authentication")
290
+ print(f"Server URL: {server_url}")
291
+
292
+ # Test connection
293
+ async with UniversalClient(config) as client:
294
+ success = await client.test_connection()
295
+
296
+ if success:
297
+ print("✅ Connection successful!")
298
+ await demo_api_calls(client)
299
+ else:
300
+ print("❌ Connection failed")
301
+
302
+ except KeyboardInterrupt:
303
+ print("\n\nDemo interrupted by user")
304
+ except Exception as e:
305
+ print(f"❌ Interactive demo failed: {e}")
306
+
307
+
308
+ def main():
309
+ """Main demo function."""
310
+ if len(sys.argv) > 1:
311
+ command = sys.argv[1]
312
+
313
+ if command == "config":
314
+ if len(sys.argv) > 2:
315
+ config_file = sys.argv[2]
316
+ asyncio.run(demo_from_config_file(config_file))
317
+ else:
318
+ print("Usage: python demo_client.py config <config_file>")
319
+
320
+ elif command == "all":
321
+ asyncio.run(demo_all_configs())
322
+
323
+ elif command == "programmatic":
324
+ asyncio.run(demo_programmatic_config())
325
+
326
+ elif command == "interactive":
327
+ asyncio.run(interactive_demo())
328
+
329
+ else:
330
+ print("Unknown command. Available commands:")
331
+ print(" config <file> - Demo with config file")
332
+ print(" all - Demo all config files")
333
+ print(" programmatic - Demo programmatic configs")
334
+ print(" interactive - Interactive demo")
335
+ else:
336
+ # Default: demo all configs
337
+ asyncio.run(demo_all_configs())
338
+
339
+
340
+ if __name__ == "__main__":
341
+ main()
@@ -0,0 +1,99 @@
1
+ """
2
+ Custom Echo Command
3
+
4
+ This module demonstrates a custom command implementation for the full application example.
5
+
6
+ Author: Vasiliy Zdanovskiy
7
+ email: vasilyvz@gmail.com
8
+ """
9
+
10
+ from typing import Dict, Any, Optional
11
+ from mcp_proxy_adapter.commands.base import BaseCommand
12
+ from mcp_proxy_adapter.commands.result import CommandResult
13
+
14
+
15
+ class CustomEchoResult(CommandResult):
16
+ """Result class for custom echo command."""
17
+
18
+ def __init__(self, message: str, timestamp: str, echo_count: int):
19
+ self.message = message
20
+ self.timestamp = timestamp
21
+ self.echo_count = echo_count
22
+
23
+ def to_dict(self) -> Dict[str, Any]:
24
+ """Convert result to dictionary."""
25
+ return {
26
+ "message": self.message,
27
+ "timestamp": self.timestamp,
28
+ "echo_count": self.echo_count,
29
+ "command_type": "custom_echo"
30
+ }
31
+
32
+ def get_schema(self) -> Dict[str, Any]:
33
+ """Get result schema."""
34
+ return {
35
+ "type": "object",
36
+ "properties": {
37
+ "message": {"type": "string", "description": "Echoed message"},
38
+ "timestamp": {"type": "string", "description": "Timestamp of echo"},
39
+ "echo_count": {"type": "integer", "description": "Number of echoes"},
40
+ "command_type": {"type": "string", "description": "Command type"}
41
+ },
42
+ "required": ["message", "timestamp", "echo_count", "command_type"]
43
+ }
44
+
45
+
46
+ class CustomEchoCommand(BaseCommand):
47
+ """Custom echo command implementation."""
48
+
49
+ def __init__(self):
50
+ super().__init__()
51
+ self.echo_count = 0
52
+
53
+ def get_name(self) -> str:
54
+ """Get command name."""
55
+ return "custom_echo"
56
+
57
+ def get_description(self) -> str:
58
+ """Get command description."""
59
+ return "Custom echo command with enhanced features"
60
+
61
+ def get_schema(self) -> Dict[str, Any]:
62
+ """Get command schema."""
63
+ return {
64
+ "type": "object",
65
+ "properties": {
66
+ "message": {
67
+ "type": "string",
68
+ "description": "Message to echo",
69
+ "default": "Hello from custom echo!"
70
+ },
71
+ "repeat": {
72
+ "type": "integer",
73
+ "description": "Number of times to repeat",
74
+ "default": 1,
75
+ "minimum": 1,
76
+ "maximum": 10
77
+ }
78
+ },
79
+ "required": ["message"]
80
+ }
81
+
82
+ async def execute(self, params: Dict[str, Any]) -> CustomEchoResult:
83
+ """Execute the custom echo command."""
84
+ message = params.get("message", "Hello from custom echo!")
85
+ repeat = min(max(params.get("repeat", 1), 1), 10)
86
+
87
+ self.echo_count += 1
88
+
89
+ from datetime import datetime
90
+ timestamp = datetime.now().isoformat()
91
+
92
+ # Repeat the message
93
+ echoed_message = " ".join([message] * repeat)
94
+
95
+ return CustomEchoResult(
96
+ message=echoed_message,
97
+ timestamp=timestamp,
98
+ echo_count=self.echo_count
99
+ )