mcp-proxy-adapter 6.1.0__py3-none-any.whl → 6.2.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 +27 -7
- mcp_proxy_adapter/api/app.py +18 -7
- mcp_proxy_adapter/api/middleware/__init__.py +2 -2
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +32 -13
- mcp_proxy_adapter/api/middleware/unified_security.py +12 -4
- mcp_proxy_adapter/commands/ssl_setup_command.py +234 -351
- mcp_proxy_adapter/core/app_factory.py +87 -3
- mcp_proxy_adapter/core/app_runner.py +272 -0
- mcp_proxy_adapter/core/certificate_utils.py +291 -73
- mcp_proxy_adapter/core/client.py +574 -0
- mcp_proxy_adapter/core/client_manager.py +284 -0
- mcp_proxy_adapter/core/protocol_manager.py +132 -10
- mcp_proxy_adapter/core/security_integration.py +19 -11
- mcp_proxy_adapter/core/server_adapter.py +17 -80
- mcp_proxy_adapter/core/server_engine.py +5 -99
- mcp_proxy_adapter/core/ssl_utils.py +13 -12
- mcp_proxy_adapter/core/transport_manager.py +5 -5
- mcp_proxy_adapter/examples/__init__.py +16 -0
- mcp_proxy_adapter/examples/basic_framework/__init__.py +7 -0
- mcp_proxy_adapter/examples/basic_framework/commands/__init__.py +4 -0
- mcp_proxy_adapter/examples/basic_framework/hooks/__init__.py +4 -0
- mcp_proxy_adapter/examples/basic_framework/main.py +21 -40
- mcp_proxy_adapter/examples/commands/__init__.py +5 -1
- mcp_proxy_adapter/examples/create_certificates_simple.py +260 -75
- mcp_proxy_adapter/examples/debug_request_state.py +4 -36
- mcp_proxy_adapter/examples/debug_role_chain.py +2 -49
- mcp_proxy_adapter/examples/demo_client.py +0 -66
- mcp_proxy_adapter/examples/full_application/__init__.py +11 -0
- mcp_proxy_adapter/examples/full_application/commands/__init__.py +7 -0
- mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +0 -19
- mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +0 -16
- mcp_proxy_adapter/examples/full_application/hooks/__init__.py +7 -0
- mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +0 -22
- mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +0 -24
- mcp_proxy_adapter/examples/full_application/main.py +65 -44
- mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +154 -0
- mcp_proxy_adapter/examples/generate_all_certificates.py +0 -67
- mcp_proxy_adapter/examples/generate_certificates.py +0 -15
- mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +369 -0
- mcp_proxy_adapter/examples/generate_test_configs.py +204 -0
- mcp_proxy_adapter/examples/proxy_registration_example.py +3 -70
- mcp_proxy_adapter/examples/run_example.py +1 -23
- mcp_proxy_adapter/examples/run_security_tests.py +2 -60
- mcp_proxy_adapter/examples/run_security_tests_fixed.py +0 -53
- mcp_proxy_adapter/examples/security_test_client.py +18 -123
- mcp_proxy_adapter/examples/setup_test_environment.py +179 -0
- mcp_proxy_adapter/examples/test_config.py +148 -0
- mcp_proxy_adapter/examples/test_config_generator.py +86 -0
- mcp_proxy_adapter/examples/test_examples.py +4 -67
- mcp_proxy_adapter/examples/universal_client.py +154 -162
- mcp_proxy_adapter/main.py +51 -161
- mcp_proxy_adapter/utils/config_generator.py +90 -2
- mcp_proxy_adapter/version.py +4 -2
- mcp_proxy_adapter-6.2.0.dist-info/METADATA +687 -0
- mcp_proxy_adapter-6.2.0.dist-info/RECORD +122 -0
- mcp_proxy_adapter/examples/README.md +0 -257
- mcp_proxy_adapter/examples/README_EN.md +0 -258
- mcp_proxy_adapter/examples/SECURITY_TESTING.md +0 -455
- mcp_proxy_adapter/examples/__pycache__/security_configurations.cpython-312.pyc +0 -0
- mcp_proxy_adapter/examples/__pycache__/security_test_client.cpython-312.pyc +0 -0
- mcp_proxy_adapter/examples/basic_framework/configs/http_auth.json +0 -37
- mcp_proxy_adapter/examples/basic_framework/configs/http_simple.json +0 -23
- mcp_proxy_adapter/examples/basic_framework/configs/https_auth.json +0 -39
- mcp_proxy_adapter/examples/basic_framework/configs/https_simple.json +0 -25
- mcp_proxy_adapter/examples/basic_framework/configs/mtls_no_roles.json +0 -39
- mcp_proxy_adapter/examples/basic_framework/configs/mtls_with_roles.json +0 -45
- mcp_proxy_adapter/examples/basic_framework/roles.json +0 -21
- mcp_proxy_adapter/examples/cert_config.json +0 -9
- mcp_proxy_adapter/examples/certs/admin.crt +0 -32
- mcp_proxy_adapter/examples/certs/admin.key +0 -52
- mcp_proxy_adapter/examples/certs/admin_cert.pem +0 -21
- mcp_proxy_adapter/examples/certs/admin_key.pem +0 -28
- mcp_proxy_adapter/examples/certs/ca_cert.pem +0 -23
- mcp_proxy_adapter/examples/certs/ca_cert.srl +0 -1
- mcp_proxy_adapter/examples/certs/ca_key.pem +0 -28
- mcp_proxy_adapter/examples/certs/cert_config.json +0 -9
- mcp_proxy_adapter/examples/certs/client.crt +0 -32
- mcp_proxy_adapter/examples/certs/client.key +0 -52
- mcp_proxy_adapter/examples/certs/client_admin.crt +0 -32
- mcp_proxy_adapter/examples/certs/client_admin.key +0 -52
- mcp_proxy_adapter/examples/certs/client_user.crt +0 -32
- mcp_proxy_adapter/examples/certs/client_user.key +0 -52
- mcp_proxy_adapter/examples/certs/guest_cert.pem +0 -21
- mcp_proxy_adapter/examples/certs/guest_key.pem +0 -28
- mcp_proxy_adapter/examples/certs/mcp_proxy_adapter_ca_ca.crt +0 -23
- mcp_proxy_adapter/examples/certs/proxy_cert.pem +0 -21
- mcp_proxy_adapter/examples/certs/proxy_key.pem +0 -28
- mcp_proxy_adapter/examples/certs/readonly.crt +0 -32
- mcp_proxy_adapter/examples/certs/readonly.key +0 -52
- mcp_proxy_adapter/examples/certs/readonly_cert.pem +0 -21
- mcp_proxy_adapter/examples/certs/readonly_key.pem +0 -28
- mcp_proxy_adapter/examples/certs/server.crt +0 -32
- mcp_proxy_adapter/examples/certs/server.key +0 -52
- mcp_proxy_adapter/examples/certs/server_cert.pem +0 -32
- mcp_proxy_adapter/examples/certs/server_key.pem +0 -52
- mcp_proxy_adapter/examples/certs/test_ca_ca.crt +0 -20
- mcp_proxy_adapter/examples/certs/user.crt +0 -32
- mcp_proxy_adapter/examples/certs/user.key +0 -52
- mcp_proxy_adapter/examples/certs/user_cert.pem +0 -21
- mcp_proxy_adapter/examples/certs/user_key.pem +0 -28
- mcp_proxy_adapter/examples/client_configs/api_key_client.json +0 -13
- mcp_proxy_adapter/examples/client_configs/basic_auth_client.json +0 -13
- mcp_proxy_adapter/examples/client_configs/certificate_client.json +0 -22
- mcp_proxy_adapter/examples/client_configs/jwt_client.json +0 -15
- mcp_proxy_adapter/examples/client_configs/no_auth_client.json +0 -9
- mcp_proxy_adapter/examples/full_application/configs/http_auth.json +0 -37
- mcp_proxy_adapter/examples/full_application/configs/http_simple.json +0 -23
- mcp_proxy_adapter/examples/full_application/configs/https_auth.json +0 -39
- mcp_proxy_adapter/examples/full_application/configs/https_simple.json +0 -25
- mcp_proxy_adapter/examples/full_application/configs/mtls_no_roles.json +0 -39
- mcp_proxy_adapter/examples/full_application/configs/mtls_with_roles.json +0 -45
- mcp_proxy_adapter/examples/full_application/roles.json +0 -21
- mcp_proxy_adapter/examples/keys/ca_key.pem +0 -28
- mcp_proxy_adapter/examples/keys/mcp_proxy_adapter_ca_ca.key +0 -28
- mcp_proxy_adapter/examples/keys/test_ca_ca.key +0 -28
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log +0 -220
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.1 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.2 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.3 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.4 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.5 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log +0 -220
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.1 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.2 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.3 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.4 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.5 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log +0 -2
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.1 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.2 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.3 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.4 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.5 +0 -1
- mcp_proxy_adapter/examples/roles.json +0 -38
- mcp_proxy_adapter/examples/server_configs/config_basic_http.json +0 -204
- mcp_proxy_adapter/examples/server_configs/config_http_token.json +0 -238
- mcp_proxy_adapter/examples/server_configs/config_https.json +0 -215
- mcp_proxy_adapter/examples/server_configs/config_https_token.json +0 -231
- mcp_proxy_adapter/examples/server_configs/config_mtls.json +0 -215
- mcp_proxy_adapter/examples/server_configs/config_proxy_registration.json +0 -250
- mcp_proxy_adapter/examples/server_configs/config_simple.json +0 -46
- mcp_proxy_adapter/examples/server_configs/roles.json +0 -38
- mcp_proxy_adapter-6.1.0.dist-info/METADATA +0 -205
- mcp_proxy_adapter-6.1.0.dist-info/RECORD +0 -193
- {mcp_proxy_adapter-6.1.0.dist-info → mcp_proxy_adapter-6.2.0.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.1.0.dist-info → mcp_proxy_adapter-6.2.0.dist-info}/entry_points.txt +0 -0
- {mcp_proxy_adapter-6.1.0.dist-info → mcp_proxy_adapter-6.2.0.dist-info}/licenses/LICENSE +0 -0
- {mcp_proxy_adapter-6.1.0.dist-info → mcp_proxy_adapter-6.2.0.dist-info}/top_level.txt +0 -0
@@ -1,453 +1,284 @@
|
|
1
1
|
"""
|
2
2
|
SSL Setup Command
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
Author: Vasiliy Zdanovskiy
|
5
|
+
email: vasilyvz@gmail.com
|
6
6
|
|
7
|
-
|
8
|
-
Version: 1.0.0
|
7
|
+
Command for SSL/TLS configuration and certificate management.
|
9
8
|
"""
|
10
9
|
|
11
10
|
import logging
|
12
|
-
import os
|
13
11
|
import ssl
|
14
|
-
from typing import Dict,
|
15
|
-
|
12
|
+
from typing import Dict, Any, Optional
|
13
|
+
|
14
|
+
# Import mcp_security_framework
|
15
|
+
try:
|
16
|
+
from mcp_security_framework.core.ssl_manager import SSLManager
|
17
|
+
from mcp_security_framework.schemas.config import SSLConfig
|
18
|
+
from mcp_security_framework.utils.cert_utils import validate_certificate_chain
|
19
|
+
SECURITY_FRAMEWORK_AVAILABLE = True
|
20
|
+
except ImportError:
|
21
|
+
SECURITY_FRAMEWORK_AVAILABLE = False
|
16
22
|
|
17
23
|
from .base import Command
|
18
|
-
from .result import
|
19
|
-
from ..
|
20
|
-
from ..core.auth_validator import AuthValidator
|
24
|
+
from .result import SuccessResult, ErrorResult
|
25
|
+
from ..config import Config
|
21
26
|
|
22
27
|
logger = logging.getLogger(__name__)
|
23
28
|
|
24
29
|
|
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
30
|
class SSLSetupCommand(Command):
|
92
31
|
"""
|
93
|
-
|
32
|
+
SSL Setup Command
|
94
33
|
|
95
|
-
|
34
|
+
Handles SSL/TLS configuration and certificate management.
|
96
35
|
"""
|
97
36
|
|
98
37
|
# Command metadata
|
99
38
|
name = "ssl_setup"
|
100
39
|
version = "1.0.0"
|
101
|
-
descr = "SSL
|
40
|
+
descr = "Configure SSL/TLS settings and manage certificates"
|
102
41
|
category = "security"
|
103
42
|
author = "MCP Proxy Adapter Team"
|
104
43
|
email = "team@mcp-proxy-adapter.com"
|
105
44
|
source_url = "https://github.com/mcp-proxy-adapter"
|
106
|
-
result_class =
|
45
|
+
result_class = SuccessResult
|
107
46
|
|
108
47
|
def __init__(self):
|
109
|
-
"""Initialize SSL
|
48
|
+
"""Initialize SSL Setup Command."""
|
110
49
|
super().__init__()
|
111
|
-
self.certificate_utils = CertificateUtils()
|
112
|
-
self.auth_validator = AuthValidator()
|
113
50
|
|
114
|
-
async def execute(self, **kwargs) ->
|
51
|
+
async def execute(self, **kwargs) -> SuccessResult | ErrorResult:
|
115
52
|
"""
|
116
53
|
Execute SSL setup command.
|
117
54
|
|
118
55
|
Args:
|
119
|
-
|
120
|
-
- action:
|
121
|
-
-
|
122
|
-
- cert_file: Certificate file path for
|
123
|
-
- key_file:
|
124
|
-
- action: Action for ssl_config (get, set, update, reset)
|
125
|
-
- config_data: Configuration data for ssl_config action
|
56
|
+
params: Command parameters including:
|
57
|
+
- action: Operation to perform (get, set, update, reset, test)
|
58
|
+
- config_data: Configuration data for set/update actions
|
59
|
+
- cert_file: Certificate file path for testing
|
60
|
+
- key_file: Private key file path for testing
|
126
61
|
|
127
62
|
Returns:
|
128
|
-
|
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
|
63
|
+
SuccessResult or ErrorResult
|
165
64
|
"""
|
166
65
|
try:
|
167
|
-
|
66
|
+
action = kwargs.get("action", "get")
|
168
67
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
68
|
+
if action == "get":
|
69
|
+
return await self._get_ssl_config()
|
70
|
+
elif action == "set":
|
71
|
+
return await self._set_ssl_config(kwargs.get("config_data", {}))
|
72
|
+
elif action == "update":
|
73
|
+
return await self._update_ssl_config(kwargs.get("config_data", {}))
|
74
|
+
elif action == "reset":
|
75
|
+
return await self._reset_ssl_config()
|
76
|
+
elif action == "test":
|
77
|
+
return await self._test_ssl_config(
|
78
|
+
kwargs.get("cert_file"),
|
79
|
+
kwargs.get("key_file")
|
173
80
|
)
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
result = SSLSetupResult(
|
178
|
-
ssl_enabled=False,
|
179
|
-
status="disabled",
|
180
|
-
config=ssl_config
|
81
|
+
else:
|
82
|
+
return ErrorResult(
|
83
|
+
message=f"Unknown action: {action}. Supported actions: get, set, update, reset, test"
|
181
84
|
)
|
182
|
-
|
85
|
+
|
86
|
+
except Exception as e:
|
87
|
+
logger.error(f"SSL setup command failed: {e}")
|
88
|
+
return ErrorResult(
|
89
|
+
message=f"SSL setup command failed: {str(e)}"
|
90
|
+
)
|
91
|
+
|
92
|
+
async def _get_ssl_config(self) -> SuccessResult | ErrorResult:
|
93
|
+
"""Get current SSL configuration."""
|
94
|
+
try:
|
95
|
+
config = Config()
|
96
|
+
ssl_config = config.get("ssl", {})
|
183
97
|
|
184
|
-
#
|
185
|
-
|
186
|
-
key_file = ssl_config.get("key_file")
|
98
|
+
# Add framework information
|
99
|
+
ssl_config["framework_available"] = SECURITY_FRAMEWORK_AVAILABLE
|
187
100
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
)
|
101
|
+
return SuccessResult(
|
102
|
+
data={"ssl_config": ssl_config}
|
103
|
+
)
|
192
104
|
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
105
|
+
except Exception as e:
|
106
|
+
logger.error(f"Failed to get SSL config: {e}")
|
107
|
+
return ErrorResult(
|
108
|
+
message=f"Failed to get SSL config: {str(e)}"
|
109
|
+
)
|
198
110
|
|
199
|
-
|
111
|
+
async def _set_ssl_config(self, config_data: Dict[str, Any]) -> SuccessResult | ErrorResult:
|
112
|
+
"""Set SSL configuration."""
|
113
|
+
try:
|
114
|
+
if not isinstance(config_data, dict):
|
200
115
|
return ErrorResult(
|
201
|
-
message=
|
116
|
+
message="Configuration data must be a dictionary"
|
202
117
|
)
|
203
118
|
|
204
|
-
# Validate
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
119
|
+
# Validate configuration if mcp_security_framework is available
|
120
|
+
if SECURITY_FRAMEWORK_AVAILABLE:
|
121
|
+
try:
|
122
|
+
ssl_config = SSLConfig(**config_data)
|
123
|
+
config_data = ssl_config.dict()
|
124
|
+
except Exception as e:
|
125
|
+
return ErrorResult(
|
126
|
+
message=f"Invalid SSL configuration: {str(e)}"
|
127
|
+
)
|
210
128
|
|
211
|
-
#
|
212
|
-
|
213
|
-
|
214
|
-
return ErrorResult(
|
215
|
-
message=f"SSL configuration test failed: {test_result['error']}"
|
216
|
-
)
|
129
|
+
# Update configuration
|
130
|
+
config = Config()
|
131
|
+
config.update_config({"ssl": config_data})
|
217
132
|
|
218
|
-
|
219
|
-
|
220
|
-
cert_path=cert_file,
|
221
|
-
key_path=key_file,
|
222
|
-
config=ssl_config,
|
223
|
-
status="enabled"
|
133
|
+
return SuccessResult(
|
134
|
+
data={"message": "SSL configuration updated", "ssl_config": config_data}
|
224
135
|
)
|
225
136
|
|
226
|
-
logger.info("SSL configuration setup completed successfully")
|
227
|
-
return SuccessResult(data=result.to_dict())
|
228
|
-
|
229
137
|
except Exception as e:
|
230
|
-
logger.error(f"SSL
|
138
|
+
logger.error(f"Failed to set SSL config: {e}")
|
231
139
|
return ErrorResult(
|
232
|
-
message=f"SSL
|
140
|
+
message=f"Failed to set SSL config: {str(e)}"
|
233
141
|
)
|
234
142
|
|
235
|
-
async def
|
236
|
-
"""
|
237
|
-
Get current SSL status.
|
238
|
-
|
239
|
-
Returns:
|
240
|
-
CommandResult with SSL status information
|
241
|
-
"""
|
143
|
+
async def _update_ssl_config(self, config_data: Dict[str, Any]) -> SuccessResult | ErrorResult:
|
144
|
+
"""Update SSL configuration."""
|
242
145
|
try:
|
243
|
-
|
146
|
+
if not isinstance(config_data, dict):
|
147
|
+
return ErrorResult(
|
148
|
+
message="Configuration data must be a dictionary"
|
149
|
+
)
|
244
150
|
|
245
|
-
# Check if SSL is configured in the application
|
246
|
-
from ...config import Config
|
247
151
|
config = Config()
|
152
|
+
current_config = config.get("ssl", {})
|
248
153
|
|
249
|
-
|
250
|
-
|
154
|
+
# Update with new data
|
155
|
+
current_config.update(config_data)
|
251
156
|
|
252
|
-
if
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
157
|
+
# Validate configuration if mcp_security_framework is available
|
158
|
+
if SECURITY_FRAMEWORK_AVAILABLE:
|
159
|
+
try:
|
160
|
+
ssl_config = SSLConfig(**current_config)
|
161
|
+
current_config = ssl_config.dict()
|
162
|
+
except Exception as e:
|
163
|
+
return ErrorResult(
|
164
|
+
message=f"Invalid SSL configuration: {str(e)}"
|
165
|
+
)
|
259
166
|
|
260
|
-
|
261
|
-
|
167
|
+
# Update configuration
|
168
|
+
config.update_config({"ssl": current_config})
|
262
169
|
|
263
|
-
|
264
|
-
|
265
|
-
|
170
|
+
return SuccessResult(
|
171
|
+
data={"message": "SSL configuration updated", "ssl_config": current_config}
|
172
|
+
)
|
266
173
|
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
174
|
+
except Exception as e:
|
175
|
+
logger.error(f"Failed to update SSL config: {e}")
|
176
|
+
return ErrorResult(
|
177
|
+
message=f"Failed to update SSL config: {str(e)}"
|
178
|
+
)
|
179
|
+
|
180
|
+
async def _reset_ssl_config(self) -> SuccessResult | ErrorResult:
|
181
|
+
"""Reset SSL configuration to defaults."""
|
182
|
+
try:
|
183
|
+
default_config = {
|
184
|
+
"enabled": False,
|
185
|
+
"cert_file": None,
|
186
|
+
"key_file": None,
|
187
|
+
"ca_file": None,
|
188
|
+
"verify_mode": "CERT_REQUIRED",
|
189
|
+
"cipher_suites": [],
|
190
|
+
"framework_available": SECURITY_FRAMEWORK_AVAILABLE
|
191
|
+
}
|
277
192
|
|
278
|
-
|
279
|
-
|
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())
|
193
|
+
config = Config()
|
194
|
+
config.update_config({"ssl": default_config})
|
290
195
|
|
291
|
-
|
292
|
-
|
293
|
-
cert_path=cert_file,
|
294
|
-
key_path=key_file,
|
295
|
-
config=ssl_config,
|
296
|
-
status="enabled"
|
196
|
+
return SuccessResult(
|
197
|
+
data={"message": "SSL configuration reset to defaults", "ssl_config": default_config}
|
297
198
|
)
|
298
199
|
|
299
|
-
logger.info("SSL status check completed")
|
300
|
-
return SuccessResult(data=result.to_dict())
|
301
|
-
|
302
200
|
except Exception as e:
|
303
|
-
logger.error(f"
|
201
|
+
logger.error(f"Failed to reset SSL config: {e}")
|
304
202
|
return ErrorResult(
|
305
|
-
message=f"
|
203
|
+
message=f"Failed to reset SSL config: {str(e)}"
|
306
204
|
)
|
307
205
|
|
308
|
-
async def
|
206
|
+
async def _test_ssl_config(self, cert_file: Optional[str], key_file: Optional[str]) -> SuccessResult | ErrorResult:
|
309
207
|
"""
|
310
|
-
Test SSL configuration
|
208
|
+
Test SSL configuration.
|
311
209
|
|
312
210
|
Args:
|
313
211
|
cert_file: Path to certificate file
|
314
212
|
key_file: Path to private key file
|
315
213
|
|
316
214
|
Returns:
|
317
|
-
|
215
|
+
SuccessResult or ErrorResult with test results
|
318
216
|
"""
|
319
217
|
try:
|
320
|
-
logger.info(f"Testing SSL configuration with cert: {cert_file}, key: {key_file}")
|
321
|
-
|
322
|
-
# Validate parameters
|
323
218
|
if not cert_file or not key_file:
|
324
219
|
return ErrorResult(
|
325
|
-
message="
|
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}"
|
220
|
+
message="Both cert_file and key_file are required for testing"
|
332
221
|
)
|
333
222
|
|
334
|
-
if
|
335
|
-
return
|
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
|
-
)
|
223
|
+
if SECURITY_FRAMEWORK_AVAILABLE:
|
224
|
+
return await self._test_ssl_config_with_framework(cert_file, key_file)
|
352
225
|
else:
|
353
|
-
|
354
|
-
return ErrorResult(
|
355
|
-
message=test_result["error"]
|
356
|
-
)
|
226
|
+
return await self._test_ssl_config_fallback(cert_file, key_file)
|
357
227
|
|
358
228
|
except Exception as e:
|
359
|
-
logger.error(f"
|
229
|
+
logger.error(f"Failed to test SSL config: {e}")
|
360
230
|
return ErrorResult(
|
361
|
-
message=f"
|
231
|
+
message=f"Failed to test SSL config: {str(e)}"
|
362
232
|
)
|
363
233
|
|
364
|
-
async def
|
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
|
-
"""
|
234
|
+
async def _test_ssl_config_with_framework(self, cert_file: str, key_file: str) -> SuccessResult | ErrorResult:
|
235
|
+
"""Test SSL configuration using mcp_security_framework."""
|
375
236
|
try:
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
237
|
+
# Create SSL manager
|
238
|
+
ssl_config = SSLConfig(
|
239
|
+
cert_file=cert_file,
|
240
|
+
key_file=key_file,
|
241
|
+
enabled=True
|
242
|
+
)
|
380
243
|
|
381
|
-
|
382
|
-
ssl_config = config.get("ssl", {})
|
383
|
-
return SuccessResult(
|
384
|
-
data={"ssl_config": ssl_config}
|
385
|
-
)
|
244
|
+
ssl_manager = SSLManager(ssl_config)
|
386
245
|
|
387
|
-
|
388
|
-
|
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
|
-
)
|
246
|
+
# Test SSL context creation
|
247
|
+
context = ssl_manager.create_server_ssl_context()
|
399
248
|
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
config.update_config({"ssl": current_config})
|
409
|
-
return SuccessResult(
|
410
|
-
data={"message": "SSL configuration updated", "ssl_config": current_config}
|
411
|
-
)
|
249
|
+
details = {
|
250
|
+
"framework": "mcp_security_framework",
|
251
|
+
"certificate_loaded": True,
|
252
|
+
"private_key_loaded": True,
|
253
|
+
"context_created": True,
|
254
|
+
"cert_file": cert_file,
|
255
|
+
"key_file": key_file
|
256
|
+
}
|
412
257
|
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
"
|
417
|
-
"cert_file": None,
|
418
|
-
"key_file": None,
|
419
|
-
"ca_file": None,
|
420
|
-
"verify_mode": "CERT_REQUIRED",
|
421
|
-
"cipher_suites": []
|
258
|
+
return SuccessResult(
|
259
|
+
data={
|
260
|
+
"success": True,
|
261
|
+
"details": details
|
422
262
|
}
|
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
|
-
)
|
263
|
+
)
|
433
264
|
|
434
265
|
except Exception as e:
|
435
|
-
logger.error(f"SSL config action failed: {e}")
|
436
266
|
return ErrorResult(
|
437
|
-
message=f"SSL
|
267
|
+
message=f"SSL test failed: {str(e)}",
|
268
|
+
data={
|
269
|
+
"success": False,
|
270
|
+
"error": str(e),
|
271
|
+
"details": {
|
272
|
+
"framework": "mcp_security_framework",
|
273
|
+
"certificate_loaded": False,
|
274
|
+
"private_key_loaded": False,
|
275
|
+
"context_created": False
|
276
|
+
}
|
277
|
+
}
|
438
278
|
)
|
439
279
|
|
440
|
-
async def
|
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
|
-
"""
|
280
|
+
async def _test_ssl_config_fallback(self, cert_file: str, key_file: str) -> SuccessResult | ErrorResult:
|
281
|
+
"""Test SSL configuration using fallback method."""
|
451
282
|
try:
|
452
283
|
# Create SSL context
|
453
284
|
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
|
@@ -459,25 +290,77 @@ class SSLSetupCommand(Command):
|
|
459
290
|
|
460
291
|
# Test basic SSL functionality
|
461
292
|
details = {
|
293
|
+
"framework": "fallback (ssl module)",
|
462
294
|
"ssl_version": ssl.OPENSSL_VERSION,
|
463
295
|
"certificate_loaded": True,
|
464
296
|
"private_key_loaded": True,
|
465
|
-
"context_created": True
|
297
|
+
"context_created": True,
|
298
|
+
"cert_file": cert_file,
|
299
|
+
"key_file": key_file
|
466
300
|
}
|
467
301
|
|
468
|
-
return
|
302
|
+
return SuccessResult(
|
303
|
+
data={
|
469
304
|
"success": True,
|
470
305
|
"details": details
|
471
306
|
}
|
307
|
+
)
|
472
308
|
|
473
309
|
except Exception as e:
|
474
|
-
return
|
310
|
+
return ErrorResult(
|
311
|
+
message=f"SSL test failed: {str(e)}",
|
312
|
+
data={
|
475
313
|
"success": False,
|
476
314
|
"error": str(e),
|
477
315
|
"details": {
|
316
|
+
"framework": "fallback (ssl module)",
|
478
317
|
"ssl_version": ssl.OPENSSL_VERSION,
|
479
318
|
"certificate_loaded": False,
|
480
319
|
"private_key_loaded": False,
|
481
320
|
"context_created": False
|
482
321
|
}
|
322
|
+
}
|
323
|
+
)
|
324
|
+
|
325
|
+
def to_dict(self) -> Dict[str, Any]:
|
326
|
+
"""Convert command to dictionary."""
|
327
|
+
return {
|
328
|
+
"name": self.name,
|
329
|
+
"description": self.description,
|
330
|
+
"version": self.version,
|
331
|
+
"framework_available": SECURITY_FRAMEWORK_AVAILABLE
|
332
|
+
}
|
333
|
+
|
334
|
+
def get_schema(self) -> Dict[str, Any]:
|
335
|
+
"""Get command schema."""
|
336
|
+
return {
|
337
|
+
"type": "object",
|
338
|
+
"properties": {
|
339
|
+
"action": {
|
340
|
+
"type": "string",
|
341
|
+
"enum": ["get", "set", "update", "reset", "test"],
|
342
|
+
"description": "Action to perform"
|
343
|
+
},
|
344
|
+
"config_data": {
|
345
|
+
"type": "object",
|
346
|
+
"description": "SSL configuration data",
|
347
|
+
"properties": {
|
348
|
+
"enabled": {"type": "boolean"},
|
349
|
+
"cert_file": {"type": "string"},
|
350
|
+
"key_file": {"type": "string"},
|
351
|
+
"ca_file": {"type": "string"},
|
352
|
+
"verify_mode": {"type": "string"},
|
353
|
+
"cipher_suites": {"type": "array", "items": {"type": "string"}}
|
354
|
+
}
|
355
|
+
},
|
356
|
+
"cert_file": {
|
357
|
+
"type": "string",
|
358
|
+
"description": "Certificate file path for testing"
|
359
|
+
},
|
360
|
+
"key_file": {
|
361
|
+
"type": "string",
|
362
|
+
"description": "Private key file path for testing"
|
363
|
+
}
|
364
|
+
},
|
365
|
+
"required": ["action"]
|
483
366
|
}
|