mcp-proxy-adapter 6.3.4__py3-none-any.whl → 6.3.6__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 (131) hide show
  1. mcp_proxy_adapter/__init__.py +9 -5
  2. mcp_proxy_adapter/__main__.py +1 -1
  3. mcp_proxy_adapter/api/app.py +227 -176
  4. mcp_proxy_adapter/api/handlers.py +68 -60
  5. mcp_proxy_adapter/api/middleware/__init__.py +7 -5
  6. mcp_proxy_adapter/api/middleware/base.py +19 -16
  7. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +44 -34
  8. mcp_proxy_adapter/api/middleware/error_handling.py +57 -67
  9. mcp_proxy_adapter/api/middleware/factory.py +50 -52
  10. mcp_proxy_adapter/api/middleware/logging.py +46 -30
  11. mcp_proxy_adapter/api/middleware/performance.py +19 -16
  12. mcp_proxy_adapter/api/middleware/protocol_middleware.py +80 -50
  13. mcp_proxy_adapter/api/middleware/transport_middleware.py +26 -24
  14. mcp_proxy_adapter/api/middleware/unified_security.py +70 -51
  15. mcp_proxy_adapter/api/middleware/user_info_middleware.py +43 -34
  16. mcp_proxy_adapter/api/schemas.py +69 -43
  17. mcp_proxy_adapter/api/tool_integration.py +83 -63
  18. mcp_proxy_adapter/api/tools.py +60 -50
  19. mcp_proxy_adapter/commands/__init__.py +15 -6
  20. mcp_proxy_adapter/commands/auth_validation_command.py +107 -110
  21. mcp_proxy_adapter/commands/base.py +108 -112
  22. mcp_proxy_adapter/commands/builtin_commands.py +28 -18
  23. mcp_proxy_adapter/commands/catalog_manager.py +394 -265
  24. mcp_proxy_adapter/commands/cert_monitor_command.py +222 -204
  25. mcp_proxy_adapter/commands/certificate_management_command.py +210 -213
  26. mcp_proxy_adapter/commands/command_registry.py +275 -226
  27. mcp_proxy_adapter/commands/config_command.py +48 -33
  28. mcp_proxy_adapter/commands/dependency_container.py +22 -23
  29. mcp_proxy_adapter/commands/dependency_manager.py +65 -56
  30. mcp_proxy_adapter/commands/echo_command.py +15 -15
  31. mcp_proxy_adapter/commands/health_command.py +31 -29
  32. mcp_proxy_adapter/commands/help_command.py +97 -61
  33. mcp_proxy_adapter/commands/hooks.py +65 -49
  34. mcp_proxy_adapter/commands/key_management_command.py +148 -147
  35. mcp_proxy_adapter/commands/load_command.py +58 -40
  36. mcp_proxy_adapter/commands/plugins_command.py +80 -54
  37. mcp_proxy_adapter/commands/protocol_management_command.py +60 -48
  38. mcp_proxy_adapter/commands/proxy_registration_command.py +107 -115
  39. mcp_proxy_adapter/commands/reload_command.py +43 -37
  40. mcp_proxy_adapter/commands/result.py +26 -33
  41. mcp_proxy_adapter/commands/role_test_command.py +26 -26
  42. mcp_proxy_adapter/commands/roles_management_command.py +176 -173
  43. mcp_proxy_adapter/commands/security_command.py +134 -122
  44. mcp_proxy_adapter/commands/settings_command.py +47 -56
  45. mcp_proxy_adapter/commands/ssl_setup_command.py +109 -129
  46. mcp_proxy_adapter/commands/token_management_command.py +129 -158
  47. mcp_proxy_adapter/commands/transport_management_command.py +41 -36
  48. mcp_proxy_adapter/commands/unload_command.py +42 -37
  49. mcp_proxy_adapter/config.py +36 -35
  50. mcp_proxy_adapter/core/__init__.py +19 -21
  51. mcp_proxy_adapter/core/app_factory.py +30 -9
  52. mcp_proxy_adapter/core/app_runner.py +81 -64
  53. mcp_proxy_adapter/core/auth_validator.py +176 -182
  54. mcp_proxy_adapter/core/certificate_utils.py +469 -426
  55. mcp_proxy_adapter/core/client.py +155 -126
  56. mcp_proxy_adapter/core/client_manager.py +60 -54
  57. mcp_proxy_adapter/core/client_security.py +120 -91
  58. mcp_proxy_adapter/core/config_converter.py +176 -143
  59. mcp_proxy_adapter/core/config_validator.py +12 -4
  60. mcp_proxy_adapter/core/crl_utils.py +21 -7
  61. mcp_proxy_adapter/core/errors.py +64 -20
  62. mcp_proxy_adapter/core/logging.py +34 -29
  63. mcp_proxy_adapter/core/mtls_asgi.py +29 -25
  64. mcp_proxy_adapter/core/mtls_asgi_app.py +66 -54
  65. mcp_proxy_adapter/core/protocol_manager.py +154 -104
  66. mcp_proxy_adapter/core/proxy_client.py +202 -144
  67. mcp_proxy_adapter/core/proxy_registration.py +7 -3
  68. mcp_proxy_adapter/core/role_utils.py +139 -125
  69. mcp_proxy_adapter/core/security_adapter.py +88 -77
  70. mcp_proxy_adapter/core/security_factory.py +50 -44
  71. mcp_proxy_adapter/core/security_integration.py +72 -24
  72. mcp_proxy_adapter/core/server_adapter.py +68 -64
  73. mcp_proxy_adapter/core/server_engine.py +71 -53
  74. mcp_proxy_adapter/core/settings.py +68 -58
  75. mcp_proxy_adapter/core/ssl_utils.py +69 -56
  76. mcp_proxy_adapter/core/transport_manager.py +72 -60
  77. mcp_proxy_adapter/core/unified_config_adapter.py +201 -150
  78. mcp_proxy_adapter/core/utils.py +4 -2
  79. mcp_proxy_adapter/custom_openapi.py +107 -99
  80. mcp_proxy_adapter/examples/basic_framework/main.py +9 -2
  81. mcp_proxy_adapter/examples/commands/__init__.py +1 -1
  82. mcp_proxy_adapter/examples/create_certificates_simple.py +182 -71
  83. mcp_proxy_adapter/examples/debug_request_state.py +38 -19
  84. mcp_proxy_adapter/examples/debug_role_chain.py +53 -20
  85. mcp_proxy_adapter/examples/demo_client.py +48 -36
  86. mcp_proxy_adapter/examples/examples/basic_framework/main.py +9 -2
  87. mcp_proxy_adapter/examples/examples/full_application/__init__.py +1 -0
  88. mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +22 -10
  89. mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +24 -17
  90. mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +16 -3
  91. mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +13 -3
  92. mcp_proxy_adapter/examples/examples/full_application/main.py +27 -2
  93. mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +48 -14
  94. mcp_proxy_adapter/examples/full_application/__init__.py +1 -0
  95. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +22 -10
  96. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +24 -17
  97. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +16 -3
  98. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +13 -3
  99. mcp_proxy_adapter/examples/full_application/main.py +27 -2
  100. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +48 -14
  101. mcp_proxy_adapter/examples/generate_all_certificates.py +198 -73
  102. mcp_proxy_adapter/examples/generate_certificates.py +31 -16
  103. mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +220 -74
  104. mcp_proxy_adapter/examples/generate_test_configs.py +68 -91
  105. mcp_proxy_adapter/examples/proxy_registration_example.py +76 -75
  106. mcp_proxy_adapter/examples/run_example.py +23 -5
  107. mcp_proxy_adapter/examples/run_full_test_suite.py +109 -71
  108. mcp_proxy_adapter/examples/run_proxy_server.py +22 -9
  109. mcp_proxy_adapter/examples/run_security_tests.py +103 -41
  110. mcp_proxy_adapter/examples/run_security_tests_fixed.py +72 -36
  111. mcp_proxy_adapter/examples/scripts/config_generator.py +288 -187
  112. mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +185 -72
  113. mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +220 -74
  114. mcp_proxy_adapter/examples/security_test_client.py +196 -127
  115. mcp_proxy_adapter/examples/setup_test_environment.py +17 -29
  116. mcp_proxy_adapter/examples/test_config.py +19 -4
  117. mcp_proxy_adapter/examples/test_config_generator.py +23 -7
  118. mcp_proxy_adapter/examples/test_examples.py +84 -56
  119. mcp_proxy_adapter/examples/universal_client.py +119 -62
  120. mcp_proxy_adapter/openapi.py +108 -115
  121. mcp_proxy_adapter/utils/config_generator.py +429 -274
  122. mcp_proxy_adapter/version.py +1 -2
  123. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/METADATA +1 -1
  124. mcp_proxy_adapter-6.3.6.dist-info/RECORD +144 -0
  125. mcp_proxy_adapter-6.3.6.dist-info/top_level.txt +2 -0
  126. mcp_proxy_adapter_issue_package/demonstrate_issue.py +178 -0
  127. mcp_proxy_adapter-6.3.4.dist-info/RECORD +0 -143
  128. mcp_proxy_adapter-6.3.4.dist-info/top_level.txt +0 -1
  129. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/WHEEL +0 -0
  130. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/entry_points.txt +0 -0
  131. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/licenses/LICENSE +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 = self.app_config if self.app_config is not None else config.get_all()
