mcp-proxy-adapter 6.0.0__py3-none-any.whl → 6.0.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 (212) hide show
  1. mcp_proxy_adapter/__main__.py +27 -7
  2. mcp_proxy_adapter/api/app.py +209 -79
  3. mcp_proxy_adapter/api/handlers.py +16 -5
  4. mcp_proxy_adapter/api/middleware/__init__.py +14 -9
  5. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +148 -0
  6. mcp_proxy_adapter/api/middleware/factory.py +36 -12
  7. mcp_proxy_adapter/api/middleware/protocol_middleware.py +84 -18
  8. mcp_proxy_adapter/api/middleware/unified_security.py +197 -0
  9. mcp_proxy_adapter/api/middleware/user_info_middleware.py +158 -0
  10. mcp_proxy_adapter/commands/__init__.py +7 -1
  11. mcp_proxy_adapter/commands/base.py +7 -4
  12. mcp_proxy_adapter/commands/builtin_commands.py +8 -2
  13. mcp_proxy_adapter/commands/command_registry.py +8 -0
  14. mcp_proxy_adapter/commands/echo_command.py +81 -0
  15. mcp_proxy_adapter/commands/health_command.py +1 -1
  16. mcp_proxy_adapter/commands/help_command.py +21 -14
  17. mcp_proxy_adapter/commands/proxy_registration_command.py +326 -185
  18. mcp_proxy_adapter/commands/role_test_command.py +141 -0
  19. mcp_proxy_adapter/commands/security_command.py +488 -0
  20. mcp_proxy_adapter/commands/ssl_setup_command.py +234 -351
  21. mcp_proxy_adapter/commands/token_management_command.py +1 -1
  22. mcp_proxy_adapter/config.py +323 -40
  23. mcp_proxy_adapter/core/app_factory.py +410 -0
  24. mcp_proxy_adapter/core/app_runner.py +272 -0
  25. mcp_proxy_adapter/core/certificate_utils.py +291 -73
  26. mcp_proxy_adapter/core/client.py +574 -0
  27. mcp_proxy_adapter/core/client_manager.py +284 -0
  28. mcp_proxy_adapter/core/client_security.py +384 -0
  29. mcp_proxy_adapter/core/logging.py +8 -3
  30. mcp_proxy_adapter/core/mtls_asgi.py +156 -0
  31. mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
  32. mcp_proxy_adapter/core/protocol_manager.py +169 -10
  33. mcp_proxy_adapter/core/proxy_client.py +602 -0
  34. mcp_proxy_adapter/core/proxy_registration.py +299 -47
  35. mcp_proxy_adapter/core/security_adapter.py +12 -15
  36. mcp_proxy_adapter/core/security_integration.py +286 -0
  37. mcp_proxy_adapter/core/server_adapter.py +282 -0
  38. mcp_proxy_adapter/core/server_engine.py +270 -0
  39. mcp_proxy_adapter/core/ssl_utils.py +13 -12
  40. mcp_proxy_adapter/core/transport_manager.py +5 -5
  41. mcp_proxy_adapter/core/unified_config_adapter.py +579 -0
  42. mcp_proxy_adapter/examples/__init__.py +13 -4
  43. mcp_proxy_adapter/examples/basic_framework/__init__.py +9 -0
  44. mcp_proxy_adapter/examples/basic_framework/commands/__init__.py +4 -0
  45. mcp_proxy_adapter/examples/basic_framework/hooks/__init__.py +4 -0
  46. mcp_proxy_adapter/examples/basic_framework/main.py +44 -0
  47. mcp_proxy_adapter/examples/commands/__init__.py +5 -0
  48. mcp_proxy_adapter/examples/create_certificates_simple.py +550 -0
  49. mcp_proxy_adapter/examples/debug_request_state.py +112 -0
  50. mcp_proxy_adapter/examples/debug_role_chain.py +158 -0
  51. mcp_proxy_adapter/examples/demo_client.py +275 -0
  52. mcp_proxy_adapter/examples/examples/basic_framework/__init__.py +9 -0
  53. mcp_proxy_adapter/examples/examples/basic_framework/commands/__init__.py +4 -0
  54. mcp_proxy_adapter/examples/examples/basic_framework/hooks/__init__.py +4 -0
  55. mcp_proxy_adapter/examples/examples/basic_framework/main.py +44 -0
  56. mcp_proxy_adapter/examples/examples/full_application/__init__.py +12 -0
  57. mcp_proxy_adapter/examples/examples/full_application/commands/__init__.py +7 -0
  58. mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +80 -0
  59. mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +90 -0
  60. mcp_proxy_adapter/examples/examples/full_application/hooks/__init__.py +7 -0
  61. mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +75 -0
  62. mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +71 -0
  63. mcp_proxy_adapter/examples/examples/full_application/main.py +173 -0
  64. mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +154 -0
  65. mcp_proxy_adapter/examples/full_application/__init__.py +12 -0
  66. mcp_proxy_adapter/examples/full_application/commands/__init__.py +7 -0
  67. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +80 -0
  68. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +90 -0
  69. mcp_proxy_adapter/examples/full_application/hooks/__init__.py +7 -0
  70. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +75 -0
  71. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +71 -0
  72. mcp_proxy_adapter/examples/full_application/main.py +173 -0
  73. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +154 -0
  74. mcp_proxy_adapter/examples/generate_all_certificates.py +362 -0
  75. mcp_proxy_adapter/examples/generate_certificates.py +177 -0
  76. mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +369 -0
  77. mcp_proxy_adapter/examples/generate_test_configs.py +331 -0
  78. mcp_proxy_adapter/examples/proxy_registration_example.py +334 -0
  79. mcp_proxy_adapter/examples/run_example.py +59 -0
  80. mcp_proxy_adapter/examples/run_full_test_suite.py +318 -0
  81. mcp_proxy_adapter/examples/run_proxy_server.py +146 -0
  82. mcp_proxy_adapter/examples/run_security_tests.py +544 -0
  83. mcp_proxy_adapter/examples/run_security_tests_fixed.py +247 -0
  84. mcp_proxy_adapter/examples/scripts/config_generator.py +740 -0
  85. mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +560 -0
  86. mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +369 -0
  87. mcp_proxy_adapter/examples/security_test_client.py +782 -0
  88. mcp_proxy_adapter/examples/setup_test_environment.py +328 -0
  89. mcp_proxy_adapter/examples/test_config.py +148 -0
  90. mcp_proxy_adapter/examples/test_config_generator.py +86 -0
  91. mcp_proxy_adapter/examples/test_examples.py +281 -0
  92. mcp_proxy_adapter/examples/universal_client.py +620 -0
  93. mcp_proxy_adapter/main.py +66 -148
  94. mcp_proxy_adapter/utils/config_generator.py +1008 -0
  95. mcp_proxy_adapter/version.py +5 -2
  96. mcp_proxy_adapter-6.0.1.dist-info/METADATA +679 -0
  97. mcp_proxy_adapter-6.0.1.dist-info/RECORD +140 -0
  98. mcp_proxy_adapter-6.0.1.dist-info/entry_points.txt +2 -0
  99. {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/licenses/LICENSE +2 -2
  100. mcp_proxy_adapter/api/middleware/auth.py +0 -146
  101. mcp_proxy_adapter/api/middleware/auth_adapter.py +0 -235
  102. mcp_proxy_adapter/api/middleware/mtls_adapter.py +0 -305
  103. mcp_proxy_adapter/api/middleware/mtls_middleware.py +0 -296
  104. mcp_proxy_adapter/api/middleware/rate_limit.py +0 -152
  105. mcp_proxy_adapter/api/middleware/rate_limit_adapter.py +0 -241
  106. mcp_proxy_adapter/api/middleware/roles_adapter.py +0 -365
  107. mcp_proxy_adapter/api/middleware/roles_middleware.py +0 -381
  108. mcp_proxy_adapter/api/middleware/security.py +0 -376
  109. mcp_proxy_adapter/api/middleware/token_auth_middleware.py +0 -261
  110. mcp_proxy_adapter/examples/README.md +0 -124
  111. mcp_proxy_adapter/examples/basic_server/README.md +0 -60
  112. mcp_proxy_adapter/examples/basic_server/__init__.py +0 -7
  113. mcp_proxy_adapter/examples/basic_server/basic_custom_settings.json +0 -39
  114. mcp_proxy_adapter/examples/basic_server/config.json +0 -70
  115. mcp_proxy_adapter/examples/basic_server/config_all_protocols.json +0 -54
  116. mcp_proxy_adapter/examples/basic_server/config_http.json +0 -70
  117. mcp_proxy_adapter/examples/basic_server/config_http_only.json +0 -52
  118. mcp_proxy_adapter/examples/basic_server/config_https.json +0 -58
  119. mcp_proxy_adapter/examples/basic_server/config_mtls.json +0 -58
  120. mcp_proxy_adapter/examples/basic_server/config_ssl.json +0 -46
  121. mcp_proxy_adapter/examples/basic_server/custom_settings_example.py +0 -238
  122. mcp_proxy_adapter/examples/basic_server/server.py +0 -114
  123. mcp_proxy_adapter/examples/custom_commands/README.md +0 -127
  124. mcp_proxy_adapter/examples/custom_commands/__init__.py +0 -27
  125. mcp_proxy_adapter/examples/custom_commands/advanced_hooks.py +0 -566
  126. mcp_proxy_adapter/examples/custom_commands/auto_commands/__init__.py +0 -6
  127. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_echo_command.py +0 -103
  128. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_info_command.py +0 -111
  129. mcp_proxy_adapter/examples/custom_commands/auto_commands/test_command.py +0 -105
  130. mcp_proxy_adapter/examples/custom_commands/catalog/commands/test_command.py +0 -129
  131. mcp_proxy_adapter/examples/custom_commands/config.json +0 -118
  132. mcp_proxy_adapter/examples/custom_commands/config_all_protocols.json +0 -46
  133. mcp_proxy_adapter/examples/custom_commands/config_https_only.json +0 -46
  134. mcp_proxy_adapter/examples/custom_commands/config_https_transport.json +0 -33
  135. mcp_proxy_adapter/examples/custom_commands/config_mtls_only.json +0 -46
  136. mcp_proxy_adapter/examples/custom_commands/config_mtls_transport.json +0 -33
  137. mcp_proxy_adapter/examples/custom_commands/config_single_transport.json +0 -33
  138. mcp_proxy_adapter/examples/custom_commands/custom_health_command.py +0 -169
  139. mcp_proxy_adapter/examples/custom_commands/custom_help_command.py +0 -215
  140. mcp_proxy_adapter/examples/custom_commands/custom_openapi_generator.py +0 -76
  141. mcp_proxy_adapter/examples/custom_commands/custom_settings.json +0 -96
  142. mcp_proxy_adapter/examples/custom_commands/custom_settings_manager.py +0 -241
  143. mcp_proxy_adapter/examples/custom_commands/data_transform_command.py +0 -135
  144. mcp_proxy_adapter/examples/custom_commands/echo_command.py +0 -122
  145. mcp_proxy_adapter/examples/custom_commands/full_help_response.json +0 -1
  146. mcp_proxy_adapter/examples/custom_commands/generated_openapi.json +0 -629
  147. mcp_proxy_adapter/examples/custom_commands/get_openapi.py +0 -103
  148. mcp_proxy_adapter/examples/custom_commands/hooks.py +0 -230
  149. mcp_proxy_adapter/examples/custom_commands/intercept_command.py +0 -123
  150. mcp_proxy_adapter/examples/custom_commands/loadable_commands/test_ignored.py +0 -129
  151. mcp_proxy_adapter/examples/custom_commands/manual_echo_command.py +0 -103
  152. mcp_proxy_adapter/examples/custom_commands/proxy_connection_manager.py +0 -278
  153. mcp_proxy_adapter/examples/custom_commands/server.py +0 -252
  154. mcp_proxy_adapter/examples/custom_commands/simple_openapi_server.py +0 -75
  155. mcp_proxy_adapter/examples/custom_commands/start_server_with_proxy_manager.py +0 -299
  156. mcp_proxy_adapter/examples/custom_commands/start_server_with_registration.py +0 -278
  157. mcp_proxy_adapter/examples/custom_commands/test_hooks.py +0 -176
  158. mcp_proxy_adapter/examples/custom_commands/test_openapi.py +0 -27
  159. mcp_proxy_adapter/examples/custom_commands/test_registry.py +0 -23
  160. mcp_proxy_adapter/examples/custom_commands/test_simple.py +0 -19
  161. mcp_proxy_adapter/examples/custom_project_example/README.md +0 -103
  162. mcp_proxy_adapter/examples/custom_project_example/README_EN.md +0 -103
  163. mcp_proxy_adapter/examples/deployment/README.md +0 -49
  164. mcp_proxy_adapter/examples/deployment/__init__.py +0 -7
  165. mcp_proxy_adapter/examples/deployment/config.development.json +0 -8
  166. mcp_proxy_adapter/examples/deployment/config.json +0 -29
  167. mcp_proxy_adapter/examples/deployment/config.production.json +0 -12
  168. mcp_proxy_adapter/examples/deployment/config.staging.json +0 -11
  169. mcp_proxy_adapter/examples/deployment/docker-compose.yml +0 -31
  170. mcp_proxy_adapter/examples/deployment/run.sh +0 -43
  171. mcp_proxy_adapter/examples/deployment/run_docker.sh +0 -84
  172. mcp_proxy_adapter/examples/simple_custom_commands/README.md +0 -149
  173. mcp_proxy_adapter/examples/simple_custom_commands/README_EN.md +0 -149
  174. mcp_proxy_adapter/schemas/base_schema.json +0 -114
  175. mcp_proxy_adapter/schemas/openapi_schema.json +0 -314
  176. mcp_proxy_adapter/schemas/roles_schema.json +0 -162
  177. mcp_proxy_adapter/tests/__init__.py +0 -0
  178. mcp_proxy_adapter/tests/api/__init__.py +0 -3
  179. mcp_proxy_adapter/tests/api/test_cmd_endpoint.py +0 -115
  180. mcp_proxy_adapter/tests/api/test_custom_openapi.py +0 -617
  181. mcp_proxy_adapter/tests/api/test_handlers.py +0 -522
  182. mcp_proxy_adapter/tests/api/test_middleware.py +0 -340
  183. mcp_proxy_adapter/tests/api/test_schemas.py +0 -546
  184. mcp_proxy_adapter/tests/api/test_tool_integration.py +0 -531
  185. mcp_proxy_adapter/tests/commands/__init__.py +0 -3
  186. mcp_proxy_adapter/tests/commands/test_config_command.py +0 -211
  187. mcp_proxy_adapter/tests/commands/test_echo_command.py +0 -127
  188. mcp_proxy_adapter/tests/commands/test_help_command.py +0 -136
  189. mcp_proxy_adapter/tests/conftest.py +0 -131
  190. mcp_proxy_adapter/tests/functional/__init__.py +0 -3
  191. mcp_proxy_adapter/tests/functional/test_api.py +0 -253
  192. mcp_proxy_adapter/tests/integration/__init__.py +0 -3
  193. mcp_proxy_adapter/tests/integration/test_cmd_integration.py +0 -129
  194. mcp_proxy_adapter/tests/integration/test_integration.py +0 -255
  195. mcp_proxy_adapter/tests/performance/__init__.py +0 -3
  196. mcp_proxy_adapter/tests/performance/test_performance.py +0 -189
  197. mcp_proxy_adapter/tests/stubs/__init__.py +0 -10
  198. mcp_proxy_adapter/tests/stubs/echo_command.py +0 -104
  199. mcp_proxy_adapter/tests/test_api_endpoints.py +0 -271
  200. mcp_proxy_adapter/tests/test_api_handlers.py +0 -289
  201. mcp_proxy_adapter/tests/test_base_command.py +0 -123
  202. mcp_proxy_adapter/tests/test_batch_requests.py +0 -117
  203. mcp_proxy_adapter/tests/test_command_registry.py +0 -281
  204. mcp_proxy_adapter/tests/test_config.py +0 -127
  205. mcp_proxy_adapter/tests/test_utils.py +0 -65
  206. mcp_proxy_adapter/tests/unit/__init__.py +0 -3
  207. mcp_proxy_adapter/tests/unit/test_base_command.py +0 -436
  208. mcp_proxy_adapter/tests/unit/test_config.py +0 -270
  209. mcp_proxy_adapter-6.0.0.dist-info/METADATA +0 -201
  210. mcp_proxy_adapter-6.0.0.dist-info/RECORD +0 -179
  211. {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/WHEEL +0 -0
  212. {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,247 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Security Testing Script - Fixed Version
4
+ This script runs comprehensive security tests without fallback mode
5
+ and with proper port management.
6
+ Author: Vasiliy Zdanovskiy
7
+ email: vasilyvz@gmail.com
8
+ """
9
+ import asyncio
10
+ import json
11
+ import os
12
+ import signal
13
+ import subprocess
14
+ import sys
15
+ import time
16
+ from pathlib import Path
17
+ from typing import Dict, List, Optional, Tuple
18
+ # Add project root to path
19
+ project_root = Path(__file__).parent.parent.parent
20
+ sys.path.insert(0, str(project_root))
21
+ from security_test_client import SecurityTestClient, TestResult
22
+ class SecurityTestRunner:
23
+ """Security test runner with proper port management."""
24
+ def __init__(self):
25
+ self.project_root = Path(__file__).parent.parent.parent
26
+ self.configs_dir = self.project_root / "mcp_proxy_adapter" / "examples" / "server_configs"
27
+ self.server_processes = {}
28
+ self.test_results = []
29
+ def kill_process_on_port(self, port: int) -> bool:
30
+ """Kill process using specific port."""
31
+ try:
32
+ # Find process using the port
33
+ result = subprocess.run(
34
+ ["lsof", "-ti", f":{port}"],
35
+ capture_output=True,
36
+ text=True,
37
+ timeout=5
38
+ )
39
+ if result.returncode == 0 and result.stdout.strip():
40
+ pid = result.stdout.strip()
41
+ # Kill the process
42
+ subprocess.run(["kill", "-9", pid], check=True)
43
+ print(f"✅ Killed process {pid} on port {port}")
44
+ time.sleep(1) # Wait for port to be released
45
+ return True
46
+ else:
47
+ print(f"ℹ️ No process found on port {port}")
48
+ return True
49
+ except subprocess.TimeoutExpired:
50
+ print(f"⚠️ Timeout checking port {port}")
51
+ return False
52
+ except Exception as e:
53
+ print(f"❌ Error killing process on port {port}: {e}")
54
+ return False
55
+ def start_server(self, config_name: str, config_path: Path) -> Optional[subprocess.Popen]:
56
+ """Start server with proper error handling."""
57
+ try:
58
+ # Get port from config
59
+ with open(config_path) as f:
60
+ config = json.load(f)
61
+ port = config.get("server", {}).get("port", 8000)
62
+ # Kill any existing process on this port
63
+ self.kill_process_on_port(port)
64
+ # Start server
65
+ cmd = [
66
+ sys.executable, "-m", "mcp_proxy_adapter.main",
67
+ "--config", str(config_path)
68
+ ]
69
+ # For mTLS, start from examples directory
70
+ if config_name == "mtls":
71
+ cwd = self.project_root / "mcp_proxy_adapter" / "examples"
72
+ else:
73
+ cwd = self.project_root
74
+ print(f"🚀 Starting {config_name} on port {port}...")
75
+ process = subprocess.Popen(
76
+ cmd,
77
+ cwd=cwd,
78
+ stdout=subprocess.PIPE,
79
+ stderr=subprocess.PIPE,
80
+ text=True
81
+ )
82
+ # Wait a bit for server to start
83
+ time.sleep(3)
84
+ # Check if process is still running
85
+ if process.poll() is None:
86
+ print(f"✅ {config_name} started successfully on port {port}")
87
+ return process
88
+ else:
89
+ stdout, stderr = process.communicate()
90
+ print(f"❌ {config_name} failed to start:")
91
+ print(f"STDOUT: {stdout}")
92
+ print(f"STDERR: {stderr}")
93
+ return None
94
+ except Exception as e:
95
+ print(f"❌ Error starting {config_name}: {e}")
96
+ return None
97
+ def stop_server(self, config_name: str, process: subprocess.Popen):
98
+ """Stop server gracefully."""
99
+ try:
100
+ print(f"🛑 Stopping {config_name}...")
101
+ process.terminate()
102
+ process.wait(timeout=5)
103
+ print(f"✅ {config_name} stopped")
104
+ except subprocess.TimeoutExpired:
105
+ print(f"⚠️ Force killing {config_name}...")
106
+ process.kill()
107
+ process.wait()
108
+ except Exception as e:
109
+ print(f"❌ Error stopping {config_name}: {e}")
110
+ async def test_server(self, config_name: str, config_path: Path) -> List[TestResult]:
111
+ """Test a single server configuration."""
112
+ results = []
113
+ # Start server
114
+ process = self.start_server(config_name, config_path)
115
+ if not process:
116
+ return [TestResult(
117
+ test_name=f"{config_name}_startup",
118
+ server_url=f"http://localhost:{port}",
119
+ auth_type="none",
120
+ success=False,
121
+ error_message="Server failed to start"
122
+ )]
123
+ try:
124
+ # Get config for client setup
125
+ with open(config_path) as f:
126
+ config = json.load(f)
127
+ port = config.get("server", {}).get("port", 8000)
128
+ auth_enabled = config.get("security", {}).get("auth", {}).get("enabled", False)
129
+ auth_methods = config.get("security", {}).get("auth", {}).get("methods", [])
130
+ # Create test client with correct protocol
131
+ protocol = "https" if config.get("ssl", {}).get("enabled", False) else "http"
132
+ client = SecurityTestClient(base_url=f"{protocol}://localhost:{port}")
133
+ client.auth_enabled = auth_enabled
134
+ client.auth_methods = auth_methods
135
+ client.api_keys = config.get("security", {}).get("auth", {}).get("api_keys", {})
136
+ # For mTLS, override SSL context creation and change working directory
137
+ if config_name == "mtls":
138
+ client.create_ssl_context = client.create_ssl_context_for_mtls
139
+ # Ensure mTLS uses certificate auth
140
+ client.auth_methods = ["certificate"]
141
+ # Change to examples directory for mTLS tests
142
+ import os
143
+ os.chdir(self.project_root / "mcp_proxy_adapter" / "examples")
144
+ # Run tests
145
+ async with client:
146
+ # Test 1: Health check
147
+ result = await client.test_health()
148
+ results.append(result)
149
+ # Test 2: Command execution
150
+ result = await client.test_command_execution()
151
+ results.append(result)
152
+ # Test 3: Authentication (if enabled)
153
+ if auth_enabled:
154
+ result = await client.test_authentication()
155
+ results.append(result)
156
+ # Test 4: Negative authentication
157
+ result = await client.test_negative_authentication()
158
+ results.append(result)
159
+ # Test 5: Role-based access
160
+ result = await client.test_role_based_access(client.base_url, "api_key")
161
+ results.append(result)
162
+ # Test 6: Role permissions
163
+ result = await client.test_role_permissions(client.base_url, "api_key")
164
+ results.append(result)
165
+ # Test 7: Multiple roles test
166
+ result = await client.test_multiple_roles(client.base_url, "api_key")
167
+ results.append(result)
168
+ else:
169
+ # Test 3: No authentication required
170
+ result = await client.test_no_auth_required()
171
+ results.append(result)
172
+ # Test 4: Negative auth (should fail)
173
+ result = await client.test_negative_authentication()
174
+ results.append(result)
175
+ except Exception as e:
176
+ results.append(TestResult(
177
+ test_name=f"{config_name}_client_error",
178
+ server_url=f"http://localhost:{port}",
179
+ auth_type="none",
180
+ success=False,
181
+ error_message=str(e)
182
+ ))
183
+ finally:
184
+ # Stop server
185
+ self.stop_server(config_name, process)
186
+ return results
187
+ async def run_all_tests(self):
188
+ """Run all security tests."""
189
+ print("🔒 Starting Security Testing Suite")
190
+ print("=" * 50)
191
+ # Test configurations
192
+ configs = [
193
+ ("basic_http", "config_basic_http.json"),
194
+ ("http_token", "config_http_token.json"),
195
+ ("https", "config_https.json"),
196
+ ("https_token", "config_https_token.json"),
197
+ ("mtls", "config_mtls.json")
198
+ ]
199
+ total_tests = 0
200
+ passed_tests = 0
201
+ for config_name, config_file in configs:
202
+ config_path = self.configs_dir / config_file
203
+ if not config_path.exists():
204
+ print(f"❌ Configuration not found: {config_path}")
205
+ continue
206
+ print(f"\n📋 Testing {config_name.upper()} configuration")
207
+ print("-" * 30)
208
+ results = await self.test_server(config_name, config_path)
209
+ for result in results:
210
+ total_tests += 1
211
+ if result.success:
212
+ passed_tests += 1
213
+ print(f"✅ {result.test_name}: PASS")
214
+ else:
215
+ print(f"❌ {result.test_name}: FAIL - {result.error_message}")
216
+ self.test_results.extend(results)
217
+ # Print summary
218
+ print("\n" + "=" * 50)
219
+ print("📊 TEST SUMMARY")
220
+ print("=" * 50)
221
+ print(f"Total tests: {total_tests}")
222
+ print(f"Passed: {passed_tests}")
223
+ print(f"Failed: {total_tests - passed_tests}")
224
+ print(f"Success rate: {(passed_tests/total_tests*100):.1f}%" if total_tests > 0 else "N/A")
225
+ # Detailed results
226
+ print("\n📋 DETAILED RESULTS")
227
+ print("-" * 30)
228
+ for result in self.test_results:
229
+ status = "✅ PASS" if result.success else "❌ FAIL"
230
+ print(f"{status} {result.test_name}")
231
+ if not result.success and result.error_message:
232
+ print(f" Error: {result.error_message}")
233
+ return passed_tests == total_tests
234
+ async def main():
235
+ """Main function."""
236
+ runner = SecurityTestRunner()
237
+ try:
238
+ success = await runner.run_all_tests()
239
+ sys.exit(0 if success else 1)
240
+ except KeyboardInterrupt:
241
+ print("\n⚠️ Testing interrupted by user")
242
+ sys.exit(1)
243
+ except Exception as e:
244
+ print(f"\n❌ Testing failed: {e}")
245
+ sys.exit(1)
246
+ if __name__ == "__main__":
247
+ asyncio.run(main())