mcp-proxy-adapter 2.0.1__py3-none-any.whl → 6.9.50__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.
Potentially problematic release.
This version of mcp-proxy-adapter might be problematic. Click here for more details.
- mcp_proxy_adapter/__init__.py +47 -0
- mcp_proxy_adapter/__main__.py +13 -0
- mcp_proxy_adapter/api/__init__.py +0 -0
- mcp_proxy_adapter/api/app.py +66 -0
- mcp_proxy_adapter/api/core/__init__.py +18 -0
- mcp_proxy_adapter/api/core/app_factory.py +400 -0
- mcp_proxy_adapter/api/core/lifespan_manager.py +55 -0
- mcp_proxy_adapter/api/core/registration_context.py +356 -0
- mcp_proxy_adapter/api/core/registration_manager.py +307 -0
- mcp_proxy_adapter/api/core/registration_tasks.py +84 -0
- mcp_proxy_adapter/api/core/ssl_context_factory.py +88 -0
- mcp_proxy_adapter/api/handlers.py +181 -0
- mcp_proxy_adapter/api/middleware/__init__.py +21 -0
- mcp_proxy_adapter/api/middleware/base.py +54 -0
- mcp_proxy_adapter/api/middleware/command_permission_middleware.py +73 -0
- mcp_proxy_adapter/api/middleware/error_handling.py +76 -0
- mcp_proxy_adapter/api/middleware/factory.py +147 -0
- mcp_proxy_adapter/api/middleware/logging.py +31 -0
- mcp_proxy_adapter/api/middleware/performance.py +51 -0
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +140 -0
- mcp_proxy_adapter/api/middleware/transport_middleware.py +87 -0
- mcp_proxy_adapter/api/middleware/unified_security.py +223 -0
- mcp_proxy_adapter/api/middleware/user_info_middleware.py +132 -0
- mcp_proxy_adapter/api/openapi/__init__.py +21 -0
- mcp_proxy_adapter/api/openapi/command_integration.py +105 -0
- mcp_proxy_adapter/api/openapi/openapi_generator.py +40 -0
- mcp_proxy_adapter/api/openapi/openapi_registry.py +62 -0
- mcp_proxy_adapter/api/openapi/schema_loader.py +116 -0
- mcp_proxy_adapter/api/schemas.py +270 -0
- mcp_proxy_adapter/api/tool_integration.py +131 -0
- mcp_proxy_adapter/api/tools.py +163 -0
- mcp_proxy_adapter/cli/__init__.py +12 -0
- mcp_proxy_adapter/cli/commands/__init__.py +15 -0
- mcp_proxy_adapter/cli/commands/client.py +100 -0
- mcp_proxy_adapter/cli/commands/config_generate.py +105 -0
- mcp_proxy_adapter/cli/commands/config_validate.py +94 -0
- mcp_proxy_adapter/cli/commands/generate.py +259 -0
- mcp_proxy_adapter/cli/commands/server.py +174 -0
- mcp_proxy_adapter/cli/commands/sets.py +132 -0
- mcp_proxy_adapter/cli/commands/testconfig.py +177 -0
- mcp_proxy_adapter/cli/examples/__init__.py +8 -0
- mcp_proxy_adapter/cli/examples/http_basic.py +82 -0
- mcp_proxy_adapter/cli/examples/https_token.py +96 -0
- mcp_proxy_adapter/cli/examples/mtls_roles.py +103 -0
- mcp_proxy_adapter/cli/main.py +63 -0
- mcp_proxy_adapter/cli/parser.py +338 -0
- mcp_proxy_adapter/cli/validators.py +231 -0
- mcp_proxy_adapter/client/jsonrpc_client/__init__.py +9 -0
- mcp_proxy_adapter/client/jsonrpc_client/client.py +42 -0
- mcp_proxy_adapter/client/jsonrpc_client/command_api.py +45 -0
- mcp_proxy_adapter/client/jsonrpc_client/proxy_api.py +224 -0
- mcp_proxy_adapter/client/jsonrpc_client/queue_api.py +60 -0
- mcp_proxy_adapter/client/jsonrpc_client/transport.py +108 -0
- mcp_proxy_adapter/client/proxy.py +123 -0
- mcp_proxy_adapter/commands/__init__.py +66 -0
- mcp_proxy_adapter/commands/auth_validation_command.py +69 -0
- mcp_proxy_adapter/commands/base.py +389 -0
- mcp_proxy_adapter/commands/builtin_commands.py +30 -0
- mcp_proxy_adapter/commands/catalog/__init__.py +20 -0
- mcp_proxy_adapter/commands/catalog/catalog_loader.py +34 -0
- mcp_proxy_adapter/commands/catalog/catalog_manager.py +122 -0
- mcp_proxy_adapter/commands/catalog/catalog_syncer.py +149 -0
- mcp_proxy_adapter/commands/catalog/command_catalog.py +43 -0
- mcp_proxy_adapter/commands/catalog/dependency_manager.py +37 -0
- mcp_proxy_adapter/commands/catalog_manager.py +97 -0
- mcp_proxy_adapter/commands/cert_monitor_command.py +552 -0
- mcp_proxy_adapter/commands/certificate_management_command.py +562 -0
- mcp_proxy_adapter/commands/command_registry.py +298 -0
- mcp_proxy_adapter/commands/config_command.py +102 -0
- mcp_proxy_adapter/commands/dependency_container.py +40 -0
- mcp_proxy_adapter/commands/dependency_manager.py +143 -0
- mcp_proxy_adapter/commands/echo_command.py +48 -0
- mcp_proxy_adapter/commands/health_command.py +142 -0
- mcp_proxy_adapter/commands/help_command.py +175 -0
- mcp_proxy_adapter/commands/hooks.py +172 -0
- mcp_proxy_adapter/commands/key_management_command.py +484 -0
- mcp_proxy_adapter/commands/load_command.py +123 -0
- mcp_proxy_adapter/commands/plugins_command.py +246 -0
- mcp_proxy_adapter/commands/protocol_management_command.py +216 -0
- mcp_proxy_adapter/commands/proxy_registration_command.py +319 -0
- mcp_proxy_adapter/commands/queue_commands.py +750 -0
- mcp_proxy_adapter/commands/registration_status_command.py +76 -0
- mcp_proxy_adapter/commands/registry/__init__.py +18 -0
- mcp_proxy_adapter/commands/registry/command_info.py +103 -0
- mcp_proxy_adapter/commands/registry/command_loader.py +207 -0
- mcp_proxy_adapter/commands/registry/command_manager.py +119 -0
- mcp_proxy_adapter/commands/registry/command_registry.py +217 -0
- mcp_proxy_adapter/commands/reload_command.py +136 -0
- mcp_proxy_adapter/commands/result.py +157 -0
- mcp_proxy_adapter/commands/role_test_command.py +99 -0
- mcp_proxy_adapter/commands/roles_management_command.py +502 -0
- mcp_proxy_adapter/commands/security_command.py +472 -0
- mcp_proxy_adapter/commands/settings_command.py +113 -0
- mcp_proxy_adapter/commands/ssl_setup_command.py +306 -0
- mcp_proxy_adapter/commands/token_management_command.py +500 -0
- mcp_proxy_adapter/commands/transport_management_command.py +129 -0
- mcp_proxy_adapter/commands/unload_command.py +92 -0
- mcp_proxy_adapter/config.py +32 -0
- mcp_proxy_adapter/core/__init__.py +8 -0
- mcp_proxy_adapter/core/app_factory.py +560 -0
- mcp_proxy_adapter/core/app_runner.py +318 -0
- mcp_proxy_adapter/core/auth_validator.py +508 -0
- mcp_proxy_adapter/core/certificate/__init__.py +20 -0
- mcp_proxy_adapter/core/certificate/certificate_creator.py +372 -0
- mcp_proxy_adapter/core/certificate/certificate_extractor.py +185 -0
- mcp_proxy_adapter/core/certificate/certificate_utils.py +249 -0
- mcp_proxy_adapter/core/certificate/certificate_validator.py +481 -0
- mcp_proxy_adapter/core/certificate/ssl_context_manager.py +65 -0
- mcp_proxy_adapter/core/certificate_utils.py +249 -0
- mcp_proxy_adapter/core/client.py +608 -0
- mcp_proxy_adapter/core/client_manager.py +271 -0
- mcp_proxy_adapter/core/client_security.py +411 -0
- mcp_proxy_adapter/core/config/__init__.py +18 -0
- mcp_proxy_adapter/core/config/config.py +237 -0
- mcp_proxy_adapter/core/config/config_factory.py +22 -0
- mcp_proxy_adapter/core/config/config_loader.py +66 -0
- mcp_proxy_adapter/core/config/feature_manager.py +31 -0
- mcp_proxy_adapter/core/config/simple_config.py +204 -0
- mcp_proxy_adapter/core/config/simple_config_generator.py +131 -0
- mcp_proxy_adapter/core/config/simple_config_validator.py +476 -0
- mcp_proxy_adapter/core/config_converter.py +252 -0
- mcp_proxy_adapter/core/config_validator.py +211 -0
- mcp_proxy_adapter/core/crl_utils.py +362 -0
- mcp_proxy_adapter/core/errors.py +276 -0
- mcp_proxy_adapter/core/job_manager.py +54 -0
- mcp_proxy_adapter/core/logging.py +250 -0
- mcp_proxy_adapter/core/mtls_asgi.py +140 -0
- mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
- mcp_proxy_adapter/core/mtls_proxy.py +229 -0
- mcp_proxy_adapter/core/mtls_server.py +154 -0
- mcp_proxy_adapter/core/protocol_manager.py +232 -0
- mcp_proxy_adapter/core/proxy/__init__.py +19 -0
- mcp_proxy_adapter/core/proxy/auth_manager.py +26 -0
- mcp_proxy_adapter/core/proxy/proxy_registration_manager.py +160 -0
- mcp_proxy_adapter/core/proxy/registration_client.py +186 -0
- mcp_proxy_adapter/core/proxy/ssl_manager.py +101 -0
- mcp_proxy_adapter/core/proxy_client.py +184 -0
- mcp_proxy_adapter/core/proxy_registration.py +80 -0
- mcp_proxy_adapter/core/role_utils.py +103 -0
- mcp_proxy_adapter/core/security_adapter.py +343 -0
- mcp_proxy_adapter/core/security_factory.py +96 -0
- mcp_proxy_adapter/core/security_integration.py +342 -0
- mcp_proxy_adapter/core/server_adapter.py +251 -0
- mcp_proxy_adapter/core/server_engine.py +217 -0
- mcp_proxy_adapter/core/settings.py +260 -0
- mcp_proxy_adapter/core/signal_handler.py +107 -0
- mcp_proxy_adapter/core/ssl_utils.py +161 -0
- mcp_proxy_adapter/core/transport_manager.py +153 -0
- mcp_proxy_adapter/core/unified_config_adapter.py +471 -0
- mcp_proxy_adapter/core/utils.py +101 -0
- mcp_proxy_adapter/core/validation/__init__.py +21 -0
- mcp_proxy_adapter/core/validation/config_validator.py +219 -0
- mcp_proxy_adapter/core/validation/file_validator.py +131 -0
- mcp_proxy_adapter/core/validation/protocol_validator.py +205 -0
- mcp_proxy_adapter/core/validation/security_validator.py +140 -0
- mcp_proxy_adapter/core/validation/validation_result.py +27 -0
- mcp_proxy_adapter/custom_openapi.py +58 -0
- mcp_proxy_adapter/examples/__init__.py +16 -0
- mcp_proxy_adapter/examples/basic_framework/__init__.py +9 -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 +52 -0
- mcp_proxy_adapter/examples/bugfix_certificate_config.py +261 -0
- mcp_proxy_adapter/examples/cert_manager_bugfix.py +203 -0
- mcp_proxy_adapter/examples/check_config.py +413 -0
- mcp_proxy_adapter/examples/client_usage_example.py +164 -0
- mcp_proxy_adapter/examples/commands/__init__.py +5 -0
- mcp_proxy_adapter/examples/config_builder.py +234 -0
- mcp_proxy_adapter/examples/config_cli.py +282 -0
- mcp_proxy_adapter/examples/create_test_configs.py +174 -0
- mcp_proxy_adapter/examples/debug_request_state.py +130 -0
- mcp_proxy_adapter/examples/debug_role_chain.py +191 -0
- mcp_proxy_adapter/examples/demo_client.py +287 -0
- mcp_proxy_adapter/examples/full_application/__init__.py +12 -0
- mcp_proxy_adapter/examples/full_application/commands/__init__.py +8 -0
- mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +45 -0
- mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +52 -0
- mcp_proxy_adapter/examples/full_application/commands/echo_command.py +32 -0
- mcp_proxy_adapter/examples/full_application/commands/help_command.py +54 -0
- mcp_proxy_adapter/examples/full_application/commands/list_command.py +57 -0
- mcp_proxy_adapter/examples/full_application/hooks/__init__.py +5 -0
- mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +29 -0
- mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +27 -0
- mcp_proxy_adapter/examples/full_application/main.py +311 -0
- mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +161 -0
- mcp_proxy_adapter/examples/full_application/run_mtls.py +252 -0
- mcp_proxy_adapter/examples/full_application/run_simple.py +152 -0
- mcp_proxy_adapter/examples/full_application/test_minimal_server.py +45 -0
- mcp_proxy_adapter/examples/full_application/test_server.py +163 -0
- mcp_proxy_adapter/examples/full_application/test_simple_server.py +62 -0
- mcp_proxy_adapter/examples/generate_config.py +502 -0
- mcp_proxy_adapter/examples/proxy_registration_example.py +335 -0
- mcp_proxy_adapter/examples/queue_demo_simple.py +632 -0
- mcp_proxy_adapter/examples/queue_integration_example.py +578 -0
- mcp_proxy_adapter/examples/queue_server_demo.py +82 -0
- mcp_proxy_adapter/examples/queue_server_example.py +85 -0
- mcp_proxy_adapter/examples/queue_server_simple.py +173 -0
- mcp_proxy_adapter/examples/required_certificates.py +208 -0
- mcp_proxy_adapter/examples/run_example.py +77 -0
- mcp_proxy_adapter/examples/run_full_test_suite.py +619 -0
- mcp_proxy_adapter/examples/run_proxy_server.py +153 -0
- mcp_proxy_adapter/examples/run_security_tests_fixed.py +435 -0
- mcp_proxy_adapter/examples/security_test/__init__.py +18 -0
- mcp_proxy_adapter/examples/security_test/auth_manager.py +14 -0
- mcp_proxy_adapter/examples/security_test/ssl_context_manager.py +28 -0
- mcp_proxy_adapter/examples/security_test/test_client.py +159 -0
- mcp_proxy_adapter/examples/security_test/test_result.py +22 -0
- mcp_proxy_adapter/examples/security_test_client.py +72 -0
- mcp_proxy_adapter/examples/setup/__init__.py +24 -0
- mcp_proxy_adapter/examples/setup/certificate_manager.py +215 -0
- mcp_proxy_adapter/examples/setup/config_generator.py +12 -0
- mcp_proxy_adapter/examples/setup/config_validator.py +118 -0
- mcp_proxy_adapter/examples/setup/environment_setup.py +62 -0
- mcp_proxy_adapter/examples/setup/test_files_generator.py +10 -0
- mcp_proxy_adapter/examples/setup/test_runner.py +89 -0
- mcp_proxy_adapter/examples/setup_test_environment.py +235 -0
- mcp_proxy_adapter/examples/simple_protocol_test.py +125 -0
- mcp_proxy_adapter/examples/test_chk_hostname_automated.py +211 -0
- mcp_proxy_adapter/examples/test_config.py +205 -0
- mcp_proxy_adapter/examples/test_config_builder.py +110 -0
- mcp_proxy_adapter/examples/test_examples.py +308 -0
- mcp_proxy_adapter/examples/test_framework_complete.py +267 -0
- mcp_proxy_adapter/examples/test_mcp_server.py +187 -0
- mcp_proxy_adapter/examples/test_protocol_examples.py +337 -0
- mcp_proxy_adapter/examples/universal_client.py +674 -0
- mcp_proxy_adapter/examples/update_config_certificates.py +135 -0
- mcp_proxy_adapter/examples/validate_generator_compatibility.py +385 -0
- mcp_proxy_adapter/examples/validate_generator_compatibility_simple.py +61 -0
- mcp_proxy_adapter/integrations/__init__.py +25 -0
- mcp_proxy_adapter/integrations/queuemgr_integration.py +462 -0
- mcp_proxy_adapter/main.py +311 -0
- mcp_proxy_adapter/openapi.py +375 -0
- mcp_proxy_adapter/schemas/base_schema.json +114 -0
- mcp_proxy_adapter/schemas/openapi_schema.json +314 -0
- mcp_proxy_adapter/schemas/roles.json +37 -0
- mcp_proxy_adapter/schemas/roles_schema.json +162 -0
- mcp_proxy_adapter/version.py +5 -0
- mcp_proxy_adapter-6.9.50.dist-info/METADATA +1088 -0
- mcp_proxy_adapter-6.9.50.dist-info/RECORD +242 -0
- {mcp_proxy_adapter-2.0.1.dist-info → mcp_proxy_adapter-6.9.50.dist-info}/WHEEL +1 -1
- mcp_proxy_adapter-6.9.50.dist-info/entry_points.txt +14 -0
- mcp_proxy_adapter-6.9.50.dist-info/top_level.txt +1 -0
- adapters/__init__.py +0 -16
- analyzers/__init__.py +0 -14
- analyzers/docstring_analyzer.py +0 -199
- analyzers/type_analyzer.py +0 -151
- cli/__init__.py +0 -12
- cli/__main__.py +0 -79
- cli/command_runner.py +0 -233
- dispatchers/__init__.py +0 -14
- dispatchers/base_dispatcher.py +0 -85
- dispatchers/json_rpc_dispatcher.py +0 -198
- generators/__init__.py +0 -14
- generators/endpoint_generator.py +0 -172
- generators/openapi_generator.py +0 -254
- generators/rest_api_generator.py +0 -207
- mcp_proxy_adapter-2.0.1.dist-info/METADATA +0 -272
- mcp_proxy_adapter-2.0.1.dist-info/RECORD +0 -28
- mcp_proxy_adapter-2.0.1.dist-info/licenses/LICENSE +0 -21
- mcp_proxy_adapter-2.0.1.dist-info/top_level.txt +0 -7
- openapi_schema/__init__.py +0 -38
- openapi_schema/command_registry.py +0 -312
- openapi_schema/rest_schema.py +0 -510
- openapi_schema/rpc_generator.py +0 -307
- openapi_schema/rpc_schema.py +0 -416
- validators/__init__.py +0 -14
- validators/base_validator.py +0 -23
- validators/docstring_validator.py +0 -75
- validators/metadata_validator.py +0 -76
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: Vasiliy Zdanovskiy
|
|
3
|
+
email: vasilyvz@gmail.com
|
|
4
|
+
|
|
5
|
+
Simple configuration validator ensuring required fields and files exist.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
from typing import List
|
|
13
|
+
|
|
14
|
+
from .simple_config import SimpleConfigModel
|
|
15
|
+
from mcp_proxy_adapter.core.certificate.certificate_validator import (
|
|
16
|
+
CertificateValidator,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class ValidationError:
|
|
22
|
+
message: str
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class SimpleConfigValidator:
|
|
26
|
+
"""Validate SimpleConfigModel instances."""
|
|
27
|
+
|
|
28
|
+
def validate(self, model: SimpleConfigModel) -> List[ValidationError]:
|
|
29
|
+
errors: List[ValidationError] = []
|
|
30
|
+
errors.extend(self._validate_server(model))
|
|
31
|
+
errors.extend(self._validate_client(model))
|
|
32
|
+
errors.extend(self._validate_registration(model))
|
|
33
|
+
errors.extend(self._validate_auth(model))
|
|
34
|
+
return errors
|
|
35
|
+
|
|
36
|
+
def _validate_server(self, model: SimpleConfigModel) -> List[ValidationError]:
|
|
37
|
+
e: List[ValidationError] = []
|
|
38
|
+
s = model.server
|
|
39
|
+
if not s.host:
|
|
40
|
+
e.append(ValidationError("server.host is required"))
|
|
41
|
+
if not isinstance(s.port, int): # type: ignore[unreachable]
|
|
42
|
+
e.append(ValidationError("server.port must be integer"))
|
|
43
|
+
if s.protocol not in ("http", "https", "mtls"):
|
|
44
|
+
e.append(
|
|
45
|
+
ValidationError("server.protocol must be one of: http, https, mtls")
|
|
46
|
+
)
|
|
47
|
+
# Protocol-specific certificate requirements
|
|
48
|
+
if s.protocol == "mtls":
|
|
49
|
+
# For mtls: cert_file and key_file are required
|
|
50
|
+
# CA is required if use_system_ca=False (default), optional if use_system_ca=True
|
|
51
|
+
if not s.cert_file:
|
|
52
|
+
e.append(
|
|
53
|
+
ValidationError("server.cert_file is required for mtls protocol")
|
|
54
|
+
)
|
|
55
|
+
if not s.key_file:
|
|
56
|
+
e.append(
|
|
57
|
+
ValidationError("server.key_file is required for mtls protocol")
|
|
58
|
+
)
|
|
59
|
+
# CA validation is handled below based on use_system_ca flag
|
|
60
|
+
elif s.protocol == "https":
|
|
61
|
+
# For https: certificates are optional, but if one is specified, both must be
|
|
62
|
+
# If key is specified but cert is not - this is an error
|
|
63
|
+
if s.key_file and not s.cert_file:
|
|
64
|
+
e.append(
|
|
65
|
+
ValidationError(
|
|
66
|
+
"server.key_file is specified but server.cert_file is missing for https protocol"
|
|
67
|
+
)
|
|
68
|
+
)
|
|
69
|
+
if s.cert_file and not s.key_file:
|
|
70
|
+
e.append(
|
|
71
|
+
ValidationError(
|
|
72
|
+
"server.cert_file is specified but server.key_file is missing for https protocol"
|
|
73
|
+
)
|
|
74
|
+
)
|
|
75
|
+
# Files existence (if provided)
|
|
76
|
+
for label, path in (
|
|
77
|
+
("cert_file", s.cert_file),
|
|
78
|
+
("key_file", s.key_file),
|
|
79
|
+
("ca_cert_file", s.ca_cert_file),
|
|
80
|
+
("crl_file", s.crl_file),
|
|
81
|
+
):
|
|
82
|
+
if path and not os.path.exists(path):
|
|
83
|
+
e.append(ValidationError(f"server.{label} not found: {path}"))
|
|
84
|
+
|
|
85
|
+
# Validate certificate validity if files exist
|
|
86
|
+
if (
|
|
87
|
+
s.cert_file
|
|
88
|
+
and s.key_file
|
|
89
|
+
and os.path.exists(s.cert_file)
|
|
90
|
+
and os.path.exists(s.key_file)
|
|
91
|
+
):
|
|
92
|
+
# Check certificate-key match
|
|
93
|
+
if not CertificateValidator.validate_certificate_key_match(
|
|
94
|
+
s.cert_file, s.key_file
|
|
95
|
+
):
|
|
96
|
+
e.append(
|
|
97
|
+
ValidationError("server.cert_file does not match server.key_file")
|
|
98
|
+
)
|
|
99
|
+
# Check certificate expiry
|
|
100
|
+
if not CertificateValidator.validate_certificate_not_expired(s.cert_file):
|
|
101
|
+
e.append(ValidationError("server.cert_file is expired"))
|
|
102
|
+
|
|
103
|
+
# Validate CRL if specified
|
|
104
|
+
if s.crl_file:
|
|
105
|
+
crl_valid, crl_error = CertificateValidator.validate_crl_file(s.crl_file)
|
|
106
|
+
if not crl_valid:
|
|
107
|
+
e.append(
|
|
108
|
+
ValidationError(f"server.crl_file validation failed: {crl_error}")
|
|
109
|
+
)
|
|
110
|
+
else:
|
|
111
|
+
# Check if certificate is revoked according to CRL
|
|
112
|
+
if not CertificateValidator.validate_certificate_not_revoked(
|
|
113
|
+
s.cert_file, s.crl_file
|
|
114
|
+
):
|
|
115
|
+
e.append(
|
|
116
|
+
ValidationError(
|
|
117
|
+
"server.cert_file is revoked according to server.crl_file"
|
|
118
|
+
)
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# Validate certificate chain - use CA cert if provided, otherwise check use_system_ca
|
|
122
|
+
if s.cert_file and os.path.exists(s.cert_file):
|
|
123
|
+
if s.ca_cert_file and os.path.exists(s.ca_cert_file):
|
|
124
|
+
# Use provided CA certificate (only CA from config is used by default)
|
|
125
|
+
if not CertificateValidator.validate_certificate_chain(
|
|
126
|
+
s.cert_file, s.ca_cert_file
|
|
127
|
+
):
|
|
128
|
+
e.append(
|
|
129
|
+
ValidationError(
|
|
130
|
+
"server.cert_file is not signed by server.ca_cert_file"
|
|
131
|
+
)
|
|
132
|
+
)
|
|
133
|
+
else:
|
|
134
|
+
# CA not provided - check if system CA is allowed
|
|
135
|
+
if s.protocol == "mtls":
|
|
136
|
+
# For mTLS: CA is required if use_system_ca=False (default)
|
|
137
|
+
if s.use_system_ca:
|
|
138
|
+
# System CA is explicitly allowed
|
|
139
|
+
if not CertificateValidator.validate_certificate_with_system_store(
|
|
140
|
+
s.cert_file
|
|
141
|
+
):
|
|
142
|
+
e.append(
|
|
143
|
+
ValidationError(
|
|
144
|
+
"server.cert_file is not valid according to system CA store"
|
|
145
|
+
)
|
|
146
|
+
)
|
|
147
|
+
else:
|
|
148
|
+
# System CA is not allowed (default) - CA must be provided for mTLS
|
|
149
|
+
e.append(
|
|
150
|
+
ValidationError(
|
|
151
|
+
"server.ca_cert_file is required for mtls protocol when use_system_ca is False"
|
|
152
|
+
)
|
|
153
|
+
)
|
|
154
|
+
elif s.protocol == "https":
|
|
155
|
+
# For HTTPS: CA is optional, but if not provided, use system CA if allowed
|
|
156
|
+
if s.use_system_ca:
|
|
157
|
+
# System CA is explicitly allowed
|
|
158
|
+
if not CertificateValidator.validate_certificate_with_system_store(
|
|
159
|
+
s.cert_file
|
|
160
|
+
):
|
|
161
|
+
e.append(
|
|
162
|
+
ValidationError(
|
|
163
|
+
"server.cert_file is not valid according to system CA store"
|
|
164
|
+
)
|
|
165
|
+
)
|
|
166
|
+
# If use_system_ca=False and CA not provided for HTTPS, that's OK
|
|
167
|
+
# (HTTPS can work without explicit CA validation)
|
|
168
|
+
|
|
169
|
+
return e
|
|
170
|
+
|
|
171
|
+
def _validate_client(self, model: SimpleConfigModel) -> List[ValidationError]:
|
|
172
|
+
"""
|
|
173
|
+
Validate client configuration (for connecting to external servers).
|
|
174
|
+
"""
|
|
175
|
+
e: List[ValidationError] = []
|
|
176
|
+
c = model.client
|
|
177
|
+
if c.enabled:
|
|
178
|
+
if c.protocol not in ("http", "https", "mtls"):
|
|
179
|
+
e.append(
|
|
180
|
+
ValidationError(
|
|
181
|
+
"client.protocol must be one of: http, https, mtls"
|
|
182
|
+
)
|
|
183
|
+
)
|
|
184
|
+
# Protocol-specific certificate requirements
|
|
185
|
+
if c.protocol == "mtls":
|
|
186
|
+
if not c.cert_file:
|
|
187
|
+
e.append(
|
|
188
|
+
ValidationError(
|
|
189
|
+
"client.cert_file is required for mtls protocol when enabled"
|
|
190
|
+
)
|
|
191
|
+
)
|
|
192
|
+
if not c.key_file:
|
|
193
|
+
e.append(
|
|
194
|
+
ValidationError(
|
|
195
|
+
"client.key_file is required for mtls protocol when enabled"
|
|
196
|
+
)
|
|
197
|
+
)
|
|
198
|
+
elif c.protocol == "https":
|
|
199
|
+
if c.key_file and not c.cert_file:
|
|
200
|
+
e.append(
|
|
201
|
+
ValidationError(
|
|
202
|
+
"client.key_file is specified but client.cert_file is missing for https protocol"
|
|
203
|
+
)
|
|
204
|
+
)
|
|
205
|
+
if c.cert_file and not c.key_file:
|
|
206
|
+
e.append(
|
|
207
|
+
ValidationError(
|
|
208
|
+
"client.cert_file is specified but client.key_file is missing for https protocol"
|
|
209
|
+
)
|
|
210
|
+
)
|
|
211
|
+
# Files existence (if provided)
|
|
212
|
+
for label, path in (
|
|
213
|
+
("cert_file", c.cert_file),
|
|
214
|
+
("key_file", c.key_file),
|
|
215
|
+
("ca_cert_file", c.ca_cert_file),
|
|
216
|
+
("crl_file", c.crl_file),
|
|
217
|
+
):
|
|
218
|
+
if path and not os.path.exists(path):
|
|
219
|
+
e.append(ValidationError(f"client.{label} not found: {path}"))
|
|
220
|
+
|
|
221
|
+
# Validate certificate validity if files exist
|
|
222
|
+
if (
|
|
223
|
+
c.cert_file
|
|
224
|
+
and c.key_file
|
|
225
|
+
and os.path.exists(c.cert_file)
|
|
226
|
+
and os.path.exists(c.key_file)
|
|
227
|
+
):
|
|
228
|
+
# Check certificate-key match
|
|
229
|
+
if not CertificateValidator.validate_certificate_key_match(
|
|
230
|
+
c.cert_file, c.key_file
|
|
231
|
+
):
|
|
232
|
+
e.append(
|
|
233
|
+
ValidationError(
|
|
234
|
+
"client.cert_file does not match client.key_file"
|
|
235
|
+
)
|
|
236
|
+
)
|
|
237
|
+
# Check certificate expiry
|
|
238
|
+
if not CertificateValidator.validate_certificate_not_expired(c.cert_file):
|
|
239
|
+
e.append(ValidationError("client.cert_file is expired"))
|
|
240
|
+
|
|
241
|
+
# Validate CRL if specified
|
|
242
|
+
if c.crl_file:
|
|
243
|
+
crl_valid, crl_error = CertificateValidator.validate_crl_file(c.crl_file)
|
|
244
|
+
if not crl_valid:
|
|
245
|
+
e.append(
|
|
246
|
+
ValidationError(f"client.crl_file validation failed: {crl_error}")
|
|
247
|
+
)
|
|
248
|
+
else:
|
|
249
|
+
# Check if certificate is revoked according to CRL
|
|
250
|
+
if not CertificateValidator.validate_certificate_not_revoked(
|
|
251
|
+
c.cert_file, c.crl_file
|
|
252
|
+
):
|
|
253
|
+
e.append(
|
|
254
|
+
ValidationError(
|
|
255
|
+
"client.cert_file is revoked according to client.crl_file"
|
|
256
|
+
)
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
# Validate certificate chain
|
|
260
|
+
if c.cert_file and os.path.exists(c.cert_file):
|
|
261
|
+
if c.ca_cert_file and os.path.exists(c.ca_cert_file):
|
|
262
|
+
if not CertificateValidator.validate_certificate_chain(
|
|
263
|
+
c.cert_file, c.ca_cert_file
|
|
264
|
+
):
|
|
265
|
+
e.append(
|
|
266
|
+
ValidationError(
|
|
267
|
+
"client.cert_file is not signed by client.ca_cert_file"
|
|
268
|
+
)
|
|
269
|
+
)
|
|
270
|
+
else:
|
|
271
|
+
if c.protocol == "mtls":
|
|
272
|
+
if c.use_system_ca:
|
|
273
|
+
if not CertificateValidator.validate_certificate_with_system_store(
|
|
274
|
+
c.cert_file
|
|
275
|
+
):
|
|
276
|
+
e.append(
|
|
277
|
+
ValidationError(
|
|
278
|
+
"client.cert_file is not valid according to system CA store"
|
|
279
|
+
)
|
|
280
|
+
)
|
|
281
|
+
else:
|
|
282
|
+
e.append(
|
|
283
|
+
ValidationError(
|
|
284
|
+
"client.ca_cert_file is required for mtls protocol when use_system_ca is False"
|
|
285
|
+
)
|
|
286
|
+
)
|
|
287
|
+
elif c.protocol == "https":
|
|
288
|
+
if c.use_system_ca:
|
|
289
|
+
if not CertificateValidator.validate_certificate_with_system_store(
|
|
290
|
+
c.cert_file
|
|
291
|
+
):
|
|
292
|
+
e.append(
|
|
293
|
+
ValidationError(
|
|
294
|
+
"client.cert_file is not valid according to system CA store"
|
|
295
|
+
)
|
|
296
|
+
)
|
|
297
|
+
return e
|
|
298
|
+
|
|
299
|
+
def _validate_registration(self, model: SimpleConfigModel) -> List[ValidationError]:
|
|
300
|
+
"""
|
|
301
|
+
Validate registration configuration (for registering with proxy server).
|
|
302
|
+
"""
|
|
303
|
+
e: List[ValidationError] = []
|
|
304
|
+
r = model.registration
|
|
305
|
+
if r.enabled:
|
|
306
|
+
if not r.host:
|
|
307
|
+
e.append(ValidationError("registration.host is required when enabled"))
|
|
308
|
+
if not isinstance(r.port, int): # type: ignore[unreachable]
|
|
309
|
+
e.append(ValidationError("registration.port must be integer"))
|
|
310
|
+
if r.protocol not in ("http", "https", "mtls"):
|
|
311
|
+
e.append(
|
|
312
|
+
ValidationError(
|
|
313
|
+
"registration.protocol must be one of: http, https, mtls"
|
|
314
|
+
)
|
|
315
|
+
)
|
|
316
|
+
# Validate server_id if provided
|
|
317
|
+
if r.server_id is not None and not isinstance(r.server_id, str):
|
|
318
|
+
e.append(ValidationError("registration.server_id must be a string"))
|
|
319
|
+
if r.server_id is not None and not r.server_id.strip():
|
|
320
|
+
e.append(ValidationError("registration.server_id cannot be empty"))
|
|
321
|
+
# Protocol-specific certificate requirements
|
|
322
|
+
if r.protocol == "mtls":
|
|
323
|
+
if not r.cert_file:
|
|
324
|
+
e.append(
|
|
325
|
+
ValidationError(
|
|
326
|
+
"registration.cert_file is required for mtls protocol when enabled"
|
|
327
|
+
)
|
|
328
|
+
)
|
|
329
|
+
if not r.key_file:
|
|
330
|
+
e.append(
|
|
331
|
+
ValidationError(
|
|
332
|
+
"registration.key_file is required for mtls protocol when enabled"
|
|
333
|
+
)
|
|
334
|
+
)
|
|
335
|
+
elif r.protocol == "https":
|
|
336
|
+
if r.key_file and not r.cert_file:
|
|
337
|
+
e.append(
|
|
338
|
+
ValidationError(
|
|
339
|
+
"registration.key_file is specified but registration.cert_file is missing for https protocol"
|
|
340
|
+
)
|
|
341
|
+
)
|
|
342
|
+
if r.cert_file and not r.key_file:
|
|
343
|
+
e.append(
|
|
344
|
+
ValidationError(
|
|
345
|
+
"registration.cert_file is specified but registration.key_file is missing for https protocol"
|
|
346
|
+
)
|
|
347
|
+
)
|
|
348
|
+
# Files existence (if provided)
|
|
349
|
+
for label, path in (
|
|
350
|
+
("cert_file", r.cert_file),
|
|
351
|
+
("key_file", r.key_file),
|
|
352
|
+
("ca_cert_file", r.ca_cert_file),
|
|
353
|
+
("crl_file", r.crl_file),
|
|
354
|
+
):
|
|
355
|
+
if path and not os.path.exists(path):
|
|
356
|
+
e.append(ValidationError(f"registration.{label} not found: {path}"))
|
|
357
|
+
|
|
358
|
+
# Validate certificate validity if files exist
|
|
359
|
+
if (
|
|
360
|
+
r.cert_file
|
|
361
|
+
and r.key_file
|
|
362
|
+
and os.path.exists(r.cert_file)
|
|
363
|
+
and os.path.exists(r.key_file)
|
|
364
|
+
):
|
|
365
|
+
# Check certificate-key match
|
|
366
|
+
if not CertificateValidator.validate_certificate_key_match(
|
|
367
|
+
r.cert_file, r.key_file
|
|
368
|
+
):
|
|
369
|
+
e.append(
|
|
370
|
+
ValidationError(
|
|
371
|
+
"registration.cert_file does not match registration.key_file"
|
|
372
|
+
)
|
|
373
|
+
)
|
|
374
|
+
# Check certificate expiry
|
|
375
|
+
if not CertificateValidator.validate_certificate_not_expired(r.cert_file):
|
|
376
|
+
e.append(ValidationError("registration.cert_file is expired"))
|
|
377
|
+
|
|
378
|
+
# Validate CRL if specified
|
|
379
|
+
if r.crl_file:
|
|
380
|
+
crl_valid, crl_error = CertificateValidator.validate_crl_file(r.crl_file)
|
|
381
|
+
if not crl_valid:
|
|
382
|
+
e.append(
|
|
383
|
+
ValidationError(f"registration.crl_file validation failed: {crl_error}")
|
|
384
|
+
)
|
|
385
|
+
else:
|
|
386
|
+
# Check if certificate is revoked according to CRL
|
|
387
|
+
if not CertificateValidator.validate_certificate_not_revoked(
|
|
388
|
+
r.cert_file, r.crl_file
|
|
389
|
+
):
|
|
390
|
+
e.append(
|
|
391
|
+
ValidationError(
|
|
392
|
+
"registration.cert_file is revoked according to registration.crl_file"
|
|
393
|
+
)
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
# Validate certificate chain
|
|
397
|
+
if r.cert_file and os.path.exists(r.cert_file):
|
|
398
|
+
if r.ca_cert_file and os.path.exists(r.ca_cert_file):
|
|
399
|
+
if not CertificateValidator.validate_certificate_chain(
|
|
400
|
+
r.cert_file, r.ca_cert_file
|
|
401
|
+
):
|
|
402
|
+
e.append(
|
|
403
|
+
ValidationError(
|
|
404
|
+
"registration.cert_file is not signed by registration.ca_cert_file"
|
|
405
|
+
)
|
|
406
|
+
)
|
|
407
|
+
else:
|
|
408
|
+
if r.protocol == "mtls":
|
|
409
|
+
if r.use_system_ca:
|
|
410
|
+
if not CertificateValidator.validate_certificate_with_system_store(
|
|
411
|
+
r.cert_file
|
|
412
|
+
):
|
|
413
|
+
e.append(
|
|
414
|
+
ValidationError(
|
|
415
|
+
"registration.cert_file is not valid according to system CA store"
|
|
416
|
+
)
|
|
417
|
+
)
|
|
418
|
+
else:
|
|
419
|
+
e.append(
|
|
420
|
+
ValidationError(
|
|
421
|
+
"registration.ca_cert_file is required for mtls protocol when use_system_ca is False"
|
|
422
|
+
)
|
|
423
|
+
)
|
|
424
|
+
elif r.protocol == "https":
|
|
425
|
+
if r.use_system_ca:
|
|
426
|
+
if not CertificateValidator.validate_certificate_with_system_store(
|
|
427
|
+
r.cert_file
|
|
428
|
+
):
|
|
429
|
+
e.append(
|
|
430
|
+
ValidationError(
|
|
431
|
+
"registration.cert_file is not valid according to system CA store"
|
|
432
|
+
)
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
# Heartbeat
|
|
436
|
+
if not r.heartbeat.endpoint:
|
|
437
|
+
e.append(ValidationError("registration.heartbeat.endpoint is required"))
|
|
438
|
+
if not isinstance(r.heartbeat.interval, int) or r.heartbeat.interval <= 0:
|
|
439
|
+
e.append(
|
|
440
|
+
ValidationError(
|
|
441
|
+
"registration.heartbeat.interval must be positive integer"
|
|
442
|
+
)
|
|
443
|
+
)
|
|
444
|
+
# Registration endpoints
|
|
445
|
+
if not r.register_endpoint:
|
|
446
|
+
e.append(
|
|
447
|
+
ValidationError("registration.register_endpoint is required")
|
|
448
|
+
)
|
|
449
|
+
if not r.unregister_endpoint:
|
|
450
|
+
e.append(
|
|
451
|
+
ValidationError("registration.unregister_endpoint is required")
|
|
452
|
+
)
|
|
453
|
+
return e
|
|
454
|
+
|
|
455
|
+
def _validate_proxy_client(self, model: SimpleConfigModel) -> List[ValidationError]:
|
|
456
|
+
"""
|
|
457
|
+
DEPRECATED: This method is kept for backward compatibility.
|
|
458
|
+
Use _validate_registration instead.
|
|
459
|
+
"""
|
|
460
|
+
# This method is no longer used but kept for compatibility
|
|
461
|
+
return []
|
|
462
|
+
|
|
463
|
+
def _validate_auth(self, model: SimpleConfigModel) -> List[ValidationError]:
|
|
464
|
+
e: List[ValidationError] = []
|
|
465
|
+
a = model.auth
|
|
466
|
+
if a.use_roles and not a.use_token:
|
|
467
|
+
e.append(
|
|
468
|
+
ValidationError("auth.use_roles requires auth.use_token to be true")
|
|
469
|
+
)
|
|
470
|
+
if a.use_token and not a.tokens:
|
|
471
|
+
e.append(
|
|
472
|
+
ValidationError(
|
|
473
|
+
"auth.tokens must be provided when auth.use_token is true"
|
|
474
|
+
)
|
|
475
|
+
)
|
|
476
|
+
return e
|