38
- logger.debug(f"ProtocolManager._load_config - current_config type: {type(current_config)}")
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, 'get'):
44
+ if not hasattr(current_config, "get"):
41
45
  # Not a dict-like config, fallback to global
42
- logger.debug(f"ProtocolManager._load_config - current_config is not dict-like, falling back to global config")
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(f"ProtocolManager._load_config - final current_config type: {type(current_config)}")
46
- if hasattr(current_config, 'get'):
47
- logger.debug(f"ProtocolManager._load_config - current_config keys: {list(current_config.keys()) if hasattr(current_config, 'keys') else 'no keys'}")
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(f"ProtocolManager._load_config - protocols_config type: {type(self.protocols_config)}")
54
- if hasattr(self.protocols_config, 'get'):
55
- logger.debug(f"ProtocolManager._load_config - protocols_config is dict-like")
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(f"ProtocolManager._load_config - protocols_config is NOT dict-like: {repr(self.protocols_config)}")
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 = self.protocols_config.get("enabled", True) if hasattr(self.protocols_config, 'get') else True
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("allowed_protocols", ["http", "https"])
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("allowed_protocols", ["http"])
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(f"Protocol manager loaded config: enabled={self.enabled}, allowed_protocols={self.allowed_protocols}, ssl_enabled={ssl_enabled}")
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(f"Protocol manager configuration updated: allowed_protocols={self.allowed_protocols}")
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 False, f"Protocol '{protocol}' is not allowed. Allowed protocols: {self.allowed_protocols}"
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 = self.app_config if self.app_config is not None else config.get_all()
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(f"SSL required for protocol '{protocol}' but SSL is disabled")
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(f"SSL required for protocol '{protocol}' but certificate files not configured")
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" or ssl_config.get("verify_client", False),
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) is not None
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(f"Protocol '{protocol}' is in allowed_protocols but not enabled")
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(f"Protocol '{protocol}' is enabled but no port configured")
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 = self.app_config if self.app_config is not None else config.get_all()
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(f"Protocol '{protocol}' requires SSL but SSL is disabled")
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(f"Protocol '{protocol}' requires SSL but certificate files not configured")
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