mcp-proxy-adapter 6.1.1__py3-none-any.whl → 6.2.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.
Files changed (146) hide show
  1. mcp_proxy_adapter/__main__.py +27 -7
  2. mcp_proxy_adapter/api/app.py +18 -7
  3. mcp_proxy_adapter/commands/ssl_setup_command.py +234 -351
  4. mcp_proxy_adapter/core/app_factory.py +87 -3
  5. mcp_proxy_adapter/core/app_runner.py +272 -0
  6. mcp_proxy_adapter/core/certificate_utils.py +291 -73
  7. mcp_proxy_adapter/core/client.py +574 -0
  8. mcp_proxy_adapter/core/client_manager.py +284 -0
  9. mcp_proxy_adapter/core/server_adapter.py +17 -80
  10. mcp_proxy_adapter/core/server_engine.py +5 -99
  11. mcp_proxy_adapter/core/ssl_utils.py +13 -12
  12. mcp_proxy_adapter/core/transport_manager.py +5 -5
  13. mcp_proxy_adapter/examples/__init__.py +16 -0
  14. mcp_proxy_adapter/examples/basic_framework/__init__.py +7 -0
  15. mcp_proxy_adapter/examples/basic_framework/commands/__init__.py +4 -0
  16. mcp_proxy_adapter/examples/basic_framework/hooks/__init__.py +4 -0
  17. mcp_proxy_adapter/examples/basic_framework/main.py +21 -40
  18. mcp_proxy_adapter/examples/commands/__init__.py +5 -1
  19. mcp_proxy_adapter/examples/create_certificates_simple.py +260 -75
  20. mcp_proxy_adapter/examples/debug_request_state.py +4 -36
  21. mcp_proxy_adapter/examples/debug_role_chain.py +2 -49
  22. mcp_proxy_adapter/examples/demo_client.py +0 -66
  23. mcp_proxy_adapter/examples/full_application/__init__.py +11 -0
  24. mcp_proxy_adapter/examples/full_application/commands/__init__.py +7 -0
  25. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +0 -19
  26. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +0 -16
  27. mcp_proxy_adapter/examples/full_application/hooks/__init__.py +7 -0
  28. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +0 -22
  29. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +0 -24
  30. mcp_proxy_adapter/examples/full_application/main.py +65 -44
  31. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +154 -0
  32. mcp_proxy_adapter/examples/generate_all_certificates.py +0 -67
  33. mcp_proxy_adapter/examples/generate_certificates.py +0 -15
  34. mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +369 -0
  35. mcp_proxy_adapter/examples/generate_test_configs.py +204 -0
  36. mcp_proxy_adapter/examples/proxy_registration_example.py +3 -70
  37. mcp_proxy_adapter/examples/run_example.py +1 -23
  38. mcp_proxy_adapter/examples/run_security_tests.py +2 -60
  39. mcp_proxy_adapter/examples/run_security_tests_fixed.py +0 -53
  40. mcp_proxy_adapter/examples/security_test_client.py +18 -123
  41. mcp_proxy_adapter/examples/setup_test_environment.py +179 -0
  42. mcp_proxy_adapter/examples/test_config.py +148 -0
  43. mcp_proxy_adapter/examples/test_config_generator.py +1 -25
  44. mcp_proxy_adapter/examples/test_examples.py +4 -67
  45. mcp_proxy_adapter/examples/universal_client.py +154 -162
  46. mcp_proxy_adapter/main.py +51 -161
  47. mcp_proxy_adapter/version.py +1 -1
  48. mcp_proxy_adapter-6.2.1.dist-info/METADATA +676 -0
  49. mcp_proxy_adapter-6.2.1.dist-info/RECORD +119 -0
  50. mcp_proxy_adapter/docs/EN/TROUBLESHOOTING.md +0 -285
  51. mcp_proxy_adapter/docs/RU/TROUBLESHOOTING.md +0 -285
  52. mcp_proxy_adapter/examples/README.md +0 -257
  53. mcp_proxy_adapter/examples/README_EN.md +0 -258
  54. mcp_proxy_adapter/examples/SECURITY_TESTING.md +0 -455
  55. mcp_proxy_adapter/examples/basic_framework/configs/http_auth.json +0 -37
  56. mcp_proxy_adapter/examples/basic_framework/configs/http_simple.json +0 -23
  57. mcp_proxy_adapter/examples/basic_framework/configs/https_auth.json +0 -43
  58. mcp_proxy_adapter/examples/basic_framework/configs/https_no_protocol_middleware.json +0 -36
  59. mcp_proxy_adapter/examples/basic_framework/configs/https_simple.json +0 -29
  60. mcp_proxy_adapter/examples/basic_framework/configs/mtls_no_protocol_middleware.json +0 -34
  61. mcp_proxy_adapter/examples/basic_framework/configs/mtls_no_roles.json +0 -39
  62. mcp_proxy_adapter/examples/basic_framework/configs/mtls_simple.json +0 -35
  63. mcp_proxy_adapter/examples/basic_framework/configs/mtls_with_roles.json +0 -45
  64. mcp_proxy_adapter/examples/basic_framework/roles.json +0 -21
  65. mcp_proxy_adapter/examples/cert_config.json +0 -9
  66. mcp_proxy_adapter/examples/certs/admin.crt +0 -32
  67. mcp_proxy_adapter/examples/certs/admin.key +0 -52
  68. mcp_proxy_adapter/examples/certs/admin_cert.pem +0 -21
  69. mcp_proxy_adapter/examples/certs/admin_key.pem +0 -28
  70. mcp_proxy_adapter/examples/certs/ca_cert.pem +0 -23
  71. mcp_proxy_adapter/examples/certs/ca_cert.srl +0 -1
  72. mcp_proxy_adapter/examples/certs/ca_key.pem +0 -28
  73. mcp_proxy_adapter/examples/certs/cert_config.json +0 -9
  74. mcp_proxy_adapter/examples/certs/client.crt +0 -32
  75. mcp_proxy_adapter/examples/certs/client.key +0 -52
  76. mcp_proxy_adapter/examples/certs/client_admin.crt +0 -32
  77. mcp_proxy_adapter/examples/certs/client_admin.key +0 -52
  78. mcp_proxy_adapter/examples/certs/client_user.crt +0 -32
  79. mcp_proxy_adapter/examples/certs/client_user.key +0 -52
  80. mcp_proxy_adapter/examples/certs/guest_cert.pem +0 -21
  81. mcp_proxy_adapter/examples/certs/guest_key.pem +0 -28
  82. mcp_proxy_adapter/examples/certs/mcp_proxy_adapter_ca_ca.crt +0 -23
  83. mcp_proxy_adapter/examples/certs/proxy_cert.pem +0 -21
  84. mcp_proxy_adapter/examples/certs/proxy_key.pem +0 -28
  85. mcp_proxy_adapter/examples/certs/readonly.crt +0 -32
  86. mcp_proxy_adapter/examples/certs/readonly.key +0 -52
  87. mcp_proxy_adapter/examples/certs/readonly_cert.pem +0 -21
  88. mcp_proxy_adapter/examples/certs/readonly_key.pem +0 -28
  89. mcp_proxy_adapter/examples/certs/server.crt +0 -32
  90. mcp_proxy_adapter/examples/certs/server.key +0 -52
  91. mcp_proxy_adapter/examples/certs/server_cert.pem +0 -32
  92. mcp_proxy_adapter/examples/certs/server_key.pem +0 -52
  93. mcp_proxy_adapter/examples/certs/test_ca_ca.crt +0 -20
  94. mcp_proxy_adapter/examples/certs/user.crt +0 -32
  95. mcp_proxy_adapter/examples/certs/user.key +0 -52
  96. mcp_proxy_adapter/examples/certs/user_cert.pem +0 -21
  97. mcp_proxy_adapter/examples/certs/user_key.pem +0 -28
  98. mcp_proxy_adapter/examples/client_configs/api_key_client.json +0 -13
  99. mcp_proxy_adapter/examples/client_configs/basic_auth_client.json +0 -13
  100. mcp_proxy_adapter/examples/client_configs/certificate_client.json +0 -22
  101. mcp_proxy_adapter/examples/client_configs/jwt_client.json +0 -15
  102. mcp_proxy_adapter/examples/client_configs/no_auth_client.json +0 -9
  103. mcp_proxy_adapter/examples/full_application/configs/http_auth.json +0 -37
  104. mcp_proxy_adapter/examples/full_application/configs/http_simple.json +0 -23
  105. mcp_proxy_adapter/examples/full_application/configs/https_auth.json +0 -39
  106. mcp_proxy_adapter/examples/full_application/configs/https_simple.json +0 -25
  107. mcp_proxy_adapter/examples/full_application/configs/mtls_no_roles.json +0 -39
  108. mcp_proxy_adapter/examples/full_application/configs/mtls_with_roles.json +0 -45
  109. mcp_proxy_adapter/examples/full_application/roles.json +0 -21
  110. mcp_proxy_adapter/examples/keys/ca_key.pem +0 -28
  111. mcp_proxy_adapter/examples/keys/mcp_proxy_adapter_ca_ca.key +0 -28
  112. mcp_proxy_adapter/examples/keys/test_ca_ca.key +0 -28
  113. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log +0 -220
  114. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.1 +0 -1
  115. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.2 +0 -1
  116. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.3 +0 -1
  117. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.4 +0 -1
  118. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.5 +0 -1
  119. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log +0 -220
  120. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.1 +0 -1
  121. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.2 +0 -1
  122. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.3 +0 -1
  123. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.4 +0 -1
  124. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.5 +0 -1
  125. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log +0 -2
  126. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.1 +0 -1
  127. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.2 +0 -1
  128. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.3 +0 -1
  129. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.4 +0 -1
  130. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.5 +0 -1
  131. mcp_proxy_adapter/examples/roles.json +0 -38
  132. mcp_proxy_adapter/examples/server_configs/config_basic_http.json +0 -204
  133. mcp_proxy_adapter/examples/server_configs/config_http_token.json +0 -238
  134. mcp_proxy_adapter/examples/server_configs/config_https.json +0 -215
  135. mcp_proxy_adapter/examples/server_configs/config_https_token.json +0 -231
  136. mcp_proxy_adapter/examples/server_configs/config_mtls.json +0 -215
  137. mcp_proxy_adapter/examples/server_configs/config_proxy_registration.json +0 -250
  138. mcp_proxy_adapter/examples/server_configs/config_simple.json +0 -46
  139. mcp_proxy_adapter/examples/server_configs/roles.json +0 -38
  140. mcp_proxy_adapter/utils/config_generator.py +0 -727
  141. mcp_proxy_adapter-6.1.1.dist-info/METADATA +0 -205
  142. mcp_proxy_adapter-6.1.1.dist-info/RECORD +0 -197
  143. mcp_proxy_adapter-6.1.1.dist-info/entry_points.txt +0 -2
  144. mcp_proxy_adapter-6.1.1.dist-info/licenses/LICENSE +0 -21
  145. {mcp_proxy_adapter-6.1.1.dist-info → mcp_proxy_adapter-6.2.1.dist-info}/WHEEL +0 -0
  146. {mcp_proxy_adapter-6.1.1.dist-info → mcp_proxy_adapter-6.2.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,154 @@
1
+ """
2
+ Proxy Registration Endpoints
3
+ This module provides proxy registration endpoints for testing.
4
+ Author: Vasiliy Zdanovskiy
5
+ email: vasilyvz@gmail.com
6
+ """
7
+ from fastapi import APIRouter, HTTPException
8
+ from pydantic import BaseModel
9
+ from typing import Dict, List, Optional
10
+ import time
11
+ import uuid
12
+ # In-memory registry for testing
13
+ _registry: Dict[str, Dict] = {}
14
+ router = APIRouter(prefix="/proxy", tags=["proxy"])
15
+ class ServerRegistration(BaseModel):
16
+ """Server registration request model."""
17
+ server_id: str
18
+ server_url: str
19
+ server_name: str
20
+ description: Optional[str] = None
21
+ version: Optional[str] = "1.0.0"
22
+ capabilities: Optional[List[str]] = None
23
+ endpoints: Optional[Dict[str, str]] = None
24
+ auth_method: Optional[str] = "none"
25
+ security_enabled: Optional[bool] = False
26
+ class ServerUnregistration(BaseModel):
27
+ """Server unregistration request model."""
28
+ server_key: str # Use server_key directly
29
+ class HeartbeatData(BaseModel):
30
+ """Heartbeat data model."""
31
+ server_id: str
32
+ server_key: str
33
+ timestamp: Optional[int] = None
34
+ status: Optional[str] = "healthy"
35
+ class RegistrationResponse(BaseModel):
36
+ """Registration response model."""
37
+ success: bool
38
+ server_key: str
39
+ message: str
40
+ copy_number: int
41
+ class DiscoveryResponse(BaseModel):
42
+ """Discovery response model."""
43
+ success: bool
44
+ servers: List[Dict]
45
+ total: int
46
+ active: int
47
+ @router.post("/register", response_model=RegistrationResponse)
48
+ async def register_server(registration: ServerRegistration):
49
+ """Register a server with the proxy."""
50
+ try:
51
+ # Generate unique server key
52
+ server_key = f"{registration.server_id}_{uuid.uuid4().hex[:8]}"
53
+ copy_number = 1
54
+ # Store server information
55
+ _registry[server_key] = {
56
+ "server_id": registration.server_id,
57
+ "server_url": registration.server_url,
58
+ "server_name": registration.server_name,
59
+ "description": registration.description,
60
+ "version": registration.version,
61
+ "capabilities": registration.capabilities or [],
62
+ "endpoints": registration.endpoints or {},
63
+ "auth_method": registration.auth_method,
64
+ "security_enabled": registration.security_enabled,
65
+ "registered_at": int(time.time()),
66
+ "last_heartbeat": int(time.time()),
67
+ "status": "active"
68
+ }
69
+ return RegistrationResponse(
70
+ success=True,
71
+ server_key=server_key,
72
+ message=f"Server {registration.server_name} registered successfully",
73
+ copy_number=copy_number
74
+ )
75
+ except Exception as e:
76
+ raise HTTPException(status_code=500, detail=f"Registration failed: {str(e)}")
77
+ @router.post("/unregister")
78
+ async def unregister_server(unregistration: ServerUnregistration):
79
+ """Unregister a server from the proxy."""
80
+ try:
81
+ # Check if server exists in registry
82
+ if unregistration.server_key not in _registry:
83
+ raise HTTPException(status_code=404, detail="Server not found")
84
+ # Remove from registry
85
+ del _registry[unregistration.server_key]
86
+ return {"success": True, "message": "Server unregistered successfully"}
87
+ except HTTPException:
88
+ raise
89
+ except Exception as e:
90
+ raise HTTPException(status_code=500, detail=f"Unregistration failed: {str(e)}")
91
+ @router.post("/heartbeat")
92
+ async def send_heartbeat(heartbeat: HeartbeatData):
93
+ """Send heartbeat for a registered server."""
94
+ try:
95
+ if heartbeat.server_key not in _registry:
96
+ raise HTTPException(status_code=404, detail="Server not found")
97
+ # Update heartbeat information
98
+ _registry[heartbeat.server_key]["last_heartbeat"] = heartbeat.timestamp or int(time.time())
99
+ _registry[heartbeat.server_key]["status"] = heartbeat.status
100
+ return {"success": True, "message": "Heartbeat received"}
101
+ except HTTPException:
102
+ raise
103
+ except Exception as e:
104
+ raise HTTPException(status_code=500, detail=f"Heartbeat failed: {str(e)}")
105
+ @router.get("/discover", response_model=DiscoveryResponse)
106
+ async def discover_servers():
107
+ """Discover active servers."""
108
+ try:
109
+ current_time = int(time.time())
110
+ active_servers = []
111
+ for server_key, server in _registry.items():
112
+ # Consider server active if heartbeat was within last 5 minutes
113
+ if current_time - server["last_heartbeat"] < 300:
114
+ active_servers.append({
115
+ "server_key": server_key,
116
+ "server_id": server["server_id"],
117
+ "server_name": server["server_name"],
118
+ "server_url": server["server_url"],
119
+ "status": server["status"],
120
+ "last_heartbeat": server["last_heartbeat"]
121
+ })
122
+ return DiscoveryResponse(
123
+ success=True,
124
+ servers=active_servers,
125
+ total=len(_registry),
126
+ active=len(active_servers)
127
+ )
128
+ except Exception as e:
129
+ raise HTTPException(status_code=500, detail=f"Discovery failed: {str(e)}")
130
+ @router.get("/status")
131
+ async def get_proxy_status():
132
+ """Get proxy status."""
133
+ try:
134
+ current_time = int(time.time())
135
+ active_count = sum(
136
+ 1 for server in _registry.values()
137
+ if current_time - server["last_heartbeat"] < 300
138
+ )
139
+ return {
140
+ "success": True,
141
+ "total_registered": len(_registry),
142
+ "active_servers": active_count,
143
+ "inactive_servers": len(_registry) - active_count
144
+ }
145
+ except Exception as e:
146
+ raise HTTPException(status_code=500, detail=f"Status check failed: {str(e)}")
147
+ @router.delete("/clear")
148
+ async def clear_registry():
149
+ """Clear the registry (for testing)."""
150
+ try:
151
+ _registry.clear()
152
+ return {"success": True, "message": "Registry cleared"}
153
+ except Exception as e:
154
+ raise HTTPException(status_code=500, detail=f"Clear failed: {str(e)}")
@@ -1,37 +1,29 @@
1
1
  #!/usr/bin/env python3
2
2
  """
3
3
  Generate All Certificates for Security Testing
4
-
5
4
  This script generates all necessary certificates for comprehensive security testing:
6
5
  - Root CA certificate and key
7
6
  - Server certificates for HTTPS and mTLS
8
7
  - Client certificates for different roles (admin, user, readonly, etc.)
9
8
  - Test certificates for negative scenarios
10
-
11
9
  Author: Vasiliy Zdanovskiy
12
10
  email: vasilyvz@gmail.com
13
11
  """
14
-
15
12
  import json
16
13
  import os
17
14
  import subprocess
18
15
  import sys
19
16
  from pathlib import Path
20
17
  from typing import Dict, List, Optional
21
-
22
-
23
18
  class CertificateGenerator:
24
19
  """Generate all certificates for security testing."""
25
-
26
20
  def __init__(self):
27
21
  self.project_root = Path(__file__).parent.parent.parent
28
22
  self.certs_dir = self.project_root / "mcp_proxy_adapter" / "examples" / "certs"
29
23
  self.keys_dir = self.project_root / "mcp_proxy_adapter" / "examples" / "keys"
30
-
31
24
  # Create directories if they don't exist
32
25
  self.certs_dir.mkdir(parents=True, exist_ok=True)
33
26
  self.keys_dir.mkdir(parents=True, exist_ok=True)
34
-
35
27
  # Certificate configuration
36
28
  self.ca_config = {
37
29
  "common_name": "MCP Proxy Adapter Test CA",
@@ -41,7 +33,6 @@ class CertificateGenerator:
41
33
  "city": "Test City",
42
34
  "validity_years": 10
43
35
  }
44
-
45
36
  self.server_config = {
46
37
  "common_name": "mcp-proxy-adapter-test.local",
47
38
  "organization": "Test Organization",
@@ -51,7 +42,6 @@ class CertificateGenerator:
51
42
  "validity_years": 2,
52
43
  "san": ["localhost", "127.0.0.1", "mcp-proxy-adapter-test.local"]
53
44
  }
54
-
55
45
  # Client certificates configuration
56
46
  self.client_certs = {
57
47
  "admin": {
@@ -85,7 +75,6 @@ class CertificateGenerator:
85
75
  "permissions": ["register", "discover"]
86
76
  }
87
77
  }
88
-
89
78
  # Negative test certificates
90
79
  self.negative_certs = {
91
80
  "expired": {
@@ -109,7 +98,6 @@ class CertificateGenerator:
109
98
  "roles": ["invalid_role"]
110
99
  }
111
100
  }
112
-
113
101
  def run_command(self, cmd: List[str], description: str) -> bool:
114
102
  """Run a command and handle errors."""
115
103
  try:
@@ -131,16 +119,13 @@ class CertificateGenerator:
131
119
  except Exception as e:
132
120
  print(f"āŒ {description} failed: {e}")
133
121
  return False
134
-
135
122
  def create_ca_certificate(self) -> bool:
136
123
  """Create Root CA certificate and key."""
137
124
  ca_cert_path = self.certs_dir / "ca_cert.pem"
138
125
  ca_key_path = self.keys_dir / "ca_key.pem"
139
-
140
126
  if ca_cert_path.exists() and ca_key_path.exists():
141
127
  print(f"ā„¹ļø CA certificate already exists: {ca_cert_path}")
142
128
  return True
143
-
144
129
  cmd = [
145
130
  sys.executable, "-m", "mcp_security_framework.cli.cert_cli", "create-ca",
146
131
  "-cn", self.ca_config["common_name"],
@@ -150,30 +135,23 @@ class CertificateGenerator:
150
135
  "-l", self.ca_config["city"],
151
136
  "-y", str(self.ca_config["validity_years"])
152
137
  ]
153
-
154
138
  success = self.run_command(cmd, "Creating Root CA certificate")
155
-
156
139
  if success:
157
140
  # Move files to correct locations
158
141
  default_ca_cert = Path("./certs") / f"{self.ca_config['common_name'].lower().replace(' ', '_')}_ca.crt"
159
142
  default_ca_key = Path("./keys") / f"{self.ca_config['common_name'].lower().replace(' ', '_')}_ca.key"
160
-
161
143
  if default_ca_cert.exists():
162
144
  self.run_command(["mv", str(default_ca_cert), str(ca_cert_path)], "Moving CA certificate")
163
145
  if default_ca_key.exists():
164
146
  self.run_command(["mv", str(default_ca_key), str(ca_key_path)], "Moving CA key")
165
-
166
147
  return success
167
-
168
148
  def create_server_certificate(self) -> bool:
169
149
  """Create server certificate for HTTPS and mTLS."""
170
150
  server_cert_path = self.certs_dir / "server_cert.pem"
171
151
  server_key_path = self.certs_dir / "server_key.pem"
172
-
173
152
  if server_cert_path.exists() and server_key_path.exists():
174
153
  print(f"ā„¹ļø Server certificate already exists: {server_cert_path}")
175
154
  return True
176
-
177
155
  # Create server certificate
178
156
  cmd = [
179
157
  sys.executable, "-m", "mcp_security_framework.cli.cert_cli", "create-server",
@@ -184,35 +162,27 @@ class CertificateGenerator:
184
162
  "-l", self.server_config["city"],
185
163
  "-d", str(self.server_config["validity_years"] * 365) # Convert years to days
186
164
  ]
187
-
188
165
  # Add SAN if supported
189
166
  if self.server_config["san"]:
190
167
  for san in self.server_config["san"]:
191
168
  cmd.extend(["--san", san])
192
-
193
169
  success = self.run_command(cmd, "Creating server certificate")
194
-
195
170
  if success:
196
171
  # Move files to correct locations
197
172
  default_server_cert = Path("./certs") / f"{self.server_config['common_name'].lower().replace('.', '_')}_server.crt"
198
173
  default_server_key = Path("./keys") / f"{self.server_config['common_name'].lower().replace('.', '_')}_server.key"
199
-
200
174
  if default_server_cert.exists():
201
175
  self.run_command(["mv", str(default_server_cert), str(server_cert_path)], "Moving server certificate")
202
176
  if default_server_key.exists():
203
177
  self.run_command(["mv", str(default_server_key), str(server_key_path)], "Moving server key")
204
-
205
178
  return success
206
-
207
179
  def create_client_certificate(self, name: str, config: Dict) -> bool:
208
180
  """Create client certificate with specific configuration."""
209
181
  cert_path = self.certs_dir / f"{name}_cert.pem"
210
182
  key_path = self.certs_dir / f"{name}_key.pem"
211
-
212
183
  if cert_path.exists() and key_path.exists():
213
184
  print(f"ā„¹ļø Client certificate {name} already exists: {cert_path}")
214
185
  return True
215
-
216
186
  cmd = [
217
187
  sys.executable, "-m", "mcp_security_framework.cli.cert_cli", "create-client",
218
188
  "-cn", config["common_name"],
@@ -222,35 +192,27 @@ class CertificateGenerator:
222
192
  "-l", self.ca_config["city"],
223
193
  "-d", "730" # 2 years in days
224
194
  ]
225
-
226
195
  # Add roles if specified
227
196
  if "roles" in config and config["roles"]:
228
197
  for role in config["roles"]:
229
198
  cmd.extend(["--roles", role])
230
-
231
199
  # Add permissions if specified
232
200
  if "permissions" in config and config["permissions"]:
233
201
  for permission in config["permissions"]:
234
202
  cmd.extend(["--permissions", permission])
235
-
236
203
  # Add custom validity for negative tests
237
204
  if "validity_days" in config:
238
205
  cmd[cmd.index("-d") + 1] = str(config["validity_days"])
239
-
240
206
  success = self.run_command(cmd, f"Creating client certificate: {name}")
241
-
242
207
  if success:
243
208
  # Move files to correct locations
244
209
  default_client_cert = Path("./certs") / f"{config['common_name'].lower().replace('-', '_')}_client.crt"
245
210
  default_client_key = Path("./keys") / f"{config['common_name'].lower().replace('-', '_')}_client.key"
246
-
247
211
  if default_client_cert.exists():
248
212
  self.run_command(["mv", str(default_client_cert), str(cert_path)], f"Moving {name} certificate")
249
213
  if default_client_key.exists():
250
214
  self.run_command(["mv", str(default_client_key), str(key_path)], f"Moving {name} key")
251
-
252
215
  return success
253
-
254
216
  def create_legacy_certificates(self) -> bool:
255
217
  """Create legacy certificate files for compatibility."""
256
218
  legacy_files = [
@@ -260,12 +222,10 @@ class CertificateGenerator:
260
222
  ("user.crt", "user.key"),
261
223
  ("readonly.crt", "readonly.key")
262
224
  ]
263
-
264
225
  success = True
265
226
  for cert_file, key_file in legacy_files:
266
227
  cert_path = self.certs_dir / cert_file
267
228
  key_path = self.certs_dir / key_file
268
-
269
229
  if not cert_path.exists() or not key_path.exists():
270
230
  # Copy from existing certificates
271
231
  if cert_file == "client.crt" and (self.certs_dir / "user_cert.pem").exists():
@@ -283,13 +243,10 @@ class CertificateGenerator:
283
243
  elif cert_file == "readonly.crt" and (self.certs_dir / "readonly_cert.pem").exists():
284
244
  self.run_command(["cp", str(self.certs_dir / "readonly_cert.pem"), str(cert_path)], f"Creating {cert_file}")
285
245
  self.run_command(["cp", str(self.certs_dir / "readonly_key.pem"), str(key_path)], f"Creating {key_file}")
286
-
287
246
  return success
288
-
289
247
  def create_certificate_config(self) -> bool:
290
248
  """Create certificate configuration file."""
291
249
  config_path = self.certs_dir / "cert_config.json"
292
-
293
250
  config = {
294
251
  "ca_cert_path": str(self.certs_dir / "ca_cert.pem"),
295
252
  "ca_key_path": str(self.keys_dir / "ca_key.pem"),
@@ -299,7 +256,6 @@ class CertificateGenerator:
299
256
  "key_size": 2048,
300
257
  "hash_algorithm": "sha256"
301
258
  }
302
-
303
259
  try:
304
260
  with open(config_path, 'w') as f:
305
261
  json.dump(config, f, indent=2)
@@ -308,11 +264,9 @@ class CertificateGenerator:
308
264
  except Exception as e:
309
265
  print(f"āŒ Failed to create certificate config: {e}")
310
266
  return False
311
-
312
267
  def validate_certificates(self) -> bool:
313
268
  """Validate all created certificates."""
314
269
  print("\nšŸ” Validating certificates...")
315
-
316
270
  cert_files = [
317
271
  "ca_cert.pem",
318
272
  "server_cert.pem",
@@ -322,7 +276,6 @@ class CertificateGenerator:
322
276
  "guest_cert.pem",
323
277
  "proxy_cert.pem"
324
278
  ]
325
-
326
279
  success = True
327
280
  for cert_file in cert_files:
328
281
  cert_path = self.certs_dir / cert_file
@@ -340,80 +293,62 @@ class CertificateGenerator:
340
293
  success = False
341
294
  else:
342
295
  print(f"āš ļø {cert_file}: Not found")
343
-
344
296
  return success
345
-
346
297
  def generate_all(self) -> bool:
347
298
  """Generate all certificates."""
348
299
  print("šŸ” Generating All Certificates for Security Testing")
349
300
  print("=" * 60)
350
-
351
301
  success = True
352
-
353
302
  # 1. Create CA certificate
354
303
  if not self.create_ca_certificate():
355
304
  success = False
356
305
  print("āŒ Cannot continue without CA certificate")
357
306
  return False
358
-
359
307
  # 2. Create server certificate
360
308
  if not self.create_server_certificate():
361
309
  success = False
362
-
363
310
  # 3. Create client certificates for different roles
364
311
  print("\nšŸ‘„ Creating client certificates...")
365
312
  for name, config in self.client_certs.items():
366
313
  if not self.create_client_certificate(name, config):
367
314
  success = False
368
-
369
315
  # 4. Create negative test certificates
370
316
  print("\n🚫 Creating negative test certificates...")
371
317
  for name, config in self.negative_certs.items():
372
318
  if not self.create_client_certificate(name, config):
373
319
  success = False
374
-
375
320
  # 5. Create legacy certificates for compatibility
376
321
  print("\nšŸ”„ Creating legacy certificates...")
377
322
  if not self.create_legacy_certificates():
378
323
  success = False
379
-
380
324
  # 6. Create certificate configuration
381
325
  if not self.create_certificate_config():
382
326
  success = False
383
-
384
327
  # 7. Validate certificates
385
328
  if not self.validate_certificates():
386
329
  success = False
387
-
388
330
  # Print summary
389
331
  print("\n" + "=" * 60)
390
332
  print("šŸ“Š CERTIFICATE GENERATION SUMMARY")
391
333
  print("=" * 60)
392
-
393
334
  if success:
394
335
  print("āœ… All certificates generated successfully!")
395
336
  print(f"šŸ“ Certificates directory: {self.certs_dir}")
396
337
  print(f"šŸ”‘ Keys directory: {self.keys_dir}")
397
338
  print("\nšŸ“‹ Generated certificates:")
398
-
399
339
  cert_files = list(self.certs_dir.glob("*.pem")) + list(self.certs_dir.glob("*.crt"))
400
340
  for cert_file in sorted(cert_files):
401
341
  print(f" - {cert_file.name}")
402
-
403
342
  key_files = list(self.keys_dir.glob("*.pem")) + list(self.keys_dir.glob("*.key"))
404
343
  for key_file in sorted(key_files):
405
344
  print(f" - {key_file.name}")
406
345
  else:
407
346
  print("āŒ Some certificates failed to generate")
408
347
  print("Check the error messages above")
409
-
410
348
  return success
411
-
412
-
413
349
  def main():
414
350
  """Main function."""
415
351
  generator = CertificateGenerator()
416
-
417
352
  try:
418
353
  success = generator.generate_all()
419
354
  sys.exit(0 if success else 1)
@@ -423,7 +358,5 @@ def main():
423
358
  except Exception as e:
424
359
  print(f"\nāŒ Certificate generation failed: {e}")
425
360
  sys.exit(1)
426
-
427
-
428
361
  if __name__ == "__main__":
429
362
  main()
@@ -1,19 +1,15 @@
1
1
  #!/usr/bin/env python3
2
2
  """
3
3
  Certificate Generation Script
4
-
5
4
  This script generates all necessary certificates for the examples using
6
5
  mcp_security_framework certificate management tools.
7
-
8
6
  Author: Vasiliy Zdanovskiy
9
7
  email: vasilyvz@gmail.com
10
8
  """
11
-
12
9
  import os
13
10
  import subprocess
14
11
  import sys
15
12
  from pathlib import Path
16
-
17
13
  def run_command(cmd, description):
18
14
  """Run a command and handle errors."""
19
15
  print(f"šŸ”§ {description}...")
@@ -25,16 +21,13 @@ def run_command(cmd, description):
25
21
  print(f"āŒ {description} failed: {e}")
26
22
  print(f"Error output: {e.stderr}")
27
23
  return False
28
-
29
24
  def main():
30
25
  """Generate all certificates for examples."""
31
26
  print("šŸ” Certificate Generation Script")
32
27
  print("=" * 50)
33
-
34
28
  # Create directories
35
29
  cert_dir = Path("certs")
36
30
  cert_dir.mkdir(exist_ok=True)
37
-
38
31
  # Check if mcp_security_framework is available
39
32
  try:
40
33
  import mcp_security_framework
@@ -42,7 +35,6 @@ def main():
42
35
  except ImportError:
43
36
  print("āŒ mcp_security_framework not found")
44
37
  return False
45
-
46
38
  # Generate CA certificate
47
39
  if not run_command(
48
40
  "python -m mcp_security_framework.cli.cert_cli create-ca "
@@ -56,7 +48,6 @@ def main():
56
48
  "Creating root CA certificate"
57
49
  ):
58
50
  return False
59
-
60
51
  # Generate server certificate
61
52
  if not run_command(
62
53
  "python -m mcp_security_framework.cli.cert_cli -c cert_config.json create-server "
@@ -68,7 +59,6 @@ def main():
68
59
  "Creating server certificate"
69
60
  ):
70
61
  return False
71
-
72
62
  # Generate admin client certificate
73
63
  if not run_command(
74
64
  "python -m mcp_security_framework.cli.cert_cli -c cert_config.json create-client "
@@ -82,7 +72,6 @@ def main():
82
72
  "Creating admin client certificate"
83
73
  ):
84
74
  return False
85
-
86
75
  # Generate user client certificate
87
76
  if not run_command(
88
77
  "python -m mcp_security_framework.cli.cert_cli -c cert_config.json create-client "
@@ -96,7 +85,6 @@ def main():
96
85
  "Creating user client certificate"
97
86
  ):
98
87
  return False
99
-
100
88
  # Generate readonly client certificate
101
89
  if not run_command(
102
90
  "python -m mcp_security_framework.cli.cert_cli -c cert_config.json create-client "
@@ -110,12 +98,9 @@ def main():
110
98
  "Creating readonly client certificate"
111
99
  ):
112
100
  return False
113
-
114
101
  print("\nšŸŽ‰ All certificates generated successfully!")
115
102
  print("šŸ“ Certificates are stored in the 'certs' directory")
116
-
117
103
  return True
118
-
119
104
  if __name__ == "__main__":
120
105
  success = main()
121
106
  sys.exit(0 if success else 1)