mcp-proxy-adapter 6.3.4__py3-none-any.whl → 6.3.5__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/__init__.py +9 -5
- mcp_proxy_adapter/__main__.py +1 -1
- mcp_proxy_adapter/api/app.py +227 -176
- mcp_proxy_adapter/api/handlers.py +68 -60
- mcp_proxy_adapter/api/middleware/__init__.py +7 -5
- mcp_proxy_adapter/api/middleware/base.py +19 -16
- mcp_proxy_adapter/api/middleware/command_permission_middleware.py +44 -34
- mcp_proxy_adapter/api/middleware/error_handling.py +57 -67
- mcp_proxy_adapter/api/middleware/factory.py +50 -52
- mcp_proxy_adapter/api/middleware/logging.py +46 -30
- mcp_proxy_adapter/api/middleware/performance.py +19 -16
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +80 -50
- mcp_proxy_adapter/api/middleware/transport_middleware.py +26 -24
- mcp_proxy_adapter/api/middleware/unified_security.py +70 -51
- mcp_proxy_adapter/api/middleware/user_info_middleware.py +43 -34
- mcp_proxy_adapter/api/schemas.py +69 -43
- mcp_proxy_adapter/api/tool_integration.py +83 -63
- mcp_proxy_adapter/api/tools.py +60 -50
- mcp_proxy_adapter/commands/__init__.py +15 -6
- mcp_proxy_adapter/commands/auth_validation_command.py +107 -110
- mcp_proxy_adapter/commands/base.py +108 -112
- mcp_proxy_adapter/commands/builtin_commands.py +28 -18
- mcp_proxy_adapter/commands/catalog_manager.py +394 -265
- mcp_proxy_adapter/commands/cert_monitor_command.py +222 -204
- mcp_proxy_adapter/commands/certificate_management_command.py +210 -213
- mcp_proxy_adapter/commands/command_registry.py +275 -226
- mcp_proxy_adapter/commands/config_command.py +48 -33
- mcp_proxy_adapter/commands/dependency_container.py +22 -23
- mcp_proxy_adapter/commands/dependency_manager.py +65 -56
- mcp_proxy_adapter/commands/echo_command.py +15 -15
- mcp_proxy_adapter/commands/health_command.py +31 -29
- mcp_proxy_adapter/commands/help_command.py +97 -61
- mcp_proxy_adapter/commands/hooks.py +65 -49
- mcp_proxy_adapter/commands/key_management_command.py +148 -147
- mcp_proxy_adapter/commands/load_command.py +58 -40
- mcp_proxy_adapter/commands/plugins_command.py +80 -54
- mcp_proxy_adapter/commands/protocol_management_command.py +60 -48
- mcp_proxy_adapter/commands/proxy_registration_command.py +107 -115
- mcp_proxy_adapter/commands/reload_command.py +43 -37
- mcp_proxy_adapter/commands/result.py +26 -33
- mcp_proxy_adapter/commands/role_test_command.py +26 -26
- mcp_proxy_adapter/commands/roles_management_command.py +176 -173
- mcp_proxy_adapter/commands/security_command.py +134 -122
- mcp_proxy_adapter/commands/settings_command.py +47 -56
- mcp_proxy_adapter/commands/ssl_setup_command.py +109 -129
- mcp_proxy_adapter/commands/token_management_command.py +129 -158
- mcp_proxy_adapter/commands/transport_management_command.py +41 -36
- mcp_proxy_adapter/commands/unload_command.py +42 -37
- mcp_proxy_adapter/config.py +36 -35
- mcp_proxy_adapter/core/__init__.py +19 -21
- mcp_proxy_adapter/core/app_factory.py +30 -9
- mcp_proxy_adapter/core/app_runner.py +81 -64
- mcp_proxy_adapter/core/auth_validator.py +176 -182
- mcp_proxy_adapter/core/certificate_utils.py +469 -426
- mcp_proxy_adapter/core/client.py +155 -126
- mcp_proxy_adapter/core/client_manager.py +60 -54
- mcp_proxy_adapter/core/client_security.py +108 -88
- mcp_proxy_adapter/core/config_converter.py +176 -143
- mcp_proxy_adapter/core/config_validator.py +12 -4
- mcp_proxy_adapter/core/crl_utils.py +21 -7
- mcp_proxy_adapter/core/errors.py +64 -20
- mcp_proxy_adapter/core/logging.py +34 -29
- mcp_proxy_adapter/core/mtls_asgi.py +29 -25
- mcp_proxy_adapter/core/mtls_asgi_app.py +66 -54
- mcp_proxy_adapter/core/protocol_manager.py +154 -104
- mcp_proxy_adapter/core/proxy_client.py +202 -144
- mcp_proxy_adapter/core/proxy_registration.py +7 -3
- mcp_proxy_adapter/core/role_utils.py +139 -125
- mcp_proxy_adapter/core/security_adapter.py +88 -77
- mcp_proxy_adapter/core/security_factory.py +50 -44
- mcp_proxy_adapter/core/security_integration.py +72 -24
- mcp_proxy_adapter/core/server_adapter.py +68 -64
- mcp_proxy_adapter/core/server_engine.py +71 -53
- mcp_proxy_adapter/core/settings.py +68 -58
- mcp_proxy_adapter/core/ssl_utils.py +69 -56
- mcp_proxy_adapter/core/transport_manager.py +72 -60
- mcp_proxy_adapter/core/unified_config_adapter.py +201 -150
- mcp_proxy_adapter/core/utils.py +4 -2
- mcp_proxy_adapter/custom_openapi.py +107 -99
- mcp_proxy_adapter/examples/basic_framework/main.py +9 -2
- mcp_proxy_adapter/examples/commands/__init__.py +1 -1
- mcp_proxy_adapter/examples/create_certificates_simple.py +182 -71
- mcp_proxy_adapter/examples/debug_request_state.py +38 -19
- mcp_proxy_adapter/examples/debug_role_chain.py +53 -20
- mcp_proxy_adapter/examples/demo_client.py +48 -36
- mcp_proxy_adapter/examples/examples/basic_framework/main.py +9 -2
- mcp_proxy_adapter/examples/examples/full_application/__init__.py +1 -0
- mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +22 -10
- mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +24 -17
- mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +16 -3
- mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +13 -3
- mcp_proxy_adapter/examples/examples/full_application/main.py +27 -2
- mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +48 -14
- mcp_proxy_adapter/examples/full_application/__init__.py +1 -0
- mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +22 -10
- mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +24 -17
- mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +16 -3
- mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +13 -3
- mcp_proxy_adapter/examples/full_application/main.py +27 -2
- mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +48 -14
- mcp_proxy_adapter/examples/generate_all_certificates.py +198 -73
- mcp_proxy_adapter/examples/generate_certificates.py +31 -16
- mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +220 -74
- mcp_proxy_adapter/examples/generate_test_configs.py +68 -91
- mcp_proxy_adapter/examples/proxy_registration_example.py +76 -75
- mcp_proxy_adapter/examples/run_example.py +23 -5
- mcp_proxy_adapter/examples/run_full_test_suite.py +109 -71
- mcp_proxy_adapter/examples/run_proxy_server.py +22 -9
- mcp_proxy_adapter/examples/run_security_tests.py +103 -41
- mcp_proxy_adapter/examples/run_security_tests_fixed.py +72 -36
- mcp_proxy_adapter/examples/scripts/config_generator.py +288 -187
- mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +185 -72
- mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +220 -74
- mcp_proxy_adapter/examples/security_test_client.py +196 -127
- mcp_proxy_adapter/examples/setup_test_environment.py +17 -29
- mcp_proxy_adapter/examples/test_config.py +19 -4
- mcp_proxy_adapter/examples/test_config_generator.py +23 -7
- mcp_proxy_adapter/examples/test_examples.py +84 -56
- mcp_proxy_adapter/examples/universal_client.py +119 -62
- mcp_proxy_adapter/openapi.py +108 -115
- mcp_proxy_adapter/utils/config_generator.py +429 -274
- mcp_proxy_adapter/version.py +1 -2
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/METADATA +1 -1
- mcp_proxy_adapter-6.3.5.dist-info/RECORD +143 -0
- mcp_proxy_adapter-6.3.4.dist-info/RECORD +0 -143
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/entry_points.txt +0 -0
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/licenses/LICENSE +0 -0
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/top_level.txt +0 -0
@@ -16,169 +16,197 @@ from mcp_proxy_adapter.core.logging import logger
|
|
16
16
|
class ProtocolManager:
|
17
17
|
"""
|
18
18
|
Manages protocol configurations and validates protocol access.
|
19
|
-
|
19
|
+
|
20
20
|
This class handles the validation of allowed protocols and their associated ports,
|
21
21
|
ensuring that only configured protocols are accessible.
|
22
22
|
"""
|
23
|
-
|
23
|
+
|
24
24
|
def __init__(self, app_config: Optional[Dict] = None):
|
25
25
|
"""
|
26
26
|
Initialize the protocol manager.
|
27
|
-
|
27
|
+
|
28
28
|
Args:
|
29
29
|
app_config: Application configuration dictionary (optional)
|
30
30
|
"""
|
31
31
|
self.app_config = app_config
|
32
32
|
self._load_config()
|
33
|
-
|
33
|
+
|
34
34
|
def _load_config(self):
|
35
35
|
"""Load protocol configuration from config."""
|
36
36
|
# Use provided config or fallback to global config; normalize types
|
37
|
-
current_config =
|
38
|
-
|
37
|
+
current_config = (
|
38
|
+
self.app_config if self.app_config is not None else config.get_all()
|
39
|
+
)
|
40
|
+
logger.debug(
|
41
|
+
f"ProtocolManager._load_config - current_config type: {type(current_config)}"
|
42
|
+
)
|
39
43
|
|
40
|
-
if not hasattr(current_config,
|
44
|
+
if not hasattr(current_config, "get"):
|
41
45
|
# Not a dict-like config, fallback to global
|
42
|
-
logger.debug(
|
46
|
+
logger.debug(
|
47
|
+
f"ProtocolManager._load_config - current_config is not dict-like, falling back to global config"
|
48
|
+
)
|
43
49
|
current_config = config.get_all()
|
44
50
|
|
45
|
-
logger.debug(
|
46
|
-
|
47
|
-
|
51
|
+
logger.debug(
|
52
|
+
f"ProtocolManager._load_config - final current_config type: {type(current_config)}"
|
53
|
+
)
|
54
|
+
if hasattr(current_config, "get"):
|
55
|
+
logger.debug(
|
56
|
+
f"ProtocolManager._load_config - current_config keys: {list(current_config.keys()) if hasattr(current_config, 'keys') else 'no keys'}"
|
57
|
+
)
|
48
58
|
|
49
59
|
# Get protocols configuration
|
50
60
|
logger.debug(f"ProtocolManager._load_config - before getting protocols")
|
51
61
|
try:
|
52
62
|
self.protocols_config = current_config.get("protocols", {})
|
53
|
-
logger.debug(
|
54
|
-
|
55
|
-
|
63
|
+
logger.debug(
|
64
|
+
f"ProtocolManager._load_config - protocols_config type: {type(self.protocols_config)}"
|
65
|
+
)
|
66
|
+
if hasattr(self.protocols_config, "get"):
|
67
|
+
logger.debug(
|
68
|
+
f"ProtocolManager._load_config - protocols_config is dict-like"
|
69
|
+
)
|
56
70
|
else:
|
57
|
-
logger.debug(
|
71
|
+
logger.debug(
|
72
|
+
f"ProtocolManager._load_config - protocols_config is NOT dict-like: {repr(self.protocols_config)}"
|
73
|
+
)
|
58
74
|
except Exception as e:
|
59
75
|
logger.debug(f"ProtocolManager._load_config - ERROR getting protocols: {e}")
|
60
76
|
self.protocols_config = {}
|
61
77
|
|
62
|
-
self.enabled =
|
63
|
-
|
78
|
+
self.enabled = (
|
79
|
+
self.protocols_config.get("enabled", True)
|
80
|
+
if hasattr(self.protocols_config, "get")
|
81
|
+
else True
|
82
|
+
)
|
83
|
+
|
64
84
|
# Get SSL configuration to determine allowed protocols
|
65
85
|
ssl_enabled = self._is_ssl_enabled(current_config)
|
66
|
-
|
86
|
+
|
67
87
|
# Set allowed protocols based on SSL configuration
|
68
88
|
if ssl_enabled:
|
69
89
|
# If SSL is enabled, allow both HTTP and HTTPS
|
70
|
-
self.allowed_protocols = self.protocols_config.get(
|
90
|
+
self.allowed_protocols = self.protocols_config.get(
|
91
|
+
"allowed_protocols", ["http", "https"]
|
92
|
+
)
|
71
93
|
# Ensure HTTPS is in allowed protocols if SSL is enabled
|
72
94
|
if "https" not in self.allowed_protocols:
|
73
95
|
self.allowed_protocols.append("https")
|
74
96
|
else:
|
75
97
|
# If SSL is disabled, only allow HTTP
|
76
|
-
self.allowed_protocols = self.protocols_config.get(
|
98
|
+
self.allowed_protocols = self.protocols_config.get(
|
99
|
+
"allowed_protocols", ["http"]
|
100
|
+
)
|
77
101
|
# Remove HTTPS from allowed protocols if SSL is disabled
|
78
102
|
if "https" in self.allowed_protocols:
|
79
103
|
self.allowed_protocols.remove("https")
|
80
|
-
|
81
|
-
logger.debug(
|
82
|
-
|
104
|
+
|
105
|
+
logger.debug(
|
106
|
+
f"Protocol manager loaded config: enabled={self.enabled}, allowed_protocols={self.allowed_protocols}, ssl_enabled={ssl_enabled}"
|
107
|
+
)
|
108
|
+
|
83
109
|
def _is_ssl_enabled(self, current_config: Dict) -> bool:
|
84
110
|
"""
|
85
111
|
Check if SSL is enabled in configuration.
|
86
|
-
|
112
|
+
|
87
113
|
Args:
|
88
114
|
current_config: Current configuration dictionary
|
89
|
-
|
115
|
+
|
90
116
|
Returns:
|
91
117
|
True if SSL is enabled, False otherwise
|
92
118
|
"""
|
93
119
|
# Try security framework SSL config first
|
94
120
|
security_config = current_config.get("security", {})
|
95
121
|
ssl_config = security_config.get("ssl", {})
|
96
|
-
|
122
|
+
|
97
123
|
if ssl_config.get("enabled", False):
|
98
124
|
logger.debug("SSL enabled via security.ssl configuration")
|
99
125
|
return True
|
100
|
-
|
126
|
+
|
101
127
|
# Fallback to legacy SSL config
|
102
128
|
legacy_ssl_config = current_config.get("ssl", {})
|
103
129
|
if legacy_ssl_config.get("enabled", False):
|
104
130
|
logger.debug("SSL enabled via legacy ssl configuration")
|
105
131
|
return True
|
106
|
-
|
132
|
+
|
107
133
|
logger.debug("SSL is disabled in configuration")
|
108
134
|
return False
|
109
|
-
|
135
|
+
|
110
136
|
def update_config(self, new_config: Dict):
|
111
137
|
"""
|
112
138
|
Update configuration and reload protocol settings.
|
113
|
-
|
139
|
+
|
114
140
|
Args:
|
115
141
|
new_config: New configuration dictionary
|
116
142
|
"""
|
117
143
|
self.app_config = new_config
|
118
144
|
self._load_config()
|
119
|
-
logger.info(
|
120
|
-
|
145
|
+
logger.info(
|
146
|
+
f"Protocol manager configuration updated: allowed_protocols={self.allowed_protocols}"
|
147
|
+
)
|
148
|
+
|
121
149
|
def reload_config(self):
|
122
150
|
"""Reload protocol configuration from global config."""
|
123
151
|
self._load_config()
|
124
|
-
|
152
|
+
|
125
153
|
def is_protocol_allowed(self, protocol: str) -> bool:
|
126
154
|
"""
|
127
155
|
Check if a protocol is allowed based on configuration.
|
128
|
-
|
156
|
+
|
129
157
|
Args:
|
130
158
|
protocol: Protocol name (http, https, mtls)
|
131
|
-
|
159
|
+
|
132
160
|
Returns:
|
133
161
|
True if protocol is allowed, False otherwise
|
134
162
|
"""
|
135
163
|
if not self.enabled:
|
136
164
|
logger.debug("Protocol management is disabled, allowing all protocols")
|
137
165
|
return True
|
138
|
-
|
166
|
+
|
139
167
|
protocol_lower = protocol.lower()
|
140
168
|
is_allowed = protocol_lower in self.allowed_protocols
|
141
|
-
|
169
|
+
|
142
170
|
logger.debug(f"Protocol '{protocol}' allowed: {is_allowed}")
|
143
171
|
return is_allowed
|
144
|
-
|
172
|
+
|
145
173
|
def get_protocol_port(self, protocol: str) -> Optional[int]:
|
146
174
|
"""
|
147
175
|
Get the configured port for a specific protocol.
|
148
|
-
|
176
|
+
|
149
177
|
Args:
|
150
178
|
protocol: Protocol name (http, https, mtls)
|
151
|
-
|
179
|
+
|
152
180
|
Returns:
|
153
181
|
Port number if configured, None otherwise
|
154
182
|
"""
|
155
183
|
protocol_lower = protocol.lower()
|
156
184
|
protocol_config = self.protocols_config.get(protocol_lower, {})
|
157
|
-
|
185
|
+
|
158
186
|
if not protocol_config.get("enabled", False):
|
159
187
|
logger.debug(f"Protocol '{protocol}' is not enabled")
|
160
188
|
return None
|
161
|
-
|
189
|
+
|
162
190
|
port = protocol_config.get("port")
|
163
191
|
logger.debug(f"Protocol '{protocol}' port: {port}")
|
164
192
|
return port
|
165
|
-
|
193
|
+
|
166
194
|
def get_allowed_protocols(self) -> List[str]:
|
167
195
|
"""
|
168
196
|
Get list of all allowed protocols.
|
169
|
-
|
197
|
+
|
170
198
|
Returns:
|
171
199
|
List of allowed protocol names
|
172
200
|
"""
|
173
201
|
return self.allowed_protocols.copy()
|
174
|
-
|
202
|
+
|
175
203
|
def get_protocol_config(self, protocol: str) -> Dict:
|
176
204
|
"""
|
177
205
|
Get full configuration for a specific protocol.
|
178
|
-
|
206
|
+
|
179
207
|
Args:
|
180
208
|
protocol: Protocol name (http, https, mtls)
|
181
|
-
|
209
|
+
|
182
210
|
Returns:
|
183
211
|
Protocol configuration dictionary
|
184
212
|
"""
|
@@ -191,118 +219,128 @@ class ProtocolManager:
|
|
191
219
|
except Exception:
|
192
220
|
return {}
|
193
221
|
return {}
|
194
|
-
|
222
|
+
|
195
223
|
def validate_url_protocol(self, url: str) -> Tuple[bool, Optional[str]]:
|
196
224
|
"""
|
197
225
|
Validate if the URL protocol is allowed.
|
198
|
-
|
226
|
+
|
199
227
|
Args:
|
200
228
|
url: URL to validate
|
201
|
-
|
229
|
+
|
202
230
|
Returns:
|
203
231
|
Tuple of (is_allowed, error_message)
|
204
232
|
"""
|
205
233
|
try:
|
206
234
|
parsed = urlparse(url)
|
207
235
|
protocol = parsed.scheme.lower()
|
208
|
-
|
236
|
+
|
209
237
|
if not protocol:
|
210
238
|
return False, "No protocol specified in URL"
|
211
|
-
|
239
|
+
|
212
240
|
if not self.is_protocol_allowed(protocol):
|
213
|
-
return
|
214
|
-
|
241
|
+
return (
|
242
|
+
False,
|
243
|
+
f"Protocol '{protocol}' is not allowed. Allowed protocols: {self.allowed_protocols}",
|
244
|
+
)
|
245
|
+
|
215
246
|
return True, None
|
216
|
-
|
247
|
+
|
217
248
|
except Exception as e:
|
218
249
|
return False, f"Invalid URL format: {str(e)}"
|
219
|
-
|
250
|
+
|
220
251
|
def get_ssl_context_for_protocol(self, protocol: str) -> Optional[ssl.SSLContext]:
|
221
252
|
"""
|
222
253
|
Get SSL context for HTTPS or MTLS protocol.
|
223
|
-
|
254
|
+
|
224
255
|
Args:
|
225
256
|
protocol: Protocol name (https, mtls)
|
226
|
-
|
257
|
+
|
227
258
|
Returns:
|
228
259
|
SSL context if protocol requires SSL, None otherwise
|
229
260
|
"""
|
230
261
|
if protocol.lower() not in ["https", "mtls"]:
|
231
262
|
return None
|
232
|
-
|
263
|
+
|
233
264
|
# Use provided config or fallback to global config
|
234
|
-
current_config =
|
235
|
-
|
265
|
+
current_config = (
|
266
|
+
self.app_config if self.app_config is not None else config.get_all()
|
267
|
+
)
|
268
|
+
|
236
269
|
# Get SSL configuration
|
237
270
|
ssl_config = self._get_ssl_config(current_config)
|
238
|
-
|
271
|
+
|
239
272
|
if not ssl_config.get("enabled", False):
|
240
|
-
logger.warning(
|
273
|
+
logger.warning(
|
274
|
+
f"SSL required for protocol '{protocol}' but SSL is disabled"
|
275
|
+
)
|
241
276
|
return None
|
242
|
-
|
277
|
+
|
243
278
|
cert_file = ssl_config.get("cert_file")
|
244
279
|
key_file = ssl_config.get("key_file")
|
245
|
-
|
280
|
+
|
246
281
|
if not cert_file or not key_file:
|
247
|
-
logger.warning(
|
282
|
+
logger.warning(
|
283
|
+
f"SSL required for protocol '{protocol}' but certificate files not configured"
|
284
|
+
)
|
248
285
|
return None
|
249
|
-
|
286
|
+
|
250
287
|
try:
|
251
288
|
from mcp_proxy_adapter.core.ssl_utils import SSLUtils
|
252
|
-
|
289
|
+
|
253
290
|
ssl_context = SSLUtils.create_ssl_context(
|
254
291
|
cert_file=cert_file,
|
255
292
|
key_file=key_file,
|
256
293
|
ca_cert=ssl_config.get("ca_cert"),
|
257
|
-
verify_client=protocol.lower() == "mtls"
|
294
|
+
verify_client=protocol.lower() == "mtls"
|
295
|
+
or ssl_config.get("verify_client", False),
|
258
296
|
cipher_suites=ssl_config.get("cipher_suites", []),
|
259
297
|
min_tls_version=ssl_config.get("min_tls_version", "1.2"),
|
260
|
-
max_tls_version=ssl_config.get("max_tls_version", "1.3")
|
298
|
+
max_tls_version=ssl_config.get("max_tls_version", "1.3"),
|
261
299
|
)
|
262
|
-
|
300
|
+
|
263
301
|
logger.info(f"SSL context created for protocol '{protocol}'")
|
264
302
|
return ssl_context
|
265
|
-
|
303
|
+
|
266
304
|
except Exception as e:
|
267
305
|
logger.error(f"Failed to create SSL context for protocol '{protocol}': {e}")
|
268
306
|
return None
|
269
|
-
|
307
|
+
|
270
308
|
def _get_ssl_config(self, current_config: Dict) -> Dict:
|
271
309
|
"""
|
272
310
|
Get SSL configuration from config.
|
273
|
-
|
311
|
+
|
274
312
|
Args:
|
275
313
|
current_config: Current configuration dictionary
|
276
|
-
|
314
|
+
|
277
315
|
Returns:
|
278
316
|
SSL configuration dictionary
|
279
317
|
"""
|
280
318
|
# Try security framework SSL config first
|
281
319
|
security_config = current_config.get("security", {})
|
282
320
|
ssl_config = security_config.get("ssl", {})
|
283
|
-
|
321
|
+
|
284
322
|
if ssl_config.get("enabled", False):
|
285
323
|
logger.debug("Using security.ssl configuration")
|
286
324
|
return ssl_config
|
287
|
-
|
325
|
+
|
288
326
|
# Fallback to legacy SSL config
|
289
327
|
legacy_ssl_config = current_config.get("ssl", {})
|
290
328
|
if legacy_ssl_config.get("enabled", False):
|
291
329
|
logger.debug("Using legacy ssl configuration")
|
292
330
|
return legacy_ssl_config
|
293
|
-
|
331
|
+
|
294
332
|
# Return empty config if SSL is disabled
|
295
333
|
return {"enabled": False}
|
296
|
-
|
334
|
+
|
297
335
|
def get_protocol_info(self) -> Dict[str, Dict]:
|
298
336
|
"""
|
299
337
|
Get information about all configured protocols.
|
300
|
-
|
338
|
+
|
301
339
|
Returns:
|
302
340
|
Dictionary with protocol information
|
303
341
|
"""
|
304
342
|
info = {}
|
305
|
-
|
343
|
+
|
306
344
|
for protocol in ["http", "https", "mtls"]:
|
307
345
|
protocol_config = self.get_protocol_config(protocol)
|
308
346
|
info[protocol] = {
|
@@ -310,76 +348,88 @@ class ProtocolManager:
|
|
310
348
|
"allowed": self.is_protocol_allowed(protocol),
|
311
349
|
"port": protocol_config.get("port"),
|
312
350
|
"requires_ssl": protocol in ["https", "mtls"],
|
313
|
-
"ssl_context_available": self.get_ssl_context_for_protocol(protocol)
|
351
|
+
"ssl_context_available": self.get_ssl_context_for_protocol(protocol)
|
352
|
+
is not None,
|
314
353
|
}
|
315
|
-
|
354
|
+
|
316
355
|
return info
|
317
|
-
|
356
|
+
|
318
357
|
def validate_protocol_configuration(self) -> List[str]:
|
319
358
|
"""
|
320
359
|
Validate the current protocol configuration.
|
321
|
-
|
360
|
+
|
322
361
|
Returns:
|
323
362
|
List of validation errors (empty if configuration is valid)
|
324
363
|
"""
|
325
364
|
errors = []
|
326
|
-
|
365
|
+
|
327
366
|
if not self.enabled:
|
328
367
|
return errors
|
329
|
-
|
368
|
+
|
330
369
|
# Check if allowed protocols are configured
|
331
370
|
for protocol in self.allowed_protocols:
|
332
371
|
if protocol not in ["http", "https", "mtls"]:
|
333
372
|
errors.append(f"Unknown protocol '{protocol}' in allowed_protocols")
|
334
373
|
continue
|
335
|
-
|
374
|
+
|
336
375
|
protocol_config = self.get_protocol_config(protocol)
|
337
|
-
|
376
|
+
|
338
377
|
if not protocol_config.get("enabled", False):
|
339
|
-
errors.append(
|
378
|
+
errors.append(
|
379
|
+
f"Protocol '{protocol}' is in allowed_protocols but not enabled"
|
380
|
+
)
|
340
381
|
continue
|
341
|
-
|
382
|
+
|
342
383
|
port = protocol_config.get("port")
|
343
384
|
if not port:
|
344
|
-
errors.append(
|
385
|
+
errors.append(
|
386
|
+
f"Protocol '{protocol}' is enabled but no port configured"
|
387
|
+
)
|
345
388
|
continue
|
346
|
-
|
389
|
+
|
347
390
|
# Check SSL requirements
|
348
391
|
if protocol in ["https", "mtls"]:
|
349
392
|
# Use provided config or fallback to global config
|
350
|
-
current_config =
|
393
|
+
current_config = (
|
394
|
+
self.app_config if self.app_config is not None else config.get_all()
|
395
|
+
)
|
351
396
|
ssl_config = self._get_ssl_config(current_config)
|
352
|
-
|
397
|
+
|
353
398
|
if not ssl_config.get("enabled", False):
|
354
|
-
errors.append(
|
399
|
+
errors.append(
|
400
|
+
f"Protocol '{protocol}' requires SSL but SSL is disabled"
|
401
|
+
)
|
355
402
|
elif not ssl_config.get("cert_file") or not ssl_config.get("key_file"):
|
356
|
-
errors.append(
|
357
|
-
|
403
|
+
errors.append(
|
404
|
+
f"Protocol '{protocol}' requires SSL but certificate files not configured"
|
405
|
+
)
|
406
|
+
|
358
407
|
return errors
|
359
408
|
|
360
409
|
|
361
410
|
# Global protocol manager instance - will be updated with config when needed
|
362
411
|
protocol_manager = None
|
363
412
|
|
413
|
+
|
364
414
|
def get_protocol_manager(app_config: Optional[Dict] = None) -> ProtocolManager:
|
365
415
|
"""
|
366
416
|
Get protocol manager instance with current configuration.
|
367
|
-
|
417
|
+
|
368
418
|
Args:
|
369
419
|
app_config: Application configuration dictionary (optional)
|
370
|
-
|
420
|
+
|
371
421
|
Returns:
|
372
422
|
ProtocolManager instance
|
373
423
|
"""
|
374
424
|
global protocol_manager
|
375
|
-
|
425
|
+
|
376
426
|
# If no app_config provided, use global config
|
377
427
|
if app_config is None:
|
378
428
|
app_config = config.get_all()
|
379
|
-
|
429
|
+
|
380
430
|
# Create new instance if none exists or config changed
|
381
431
|
if protocol_manager is None or protocol_manager.app_config != app_config:
|
382
432
|
protocol_manager = ProtocolManager(app_config)
|
383
433
|
logger.info("Protocol manager created with new configuration")
|
384
|
-
|
385
|
-
return protocol_manager
|
434
|
+
|
435
|
+
return protocol_manager
|