mcp-proxy-adapter 6.0.0__py3-none-any.whl → 6.0.1__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 +209 -79
- mcp_proxy_adapter/api/handlers.py +16 -5
- mcp_proxy_adapter/api/middleware/__init__.py +14 -9
- mcp_proxy_adapter/api/middleware/command_permission_middleware.py +148 -0
- mcp_proxy_adapter/api/middleware/factory.py +36 -12
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +84 -18
- mcp_proxy_adapter/api/middleware/unified_security.py +197 -0
- mcp_proxy_adapter/api/middleware/user_info_middleware.py +158 -0
- mcp_proxy_adapter/commands/__init__.py +7 -1
- mcp_proxy_adapter/commands/base.py +7 -4
- mcp_proxy_adapter/commands/builtin_commands.py +8 -2
- mcp_proxy_adapter/commands/command_registry.py +8 -0
- mcp_proxy_adapter/commands/echo_command.py +81 -0
- mcp_proxy_adapter/commands/health_command.py +1 -1
- mcp_proxy_adapter/commands/help_command.py +21 -14
- mcp_proxy_adapter/commands/proxy_registration_command.py +326 -185
- mcp_proxy_adapter/commands/role_test_command.py +141 -0
- mcp_proxy_adapter/commands/security_command.py +488 -0
- mcp_proxy_adapter/commands/ssl_setup_command.py +234 -351
- mcp_proxy_adapter/commands/token_management_command.py +1 -1
- mcp_proxy_adapter/config.py +323 -40
- mcp_proxy_adapter/core/app_factory.py +410 -0
- 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/client_security.py +384 -0
- mcp_proxy_adapter/core/logging.py +8 -3
- mcp_proxy_adapter/core/mtls_asgi.py +156 -0
- mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
- mcp_proxy_adapter/core/protocol_manager.py +169 -10
- mcp_proxy_adapter/core/proxy_client.py +602 -0
- mcp_proxy_adapter/core/proxy_registration.py +299 -47
- mcp_proxy_adapter/core/security_adapter.py +12 -15
- mcp_proxy_adapter/core/security_integration.py +286 -0
- mcp_proxy_adapter/core/server_adapter.py +282 -0
- mcp_proxy_adapter/core/server_engine.py +270 -0
- mcp_proxy_adapter/core/ssl_utils.py +13 -12
- mcp_proxy_adapter/core/transport_manager.py +5 -5
- mcp_proxy_adapter/core/unified_config_adapter.py +579 -0
- mcp_proxy_adapter/examples/__init__.py +13 -4
- 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 +44 -0
- mcp_proxy_adapter/examples/commands/__init__.py +5 -0
- mcp_proxy_adapter/examples/create_certificates_simple.py +550 -0
- mcp_proxy_adapter/examples/debug_request_state.py +112 -0
- mcp_proxy_adapter/examples/debug_role_chain.py +158 -0
- mcp_proxy_adapter/examples/demo_client.py +275 -0
- mcp_proxy_adapter/examples/examples/basic_framework/__init__.py +9 -0
- mcp_proxy_adapter/examples/examples/basic_framework/commands/__init__.py +4 -0
- mcp_proxy_adapter/examples/examples/basic_framework/hooks/__init__.py +4 -0
- mcp_proxy_adapter/examples/examples/basic_framework/main.py +44 -0
- mcp_proxy_adapter/examples/examples/full_application/__init__.py +12 -0
- mcp_proxy_adapter/examples/examples/full_application/commands/__init__.py +7 -0
- mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +80 -0
- mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +90 -0
- mcp_proxy_adapter/examples/examples/full_application/hooks/__init__.py +7 -0
- mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +75 -0
- mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +71 -0
- mcp_proxy_adapter/examples/examples/full_application/main.py +173 -0
- mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +154 -0
- mcp_proxy_adapter/examples/full_application/__init__.py +12 -0
- mcp_proxy_adapter/examples/full_application/commands/__init__.py +7 -0
- mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +80 -0
- mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +90 -0
- mcp_proxy_adapter/examples/full_application/hooks/__init__.py +7 -0
- mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +75 -0
- mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +71 -0
- mcp_proxy_adapter/examples/full_application/main.py +173 -0
- mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +154 -0
- mcp_proxy_adapter/examples/generate_all_certificates.py +362 -0
- mcp_proxy_adapter/examples/generate_certificates.py +177 -0
- mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +369 -0
- mcp_proxy_adapter/examples/generate_test_configs.py +331 -0
- mcp_proxy_adapter/examples/proxy_registration_example.py +334 -0
- mcp_proxy_adapter/examples/run_example.py +59 -0
- mcp_proxy_adapter/examples/run_full_test_suite.py +318 -0
- mcp_proxy_adapter/examples/run_proxy_server.py +146 -0
- mcp_proxy_adapter/examples/run_security_tests.py +544 -0
- mcp_proxy_adapter/examples/run_security_tests_fixed.py +247 -0
- mcp_proxy_adapter/examples/scripts/config_generator.py +740 -0
- mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +560 -0
- mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +369 -0
- mcp_proxy_adapter/examples/security_test_client.py +782 -0
- mcp_proxy_adapter/examples/setup_test_environment.py +328 -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 +281 -0
- mcp_proxy_adapter/examples/universal_client.py +620 -0
- mcp_proxy_adapter/main.py +66 -148
- mcp_proxy_adapter/utils/config_generator.py +1008 -0
- mcp_proxy_adapter/version.py +5 -2
- mcp_proxy_adapter-6.0.1.dist-info/METADATA +679 -0
- mcp_proxy_adapter-6.0.1.dist-info/RECORD +140 -0
- mcp_proxy_adapter-6.0.1.dist-info/entry_points.txt +2 -0
- {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/licenses/LICENSE +2 -2
- mcp_proxy_adapter/api/middleware/auth.py +0 -146
- mcp_proxy_adapter/api/middleware/auth_adapter.py +0 -235
- mcp_proxy_adapter/api/middleware/mtls_adapter.py +0 -305
- mcp_proxy_adapter/api/middleware/mtls_middleware.py +0 -296
- mcp_proxy_adapter/api/middleware/rate_limit.py +0 -152
- mcp_proxy_adapter/api/middleware/rate_limit_adapter.py +0 -241
- mcp_proxy_adapter/api/middleware/roles_adapter.py +0 -365
- mcp_proxy_adapter/api/middleware/roles_middleware.py +0 -381
- mcp_proxy_adapter/api/middleware/security.py +0 -376
- mcp_proxy_adapter/api/middleware/token_auth_middleware.py +0 -261
- mcp_proxy_adapter/examples/README.md +0 -124
- mcp_proxy_adapter/examples/basic_server/README.md +0 -60
- mcp_proxy_adapter/examples/basic_server/__init__.py +0 -7
- mcp_proxy_adapter/examples/basic_server/basic_custom_settings.json +0 -39
- mcp_proxy_adapter/examples/basic_server/config.json +0 -70
- mcp_proxy_adapter/examples/basic_server/config_all_protocols.json +0 -54
- mcp_proxy_adapter/examples/basic_server/config_http.json +0 -70
- mcp_proxy_adapter/examples/basic_server/config_http_only.json +0 -52
- mcp_proxy_adapter/examples/basic_server/config_https.json +0 -58
- mcp_proxy_adapter/examples/basic_server/config_mtls.json +0 -58
- mcp_proxy_adapter/examples/basic_server/config_ssl.json +0 -46
- mcp_proxy_adapter/examples/basic_server/custom_settings_example.py +0 -238
- mcp_proxy_adapter/examples/basic_server/server.py +0 -114
- mcp_proxy_adapter/examples/custom_commands/README.md +0 -127
- mcp_proxy_adapter/examples/custom_commands/__init__.py +0 -27
- mcp_proxy_adapter/examples/custom_commands/advanced_hooks.py +0 -566
- mcp_proxy_adapter/examples/custom_commands/auto_commands/__init__.py +0 -6
- mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_echo_command.py +0 -103
- mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_info_command.py +0 -111
- mcp_proxy_adapter/examples/custom_commands/auto_commands/test_command.py +0 -105
- mcp_proxy_adapter/examples/custom_commands/catalog/commands/test_command.py +0 -129
- mcp_proxy_adapter/examples/custom_commands/config.json +0 -118
- mcp_proxy_adapter/examples/custom_commands/config_all_protocols.json +0 -46
- mcp_proxy_adapter/examples/custom_commands/config_https_only.json +0 -46
- mcp_proxy_adapter/examples/custom_commands/config_https_transport.json +0 -33
- mcp_proxy_adapter/examples/custom_commands/config_mtls_only.json +0 -46
- mcp_proxy_adapter/examples/custom_commands/config_mtls_transport.json +0 -33
- mcp_proxy_adapter/examples/custom_commands/config_single_transport.json +0 -33
- mcp_proxy_adapter/examples/custom_commands/custom_health_command.py +0 -169
- mcp_proxy_adapter/examples/custom_commands/custom_help_command.py +0 -215
- mcp_proxy_adapter/examples/custom_commands/custom_openapi_generator.py +0 -76
- mcp_proxy_adapter/examples/custom_commands/custom_settings.json +0 -96
- mcp_proxy_adapter/examples/custom_commands/custom_settings_manager.py +0 -241
- mcp_proxy_adapter/examples/custom_commands/data_transform_command.py +0 -135
- mcp_proxy_adapter/examples/custom_commands/echo_command.py +0 -122
- mcp_proxy_adapter/examples/custom_commands/full_help_response.json +0 -1
- mcp_proxy_adapter/examples/custom_commands/generated_openapi.json +0 -629
- mcp_proxy_adapter/examples/custom_commands/get_openapi.py +0 -103
- mcp_proxy_adapter/examples/custom_commands/hooks.py +0 -230
- mcp_proxy_adapter/examples/custom_commands/intercept_command.py +0 -123
- mcp_proxy_adapter/examples/custom_commands/loadable_commands/test_ignored.py +0 -129
- mcp_proxy_adapter/examples/custom_commands/manual_echo_command.py +0 -103
- mcp_proxy_adapter/examples/custom_commands/proxy_connection_manager.py +0 -278
- mcp_proxy_adapter/examples/custom_commands/server.py +0 -252
- mcp_proxy_adapter/examples/custom_commands/simple_openapi_server.py +0 -75
- mcp_proxy_adapter/examples/custom_commands/start_server_with_proxy_manager.py +0 -299
- mcp_proxy_adapter/examples/custom_commands/start_server_with_registration.py +0 -278
- mcp_proxy_adapter/examples/custom_commands/test_hooks.py +0 -176
- mcp_proxy_adapter/examples/custom_commands/test_openapi.py +0 -27
- mcp_proxy_adapter/examples/custom_commands/test_registry.py +0 -23
- mcp_proxy_adapter/examples/custom_commands/test_simple.py +0 -19
- mcp_proxy_adapter/examples/custom_project_example/README.md +0 -103
- mcp_proxy_adapter/examples/custom_project_example/README_EN.md +0 -103
- mcp_proxy_adapter/examples/deployment/README.md +0 -49
- mcp_proxy_adapter/examples/deployment/__init__.py +0 -7
- mcp_proxy_adapter/examples/deployment/config.development.json +0 -8
- mcp_proxy_adapter/examples/deployment/config.json +0 -29
- mcp_proxy_adapter/examples/deployment/config.production.json +0 -12
- mcp_proxy_adapter/examples/deployment/config.staging.json +0 -11
- mcp_proxy_adapter/examples/deployment/docker-compose.yml +0 -31
- mcp_proxy_adapter/examples/deployment/run.sh +0 -43
- mcp_proxy_adapter/examples/deployment/run_docker.sh +0 -84
- mcp_proxy_adapter/examples/simple_custom_commands/README.md +0 -149
- mcp_proxy_adapter/examples/simple_custom_commands/README_EN.md +0 -149
- mcp_proxy_adapter/schemas/base_schema.json +0 -114
- mcp_proxy_adapter/schemas/openapi_schema.json +0 -314
- mcp_proxy_adapter/schemas/roles_schema.json +0 -162
- mcp_proxy_adapter/tests/__init__.py +0 -0
- mcp_proxy_adapter/tests/api/__init__.py +0 -3
- mcp_proxy_adapter/tests/api/test_cmd_endpoint.py +0 -115
- mcp_proxy_adapter/tests/api/test_custom_openapi.py +0 -617
- mcp_proxy_adapter/tests/api/test_handlers.py +0 -522
- mcp_proxy_adapter/tests/api/test_middleware.py +0 -340
- mcp_proxy_adapter/tests/api/test_schemas.py +0 -546
- mcp_proxy_adapter/tests/api/test_tool_integration.py +0 -531
- mcp_proxy_adapter/tests/commands/__init__.py +0 -3
- mcp_proxy_adapter/tests/commands/test_config_command.py +0 -211
- mcp_proxy_adapter/tests/commands/test_echo_command.py +0 -127
- mcp_proxy_adapter/tests/commands/test_help_command.py +0 -136
- mcp_proxy_adapter/tests/conftest.py +0 -131
- mcp_proxy_adapter/tests/functional/__init__.py +0 -3
- mcp_proxy_adapter/tests/functional/test_api.py +0 -253
- mcp_proxy_adapter/tests/integration/__init__.py +0 -3
- mcp_proxy_adapter/tests/integration/test_cmd_integration.py +0 -129
- mcp_proxy_adapter/tests/integration/test_integration.py +0 -255
- mcp_proxy_adapter/tests/performance/__init__.py +0 -3
- mcp_proxy_adapter/tests/performance/test_performance.py +0 -189
- mcp_proxy_adapter/tests/stubs/__init__.py +0 -10
- mcp_proxy_adapter/tests/stubs/echo_command.py +0 -104
- mcp_proxy_adapter/tests/test_api_endpoints.py +0 -271
- mcp_proxy_adapter/tests/test_api_handlers.py +0 -289
- mcp_proxy_adapter/tests/test_base_command.py +0 -123
- mcp_proxy_adapter/tests/test_batch_requests.py +0 -117
- mcp_proxy_adapter/tests/test_command_registry.py +0 -281
- mcp_proxy_adapter/tests/test_config.py +0 -127
- mcp_proxy_adapter/tests/test_utils.py +0 -65
- mcp_proxy_adapter/tests/unit/__init__.py +0 -3
- mcp_proxy_adapter/tests/unit/test_base_command.py +0 -436
- mcp_proxy_adapter/tests/unit/test_config.py +0 -270
- mcp_proxy_adapter-6.0.0.dist-info/METADATA +0 -201
- mcp_proxy_adapter-6.0.0.dist-info/RECORD +0 -179
- {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,362 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
Generate All Certificates for Security Testing
|
4
|
+
This script generates all necessary certificates for comprehensive security testing:
|
5
|
+
- Root CA certificate and key
|
6
|
+
- Server certificates for HTTPS and mTLS
|
7
|
+
- Client certificates for different roles (admin, user, readonly, etc.)
|
8
|
+
- Test certificates for negative scenarios
|
9
|
+
Author: Vasiliy Zdanovskiy
|
10
|
+
email: vasilyvz@gmail.com
|
11
|
+
"""
|
12
|
+
import json
|
13
|
+
import os
|
14
|
+
import subprocess
|
15
|
+
import sys
|
16
|
+
from pathlib import Path
|
17
|
+
from typing import Dict, List, Optional
|
18
|
+
class CertificateGenerator:
|
19
|
+
"""Generate all certificates for security testing."""
|
20
|
+
def __init__(self):
|
21
|
+
self.project_root = Path(__file__).parent.parent.parent
|
22
|
+
self.certs_dir = self.project_root / "mcp_proxy_adapter" / "examples" / "certs"
|
23
|
+
self.keys_dir = self.project_root / "mcp_proxy_adapter" / "examples" / "keys"
|
24
|
+
# Create directories if they don't exist
|
25
|
+
self.certs_dir.mkdir(parents=True, exist_ok=True)
|
26
|
+
self.keys_dir.mkdir(parents=True, exist_ok=True)
|
27
|
+
# Certificate configuration
|
28
|
+
self.ca_config = {
|
29
|
+
"common_name": "MCP Proxy Adapter Test CA",
|
30
|
+
"organization": "Test Organization",
|
31
|
+
"country": "US",
|
32
|
+
"state": "Test State",
|
33
|
+
"city": "Test City",
|
34
|
+
"validity_years": 10
|
35
|
+
}
|
36
|
+
self.server_config = {
|
37
|
+
"common_name": "mcp-proxy-adapter-test.local",
|
38
|
+
"organization": "Test Organization",
|
39
|
+
"country": "US",
|
40
|
+
"state": "Test State",
|
41
|
+
"city": "Test City",
|
42
|
+
"validity_years": 2,
|
43
|
+
"san": ["localhost", "127.0.0.1", "mcp-proxy-adapter-test.local"]
|
44
|
+
}
|
45
|
+
# Client certificates configuration
|
46
|
+
self.client_certs = {
|
47
|
+
"admin": {
|
48
|
+
"common_name": "admin-client",
|
49
|
+
"organization": "Test Organization",
|
50
|
+
"roles": ["admin"],
|
51
|
+
"permissions": ["*"]
|
52
|
+
},
|
53
|
+
"user": {
|
54
|
+
"common_name": "user-client",
|
55
|
+
"organization": "Test Organization",
|
56
|
+
"roles": ["user"],
|
57
|
+
"permissions": ["read", "write"]
|
58
|
+
},
|
59
|
+
"readonly": {
|
60
|
+
"common_name": "readonly-client",
|
61
|
+
"organization": "Test Organization",
|
62
|
+
"roles": ["readonly"],
|
63
|
+
"permissions": ["read"]
|
64
|
+
},
|
65
|
+
"guest": {
|
66
|
+
"common_name": "guest-client",
|
67
|
+
"organization": "Test Organization",
|
68
|
+
"roles": ["guest"],
|
69
|
+
"permissions": ["read"]
|
70
|
+
},
|
71
|
+
"proxy": {
|
72
|
+
"common_name": "proxy-client",
|
73
|
+
"organization": "Test Organization",
|
74
|
+
"roles": ["proxy"],
|
75
|
+
"permissions": ["register", "discover"]
|
76
|
+
}
|
77
|
+
}
|
78
|
+
# Negative test certificates
|
79
|
+
self.negative_certs = {
|
80
|
+
"expired": {
|
81
|
+
"common_name": "expired-client",
|
82
|
+
"organization": "Test Organization",
|
83
|
+
"validity_days": 1 # Will expire quickly
|
84
|
+
},
|
85
|
+
"wrong_org": {
|
86
|
+
"common_name": "wrong-org-client",
|
87
|
+
"organization": "Wrong Organization",
|
88
|
+
"roles": ["user"]
|
89
|
+
},
|
90
|
+
"no_roles": {
|
91
|
+
"common_name": "no-roles-client",
|
92
|
+
"organization": "Test Organization",
|
93
|
+
"roles": []
|
94
|
+
},
|
95
|
+
"invalid_roles": {
|
96
|
+
"common_name": "invalid-roles-client",
|
97
|
+
"organization": "Test Organization",
|
98
|
+
"roles": ["invalid_role"]
|
99
|
+
}
|
100
|
+
}
|
101
|
+
def run_command(self, cmd: List[str], description: str) -> bool:
|
102
|
+
"""Run a command and handle errors."""
|
103
|
+
try:
|
104
|
+
print(f"🔧 {description}...")
|
105
|
+
result = subprocess.run(
|
106
|
+
cmd,
|
107
|
+
cwd=self.project_root,
|
108
|
+
capture_output=True,
|
109
|
+
text=True,
|
110
|
+
check=True
|
111
|
+
)
|
112
|
+
print(f"✅ {description} completed successfully")
|
113
|
+
return True
|
114
|
+
except subprocess.CalledProcessError as e:
|
115
|
+
print(f"❌ {description} failed:")
|
116
|
+
print(f" Command: {' '.join(cmd)}")
|
117
|
+
print(f" Error: {e.stderr}")
|
118
|
+
return False
|
119
|
+
except Exception as e:
|
120
|
+
print(f"❌ {description} failed: {e}")
|
121
|
+
return False
|
122
|
+
def create_ca_certificate(self) -> bool:
|
123
|
+
"""Create Root CA certificate and key."""
|
124
|
+
ca_cert_path = self.certs_dir / "ca_cert.pem"
|
125
|
+
ca_key_path = self.keys_dir / "ca_key.pem"
|
126
|
+
if ca_cert_path.exists() and ca_key_path.exists():
|
127
|
+
print(f"ℹ️ CA certificate already exists: {ca_cert_path}")
|
128
|
+
return True
|
129
|
+
cmd = [
|
130
|
+
sys.executable, "-m", "mcp_security_framework.cli.cert_cli", "create-ca",
|
131
|
+
"-cn", self.ca_config["common_name"],
|
132
|
+
"-o", self.ca_config["organization"],
|
133
|
+
"-c", self.ca_config["country"],
|
134
|
+
"-s", self.ca_config["state"],
|
135
|
+
"-l", self.ca_config["city"],
|
136
|
+
"-y", str(self.ca_config["validity_years"])
|
137
|
+
]
|
138
|
+
success = self.run_command(cmd, "Creating Root CA certificate")
|
139
|
+
if success:
|
140
|
+
# Move files to correct locations
|
141
|
+
default_ca_cert = Path("./certs") / f"{self.ca_config['common_name'].lower().replace(' ', '_')}_ca.crt"
|
142
|
+
default_ca_key = Path("./keys") / f"{self.ca_config['common_name'].lower().replace(' ', '_')}_ca.key"
|
143
|
+
if default_ca_cert.exists():
|
144
|
+
self.run_command(["mv", str(default_ca_cert), str(ca_cert_path)], "Moving CA certificate")
|
145
|
+
if default_ca_key.exists():
|
146
|
+
self.run_command(["mv", str(default_ca_key), str(ca_key_path)], "Moving CA key")
|
147
|
+
return success
|
148
|
+
def create_server_certificate(self) -> bool:
|
149
|
+
"""Create server certificate for HTTPS and mTLS."""
|
150
|
+
server_cert_path = self.certs_dir / "server_cert.pem"
|
151
|
+
server_key_path = self.certs_dir / "server_key.pem"
|
152
|
+
if server_cert_path.exists() and server_key_path.exists():
|
153
|
+
print(f"ℹ️ Server certificate already exists: {server_cert_path}")
|
154
|
+
return True
|
155
|
+
# Create server certificate
|
156
|
+
cmd = [
|
157
|
+
sys.executable, "-m", "mcp_security_framework.cli.cert_cli", "create-server",
|
158
|
+
"-cn", self.server_config["common_name"],
|
159
|
+
"-o", self.server_config["organization"],
|
160
|
+
"-c", self.server_config["country"],
|
161
|
+
"-s", self.server_config["state"],
|
162
|
+
"-l", self.server_config["city"],
|
163
|
+
"-d", str(self.server_config["validity_years"] * 365) # Convert years to days
|
164
|
+
]
|
165
|
+
# Add SAN if supported
|
166
|
+
if self.server_config["san"]:
|
167
|
+
for san in self.server_config["san"]:
|
168
|
+
cmd.extend(["--san", san])
|
169
|
+
success = self.run_command(cmd, "Creating server certificate")
|
170
|
+
if success:
|
171
|
+
# Move files to correct locations
|
172
|
+
default_server_cert = Path("./certs") / f"{self.server_config['common_name'].lower().replace('.', '_')}_server.crt"
|
173
|
+
default_server_key = Path("./keys") / f"{self.server_config['common_name'].lower().replace('.', '_')}_server.key"
|
174
|
+
if default_server_cert.exists():
|
175
|
+
self.run_command(["mv", str(default_server_cert), str(server_cert_path)], "Moving server certificate")
|
176
|
+
if default_server_key.exists():
|
177
|
+
self.run_command(["mv", str(default_server_key), str(server_key_path)], "Moving server key")
|
178
|
+
return success
|
179
|
+
def create_client_certificate(self, name: str, config: Dict) -> bool:
|
180
|
+
"""Create client certificate with specific configuration."""
|
181
|
+
cert_path = self.certs_dir / f"{name}_cert.pem"
|
182
|
+
key_path = self.certs_dir / f"{name}_key.pem"
|
183
|
+
if cert_path.exists() and key_path.exists():
|
184
|
+
print(f"ℹ️ Client certificate {name} already exists: {cert_path}")
|
185
|
+
return True
|
186
|
+
cmd = [
|
187
|
+
sys.executable, "-m", "mcp_security_framework.cli.cert_cli", "create-client",
|
188
|
+
"-cn", config["common_name"],
|
189
|
+
"-o", config["organization"],
|
190
|
+
"-c", self.ca_config["country"],
|
191
|
+
"-s", self.ca_config["state"],
|
192
|
+
"-l", self.ca_config["city"],
|
193
|
+
"-d", "730" # 2 years in days
|
194
|
+
]
|
195
|
+
# Add roles if specified
|
196
|
+
if "roles" in config and config["roles"]:
|
197
|
+
for role in config["roles"]:
|
198
|
+
cmd.extend(["--roles", role])
|
199
|
+
# Add permissions if specified
|
200
|
+
if "permissions" in config and config["permissions"]:
|
201
|
+
for permission in config["permissions"]:
|
202
|
+
cmd.extend(["--permissions", permission])
|
203
|
+
# Add custom validity for negative tests
|
204
|
+
if "validity_days" in config:
|
205
|
+
cmd[cmd.index("-d") + 1] = str(config["validity_days"])
|
206
|
+
success = self.run_command(cmd, f"Creating client certificate: {name}")
|
207
|
+
if success:
|
208
|
+
# Move files to correct locations
|
209
|
+
default_client_cert = Path("./certs") / f"{config['common_name'].lower().replace('-', '_')}_client.crt"
|
210
|
+
default_client_key = Path("./keys") / f"{config['common_name'].lower().replace('-', '_')}_client.key"
|
211
|
+
if default_client_cert.exists():
|
212
|
+
self.run_command(["mv", str(default_client_cert), str(cert_path)], f"Moving {name} certificate")
|
213
|
+
if default_client_key.exists():
|
214
|
+
self.run_command(["mv", str(default_client_key), str(key_path)], f"Moving {name} key")
|
215
|
+
return success
|
216
|
+
def create_legacy_certificates(self) -> bool:
|
217
|
+
"""Create legacy certificate files for compatibility."""
|
218
|
+
legacy_files = [
|
219
|
+
("client.crt", "client.key"),
|
220
|
+
("client_admin.crt", "client_admin.key"),
|
221
|
+
("admin.crt", "admin.key"),
|
222
|
+
("user.crt", "user.key"),
|
223
|
+
("readonly.crt", "readonly.key")
|
224
|
+
]
|
225
|
+
success = True
|
226
|
+
for cert_file, key_file in legacy_files:
|
227
|
+
cert_path = self.certs_dir / cert_file
|
228
|
+
key_path = self.certs_dir / key_file
|
229
|
+
if not cert_path.exists() or not key_path.exists():
|
230
|
+
# Copy from existing certificates
|
231
|
+
if cert_file == "client.crt" and (self.certs_dir / "user_cert.pem").exists():
|
232
|
+
self.run_command(["cp", str(self.certs_dir / "user_cert.pem"), str(cert_path)], f"Creating {cert_file}")
|
233
|
+
self.run_command(["cp", str(self.certs_dir / "user_key.pem"), str(key_path)], f"Creating {key_file}")
|
234
|
+
elif cert_file == "client_admin.crt" and (self.certs_dir / "admin_cert.pem").exists():
|
235
|
+
self.run_command(["cp", str(self.certs_dir / "admin_cert.pem"), str(cert_path)], f"Creating {cert_file}")
|
236
|
+
self.run_command(["cp", str(self.certs_dir / "admin_key.pem"), str(key_path)], f"Creating {key_file}")
|
237
|
+
elif cert_file == "admin.crt" and (self.certs_dir / "admin_cert.pem").exists():
|
238
|
+
self.run_command(["cp", str(self.certs_dir / "admin_cert.pem"), str(cert_path)], f"Creating {cert_file}")
|
239
|
+
self.run_command(["cp", str(self.certs_dir / "admin_key.pem"), str(key_path)], f"Creating {key_file}")
|
240
|
+
elif cert_file == "user.crt" and (self.certs_dir / "user_cert.pem").exists():
|
241
|
+
self.run_command(["cp", str(self.certs_dir / "user_cert.pem"), str(cert_path)], f"Creating {cert_file}")
|
242
|
+
self.run_command(["cp", str(self.certs_dir / "user_key.pem"), str(key_path)], f"Creating {key_file}")
|
243
|
+
elif cert_file == "readonly.crt" and (self.certs_dir / "readonly_cert.pem").exists():
|
244
|
+
self.run_command(["cp", str(self.certs_dir / "readonly_cert.pem"), str(cert_path)], f"Creating {cert_file}")
|
245
|
+
self.run_command(["cp", str(self.certs_dir / "readonly_key.pem"), str(key_path)], f"Creating {key_file}")
|
246
|
+
return success
|
247
|
+
def create_certificate_config(self) -> bool:
|
248
|
+
"""Create certificate configuration file."""
|
249
|
+
config_path = self.certs_dir / "cert_config.json"
|
250
|
+
config = {
|
251
|
+
"ca_cert_path": str(self.certs_dir / "ca_cert.pem"),
|
252
|
+
"ca_key_path": str(self.keys_dir / "ca_key.pem"),
|
253
|
+
"cert_storage_path": str(self.certs_dir),
|
254
|
+
"key_storage_path": str(self.keys_dir),
|
255
|
+
"default_validity_days": 365,
|
256
|
+
"key_size": 2048,
|
257
|
+
"hash_algorithm": "sha256"
|
258
|
+
}
|
259
|
+
try:
|
260
|
+
with open(config_path, 'w') as f:
|
261
|
+
json.dump(config, f, indent=2)
|
262
|
+
print(f"✅ Created certificate config: {config_path}")
|
263
|
+
return True
|
264
|
+
except Exception as e:
|
265
|
+
print(f"❌ Failed to create certificate config: {e}")
|
266
|
+
return False
|
267
|
+
def validate_certificates(self) -> bool:
|
268
|
+
"""Validate all created certificates."""
|
269
|
+
print("\n🔍 Validating certificates...")
|
270
|
+
cert_files = [
|
271
|
+
"ca_cert.pem",
|
272
|
+
"server_cert.pem",
|
273
|
+
"admin_cert.pem",
|
274
|
+
"user_cert.pem",
|
275
|
+
"readonly_cert.pem",
|
276
|
+
"guest_cert.pem",
|
277
|
+
"proxy_cert.pem"
|
278
|
+
]
|
279
|
+
success = True
|
280
|
+
for cert_file in cert_files:
|
281
|
+
cert_path = self.certs_dir / cert_file
|
282
|
+
if cert_path.exists():
|
283
|
+
try:
|
284
|
+
result = subprocess.run(
|
285
|
+
["openssl", "x509", "-in", str(cert_path), "-text", "-noout"],
|
286
|
+
capture_output=True,
|
287
|
+
text=True,
|
288
|
+
check=True
|
289
|
+
)
|
290
|
+
print(f"✅ {cert_file}: Valid")
|
291
|
+
except subprocess.CalledProcessError:
|
292
|
+
print(f"❌ {cert_file}: Invalid")
|
293
|
+
success = False
|
294
|
+
else:
|
295
|
+
print(f"⚠️ {cert_file}: Not found")
|
296
|
+
return success
|
297
|
+
def generate_all(self) -> bool:
|
298
|
+
"""Generate all certificates."""
|
299
|
+
print("🔐 Generating All Certificates for Security Testing")
|
300
|
+
print("=" * 60)
|
301
|
+
success = True
|
302
|
+
# 1. Create CA certificate
|
303
|
+
if not self.create_ca_certificate():
|
304
|
+
success = False
|
305
|
+
print("❌ Cannot continue without CA certificate")
|
306
|
+
return False
|
307
|
+
# 2. Create server certificate
|
308
|
+
if not self.create_server_certificate():
|
309
|
+
success = False
|
310
|
+
# 3. Create client certificates for different roles
|
311
|
+
print("\n👥 Creating client certificates...")
|
312
|
+
for name, config in self.client_certs.items():
|
313
|
+
if not self.create_client_certificate(name, config):
|
314
|
+
success = False
|
315
|
+
# 4. Create negative test certificates
|
316
|
+
print("\n🚫 Creating negative test certificates...")
|
317
|
+
for name, config in self.negative_certs.items():
|
318
|
+
if not self.create_client_certificate(name, config):
|
319
|
+
success = False
|
320
|
+
# 5. Create legacy certificates for compatibility
|
321
|
+
print("\n🔄 Creating legacy certificates...")
|
322
|
+
if not self.create_legacy_certificates():
|
323
|
+
success = False
|
324
|
+
# 6. Create certificate configuration
|
325
|
+
if not self.create_certificate_config():
|
326
|
+
success = False
|
327
|
+
# 7. Validate certificates
|
328
|
+
if not self.validate_certificates():
|
329
|
+
success = False
|
330
|
+
# Print summary
|
331
|
+
print("\n" + "=" * 60)
|
332
|
+
print("📊 CERTIFICATE GENERATION SUMMARY")
|
333
|
+
print("=" * 60)
|
334
|
+
if success:
|
335
|
+
print("✅ All certificates generated successfully!")
|
336
|
+
print(f"📁 Certificates directory: {self.certs_dir}")
|
337
|
+
print(f"🔑 Keys directory: {self.keys_dir}")
|
338
|
+
print("\n📋 Generated certificates:")
|
339
|
+
cert_files = list(self.certs_dir.glob("*.pem")) + list(self.certs_dir.glob("*.crt"))
|
340
|
+
for cert_file in sorted(cert_files):
|
341
|
+
print(f" - {cert_file.name}")
|
342
|
+
key_files = list(self.keys_dir.glob("*.pem")) + list(self.keys_dir.glob("*.key"))
|
343
|
+
for key_file in sorted(key_files):
|
344
|
+
print(f" - {key_file.name}")
|
345
|
+
else:
|
346
|
+
print("❌ Some certificates failed to generate")
|
347
|
+
print("Check the error messages above")
|
348
|
+
return success
|
349
|
+
def main():
|
350
|
+
"""Main function."""
|
351
|
+
generator = CertificateGenerator()
|
352
|
+
try:
|
353
|
+
success = generator.generate_all()
|
354
|
+
sys.exit(0 if success else 1)
|
355
|
+
except KeyboardInterrupt:
|
356
|
+
print("\n⚠️ Certificate generation interrupted by user")
|
357
|
+
sys.exit(1)
|
358
|
+
except Exception as e:
|
359
|
+
print(f"\n❌ Certificate generation failed: {e}")
|
360
|
+
sys.exit(1)
|
361
|
+
if __name__ == "__main__":
|
362
|
+
main()
|
@@ -0,0 +1,177 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
Certificate Generation Script
|
4
|
+
This script generates all necessary certificates for the examples using
|
5
|
+
mcp_security_framework API directly.
|
6
|
+
Author: Vasiliy Zdanovskiy
|
7
|
+
email: vasilyvz@gmail.com
|
8
|
+
"""
|
9
|
+
import os
|
10
|
+
import sys
|
11
|
+
from pathlib import Path
|
12
|
+
from datetime import datetime, timedelta, timezone
|
13
|
+
|
14
|
+
def main():
|
15
|
+
"""Generate all certificates for examples."""
|
16
|
+
print("🔐 Certificate Generation Script")
|
17
|
+
print("=" * 50)
|
18
|
+
|
19
|
+
# Create directories
|
20
|
+
cert_dir = Path("certs")
|
21
|
+
key_dir = Path("keys")
|
22
|
+
cert_dir.mkdir(exist_ok=True)
|
23
|
+
key_dir.mkdir(exist_ok=True)
|
24
|
+
|
25
|
+
# Check if mcp_security_framework is available
|
26
|
+
try:
|
27
|
+
from mcp_security_framework.core.cert_manager import CertificateManager
|
28
|
+
from mcp_security_framework.schemas import (
|
29
|
+
CAConfig, ServerCertConfig, ClientCertConfig, CertificateConfig
|
30
|
+
)
|
31
|
+
print("✅ mcp_security_framework API available")
|
32
|
+
except ImportError as e:
|
33
|
+
print(f"❌ mcp_security_framework not found: {e}")
|
34
|
+
return False
|
35
|
+
|
36
|
+
try:
|
37
|
+
print("🔧 Creating root CA certificate...")
|
38
|
+
|
39
|
+
# Initialize certificate manager first
|
40
|
+
cert_config = CertificateConfig(
|
41
|
+
cert_storage_path=str(cert_dir),
|
42
|
+
key_storage_path=str(key_dir),
|
43
|
+
default_validity_days=365,
|
44
|
+
key_size=2048,
|
45
|
+
hash_algorithm="sha256"
|
46
|
+
)
|
47
|
+
cert_manager = CertificateManager(cert_config)
|
48
|
+
|
49
|
+
# Create CA certificate using API
|
50
|
+
ca_config = CAConfig(
|
51
|
+
common_name="MCP Proxy Adapter CA",
|
52
|
+
organization="MCP Proxy Adapter",
|
53
|
+
organizational_unit="Development",
|
54
|
+
country="US",
|
55
|
+
state="State",
|
56
|
+
locality="City",
|
57
|
+
validity_years=10,
|
58
|
+
key_size=2048,
|
59
|
+
hash_algorithm="sha256"
|
60
|
+
)
|
61
|
+
|
62
|
+
ca_cert_pair = cert_manager.create_root_ca(ca_config)
|
63
|
+
if not ca_cert_pair or not ca_cert_pair.certificate_path:
|
64
|
+
print("❌ Failed to create CA certificate")
|
65
|
+
return False
|
66
|
+
|
67
|
+
ca_cert_path = ca_cert_pair.certificate_path
|
68
|
+
ca_key_path = ca_cert_pair.private_key_path
|
69
|
+
print(f"✅ Root CA certificate created: {ca_cert_path}")
|
70
|
+
|
71
|
+
print("🔧 Creating server certificate...")
|
72
|
+
# Create server certificate
|
73
|
+
server_config = ServerCertConfig(
|
74
|
+
common_name="localhost",
|
75
|
+
organization="MCP Proxy Adapter",
|
76
|
+
country="US",
|
77
|
+
validity_days=365,
|
78
|
+
key_size=2048,
|
79
|
+
subject_alt_names=["localhost", "127.0.0.1"],
|
80
|
+
ca_cert_path=str(ca_cert_path),
|
81
|
+
ca_key_path=str(ca_key_path)
|
82
|
+
)
|
83
|
+
|
84
|
+
server_cert_pair = cert_manager.create_server_certificate(server_config)
|
85
|
+
print(f"✅ Server certificate created: {server_cert_pair.certificate_path}")
|
86
|
+
|
87
|
+
print("🔧 Creating admin client certificate...")
|
88
|
+
# Create admin client certificate
|
89
|
+
admin_config = ClientCertConfig(
|
90
|
+
common_name="admin",
|
91
|
+
organization="MCP Proxy Adapter",
|
92
|
+
country="US",
|
93
|
+
validity_days=365,
|
94
|
+
key_size=2048,
|
95
|
+
roles=["admin"],
|
96
|
+
permissions=["read", "write", "delete"],
|
97
|
+
ca_cert_path=str(ca_cert_path),
|
98
|
+
ca_key_path=str(ca_key_path)
|
99
|
+
)
|
100
|
+
|
101
|
+
admin_cert_pair = cert_manager.create_client_certificate(admin_config)
|
102
|
+
print(f"✅ Admin client certificate created: {admin_cert_pair.certificate_path}")
|
103
|
+
|
104
|
+
print("🔧 Creating user client certificate...")
|
105
|
+
# Create user client certificate
|
106
|
+
user_config = ClientCertConfig(
|
107
|
+
common_name="user",
|
108
|
+
organization="MCP Proxy Adapter",
|
109
|
+
country="US",
|
110
|
+
validity_days=365,
|
111
|
+
key_size=2048,
|
112
|
+
roles=["user"],
|
113
|
+
permissions=["read", "write"],
|
114
|
+
ca_cert_path=str(ca_cert_path),
|
115
|
+
ca_key_path=str(ca_key_path)
|
116
|
+
)
|
117
|
+
|
118
|
+
user_cert_pair = cert_manager.create_client_certificate(user_config)
|
119
|
+
print(f"✅ User client certificate created: {user_cert_pair.certificate_path}")
|
120
|
+
|
121
|
+
print("🔧 Creating readonly client certificate...")
|
122
|
+
# Create readonly client certificate
|
123
|
+
readonly_config = ClientCertConfig(
|
124
|
+
common_name="readonly",
|
125
|
+
organization="MCP Proxy Adapter",
|
126
|
+
country="US",
|
127
|
+
validity_days=365,
|
128
|
+
key_size=2048,
|
129
|
+
roles=["readonly"],
|
130
|
+
permissions=["read"],
|
131
|
+
ca_cert_path=str(ca_cert_path),
|
132
|
+
ca_key_path=str(ca_key_path)
|
133
|
+
)
|
134
|
+
|
135
|
+
readonly_cert_pair = cert_manager.create_client_certificate(readonly_config)
|
136
|
+
print(f"✅ Readonly client certificate created: {readonly_cert_pair.certificate_path}")
|
137
|
+
|
138
|
+
print("\n🎉 All certificates generated successfully!")
|
139
|
+
print(f"📁 Certificates are stored in the '{cert_dir}' directory")
|
140
|
+
print(f"🔑 Private keys are stored in the '{key_dir}' directory")
|
141
|
+
print(f"🔐 CA certificate: {ca_cert_path}")
|
142
|
+
print(f"🔐 Server certificate: {server_cert_pair.certificate_path}")
|
143
|
+
|
144
|
+
print("\n" + "=" * 60)
|
145
|
+
print("✅ CERTIFICATE GENERATION COMPLETED SUCCESSFULLY")
|
146
|
+
print("=" * 60)
|
147
|
+
print("\n📋 NEXT STEPS:")
|
148
|
+
print("1. Generate test configurations:")
|
149
|
+
print(" python -m mcp_proxy_adapter.examples.generate_test_configs --output-dir configs")
|
150
|
+
print("\n2. Run security tests:")
|
151
|
+
print(" python -m mcp_proxy_adapter.examples.run_security_tests")
|
152
|
+
print("\n3. Start basic framework example:")
|
153
|
+
print(" python -m mcp_proxy_adapter.examples.basic_framework.main --config configs/https_simple.json")
|
154
|
+
print("=" * 60)
|
155
|
+
return True
|
156
|
+
|
157
|
+
except Exception as e:
|
158
|
+
print(f"\n❌ CERTIFICATE GENERATION FAILED: {e}")
|
159
|
+
print("=" * 60)
|
160
|
+
import traceback
|
161
|
+
traceback.print_exc()
|
162
|
+
print("\n🔧 TROUBLESHOOTING:")
|
163
|
+
print("1. Check if mcp_security_framework is installed:")
|
164
|
+
print(" pip install mcp_security_framework")
|
165
|
+
print("\n2. Verify write permissions in current directory")
|
166
|
+
print("\n3. Check if certs/ and keys/ directories exist")
|
167
|
+
print("=" * 60)
|
168
|
+
return False
|
169
|
+
|
170
|
+
if __name__ == "__main__":
|
171
|
+
print("🔐 Starting certificate generation...")
|
172
|
+
success = main()
|
173
|
+
if success:
|
174
|
+
print("\n✅ Script completed successfully!")
|
175
|
+
else:
|
176
|
+
print("\n❌ Script failed with errors!")
|
177
|
+
sys.exit(0 if success else 1)
|