mcp-proxy-adapter 4.1.0__py3-none-any.whl → 6.0.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.
- mcp_proxy_adapter/__main__.py +12 -0
- mcp_proxy_adapter/api/app.py +138 -11
- mcp_proxy_adapter/api/handlers.py +16 -1
- mcp_proxy_adapter/api/middleware/__init__.py +30 -29
- mcp_proxy_adapter/api/middleware/auth_adapter.py +235 -0
- mcp_proxy_adapter/api/middleware/error_handling.py +9 -0
- mcp_proxy_adapter/api/middleware/factory.py +219 -0
- mcp_proxy_adapter/api/middleware/logging.py +32 -6
- mcp_proxy_adapter/api/middleware/mtls_adapter.py +305 -0
- mcp_proxy_adapter/api/middleware/mtls_middleware.py +296 -0
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +135 -0
- mcp_proxy_adapter/api/middleware/rate_limit_adapter.py +241 -0
- mcp_proxy_adapter/api/middleware/roles_adapter.py +365 -0
- mcp_proxy_adapter/api/middleware/roles_middleware.py +381 -0
- mcp_proxy_adapter/api/middleware/security.py +376 -0
- mcp_proxy_adapter/api/middleware/token_auth_middleware.py +261 -0
- mcp_proxy_adapter/api/middleware/transport_middleware.py +122 -0
- mcp_proxy_adapter/commands/__init__.py +13 -4
- mcp_proxy_adapter/commands/auth_validation_command.py +408 -0
- mcp_proxy_adapter/commands/base.py +61 -30
- mcp_proxy_adapter/commands/builtin_commands.py +89 -0
- mcp_proxy_adapter/commands/catalog_manager.py +838 -0
- mcp_proxy_adapter/commands/cert_monitor_command.py +620 -0
- mcp_proxy_adapter/commands/certificate_management_command.py +608 -0
- mcp_proxy_adapter/commands/command_registry.py +705 -345
- mcp_proxy_adapter/commands/dependency_manager.py +245 -0
- mcp_proxy_adapter/commands/health_command.py +7 -0
- mcp_proxy_adapter/commands/hooks.py +200 -167
- mcp_proxy_adapter/commands/key_management_command.py +506 -0
- mcp_proxy_adapter/commands/load_command.py +176 -0
- mcp_proxy_adapter/commands/plugins_command.py +235 -0
- mcp_proxy_adapter/commands/protocol_management_command.py +232 -0
- mcp_proxy_adapter/commands/proxy_registration_command.py +268 -0
- mcp_proxy_adapter/commands/reload_command.py +48 -50
- mcp_proxy_adapter/commands/result.py +1 -0
- mcp_proxy_adapter/commands/roles_management_command.py +697 -0
- mcp_proxy_adapter/commands/ssl_setup_command.py +483 -0
- mcp_proxy_adapter/commands/token_management_command.py +529 -0
- mcp_proxy_adapter/commands/transport_management_command.py +144 -0
- mcp_proxy_adapter/commands/unload_command.py +158 -0
- mcp_proxy_adapter/config.py +99 -2
- mcp_proxy_adapter/core/auth_validator.py +606 -0
- mcp_proxy_adapter/core/certificate_utils.py +827 -0
- mcp_proxy_adapter/core/config_converter.py +405 -0
- mcp_proxy_adapter/core/config_validator.py +218 -0
- mcp_proxy_adapter/core/logging.py +11 -0
- mcp_proxy_adapter/core/protocol_manager.py +226 -0
- mcp_proxy_adapter/core/proxy_registration.py +270 -0
- mcp_proxy_adapter/core/role_utils.py +426 -0
- mcp_proxy_adapter/core/security_adapter.py +373 -0
- mcp_proxy_adapter/core/security_factory.py +239 -0
- mcp_proxy_adapter/core/settings.py +1 -0
- mcp_proxy_adapter/core/ssl_utils.py +233 -0
- mcp_proxy_adapter/core/transport_manager.py +292 -0
- mcp_proxy_adapter/custom_openapi.py +22 -11
- mcp_proxy_adapter/examples/basic_server/config.json +58 -23
- mcp_proxy_adapter/examples/basic_server/config_all_protocols.json +54 -0
- mcp_proxy_adapter/examples/basic_server/config_http.json +70 -0
- mcp_proxy_adapter/examples/basic_server/config_http_only.json +52 -0
- mcp_proxy_adapter/examples/basic_server/config_https.json +58 -0
- mcp_proxy_adapter/examples/basic_server/config_mtls.json +58 -0
- mcp_proxy_adapter/examples/basic_server/config_ssl.json +46 -0
- mcp_proxy_adapter/examples/basic_server/server.py +17 -1
- mcp_proxy_adapter/examples/custom_commands/__init__.py +1 -1
- mcp_proxy_adapter/examples/custom_commands/advanced_hooks.py +339 -23
- mcp_proxy_adapter/examples/custom_commands/auto_commands/test_command.py +105 -0
- mcp_proxy_adapter/examples/custom_commands/catalog/commands/test_command.py +129 -0
- mcp_proxy_adapter/examples/custom_commands/config.json +97 -41
- mcp_proxy_adapter/examples/custom_commands/config_all_protocols.json +46 -0
- mcp_proxy_adapter/examples/custom_commands/config_https_only.json +46 -0
- mcp_proxy_adapter/examples/custom_commands/config_https_transport.json +33 -0
- mcp_proxy_adapter/examples/custom_commands/config_mtls_only.json +46 -0
- mcp_proxy_adapter/examples/custom_commands/config_mtls_transport.json +33 -0
- mcp_proxy_adapter/examples/custom_commands/config_single_transport.json +33 -0
- mcp_proxy_adapter/examples/custom_commands/full_help_response.json +1 -0
- mcp_proxy_adapter/examples/custom_commands/generated_openapi.json +629 -0
- mcp_proxy_adapter/examples/custom_commands/get_openapi.py +103 -0
- mcp_proxy_adapter/examples/custom_commands/loadable_commands/test_ignored.py +129 -0
- mcp_proxy_adapter/examples/custom_commands/proxy_connection_manager.py +278 -0
- mcp_proxy_adapter/examples/custom_commands/server.py +92 -63
- mcp_proxy_adapter/examples/custom_commands/simple_openapi_server.py +75 -0
- mcp_proxy_adapter/examples/custom_commands/start_server_with_proxy_manager.py +299 -0
- mcp_proxy_adapter/examples/custom_commands/start_server_with_registration.py +278 -0
- mcp_proxy_adapter/examples/custom_commands/test_openapi.py +27 -0
- mcp_proxy_adapter/examples/custom_commands/test_registry.py +23 -0
- mcp_proxy_adapter/examples/custom_commands/test_simple.py +19 -0
- mcp_proxy_adapter/examples/custom_project_example/README.md +103 -0
- mcp_proxy_adapter/examples/custom_project_example/README_EN.md +103 -0
- mcp_proxy_adapter/examples/simple_custom_commands/README.md +149 -0
- mcp_proxy_adapter/examples/simple_custom_commands/README_EN.md +149 -0
- mcp_proxy_adapter/main.py +175 -0
- mcp_proxy_adapter/schemas/roles_schema.json +162 -0
- mcp_proxy_adapter/tests/unit/test_config.py +53 -0
- mcp_proxy_adapter/version.py +1 -1
- {mcp_proxy_adapter-4.1.0.dist-info → mcp_proxy_adapter-6.0.0.dist-info}/METADATA +2 -1
- mcp_proxy_adapter-6.0.0.dist-info/RECORD +179 -0
- mcp_proxy_adapter/commands/reload_settings_command.py +0 -125
- mcp_proxy_adapter-4.1.0.dist-info/RECORD +0 -110
- {mcp_proxy_adapter-4.1.0.dist-info → mcp_proxy_adapter-6.0.0.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-4.1.0.dist-info → mcp_proxy_adapter-6.0.0.dist-info}/licenses/LICENSE +0 -0
- {mcp_proxy_adapter-4.1.0.dist-info → mcp_proxy_adapter-6.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,483 @@
|
|
1
|
+
"""
|
2
|
+
SSL Setup Command
|
3
|
+
|
4
|
+
This module provides commands for SSL configuration and management including
|
5
|
+
setup, status checking, testing, and configuration management.
|
6
|
+
|
7
|
+
Author: MCP Proxy Adapter Team
|
8
|
+
Version: 1.0.0
|
9
|
+
"""
|
10
|
+
|
11
|
+
import logging
|
12
|
+
import os
|
13
|
+
import ssl
|
14
|
+
from typing import Dict, List, Optional, Any
|
15
|
+
from pathlib import Path
|
16
|
+
|
17
|
+
from .base import Command
|
18
|
+
from .result import CommandResult, SuccessResult, ErrorResult
|
19
|
+
from ..core.certificate_utils import CertificateUtils
|
20
|
+
from ..core.auth_validator import AuthValidator
|
21
|
+
|
22
|
+
logger = logging.getLogger(__name__)
|
23
|
+
|
24
|
+
|
25
|
+
class SSLSetupResult:
|
26
|
+
"""
|
27
|
+
Result class for SSL setup operations.
|
28
|
+
|
29
|
+
Contains SSL configuration status and details.
|
30
|
+
"""
|
31
|
+
|
32
|
+
def __init__(self, ssl_enabled: bool, cert_path: Optional[str] = None,
|
33
|
+
key_path: Optional[str] = None, config: Optional[Dict] = None,
|
34
|
+
status: str = "unknown", error: Optional[str] = None):
|
35
|
+
"""
|
36
|
+
Initialize SSL setup result.
|
37
|
+
|
38
|
+
Args:
|
39
|
+
ssl_enabled: Whether SSL is enabled
|
40
|
+
cert_path: Path to certificate file
|
41
|
+
key_path: Path to private key file
|
42
|
+
config: SSL configuration
|
43
|
+
status: SSL status (enabled, disabled, error)
|
44
|
+
error: Error message if any
|
45
|
+
"""
|
46
|
+
self.ssl_enabled = ssl_enabled
|
47
|
+
self.cert_path = cert_path
|
48
|
+
self.key_path = key_path
|
49
|
+
self.config = config or {}
|
50
|
+
self.status = status
|
51
|
+
self.error = error
|
52
|
+
|
53
|
+
def to_dict(self) -> Dict[str, Any]:
|
54
|
+
"""
|
55
|
+
Convert to dictionary format.
|
56
|
+
|
57
|
+
Returns:
|
58
|
+
Dictionary representation
|
59
|
+
"""
|
60
|
+
return {
|
61
|
+
"ssl_enabled": self.ssl_enabled,
|
62
|
+
"cert_path": self.cert_path,
|
63
|
+
"key_path": self.key_path,
|
64
|
+
"config": self.config,
|
65
|
+
"status": self.status,
|
66
|
+
"error": self.error
|
67
|
+
}
|
68
|
+
|
69
|
+
def get_schema(self) -> Dict[str, Any]:
|
70
|
+
"""
|
71
|
+
Get JSON schema for this result.
|
72
|
+
|
73
|
+
Returns:
|
74
|
+
JSON schema dictionary
|
75
|
+
"""
|
76
|
+
return {
|
77
|
+
"type": "object",
|
78
|
+
"properties": {
|
79
|
+
"ssl_enabled": {"type": "boolean", "description": "Whether SSL is enabled"},
|
80
|
+
"cert_path": {"type": "string", "description": "Path to certificate file"},
|
81
|
+
"key_path": {"type": "string", "description": "Path to private key file"},
|
82
|
+
"config": {"type": "object", "description": "SSL configuration"},
|
83
|
+
"status": {"type": "string", "enum": ["enabled", "disabled", "error"],
|
84
|
+
"description": "SSL status"},
|
85
|
+
"error": {"type": "string", "description": "Error message if any"}
|
86
|
+
},
|
87
|
+
"required": ["ssl_enabled", "status"]
|
88
|
+
}
|
89
|
+
|
90
|
+
|
91
|
+
class SSLSetupCommand(Command):
|
92
|
+
"""
|
93
|
+
Command for SSL setup and configuration.
|
94
|
+
|
95
|
+
Provides methods for SSL setup, status checking, testing, and configuration.
|
96
|
+
"""
|
97
|
+
|
98
|
+
# Command metadata
|
99
|
+
name = "ssl_setup"
|
100
|
+
version = "1.0.0"
|
101
|
+
descr = "SSL setup and configuration management"
|
102
|
+
category = "security"
|
103
|
+
author = "MCP Proxy Adapter Team"
|
104
|
+
email = "team@mcp-proxy-adapter.com"
|
105
|
+
source_url = "https://github.com/mcp-proxy-adapter"
|
106
|
+
result_class = SSLSetupResult
|
107
|
+
|
108
|
+
def __init__(self):
|
109
|
+
"""Initialize SSL setup command."""
|
110
|
+
super().__init__()
|
111
|
+
self.certificate_utils = CertificateUtils()
|
112
|
+
self.auth_validator = AuthValidator()
|
113
|
+
|
114
|
+
async def execute(self, **kwargs) -> CommandResult:
|
115
|
+
"""
|
116
|
+
Execute SSL setup command.
|
117
|
+
|
118
|
+
Args:
|
119
|
+
**kwargs: Command parameters including:
|
120
|
+
- action: Action to perform (ssl_setup, ssl_status, ssl_test, ssl_config)
|
121
|
+
- ssl_config: SSL configuration for ssl_setup action
|
122
|
+
- cert_file: Certificate file path for ssl_test action
|
123
|
+
- key_file: Key file path for ssl_test action
|
124
|
+
- action: Action for ssl_config (get, set, update, reset)
|
125
|
+
- config_data: Configuration data for ssl_config action
|
126
|
+
|
127
|
+
Returns:
|
128
|
+
CommandResult with SSL operation status
|
129
|
+
"""
|
130
|
+
action = kwargs.get("action", "ssl_status")
|
131
|
+
|
132
|
+
if action == "ssl_setup":
|
133
|
+
ssl_config = kwargs.get("ssl_config", {})
|
134
|
+
return await self.ssl_setup(ssl_config)
|
135
|
+
elif action == "ssl_status":
|
136
|
+
return await self.ssl_status()
|
137
|
+
elif action == "ssl_test":
|
138
|
+
cert_file = kwargs.get("cert_file")
|
139
|
+
key_file = kwargs.get("key_file")
|
140
|
+
return await self.ssl_test(cert_file, key_file)
|
141
|
+
elif action == "ssl_config":
|
142
|
+
config_action = kwargs.get("config_action", "get")
|
143
|
+
config_data = kwargs.get("config_data", {})
|
144
|
+
return await self.ssl_config(config_action, config_data)
|
145
|
+
else:
|
146
|
+
return ErrorResult(
|
147
|
+
message=f"Unknown action: {action}. Supported actions: ssl_setup, ssl_status, ssl_test, ssl_config"
|
148
|
+
)
|
149
|
+
|
150
|
+
async def ssl_setup(self, ssl_config: Dict[str, Any]) -> CommandResult:
|
151
|
+
"""
|
152
|
+
Setup SSL configuration.
|
153
|
+
|
154
|
+
Args:
|
155
|
+
ssl_config: SSL configuration dictionary containing:
|
156
|
+
- enabled: Whether to enable SSL
|
157
|
+
- cert_file: Path to certificate file
|
158
|
+
- key_file: Path to private key file
|
159
|
+
- ca_file: Path to CA certificate file (optional)
|
160
|
+
- verify_mode: SSL verification mode (optional)
|
161
|
+
- cipher_suites: List of allowed cipher suites (optional)
|
162
|
+
|
163
|
+
Returns:
|
164
|
+
CommandResult with SSL setup status
|
165
|
+
"""
|
166
|
+
try:
|
167
|
+
logger.info("Setting up SSL configuration")
|
168
|
+
|
169
|
+
# Validate SSL configuration
|
170
|
+
if not isinstance(ssl_config, dict):
|
171
|
+
return ErrorResult(
|
172
|
+
message="SSL configuration must be a dictionary"
|
173
|
+
)
|
174
|
+
|
175
|
+
enabled = ssl_config.get("enabled", False)
|
176
|
+
if not enabled:
|
177
|
+
result = SSLSetupResult(
|
178
|
+
ssl_enabled=False,
|
179
|
+
status="disabled",
|
180
|
+
config=ssl_config
|
181
|
+
)
|
182
|
+
return SuccessResult(data=result.to_dict())
|
183
|
+
|
184
|
+
# Validate required files
|
185
|
+
cert_file = ssl_config.get("cert_file")
|
186
|
+
key_file = ssl_config.get("key_file")
|
187
|
+
|
188
|
+
if not cert_file or not key_file:
|
189
|
+
return ErrorResult(
|
190
|
+
message="Certificate and key files are required when SSL is enabled"
|
191
|
+
)
|
192
|
+
|
193
|
+
# Check if files exist
|
194
|
+
if not os.path.exists(cert_file):
|
195
|
+
return ErrorResult(
|
196
|
+
message=f"Certificate file not found: {cert_file}"
|
197
|
+
)
|
198
|
+
|
199
|
+
if not os.path.exists(key_file):
|
200
|
+
return ErrorResult(
|
201
|
+
message=f"Private key file not found: {key_file}"
|
202
|
+
)
|
203
|
+
|
204
|
+
# Validate certificate and key
|
205
|
+
cert_validation = self.auth_validator.validate_certificate(cert_file)
|
206
|
+
if not cert_validation.is_valid:
|
207
|
+
return ErrorResult(
|
208
|
+
message=f"Certificate validation failed: {cert_validation.error_message}"
|
209
|
+
)
|
210
|
+
|
211
|
+
# Test SSL configuration
|
212
|
+
test_result = await self._test_ssl_config(cert_file, key_file)
|
213
|
+
if not test_result["success"]:
|
214
|
+
return ErrorResult(
|
215
|
+
message=f"SSL configuration test failed: {test_result['error']}"
|
216
|
+
)
|
217
|
+
|
218
|
+
result = SSLSetupResult(
|
219
|
+
ssl_enabled=True,
|
220
|
+
cert_path=cert_file,
|
221
|
+
key_path=key_file,
|
222
|
+
config=ssl_config,
|
223
|
+
status="enabled"
|
224
|
+
)
|
225
|
+
|
226
|
+
logger.info("SSL configuration setup completed successfully")
|
227
|
+
return SuccessResult(data=result.to_dict())
|
228
|
+
|
229
|
+
except Exception as e:
|
230
|
+
logger.error(f"SSL setup failed: {e}")
|
231
|
+
return ErrorResult(
|
232
|
+
message=f"SSL setup failed: {str(e)}"
|
233
|
+
)
|
234
|
+
|
235
|
+
async def ssl_status(self) -> CommandResult:
|
236
|
+
"""
|
237
|
+
Get current SSL status.
|
238
|
+
|
239
|
+
Returns:
|
240
|
+
CommandResult with SSL status information
|
241
|
+
"""
|
242
|
+
try:
|
243
|
+
logger.info("Checking SSL status")
|
244
|
+
|
245
|
+
# Check if SSL is configured in the application
|
246
|
+
from ..config import Config
|
247
|
+
config = Config()
|
248
|
+
|
249
|
+
ssl_config = config.get("ssl", {})
|
250
|
+
enabled = ssl_config.get("enabled", False)
|
251
|
+
|
252
|
+
if not enabled:
|
253
|
+
result = SSLSetupResult(
|
254
|
+
ssl_enabled=False,
|
255
|
+
status="disabled",
|
256
|
+
config=ssl_config
|
257
|
+
)
|
258
|
+
return SuccessResult(data=result.to_dict())
|
259
|
+
|
260
|
+
cert_file = ssl_config.get("cert_file")
|
261
|
+
key_file = ssl_config.get("key_file")
|
262
|
+
|
263
|
+
# Check file existence
|
264
|
+
cert_exists = os.path.exists(cert_file) if cert_file else False
|
265
|
+
key_exists = os.path.exists(key_file) if key_file else False
|
266
|
+
|
267
|
+
if not cert_exists or not key_exists:
|
268
|
+
result = SSLSetupResult(
|
269
|
+
ssl_enabled=False,
|
270
|
+
status="error",
|
271
|
+
cert_path=cert_file,
|
272
|
+
key_path=key_file,
|
273
|
+
config=ssl_config,
|
274
|
+
error="Certificate or key file not found"
|
275
|
+
)
|
276
|
+
return SuccessResult(data=result.to_dict())
|
277
|
+
|
278
|
+
# Validate certificate
|
279
|
+
cert_validation = self.auth_validator.validate_certificate(cert_file)
|
280
|
+
if not cert_validation.is_valid:
|
281
|
+
result = SSLSetupResult(
|
282
|
+
ssl_enabled=False,
|
283
|
+
status="error",
|
284
|
+
cert_path=cert_file,
|
285
|
+
key_path=key_file,
|
286
|
+
config=ssl_config,
|
287
|
+
error=f"Certificate validation failed: {cert_validation.error_message}"
|
288
|
+
)
|
289
|
+
return SuccessResult(data=result.to_dict())
|
290
|
+
|
291
|
+
result = SSLSetupResult(
|
292
|
+
ssl_enabled=True,
|
293
|
+
cert_path=cert_file,
|
294
|
+
key_path=key_file,
|
295
|
+
config=ssl_config,
|
296
|
+
status="enabled"
|
297
|
+
)
|
298
|
+
|
299
|
+
logger.info("SSL status check completed")
|
300
|
+
return SuccessResult(data=result.to_dict())
|
301
|
+
|
302
|
+
except Exception as e:
|
303
|
+
logger.error(f"SSL status check failed: {e}")
|
304
|
+
return ErrorResult(
|
305
|
+
message=f"SSL status check failed: {str(e)}"
|
306
|
+
)
|
307
|
+
|
308
|
+
async def ssl_test(self, cert_file: str, key_file: str) -> CommandResult:
|
309
|
+
"""
|
310
|
+
Test SSL configuration with certificate and key files.
|
311
|
+
|
312
|
+
Args:
|
313
|
+
cert_file: Path to certificate file
|
314
|
+
key_file: Path to private key file
|
315
|
+
|
316
|
+
Returns:
|
317
|
+
CommandResult with test results
|
318
|
+
"""
|
319
|
+
try:
|
320
|
+
logger.info(f"Testing SSL configuration with cert: {cert_file}, key: {key_file}")
|
321
|
+
|
322
|
+
# Validate parameters
|
323
|
+
if not cert_file or not key_file:
|
324
|
+
return ErrorResult(
|
325
|
+
message="Certificate and key file paths are required"
|
326
|
+
)
|
327
|
+
|
328
|
+
# Check file existence
|
329
|
+
if not os.path.exists(cert_file):
|
330
|
+
return ErrorResult(
|
331
|
+
message=f"Certificate file not found: {cert_file}"
|
332
|
+
)
|
333
|
+
|
334
|
+
if not os.path.exists(key_file):
|
335
|
+
return ErrorResult(
|
336
|
+
message=f"Private key file not found: {key_file}"
|
337
|
+
)
|
338
|
+
|
339
|
+
# Test SSL configuration
|
340
|
+
test_result = await self._test_ssl_config(cert_file, key_file)
|
341
|
+
|
342
|
+
if test_result["success"]:
|
343
|
+
logger.info("SSL configuration test passed")
|
344
|
+
return SuccessResult(
|
345
|
+
data={
|
346
|
+
"test_passed": True,
|
347
|
+
"cert_file": cert_file,
|
348
|
+
"key_file": key_file,
|
349
|
+
"details": test_result["details"]
|
350
|
+
}
|
351
|
+
)
|
352
|
+
else:
|
353
|
+
logger.error(f"SSL configuration test failed: {test_result['error']}")
|
354
|
+
return ErrorResult(
|
355
|
+
message=test_result["error"]
|
356
|
+
)
|
357
|
+
|
358
|
+
except Exception as e:
|
359
|
+
logger.error(f"SSL test failed: {e}")
|
360
|
+
return ErrorResult(
|
361
|
+
message=f"SSL test failed: {str(e)}"
|
362
|
+
)
|
363
|
+
|
364
|
+
async def ssl_config(self, action: str, config_data: Dict[str, Any]) -> CommandResult:
|
365
|
+
"""
|
366
|
+
Manage SSL configuration.
|
367
|
+
|
368
|
+
Args:
|
369
|
+
action: Action to perform (get, set, update, reset)
|
370
|
+
config_data: Configuration data for the action
|
371
|
+
|
372
|
+
Returns:
|
373
|
+
CommandResult with configuration operation result
|
374
|
+
"""
|
375
|
+
try:
|
376
|
+
logger.info(f"Performing SSL config action: {action}")
|
377
|
+
|
378
|
+
from ..config import Config
|
379
|
+
config = Config()
|
380
|
+
|
381
|
+
if action == "get":
|
382
|
+
ssl_config = config.get("ssl", {})
|
383
|
+
return SuccessResult(
|
384
|
+
data={"ssl_config": ssl_config}
|
385
|
+
)
|
386
|
+
|
387
|
+
elif action == "set":
|
388
|
+
# Validate configuration
|
389
|
+
if not isinstance(config_data, dict):
|
390
|
+
return ErrorResult(
|
391
|
+
message="Configuration data must be a dictionary"
|
392
|
+
)
|
393
|
+
|
394
|
+
# Update configuration
|
395
|
+
config.update_config({"ssl": config_data})
|
396
|
+
return SuccessResult(
|
397
|
+
data={"message": "SSL configuration updated", "ssl_config": config_data}
|
398
|
+
)
|
399
|
+
|
400
|
+
elif action == "update":
|
401
|
+
# Get current configuration
|
402
|
+
current_config = config.get("ssl", {})
|
403
|
+
|
404
|
+
# Update with new data
|
405
|
+
current_config.update(config_data)
|
406
|
+
|
407
|
+
# Update configuration
|
408
|
+
config.update_config({"ssl": current_config})
|
409
|
+
return SuccessResult(
|
410
|
+
data={"message": "SSL configuration updated", "ssl_config": current_config}
|
411
|
+
)
|
412
|
+
|
413
|
+
elif action == "reset":
|
414
|
+
# Reset to default configuration
|
415
|
+
default_config = {
|
416
|
+
"enabled": False,
|
417
|
+
"cert_file": None,
|
418
|
+
"key_file": None,
|
419
|
+
"ca_file": None,
|
420
|
+
"verify_mode": "CERT_REQUIRED",
|
421
|
+
"cipher_suites": []
|
422
|
+
}
|
423
|
+
|
424
|
+
config.update_config({"ssl": default_config})
|
425
|
+
return SuccessResult(
|
426
|
+
data={"message": "SSL configuration reset to defaults", "ssl_config": default_config}
|
427
|
+
)
|
428
|
+
|
429
|
+
else:
|
430
|
+
return ErrorResult(
|
431
|
+
message=f"Unknown action: {action}. Supported actions: get, set, update, reset"
|
432
|
+
)
|
433
|
+
|
434
|
+
except Exception as e:
|
435
|
+
logger.error(f"SSL config action failed: {e}")
|
436
|
+
return ErrorResult(
|
437
|
+
message=f"SSL config action failed: {str(e)}"
|
438
|
+
)
|
439
|
+
|
440
|
+
async def _test_ssl_config(self, cert_file: str, key_file: str) -> Dict[str, Any]:
|
441
|
+
"""
|
442
|
+
Test SSL configuration internally.
|
443
|
+
|
444
|
+
Args:
|
445
|
+
cert_file: Path to certificate file
|
446
|
+
key_file: Path to private key file
|
447
|
+
|
448
|
+
Returns:
|
449
|
+
Dictionary with test results
|
450
|
+
"""
|
451
|
+
try:
|
452
|
+
# Create SSL context
|
453
|
+
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
|
454
|
+
context.check_hostname = False
|
455
|
+
context.verify_mode = ssl.CERT_NONE
|
456
|
+
|
457
|
+
# Load certificate and key
|
458
|
+
context.load_cert_chain(cert_file, key_file)
|
459
|
+
|
460
|
+
# Test basic SSL functionality
|
461
|
+
details = {
|
462
|
+
"ssl_version": ssl.OPENSSL_VERSION,
|
463
|
+
"certificate_loaded": True,
|
464
|
+
"private_key_loaded": True,
|
465
|
+
"context_created": True
|
466
|
+
}
|
467
|
+
|
468
|
+
return {
|
469
|
+
"success": True,
|
470
|
+
"details": details
|
471
|
+
}
|
472
|
+
|
473
|
+
except Exception as e:
|
474
|
+
return {
|
475
|
+
"success": False,
|
476
|
+
"error": str(e),
|
477
|
+
"details": {
|
478
|
+
"ssl_version": ssl.OPENSSL_VERSION,
|
479
|
+
"certificate_loaded": False,
|
480
|
+
"private_key_loaded": False,
|
481
|
+
"context_created": False
|
482
|
+
}
|
483
|
+
}
|