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.
- mcp_proxy_adapter/__init__.py +9 -5
- mcp_proxy_adapter/__main__.py +1 -1
- mcp_proxy_adapter/api/app.py +227 -176
- mcp_proxy_adapter/api/handlers.py +68 -60
- mcp_proxy_adapter/api/middleware/__init__.py +7 -5
- mcp_proxy_adapter/api/middleware/base.py +19 -16
- mcp_proxy_adapter/api/middleware/command_permission_middleware.py +44 -34
- mcp_proxy_adapter/api/middleware/error_handling.py +57 -67
- mcp_proxy_adapter/api/middleware/factory.py +50 -52
- mcp_proxy_adapter/api/middleware/logging.py +46 -30
- mcp_proxy_adapter/api/middleware/performance.py +19 -16
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +80 -50
- mcp_proxy_adapter/api/middleware/transport_middleware.py +26 -24
- mcp_proxy_adapter/api/middleware/unified_security.py +70 -51
- mcp_proxy_adapter/api/middleware/user_info_middleware.py +43 -34
- mcp_proxy_adapter/api/schemas.py +69 -43
- mcp_proxy_adapter/api/tool_integration.py +83 -63
- mcp_proxy_adapter/api/tools.py +60 -50
- mcp_proxy_adapter/commands/__init__.py +15 -6
- mcp_proxy_adapter/commands/auth_validation_command.py +107 -110
- mcp_proxy_adapter/commands/base.py +108 -112
- mcp_proxy_adapter/commands/builtin_commands.py +28 -18
- mcp_proxy_adapter/commands/catalog_manager.py +394 -265
- mcp_proxy_adapter/commands/cert_monitor_command.py +222 -204
- mcp_proxy_adapter/commands/certificate_management_command.py +210 -213
- mcp_proxy_adapter/commands/command_registry.py +275 -226
- mcp_proxy_adapter/commands/config_command.py +48 -33
- mcp_proxy_adapter/commands/dependency_container.py +22 -23
- mcp_proxy_adapter/commands/dependency_manager.py +65 -56
- mcp_proxy_adapter/commands/echo_command.py +15 -15
- mcp_proxy_adapter/commands/health_command.py +31 -29
- mcp_proxy_adapter/commands/help_command.py +97 -61
- mcp_proxy_adapter/commands/hooks.py +65 -49
- mcp_proxy_adapter/commands/key_management_command.py +148 -147
- mcp_proxy_adapter/commands/load_command.py +58 -40
- mcp_proxy_adapter/commands/plugins_command.py +80 -54
- mcp_proxy_adapter/commands/protocol_management_command.py +60 -48
- mcp_proxy_adapter/commands/proxy_registration_command.py +107 -115
- mcp_proxy_adapter/commands/reload_command.py +43 -37
- mcp_proxy_adapter/commands/result.py +26 -33
- mcp_proxy_adapter/commands/role_test_command.py +26 -26
- mcp_proxy_adapter/commands/roles_management_command.py +176 -173
- mcp_proxy_adapter/commands/security_command.py +134 -122
- mcp_proxy_adapter/commands/settings_command.py +47 -56
- mcp_proxy_adapter/commands/ssl_setup_command.py +109 -129
- mcp_proxy_adapter/commands/token_management_command.py +129 -158
- mcp_proxy_adapter/commands/transport_management_command.py +41 -36
- mcp_proxy_adapter/commands/unload_command.py +42 -37
- mcp_proxy_adapter/config.py +36 -35
- mcp_proxy_adapter/core/__init__.py +19 -21
- mcp_proxy_adapter/core/app_factory.py +30 -9
- mcp_proxy_adapter/core/app_runner.py +81 -64
- mcp_proxy_adapter/core/auth_validator.py +176 -182
- mcp_proxy_adapter/core/certificate_utils.py +469 -426
- mcp_proxy_adapter/core/client.py +155 -126
- mcp_proxy_adapter/core/client_manager.py +60 -54
- mcp_proxy_adapter/core/client_security.py +120 -91
- mcp_proxy_adapter/core/config_converter.py +176 -143
- mcp_proxy_adapter/core/config_validator.py +12 -4
- mcp_proxy_adapter/core/crl_utils.py +21 -7
- mcp_proxy_adapter/core/errors.py +64 -20
- mcp_proxy_adapter/core/logging.py +34 -29
- mcp_proxy_adapter/core/mtls_asgi.py +29 -25
- mcp_proxy_adapter/core/mtls_asgi_app.py +66 -54
- mcp_proxy_adapter/core/protocol_manager.py +154 -104
- mcp_proxy_adapter/core/proxy_client.py +202 -144
- mcp_proxy_adapter/core/proxy_registration.py +7 -3
- mcp_proxy_adapter/core/role_utils.py +139 -125
- mcp_proxy_adapter/core/security_adapter.py +88 -77
- mcp_proxy_adapter/core/security_factory.py +50 -44
- mcp_proxy_adapter/core/security_integration.py +72 -24
- mcp_proxy_adapter/core/server_adapter.py +68 -64
- mcp_proxy_adapter/core/server_engine.py +71 -53
- mcp_proxy_adapter/core/settings.py +68 -58
- mcp_proxy_adapter/core/ssl_utils.py +69 -56
- mcp_proxy_adapter/core/transport_manager.py +72 -60
- mcp_proxy_adapter/core/unified_config_adapter.py +201 -150
- mcp_proxy_adapter/core/utils.py +4 -2
- mcp_proxy_adapter/custom_openapi.py +107 -99
- mcp_proxy_adapter/examples/basic_framework/main.py +9 -2
- mcp_proxy_adapter/examples/commands/__init__.py +1 -1
- mcp_proxy_adapter/examples/create_certificates_simple.py +182 -71
- mcp_proxy_adapter/examples/debug_request_state.py +38 -19
- mcp_proxy_adapter/examples/debug_role_chain.py +53 -20
- mcp_proxy_adapter/examples/demo_client.py +48 -36
- mcp_proxy_adapter/examples/examples/basic_framework/main.py +9 -2
- mcp_proxy_adapter/examples/examples/full_application/__init__.py +1 -0
- mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +22 -10
- mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +24 -17
- mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +16 -3
- mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +13 -3
- mcp_proxy_adapter/examples/examples/full_application/main.py +27 -2
- mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +48 -14
- mcp_proxy_adapter/examples/full_application/__init__.py +1 -0
- mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +22 -10
- mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +24 -17
- mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +16 -3
- mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +13 -3
- mcp_proxy_adapter/examples/full_application/main.py +27 -2
- mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +48 -14
- mcp_proxy_adapter/examples/generate_all_certificates.py +198 -73
- mcp_proxy_adapter/examples/generate_certificates.py +31 -16
- mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +220 -74
- mcp_proxy_adapter/examples/generate_test_configs.py +68 -91
- mcp_proxy_adapter/examples/proxy_registration_example.py +76 -75
- mcp_proxy_adapter/examples/run_example.py +23 -5
- mcp_proxy_adapter/examples/run_full_test_suite.py +109 -71
- mcp_proxy_adapter/examples/run_proxy_server.py +22 -9
- mcp_proxy_adapter/examples/run_security_tests.py +103 -41
- mcp_proxy_adapter/examples/run_security_tests_fixed.py +72 -36
- mcp_proxy_adapter/examples/scripts/config_generator.py +288 -187
- mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +185 -72
- mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +220 -74
- mcp_proxy_adapter/examples/security_test_client.py +196 -127
- mcp_proxy_adapter/examples/setup_test_environment.py +17 -29
- mcp_proxy_adapter/examples/test_config.py +19 -4
- mcp_proxy_adapter/examples/test_config_generator.py +23 -7
- mcp_proxy_adapter/examples/test_examples.py +84 -56
- mcp_proxy_adapter/examples/universal_client.py +119 -62
- mcp_proxy_adapter/openapi.py +108 -115
- mcp_proxy_adapter/utils/config_generator.py +429 -274
- mcp_proxy_adapter/version.py +1 -2
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/METADATA +1 -1
- mcp_proxy_adapter-6.3.6.dist-info/RECORD +144 -0
- mcp_proxy_adapter-6.3.6.dist-info/top_level.txt +2 -0
- mcp_proxy_adapter_issue_package/demonstrate_issue.py +178 -0
- mcp_proxy_adapter-6.3.4.dist-info/RECORD +0 -143
- mcp_proxy_adapter-6.3.4.dist-info/top_level.txt +0 -1
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/entry_points.txt +0 -0
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/licenses/LICENSE +0 -0
@@ -10,17 +10,27 @@ import subprocess
|
|
10
10
|
import sys
|
11
11
|
import argparse
|
12
12
|
from pathlib import Path
|
13
|
+
|
13
14
|
# Import mcp_security_framework
|
14
15
|
try:
|
15
16
|
from mcp_security_framework.core.cert_manager import CertificateManager
|
16
|
-
from mcp_security_framework.schemas.config import
|
17
|
+
from mcp_security_framework.schemas.config import (
|
18
|
+
CertificateConfig,
|
19
|
+
CAConfig,
|
20
|
+
ServerCertConfig,
|
21
|
+
ClientCertConfig,
|
22
|
+
)
|
17
23
|
from mcp_security_framework.schemas.models import CertificateType
|
24
|
+
|
18
25
|
SECURITY_FRAMEWORK_AVAILABLE = True
|
19
26
|
except ImportError:
|
20
27
|
SECURITY_FRAMEWORK_AVAILABLE = False
|
21
28
|
print("Warning: mcp_security_framework not available, falling back to OpenSSL")
|
29
|
+
|
30
|
+
|
22
31
|
class SimpleCertificateCreator:
|
23
32
|
"""Create certificates using OpenSSL directly."""
|
33
|
+
|
24
34
|
def __init__(self, certs_dir: str = None, keys_dir: str = None):
|
25
35
|
# Use current working directory as base
|
26
36
|
cwd = Path.cwd()
|
@@ -39,17 +49,13 @@ class SimpleCertificateCreator:
|
|
39
49
|
self.keys_dir.mkdir(parents=True, exist_ok=True)
|
40
50
|
print(f"🔧 Using certificates directory: {self.certs_dir}")
|
41
51
|
print(f"🔧 Using keys directory: {self.keys_dir}")
|
52
|
+
|
42
53
|
def run_command(self, cmd: list, description: str) -> bool:
|
43
54
|
"""Run a command and handle errors."""
|
44
55
|
try:
|
45
56
|
print(f"🔧 {description}...")
|
46
57
|
# Use current working directory instead of project_root
|
47
|
-
result = subprocess.run(
|
48
|
-
cmd,
|
49
|
-
capture_output=True,
|
50
|
-
text=True,
|
51
|
-
check=True
|
52
|
-
)
|
58
|
+
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
|
53
59
|
print(f"✅ {description} completed successfully")
|
54
60
|
return True
|
55
61
|
except subprocess.CalledProcessError as e:
|
@@ -60,6 +66,7 @@ class SimpleCertificateCreator:
|
|
60
66
|
except Exception as e:
|
61
67
|
print(f"❌ {description} failed: {e}")
|
62
68
|
return False
|
69
|
+
|
63
70
|
def create_ca_certificate(self) -> bool:
|
64
71
|
"""Create CA certificate using mcp_security_framework or OpenSSL fallback."""
|
65
72
|
ca_cert_path = self.certs_dir / "ca_cert.pem"
|
@@ -71,6 +78,7 @@ class SimpleCertificateCreator:
|
|
71
78
|
return self._create_ca_certificate_with_framework()
|
72
79
|
else:
|
73
80
|
return self._create_ca_certificate_with_openssl()
|
81
|
+
|
74
82
|
def _create_ca_certificate_with_framework(self) -> bool:
|
75
83
|
"""Create CA certificate using mcp_security_framework."""
|
76
84
|
try:
|
@@ -83,7 +91,7 @@ class SimpleCertificateCreator:
|
|
83
91
|
country="US",
|
84
92
|
state="Test State",
|
85
93
|
locality="Test City",
|
86
|
-
validity_years=10
|
94
|
+
validity_years=10,
|
87
95
|
)
|
88
96
|
# Create certificate manager
|
89
97
|
cert_config = CertificateConfig(
|
@@ -91,7 +99,7 @@ class SimpleCertificateCreator:
|
|
91
99
|
key_storage_path=str(self.keys_dir),
|
92
100
|
default_validity_days=365,
|
93
101
|
key_size=2048,
|
94
|
-
hash_algorithm="sha256"
|
102
|
+
hash_algorithm="sha256",
|
95
103
|
)
|
96
104
|
cert_manager = CertificateManager(cert_config)
|
97
105
|
# Create CA certificate
|
@@ -106,7 +114,9 @@ class SimpleCertificateCreator:
|
|
106
114
|
expected_key = self.keys_dir / "ca_key.pem"
|
107
115
|
generated_cert.rename(expected_cert)
|
108
116
|
generated_key.rename(expected_key)
|
109
|
-
print(
|
117
|
+
print(
|
118
|
+
"✅ CA certificate created successfully using mcp_security_framework"
|
119
|
+
)
|
110
120
|
return True
|
111
121
|
else:
|
112
122
|
print("❌ Generated CA certificate files not found")
|
@@ -117,24 +127,32 @@ class SimpleCertificateCreator:
|
|
117
127
|
except Exception as e:
|
118
128
|
print(f"❌ Error creating CA certificate with framework: {e}")
|
119
129
|
return False
|
130
|
+
|
120
131
|
def _create_ca_certificate_with_openssl(self) -> bool:
|
121
132
|
"""Create CA certificate using OpenSSL fallback."""
|
122
133
|
ca_cert_path = self.certs_dir / "ca_cert.pem"
|
123
134
|
ca_key_path = self.keys_dir / "ca_key.pem"
|
124
135
|
# Create CA private key
|
125
|
-
key_cmd = [
|
126
|
-
"openssl", "genrsa", "-out", str(ca_key_path), "2048"
|
127
|
-
]
|
136
|
+
key_cmd = ["openssl", "genrsa", "-out", str(ca_key_path), "2048"]
|
128
137
|
if not self.run_command(key_cmd, "Creating CA private key"):
|
129
138
|
return False
|
130
139
|
# Create CA certificate
|
131
140
|
cert_cmd = [
|
132
|
-
"openssl",
|
133
|
-
"
|
134
|
-
"-
|
135
|
-
"-
|
141
|
+
"openssl",
|
142
|
+
"req",
|
143
|
+
"-new",
|
144
|
+
"-x509",
|
145
|
+
"-days",
|
146
|
+
"3650",
|
147
|
+
"-key",
|
148
|
+
str(ca_key_path),
|
149
|
+
"-out",
|
150
|
+
str(ca_cert_path),
|
151
|
+
"-subj",
|
152
|
+
"/C=US/ST=Test State/L=Test City/O=Test Organization/CN=MCP Proxy Adapter Test CA",
|
136
153
|
]
|
137
154
|
return self.run_command(cert_cmd, "Creating CA certificate")
|
155
|
+
|
138
156
|
def create_server_certificate(self) -> bool:
|
139
157
|
"""Create server certificate using mcp_security_framework or OpenSSL fallback."""
|
140
158
|
server_cert_path = self.certs_dir / "server_cert.pem"
|
@@ -146,6 +164,7 @@ class SimpleCertificateCreator:
|
|
146
164
|
return self._create_server_certificate_with_framework()
|
147
165
|
else:
|
148
166
|
return self._create_server_certificate_with_openssl()
|
167
|
+
|
149
168
|
def _create_server_certificate_with_framework(self) -> bool:
|
150
169
|
"""Create server certificate using mcp_security_framework."""
|
151
170
|
try:
|
@@ -184,7 +203,7 @@ class SimpleCertificateCreator:
|
|
184
203
|
subject_alt_names=["localhost", "127.0.0.1"],
|
185
204
|
validity_years=1,
|
186
205
|
ca_cert_path=ca_cert_path,
|
187
|
-
ca_key_path=ca_key_path
|
206
|
+
ca_key_path=ca_key_path,
|
188
207
|
)
|
189
208
|
# Create certificate manager
|
190
209
|
cert_config = CertificateConfig(
|
@@ -192,7 +211,7 @@ class SimpleCertificateCreator:
|
|
192
211
|
key_storage_path=str(self.certs_dir), # Server keys in certs dir
|
193
212
|
default_validity_days=365,
|
194
213
|
key_size=2048,
|
195
|
-
hash_algorithm="sha256"
|
214
|
+
hash_algorithm="sha256",
|
196
215
|
)
|
197
216
|
cert_manager = CertificateManager(cert_config)
|
198
217
|
# Create server certificate
|
@@ -205,52 +224,71 @@ class SimpleCertificateCreator:
|
|
205
224
|
# Move to expected names
|
206
225
|
generated_cert.rename(self.certs_dir / "server_cert.pem")
|
207
226
|
generated_key.rename(self.certs_dir / "server_key.pem")
|
208
|
-
print(
|
227
|
+
print(
|
228
|
+
"✅ Server certificate created successfully using mcp_security_framework"
|
229
|
+
)
|
209
230
|
return True
|
210
231
|
else:
|
211
232
|
print("❌ Generated certificate files not found")
|
212
233
|
return False
|
213
234
|
else:
|
214
|
-
print(
|
235
|
+
print(
|
236
|
+
"❌ Failed to create server certificate: Invalid certificate pair"
|
237
|
+
)
|
215
238
|
return False
|
216
239
|
except Exception as e:
|
217
240
|
print(f"❌ Error creating server certificate with framework: {e}")
|
218
241
|
return False
|
242
|
+
|
219
243
|
def _create_server_certificate_with_openssl(self) -> bool:
|
220
244
|
"""Create server certificate using OpenSSL fallback."""
|
221
245
|
server_cert_path = self.certs_dir / "server_cert.pem"
|
222
246
|
server_key_path = self.certs_dir / "server_key.pem"
|
223
247
|
# Create server private key
|
224
|
-
key_cmd = [
|
225
|
-
"openssl", "genrsa", "-out", str(server_key_path), "2048"
|
226
|
-
]
|
248
|
+
key_cmd = ["openssl", "genrsa", "-out", str(server_key_path), "2048"]
|
227
249
|
if not self.run_command(key_cmd, "Creating server private key"):
|
228
250
|
return False
|
229
251
|
# Create server certificate signing request
|
230
252
|
csr_path = self.certs_dir / "server.csr"
|
231
253
|
csr_cmd = [
|
232
|
-
"openssl",
|
233
|
-
"
|
234
|
-
"-
|
235
|
-
"-
|
254
|
+
"openssl",
|
255
|
+
"req",
|
256
|
+
"-new",
|
257
|
+
"-key",
|
258
|
+
str(server_key_path),
|
259
|
+
"-out",
|
260
|
+
str(csr_path),
|
261
|
+
"-subj",
|
262
|
+
"/C=US/ST=Test State/L=Test City/O=Test Organization/CN=localhost",
|
236
263
|
]
|
237
264
|
if not self.run_command(csr_cmd, "Creating server CSR"):
|
238
265
|
return False
|
239
266
|
# Create server certificate
|
240
267
|
cert_cmd = [
|
241
|
-
"openssl",
|
242
|
-
"
|
243
|
-
"-
|
244
|
-
"-
|
268
|
+
"openssl",
|
269
|
+
"x509",
|
270
|
+
"-req",
|
271
|
+
"-days",
|
272
|
+
"730",
|
273
|
+
"-in",
|
274
|
+
str(csr_path),
|
275
|
+
"-CA",
|
276
|
+
str(self.certs_dir / "ca_cert.pem"),
|
277
|
+
"-CAkey",
|
278
|
+
str(self.keys_dir / "ca_key.pem"),
|
245
279
|
"-CAcreateserial",
|
246
|
-
"-out",
|
280
|
+
"-out",
|
281
|
+
str(server_cert_path),
|
247
282
|
]
|
248
283
|
success = self.run_command(cert_cmd, "Creating server certificate")
|
249
284
|
# Clean up CSR
|
250
285
|
if csr_path.exists():
|
251
286
|
csr_path.unlink()
|
252
287
|
return success
|
253
|
-
|
288
|
+
|
289
|
+
def create_client_certificate(
|
290
|
+
self, name: str, common_name: str, roles: list = None, permissions: list = None
|
291
|
+
) -> bool:
|
254
292
|
"""Create client certificate using mcp_security_framework or OpenSSL fallback."""
|
255
293
|
cert_path = self.certs_dir / f"{name}_cert.pem"
|
256
294
|
key_path = self.certs_dir / f"{name}_key.pem"
|
@@ -258,13 +296,20 @@ class SimpleCertificateCreator:
|
|
258
296
|
print(f"ℹ️ Client certificate {name} already exists: {cert_path}")
|
259
297
|
return True
|
260
298
|
if SECURITY_FRAMEWORK_AVAILABLE:
|
261
|
-
return self._create_client_certificate_with_framework(
|
299
|
+
return self._create_client_certificate_with_framework(
|
300
|
+
name, common_name, roles, permissions
|
301
|
+
)
|
262
302
|
else:
|
263
303
|
return self._create_client_certificate_with_openssl(name, common_name)
|
264
|
-
|
304
|
+
|
305
|
+
def _create_client_certificate_with_framework(
|
306
|
+
self, name: str, common_name: str, roles: list = None, permissions: list = None
|
307
|
+
) -> bool:
|
265
308
|
"""Create client certificate using mcp_security_framework."""
|
266
309
|
try:
|
267
|
-
print(
|
310
|
+
print(
|
311
|
+
f"🔧 Creating client certificate {name} using mcp_security_framework..."
|
312
|
+
)
|
268
313
|
# Find CA certificate and key files
|
269
314
|
ca_cert_path = None
|
270
315
|
ca_key_path = None
|
@@ -298,7 +343,7 @@ class SimpleCertificateCreator:
|
|
298
343
|
locality="Test City",
|
299
344
|
validity_years=1,
|
300
345
|
ca_cert_path=ca_cert_path,
|
301
|
-
ca_key_path=ca_key_path
|
346
|
+
ca_key_path=ca_key_path,
|
302
347
|
)
|
303
348
|
# Create certificate manager
|
304
349
|
cert_config = CertificateConfig(
|
@@ -306,7 +351,7 @@ class SimpleCertificateCreator:
|
|
306
351
|
key_storage_path=str(self.certs_dir), # Client keys in certs dir
|
307
352
|
default_validity_days=365,
|
308
353
|
key_size=2048,
|
309
|
-
hash_algorithm="sha256"
|
354
|
+
hash_algorithm="sha256",
|
310
355
|
)
|
311
356
|
cert_manager = CertificateManager(cert_config)
|
312
357
|
# Create client certificate
|
@@ -321,58 +366,77 @@ class SimpleCertificateCreator:
|
|
321
366
|
expected_key = self.certs_dir / f"{name}_key.pem"
|
322
367
|
generated_cert.rename(expected_cert)
|
323
368
|
generated_key.rename(expected_key)
|
324
|
-
print(
|
369
|
+
print(
|
370
|
+
f"✅ Client certificate {name} created successfully using mcp_security_framework"
|
371
|
+
)
|
325
372
|
return True
|
326
373
|
else:
|
327
374
|
print(f"❌ Generated certificate files not found for {name}")
|
328
375
|
return False
|
329
376
|
else:
|
330
|
-
print(
|
377
|
+
print(
|
378
|
+
f"❌ Failed to create client certificate {name}: Invalid certificate pair"
|
379
|
+
)
|
331
380
|
return False
|
332
381
|
except Exception as e:
|
333
382
|
print(f"❌ Error creating client certificate {name} with framework: {e}")
|
334
383
|
return False
|
335
|
-
|
384
|
+
|
385
|
+
def _create_client_certificate_with_openssl(
|
386
|
+
self, name: str, common_name: str
|
387
|
+
) -> bool:
|
336
388
|
"""Create client certificate using OpenSSL fallback."""
|
337
389
|
cert_path = self.certs_dir / f"{name}_cert.pem"
|
338
390
|
key_path = self.certs_dir / f"{name}_key.pem"
|
339
391
|
# Create client private key
|
340
|
-
key_cmd = [
|
341
|
-
"openssl", "genrsa", "-out", str(key_path), "2048"
|
342
|
-
]
|
392
|
+
key_cmd = ["openssl", "genrsa", "-out", str(key_path), "2048"]
|
343
393
|
if not self.run_command(key_cmd, f"Creating {name} private key"):
|
344
394
|
return False
|
345
395
|
# Create client certificate signing request
|
346
396
|
csr_path = self.certs_dir / f"{name}.csr"
|
347
397
|
csr_cmd = [
|
348
|
-
"openssl",
|
349
|
-
"
|
350
|
-
"-
|
351
|
-
"-
|
398
|
+
"openssl",
|
399
|
+
"req",
|
400
|
+
"-new",
|
401
|
+
"-key",
|
402
|
+
str(key_path),
|
403
|
+
"-out",
|
404
|
+
str(csr_path),
|
405
|
+
"-subj",
|
406
|
+
f"/C=US/ST=Test State/L=Test City/O=Test Organization/CN={common_name}",
|
352
407
|
]
|
353
408
|
if not self.run_command(csr_cmd, f"Creating {name} CSR"):
|
354
409
|
return False
|
355
410
|
# Create client certificate
|
356
411
|
cert_cmd = [
|
357
|
-
"openssl",
|
358
|
-
"
|
359
|
-
"-
|
360
|
-
"-
|
412
|
+
"openssl",
|
413
|
+
"x509",
|
414
|
+
"-req",
|
415
|
+
"-days",
|
416
|
+
"730",
|
417
|
+
"-in",
|
418
|
+
str(csr_path),
|
419
|
+
"-CA",
|
420
|
+
str(self.certs_dir / "ca_cert.pem"),
|
421
|
+
"-CAkey",
|
422
|
+
str(self.keys_dir / "ca_key.pem"),
|
361
423
|
"-CAcreateserial",
|
362
|
-
"-out",
|
424
|
+
"-out",
|
425
|
+
str(cert_path),
|
363
426
|
]
|
364
427
|
success = self.run_command(cert_cmd, f"Creating {name} certificate")
|
365
428
|
# Clean up CSR
|
366
429
|
if csr_path.exists():
|
367
430
|
csr_path.unlink()
|
368
431
|
return success
|
432
|
+
|
369
433
|
def create_legacy_certificates(self) -> bool:
|
370
434
|
"""Create legacy certificate files for compatibility."""
|
371
435
|
legacy_files = [
|
372
436
|
("client_admin.crt", "client_admin.key", "admin"),
|
373
437
|
("admin.crt", "admin.key", "admin"),
|
374
438
|
("user.crt", "user.key", "user"),
|
375
|
-
("readonly.crt", "readonly.key", "readonly")
|
439
|
+
("readonly.crt", "readonly.key", "readonly"),
|
376
440
|
]
|
377
441
|
success = True
|
378
442
|
for cert_file, key_file, source_name in legacy_files:
|
@@ -382,13 +446,21 @@ class SimpleCertificateCreator:
|
|
382
446
|
source_cert = self.certs_dir / f"{source_name}_cert.pem"
|
383
447
|
source_key = self.certs_dir / f"{source_name}_key.pem"
|
384
448
|
if source_cert.exists() and source_key.exists():
|
385
|
-
self.run_command(
|
386
|
-
|
449
|
+
self.run_command(
|
450
|
+
["cp", str(source_cert), str(cert_path)],
|
451
|
+
f"Creating {cert_file}",
|
452
|
+
)
|
453
|
+
self.run_command(
|
454
|
+
["cp", str(source_key), str(key_path)], f"Creating {key_file}"
|
455
|
+
)
|
387
456
|
else:
|
388
|
-
print(
|
457
|
+
print(
|
458
|
+
f"⚠️ Source certificate {source_name} not found for {cert_file}"
|
459
|
+
)
|
389
460
|
# Don't fail the entire process for missing legacy certificates
|
390
461
|
continue
|
391
462
|
return True # Always return True for legacy certificates
|
463
|
+
|
392
464
|
def validate_certificates(self) -> bool:
|
393
465
|
"""Validate all created certificates."""
|
394
466
|
print("\n🔍 Validating certificates...")
|
@@ -399,7 +471,7 @@ class SimpleCertificateCreator:
|
|
399
471
|
"user_cert.pem",
|
400
472
|
"readonly_cert.pem",
|
401
473
|
"guest_cert.pem",
|
402
|
-
"proxy_cert.pem"
|
474
|
+
"proxy_cert.pem",
|
403
475
|
]
|
404
476
|
success = True
|
405
477
|
for cert_file in cert_files:
|
@@ -410,7 +482,7 @@ class SimpleCertificateCreator:
|
|
410
482
|
["openssl", "x509", "-in", str(cert_path), "-text", "-noout"],
|
411
483
|
capture_output=True,
|
412
484
|
text=True,
|
413
|
-
check=True
|
485
|
+
check=True,
|
414
486
|
)
|
415
487
|
print(f"✅ {cert_file}: Valid")
|
416
488
|
except subprocess.CalledProcessError:
|
@@ -419,6 +491,7 @@ class SimpleCertificateCreator:
|
|
419
491
|
else:
|
420
492
|
print(f"⚠️ {cert_file}: Not found")
|
421
493
|
return success
|
494
|
+
|
422
495
|
def create_all(self) -> bool:
|
423
496
|
"""Create all certificates."""
|
424
497
|
print("🔐 Creating All Certificates for Security Testing")
|
@@ -435,14 +508,41 @@ class SimpleCertificateCreator:
|
|
435
508
|
# 3. Create client certificates
|
436
509
|
print("\n👥 Creating client certificates...")
|
437
510
|
client_certs = [
|
438
|
-
(
|
439
|
-
|
511
|
+
(
|
512
|
+
"admin",
|
513
|
+
"admin-client",
|
514
|
+
["admin"],
|
515
|
+
[
|
516
|
+
"read",
|
517
|
+
"write",
|
518
|
+
"execute",
|
519
|
+
"delete",
|
520
|
+
"admin",
|
521
|
+
"register",
|
522
|
+
"unregister",
|
523
|
+
"heartbeat",
|
524
|
+
"discover",
|
525
|
+
],
|
526
|
+
),
|
527
|
+
(
|
528
|
+
"user",
|
529
|
+
"user-client",
|
530
|
+
["user"],
|
531
|
+
["read", "execute", "register", "unregister", "heartbeat", "discover"],
|
532
|
+
),
|
440
533
|
("readonly", "readonly-client", ["readonly"], ["read", "discover"]),
|
441
534
|
("guest", "guest-client", ["guest"], ["read", "discover"]),
|
442
|
-
(
|
535
|
+
(
|
536
|
+
"proxy",
|
537
|
+
"proxy-client",
|
538
|
+
["proxy"],
|
539
|
+
["register", "unregister", "heartbeat", "discover"],
|
540
|
+
),
|
443
541
|
]
|
444
542
|
for name, common_name, roles, permissions in client_certs:
|
445
|
-
if not self.create_client_certificate(
|
543
|
+
if not self.create_client_certificate(
|
544
|
+
name, common_name, roles, permissions
|
545
|
+
):
|
446
546
|
success = False
|
447
547
|
# 4. Create legacy certificates
|
448
548
|
print("\n🔄 Creating legacy certificates...")
|
@@ -463,6 +563,7 @@ class SimpleCertificateCreator:
|
|
463
563
|
except OSError:
|
464
564
|
# On Windows, symlink might require admin privileges, copy instead
|
465
565
|
import shutil
|
566
|
+
|
466
567
|
shutil.copy2(ca_cert, expected_ca_cert)
|
467
568
|
print(f"✅ Created CA certificate copy: {expected_ca_cert}")
|
468
569
|
|
@@ -472,10 +573,13 @@ class SimpleCertificateCreator:
|
|
472
573
|
if server_cert.exists() and not expected_server_cert.exists():
|
473
574
|
try:
|
474
575
|
expected_server_cert.symlink_to(server_cert)
|
475
|
-
print(
|
576
|
+
print(
|
577
|
+
f"✅ Created server certificate symlink: {expected_server_cert}"
|
578
|
+
)
|
476
579
|
except OSError:
|
477
580
|
# On Windows, symlink might require admin privileges, copy instead
|
478
581
|
import shutil
|
582
|
+
|
479
583
|
shutil.copy2(server_cert, expected_server_cert)
|
480
584
|
print(f"✅ Created server certificate copy: {expected_server_cert}")
|
481
585
|
|
@@ -486,6 +590,7 @@ class SimpleCertificateCreator:
|
|
486
590
|
if server_key_certs.exists():
|
487
591
|
# Server key is in certs directory, move it to keys directory
|
488
592
|
import shutil
|
593
|
+
|
489
594
|
shutil.move(str(server_key_certs), str(server_key_keys))
|
490
595
|
print(f"✅ Moved server key to keys directory: {server_key_keys}")
|
491
596
|
|
@@ -498,6 +603,7 @@ class SimpleCertificateCreator:
|
|
498
603
|
except OSError:
|
499
604
|
# On Windows, symlink might require admin privileges, copy instead
|
500
605
|
import shutil
|
606
|
+
|
501
607
|
shutil.copy2(server_key_keys, expected_server_key)
|
502
608
|
print(f"✅ Created server key copy: {expected_server_key}")
|
503
609
|
|
@@ -510,20 +616,28 @@ class SimpleCertificateCreator:
|
|
510
616
|
print(f"📁 Certificates directory: {self.certs_dir}")
|
511
617
|
print(f"🔑 Keys directory: {self.keys_dir}")
|
512
618
|
print("\n📋 Created certificates:")
|
513
|
-
cert_files = list(self.certs_dir.glob("*.pem")) + list(
|
619
|
+
cert_files = list(self.certs_dir.glob("*.pem")) + list(
|
620
|
+
self.certs_dir.glob("*.crt")
|
621
|
+
)
|
514
622
|
for cert_file in sorted(cert_files):
|
515
623
|
print(f" - {cert_file.name}")
|
516
|
-
key_files = list(self.keys_dir.glob("*.pem")) + list(
|
624
|
+
key_files = list(self.keys_dir.glob("*.pem")) + list(
|
625
|
+
self.keys_dir.glob("*.key")
|
626
|
+
)
|
517
627
|
for key_file in sorted(key_files):
|
518
628
|
print(f" - {key_file.name}")
|
519
629
|
else:
|
520
630
|
print("❌ Some certificates failed to create")
|
521
631
|
print("Check the error messages above")
|
522
632
|
return success
|
633
|
+
|
634
|
+
|
523
635
|
def main():
|
524
636
|
"""Main function."""
|
525
637
|
parser = argparse.ArgumentParser(description="Create certificates for testing")
|
526
|
-
parser.add_argument(
|
638
|
+
parser.add_argument(
|
639
|
+
"--certs-dir", help="Directory for certificates (default: ./certs)"
|
640
|
+
)
|
527
641
|
parser.add_argument("--keys-dir", help="Directory for keys (default: ./keys)")
|
528
642
|
args = parser.parse_args()
|
529
643
|
|
@@ -543,10 +657,7 @@ def main():
|
|
543
657
|
certs_dir = args.certs_dir
|
544
658
|
keys_dir = args.keys_dir
|
545
659
|
|
546
|
-
creator = SimpleCertificateCreator(
|
547
|
-
certs_dir=certs_dir,
|
548
|
-
keys_dir=keys_dir
|
549
|
-
)
|
660
|
+
creator = SimpleCertificateCreator(certs_dir=certs_dir, keys_dir=keys_dir)
|
550
661
|
try:
|
551
662
|
success = creator.create_all()
|
552
663
|
sys.exit(0 if success else 1)
|
@@ -556,5 +667,7 @@ def main():
|
|
556
667
|
except Exception as e:
|
557
668
|
print(f"\n❌ Certificate creation failed: {e}")
|
558
669
|
sys.exit(1)
|
670
|
+
|
671
|
+
|
559
672
|
if __name__ == "__main__":
|
560
673
|
main()
|