mcp-proxy-adapter 6.1.0__py3-none-any.whl → 6.2.0__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 (148) hide show
  1. mcp_proxy_adapter/__main__.py +27 -7
  2. mcp_proxy_adapter/api/app.py +18 -7
  3. mcp_proxy_adapter/api/middleware/__init__.py +2 -2
  4. mcp_proxy_adapter/api/middleware/protocol_middleware.py +32 -13
  5. mcp_proxy_adapter/api/middleware/unified_security.py +12 -4
  6. mcp_proxy_adapter/commands/ssl_setup_command.py +234 -351
  7. mcp_proxy_adapter/core/app_factory.py +87 -3
  8. mcp_proxy_adapter/core/app_runner.py +272 -0
  9. mcp_proxy_adapter/core/certificate_utils.py +291 -73
  10. mcp_proxy_adapter/core/client.py +574 -0
  11. mcp_proxy_adapter/core/client_manager.py +284 -0
  12. mcp_proxy_adapter/core/protocol_manager.py +132 -10
  13. mcp_proxy_adapter/core/security_integration.py +19 -11
  14. mcp_proxy_adapter/core/server_adapter.py +17 -80
  15. mcp_proxy_adapter/core/server_engine.py +5 -99
  16. mcp_proxy_adapter/core/ssl_utils.py +13 -12
  17. mcp_proxy_adapter/core/transport_manager.py +5 -5
  18. mcp_proxy_adapter/examples/__init__.py +16 -0
  19. mcp_proxy_adapter/examples/basic_framework/__init__.py +7 -0
  20. mcp_proxy_adapter/examples/basic_framework/commands/__init__.py +4 -0
  21. mcp_proxy_adapter/examples/basic_framework/hooks/__init__.py +4 -0
  22. mcp_proxy_adapter/examples/basic_framework/main.py +21 -40
  23. mcp_proxy_adapter/examples/commands/__init__.py +5 -1
  24. mcp_proxy_adapter/examples/create_certificates_simple.py +260 -75
  25. mcp_proxy_adapter/examples/debug_request_state.py +4 -36
  26. mcp_proxy_adapter/examples/debug_role_chain.py +2 -49
  27. mcp_proxy_adapter/examples/demo_client.py +0 -66
  28. mcp_proxy_adapter/examples/full_application/__init__.py +11 -0
  29. mcp_proxy_adapter/examples/full_application/commands/__init__.py +7 -0
  30. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +0 -19
  31. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +0 -16
  32. mcp_proxy_adapter/examples/full_application/hooks/__init__.py +7 -0
  33. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +0 -22
  34. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +0 -24
  35. mcp_proxy_adapter/examples/full_application/main.py +65 -44
  36. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +154 -0
  37. mcp_proxy_adapter/examples/generate_all_certificates.py +0 -67
  38. mcp_proxy_adapter/examples/generate_certificates.py +0 -15
  39. mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +369 -0
  40. mcp_proxy_adapter/examples/generate_test_configs.py +204 -0
  41. mcp_proxy_adapter/examples/proxy_registration_example.py +3 -70
  42. mcp_proxy_adapter/examples/run_example.py +1 -23
  43. mcp_proxy_adapter/examples/run_security_tests.py +2 -60
  44. mcp_proxy_adapter/examples/run_security_tests_fixed.py +0 -53
  45. mcp_proxy_adapter/examples/security_test_client.py +18 -123
  46. mcp_proxy_adapter/examples/setup_test_environment.py +179 -0
  47. mcp_proxy_adapter/examples/test_config.py +148 -0
  48. mcp_proxy_adapter/examples/test_config_generator.py +86 -0
  49. mcp_proxy_adapter/examples/test_examples.py +4 -67
  50. mcp_proxy_adapter/examples/universal_client.py +154 -162
  51. mcp_proxy_adapter/main.py +51 -161
  52. mcp_proxy_adapter/utils/config_generator.py +90 -2
  53. mcp_proxy_adapter/version.py +4 -2
  54. mcp_proxy_adapter-6.2.0.dist-info/METADATA +687 -0
  55. mcp_proxy_adapter-6.2.0.dist-info/RECORD +122 -0
  56. mcp_proxy_adapter/examples/README.md +0 -257
  57. mcp_proxy_adapter/examples/README_EN.md +0 -258
  58. mcp_proxy_adapter/examples/SECURITY_TESTING.md +0 -455
  59. mcp_proxy_adapter/examples/__pycache__/security_configurations.cpython-312.pyc +0 -0
  60. mcp_proxy_adapter/examples/__pycache__/security_test_client.cpython-312.pyc +0 -0
  61. mcp_proxy_adapter/examples/basic_framework/configs/http_auth.json +0 -37
  62. mcp_proxy_adapter/examples/basic_framework/configs/http_simple.json +0 -23
  63. mcp_proxy_adapter/examples/basic_framework/configs/https_auth.json +0 -39
  64. mcp_proxy_adapter/examples/basic_framework/configs/https_simple.json +0 -25
  65. mcp_proxy_adapter/examples/basic_framework/configs/mtls_no_roles.json +0 -39
  66. mcp_proxy_adapter/examples/basic_framework/configs/mtls_with_roles.json +0 -45
  67. mcp_proxy_adapter/examples/basic_framework/roles.json +0 -21
  68. mcp_proxy_adapter/examples/cert_config.json +0 -9
  69. mcp_proxy_adapter/examples/certs/admin.crt +0 -32
  70. mcp_proxy_adapter/examples/certs/admin.key +0 -52
  71. mcp_proxy_adapter/examples/certs/admin_cert.pem +0 -21
  72. mcp_proxy_adapter/examples/certs/admin_key.pem +0 -28
  73. mcp_proxy_adapter/examples/certs/ca_cert.pem +0 -23
  74. mcp_proxy_adapter/examples/certs/ca_cert.srl +0 -1
  75. mcp_proxy_adapter/examples/certs/ca_key.pem +0 -28
  76. mcp_proxy_adapter/examples/certs/cert_config.json +0 -9
  77. mcp_proxy_adapter/examples/certs/client.crt +0 -32
  78. mcp_proxy_adapter/examples/certs/client.key +0 -52
  79. mcp_proxy_adapter/examples/certs/client_admin.crt +0 -32
  80. mcp_proxy_adapter/examples/certs/client_admin.key +0 -52
  81. mcp_proxy_adapter/examples/certs/client_user.crt +0 -32
  82. mcp_proxy_adapter/examples/certs/client_user.key +0 -52
  83. mcp_proxy_adapter/examples/certs/guest_cert.pem +0 -21
  84. mcp_proxy_adapter/examples/certs/guest_key.pem +0 -28
  85. mcp_proxy_adapter/examples/certs/mcp_proxy_adapter_ca_ca.crt +0 -23
  86. mcp_proxy_adapter/examples/certs/proxy_cert.pem +0 -21
  87. mcp_proxy_adapter/examples/certs/proxy_key.pem +0 -28
  88. mcp_proxy_adapter/examples/certs/readonly.crt +0 -32
  89. mcp_proxy_adapter/examples/certs/readonly.key +0 -52
  90. mcp_proxy_adapter/examples/certs/readonly_cert.pem +0 -21
  91. mcp_proxy_adapter/examples/certs/readonly_key.pem +0 -28
  92. mcp_proxy_adapter/examples/certs/server.crt +0 -32
  93. mcp_proxy_adapter/examples/certs/server.key +0 -52
  94. mcp_proxy_adapter/examples/certs/server_cert.pem +0 -32
  95. mcp_proxy_adapter/examples/certs/server_key.pem +0 -52
  96. mcp_proxy_adapter/examples/certs/test_ca_ca.crt +0 -20
  97. mcp_proxy_adapter/examples/certs/user.crt +0 -32
  98. mcp_proxy_adapter/examples/certs/user.key +0 -52
  99. mcp_proxy_adapter/examples/certs/user_cert.pem +0 -21
  100. mcp_proxy_adapter/examples/certs/user_key.pem +0 -28
  101. mcp_proxy_adapter/examples/client_configs/api_key_client.json +0 -13
  102. mcp_proxy_adapter/examples/client_configs/basic_auth_client.json +0 -13
  103. mcp_proxy_adapter/examples/client_configs/certificate_client.json +0 -22
  104. mcp_proxy_adapter/examples/client_configs/jwt_client.json +0 -15
  105. mcp_proxy_adapter/examples/client_configs/no_auth_client.json +0 -9
  106. mcp_proxy_adapter/examples/full_application/configs/http_auth.json +0 -37
  107. mcp_proxy_adapter/examples/full_application/configs/http_simple.json +0 -23
  108. mcp_proxy_adapter/examples/full_application/configs/https_auth.json +0 -39
  109. mcp_proxy_adapter/examples/full_application/configs/https_simple.json +0 -25
  110. mcp_proxy_adapter/examples/full_application/configs/mtls_no_roles.json +0 -39
  111. mcp_proxy_adapter/examples/full_application/configs/mtls_with_roles.json +0 -45
  112. mcp_proxy_adapter/examples/full_application/roles.json +0 -21
  113. mcp_proxy_adapter/examples/keys/ca_key.pem +0 -28
  114. mcp_proxy_adapter/examples/keys/mcp_proxy_adapter_ca_ca.key +0 -28
  115. mcp_proxy_adapter/examples/keys/test_ca_ca.key +0 -28
  116. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log +0 -220
  117. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.1 +0 -1
  118. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.2 +0 -1
  119. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.3 +0 -1
  120. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.4 +0 -1
  121. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.5 +0 -1
  122. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log +0 -220
  123. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.1 +0 -1
  124. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.2 +0 -1
  125. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.3 +0 -1
  126. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.4 +0 -1
  127. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.5 +0 -1
  128. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log +0 -2
  129. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.1 +0 -1
  130. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.2 +0 -1
  131. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.3 +0 -1
  132. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.4 +0 -1
  133. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.5 +0 -1
  134. mcp_proxy_adapter/examples/roles.json +0 -38
  135. mcp_proxy_adapter/examples/server_configs/config_basic_http.json +0 -204
  136. mcp_proxy_adapter/examples/server_configs/config_http_token.json +0 -238
  137. mcp_proxy_adapter/examples/server_configs/config_https.json +0 -215
  138. mcp_proxy_adapter/examples/server_configs/config_https_token.json +0 -231
  139. mcp_proxy_adapter/examples/server_configs/config_mtls.json +0 -215
  140. mcp_proxy_adapter/examples/server_configs/config_proxy_registration.json +0 -250
  141. mcp_proxy_adapter/examples/server_configs/config_simple.json +0 -46
  142. mcp_proxy_adapter/examples/server_configs/roles.json +0 -38
  143. mcp_proxy_adapter-6.1.0.dist-info/METADATA +0 -205
  144. mcp_proxy_adapter-6.1.0.dist-info/RECORD +0 -193
  145. {mcp_proxy_adapter-6.1.0.dist-info → mcp_proxy_adapter-6.2.0.dist-info}/WHEEL +0 -0
  146. {mcp_proxy_adapter-6.1.0.dist-info → mcp_proxy_adapter-6.2.0.dist-info}/entry_points.txt +0 -0
  147. {mcp_proxy_adapter-6.1.0.dist-info → mcp_proxy_adapter-6.2.0.dist-info}/licenses/LICENSE +0 -0
  148. {mcp_proxy_adapter-6.1.0.dist-info → mcp_proxy_adapter-6.2.0.dist-info}/top_level.txt +0 -0
@@ -1,38 +1,50 @@
1
1
  #!/usr/bin/env python3
2
2
  """
3
3
  Simple Certificate Creation Script
4
-
5
- This script creates basic certificates for testing using OpenSSL directly.
6
-
4
+ This script creates basic certificates for testing using mcp_security_framework.
7
5
  Author: Vasiliy Zdanovskiy
8
6
  email: vasilyvz@gmail.com
9
7
  """
10
-
11
8
  import os
12
9
  import subprocess
13
10
  import sys
11
+ import argparse
14
12
  from pathlib import Path
15
-
16
-
13
+ # Import mcp_security_framework
14
+ try:
15
+ from mcp_security_framework.core.cert_manager import CertificateManager
16
+ from mcp_security_framework.schemas.config import CertificateConfig, CAConfig, ServerCertConfig, ClientCertConfig
17
+ from mcp_security_framework.schemas.models import CertificateType
18
+ SECURITY_FRAMEWORK_AVAILABLE = True
19
+ except ImportError:
20
+ SECURITY_FRAMEWORK_AVAILABLE = False
21
+ print("Warning: mcp_security_framework not available, falling back to OpenSSL")
17
22
  class SimpleCertificateCreator:
18
23
  """Create certificates using OpenSSL directly."""
19
-
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
-
24
+ def __init__(self, certs_dir: str = None, keys_dir: str = None):
25
+ if certs_dir:
26
+ self.certs_dir = Path(certs_dir).resolve()
27
+ else:
28
+ self.project_root = Path(__file__).parent.parent.parent
29
+ self.certs_dir = self.project_root / "mcp_proxy_adapter" / "examples" / "certs"
30
+ if keys_dir:
31
+ self.keys_dir = Path(keys_dir).resolve()
32
+ else:
33
+ if not certs_dir:
34
+ self.project_root = Path(__file__).parent.parent.parent
35
+ self.keys_dir = self.project_root / "mcp_proxy_adapter" / "examples" / "keys"
25
36
  # Create directories
26
37
  self.certs_dir.mkdir(parents=True, exist_ok=True)
27
38
  self.keys_dir.mkdir(parents=True, exist_ok=True)
28
-
39
+ print(f"🔧 Using certificates directory: {self.certs_dir}")
40
+ print(f"🔧 Using keys directory: {self.keys_dir}")
29
41
  def run_command(self, cmd: list, description: str) -> bool:
30
42
  """Run a command and handle errors."""
31
43
  try:
32
44
  print(f"🔧 {description}...")
45
+ # Use current working directory instead of project_root
33
46
  result = subprocess.run(
34
47
  cmd,
35
- cwd=self.project_root,
36
48
  capture_output=True,
37
49
  text=True,
38
50
  check=True
@@ -47,23 +59,73 @@ class SimpleCertificateCreator:
47
59
  except Exception as e:
48
60
  print(f"❌ {description} failed: {e}")
49
61
  return False
50
-
51
62
  def create_ca_certificate(self) -> bool:
52
- """Create CA certificate using OpenSSL."""
63
+ """Create CA certificate using mcp_security_framework or OpenSSL fallback."""
53
64
  ca_cert_path = self.certs_dir / "ca_cert.pem"
54
65
  ca_key_path = self.keys_dir / "ca_key.pem"
55
-
56
66
  if ca_cert_path.exists() and ca_key_path.exists():
57
67
  print(f"ℹ️ CA certificate already exists: {ca_cert_path}")
58
68
  return True
59
-
69
+ if SECURITY_FRAMEWORK_AVAILABLE:
70
+ return self._create_ca_certificate_with_framework()
71
+ else:
72
+ return self._create_ca_certificate_with_openssl()
73
+ def _create_ca_certificate_with_framework(self) -> bool:
74
+ """Create CA certificate using mcp_security_framework."""
75
+ try:
76
+ print("🔧 Creating CA certificate using mcp_security_framework...")
77
+ # Create CA certificate configuration
78
+ ca_config = CAConfig(
79
+ common_name="mcp_proxy_adapter_test_ca",
80
+ organization="Test Organization",
81
+ organizational_unit="Test Unit",
82
+ country="US",
83
+ state="Test State",
84
+ locality="Test City",
85
+ validity_years=10
86
+ )
87
+ # Create certificate manager
88
+ cert_config = CertificateConfig(
89
+ cert_storage_path=str(self.certs_dir),
90
+ key_storage_path=str(self.keys_dir),
91
+ default_validity_days=365,
92
+ key_size=2048,
93
+ hash_algorithm="sha256"
94
+ )
95
+ cert_manager = CertificateManager(cert_config)
96
+ # Create CA certificate
97
+ cert_pair = cert_manager.create_root_ca(ca_config)
98
+ if cert_pair and cert_pair.certificate_path and cert_pair.private_key_path:
99
+ # Rename the generated files to the expected names
100
+ generated_cert = Path(cert_pair.certificate_path)
101
+ generated_key = Path(cert_pair.private_key_path)
102
+ if generated_cert.exists() and generated_key.exists():
103
+ # Move to expected names
104
+ expected_cert = self.certs_dir / "ca_cert.pem"
105
+ expected_key = self.keys_dir / "ca_key.pem"
106
+ generated_cert.rename(expected_cert)
107
+ generated_key.rename(expected_key)
108
+ print("✅ CA certificate created successfully using mcp_security_framework")
109
+ return True
110
+ else:
111
+ print("❌ Generated CA certificate files not found")
112
+ return False
113
+ else:
114
+ print("❌ Failed to create CA certificate: Invalid certificate pair")
115
+ return False
116
+ except Exception as e:
117
+ print(f"❌ Error creating CA certificate with framework: {e}")
118
+ return False
119
+ def _create_ca_certificate_with_openssl(self) -> bool:
120
+ """Create CA certificate using OpenSSL fallback."""
121
+ ca_cert_path = self.certs_dir / "ca_cert.pem"
122
+ ca_key_path = self.keys_dir / "ca_key.pem"
60
123
  # Create CA private key
61
124
  key_cmd = [
62
125
  "openssl", "genrsa", "-out", str(ca_key_path), "2048"
63
126
  ]
64
127
  if not self.run_command(key_cmd, "Creating CA private key"):
65
128
  return False
66
-
67
129
  # Create CA certificate
68
130
  cert_cmd = [
69
131
  "openssl", "req", "-new", "-x509", "-days", "3650",
@@ -72,23 +134,97 @@ class SimpleCertificateCreator:
72
134
  "-subj", "/C=US/ST=Test State/L=Test City/O=Test Organization/CN=MCP Proxy Adapter Test CA"
73
135
  ]
74
136
  return self.run_command(cert_cmd, "Creating CA certificate")
75
-
76
137
  def create_server_certificate(self) -> bool:
77
- """Create server certificate using OpenSSL."""
138
+ """Create server certificate using mcp_security_framework or OpenSSL fallback."""
78
139
  server_cert_path = self.certs_dir / "server_cert.pem"
79
140
  server_key_path = self.certs_dir / "server_key.pem"
80
-
81
141
  if server_cert_path.exists() and server_key_path.exists():
82
- print(f"ℹ️ Server certificate already exists: {server_cert_path}")
142
+ print("ℹ️ Server certificate already exists")
83
143
  return True
84
-
144
+ if SECURITY_FRAMEWORK_AVAILABLE:
145
+ return self._create_server_certificate_with_framework()
146
+ else:
147
+ return self._create_server_certificate_with_openssl()
148
+ def _create_server_certificate_with_framework(self) -> bool:
149
+ """Create server certificate using mcp_security_framework."""
150
+ try:
151
+ print("🔧 Creating server certificate using mcp_security_framework...")
152
+ # Find CA certificate and key files
153
+ ca_cert_path = None
154
+ ca_key_path = None
155
+ # Look for CA certificate files with expected names
156
+ expected_ca_cert = self.certs_dir / "ca_cert.pem"
157
+ expected_ca_key = self.keys_dir / "ca_key.pem"
158
+ if expected_ca_cert.exists():
159
+ ca_cert_path = str(expected_ca_cert)
160
+ else:
161
+ # Fallback: look for CA certificate files with pattern
162
+ for cert_file in self.certs_dir.glob("*_ca.crt"):
163
+ ca_cert_path = str(cert_file)
164
+ break
165
+ if expected_ca_key.exists():
166
+ ca_key_path = str(expected_ca_key)
167
+ else:
168
+ # Fallback: look for CA key files with pattern
169
+ for key_file in self.keys_dir.glob("*_ca.key"):
170
+ ca_key_path = str(key_file)
171
+ break
172
+ if not ca_cert_path or not ca_key_path:
173
+ print("❌ CA certificate or key not found")
174
+ return False
175
+ # Create server certificate configuration
176
+ server_config = ServerCertConfig(
177
+ common_name="localhost",
178
+ organization="Test Organization",
179
+ organizational_unit="Test Unit",
180
+ country="US",
181
+ state="Test State",
182
+ locality="Test City",
183
+ subject_alt_names=["localhost", "127.0.0.1"],
184
+ validity_years=1,
185
+ ca_cert_path=ca_cert_path,
186
+ ca_key_path=ca_key_path
187
+ )
188
+ # Create certificate manager
189
+ cert_config = CertificateConfig(
190
+ cert_storage_path=str(self.certs_dir),
191
+ key_storage_path=str(self.certs_dir), # Server keys in certs dir
192
+ default_validity_days=365,
193
+ key_size=2048,
194
+ hash_algorithm="sha256"
195
+ )
196
+ cert_manager = CertificateManager(cert_config)
197
+ # Create server certificate
198
+ cert_pair = cert_manager.create_server_certificate(server_config)
199
+ if cert_pair and cert_pair.certificate_path and cert_pair.private_key_path:
200
+ # Rename the generated files to the expected names
201
+ generated_cert = Path(cert_pair.certificate_path)
202
+ generated_key = Path(cert_pair.private_key_path)
203
+ if generated_cert.exists() and generated_key.exists():
204
+ # Move to expected names
205
+ generated_cert.rename(self.certs_dir / "server_cert.pem")
206
+ generated_key.rename(self.certs_dir / "server_key.pem")
207
+ print("✅ Server certificate created successfully using mcp_security_framework")
208
+ return True
209
+ else:
210
+ print("❌ Generated certificate files not found")
211
+ return False
212
+ else:
213
+ print("❌ Failed to create server certificate: Invalid certificate pair")
214
+ return False
215
+ except Exception as e:
216
+ print(f"❌ Error creating server certificate with framework: {e}")
217
+ return False
218
+ def _create_server_certificate_with_openssl(self) -> bool:
219
+ """Create server certificate using OpenSSL fallback."""
220
+ server_cert_path = self.certs_dir / "server_cert.pem"
221
+ server_key_path = self.certs_dir / "server_key.pem"
85
222
  # Create server private key
86
223
  key_cmd = [
87
224
  "openssl", "genrsa", "-out", str(server_key_path), "2048"
88
225
  ]
89
226
  if not self.run_command(key_cmd, "Creating server private key"):
90
227
  return False
91
-
92
228
  # Create server certificate signing request
93
229
  csr_path = self.certs_dir / "server.csr"
94
230
  csr_cmd = [
@@ -99,7 +235,6 @@ class SimpleCertificateCreator:
99
235
  ]
100
236
  if not self.run_command(csr_cmd, "Creating server CSR"):
101
237
  return False
102
-
103
238
  # Create server certificate
104
239
  cert_cmd = [
105
240
  "openssl", "x509", "-req", "-days", "730",
@@ -110,29 +245,102 @@ class SimpleCertificateCreator:
110
245
  "-out", str(server_cert_path)
111
246
  ]
112
247
  success = self.run_command(cert_cmd, "Creating server certificate")
113
-
114
248
  # Clean up CSR
115
249
  if csr_path.exists():
116
250
  csr_path.unlink()
117
-
118
251
  return success
119
-
120
- def create_client_certificate(self, name: str, common_name: str) -> bool:
121
- """Create client certificate using OpenSSL."""
252
+ def create_client_certificate(self, name: str, common_name: str, roles: list = None, permissions: list = None) -> bool:
253
+ """Create client certificate using mcp_security_framework or OpenSSL fallback."""
122
254
  cert_path = self.certs_dir / f"{name}_cert.pem"
123
255
  key_path = self.certs_dir / f"{name}_key.pem"
124
-
125
256
  if cert_path.exists() and key_path.exists():
126
257
  print(f"ℹ️ Client certificate {name} already exists: {cert_path}")
127
258
  return True
128
-
259
+ if SECURITY_FRAMEWORK_AVAILABLE:
260
+ return self._create_client_certificate_with_framework(name, common_name, roles, permissions)
261
+ else:
262
+ return self._create_client_certificate_with_openssl(name, common_name)
263
+ def _create_client_certificate_with_framework(self, name: str, common_name: str, roles: list = None, permissions: list = None) -> bool:
264
+ """Create client certificate using mcp_security_framework."""
265
+ try:
266
+ print(f"🔧 Creating client certificate {name} using mcp_security_framework...")
267
+ # Find CA certificate and key files
268
+ ca_cert_path = None
269
+ ca_key_path = None
270
+ # Look for CA certificate files with expected names
271
+ expected_ca_cert = self.certs_dir / "ca_cert.pem"
272
+ expected_ca_key = self.keys_dir / "ca_key.pem"
273
+ if expected_ca_cert.exists():
274
+ ca_cert_path = str(expected_ca_cert)
275
+ else:
276
+ # Fallback: look for CA certificate files with pattern
277
+ for cert_file in self.certs_dir.glob("*_ca.crt"):
278
+ ca_cert_path = str(cert_file)
279
+ break
280
+ if expected_ca_key.exists():
281
+ ca_key_path = str(expected_ca_key)
282
+ else:
283
+ # Fallback: look for CA key files with pattern
284
+ for key_file in self.keys_dir.glob("*_ca.key"):
285
+ ca_key_path = str(key_file)
286
+ break
287
+ if not ca_cert_path or not ca_key_path:
288
+ print("❌ CA certificate or key not found")
289
+ return False
290
+ # Create client certificate configuration
291
+ client_config = ClientCertConfig(
292
+ common_name=common_name,
293
+ organization="Test Organization",
294
+ organizational_unit="Test Unit",
295
+ country="US",
296
+ state="Test State",
297
+ locality="Test City",
298
+ validity_years=1,
299
+ ca_cert_path=ca_cert_path,
300
+ ca_key_path=ca_key_path
301
+ )
302
+ # Create certificate manager
303
+ cert_config = CertificateConfig(
304
+ cert_storage_path=str(self.certs_dir),
305
+ key_storage_path=str(self.certs_dir), # Client keys in certs dir
306
+ default_validity_days=365,
307
+ key_size=2048,
308
+ hash_algorithm="sha256"
309
+ )
310
+ cert_manager = CertificateManager(cert_config)
311
+ # Create client certificate
312
+ cert_pair = cert_manager.create_client_certificate(client_config)
313
+ if cert_pair and cert_pair.certificate_path and cert_pair.private_key_path:
314
+ # Rename the generated files to the expected names
315
+ generated_cert = Path(cert_pair.certificate_path)
316
+ generated_key = Path(cert_pair.private_key_path)
317
+ if generated_cert.exists() and generated_key.exists():
318
+ # Move to expected names
319
+ expected_cert = self.certs_dir / f"{name}_cert.pem"
320
+ expected_key = self.certs_dir / f"{name}_key.pem"
321
+ generated_cert.rename(expected_cert)
322
+ generated_key.rename(expected_key)
323
+ print(f"✅ Client certificate {name} created successfully using mcp_security_framework")
324
+ return True
325
+ else:
326
+ print(f"❌ Generated certificate files not found for {name}")
327
+ return False
328
+ else:
329
+ print(f"❌ Failed to create client certificate {name}: Invalid certificate pair")
330
+ return False
331
+ except Exception as e:
332
+ print(f"❌ Error creating client certificate {name} with framework: {e}")
333
+ return False
334
+ def _create_client_certificate_with_openssl(self, name: str, common_name: str) -> bool:
335
+ """Create client certificate using OpenSSL fallback."""
336
+ cert_path = self.certs_dir / f"{name}_cert.pem"
337
+ key_path = self.certs_dir / f"{name}_key.pem"
129
338
  # Create client private key
130
339
  key_cmd = [
131
340
  "openssl", "genrsa", "-out", str(key_path), "2048"
132
341
  ]
133
342
  if not self.run_command(key_cmd, f"Creating {name} private key"):
134
343
  return False
135
-
136
344
  # Create client certificate signing request
137
345
  csr_path = self.certs_dir / f"{name}.csr"
138
346
  csr_cmd = [
@@ -143,7 +351,6 @@ class SimpleCertificateCreator:
143
351
  ]
144
352
  if not self.run_command(csr_cmd, f"Creating {name} CSR"):
145
353
  return False
146
-
147
354
  # Create client certificate
148
355
  cert_cmd = [
149
356
  "openssl", "x509", "-req", "-days", "730",
@@ -154,45 +361,36 @@ class SimpleCertificateCreator:
154
361
  "-out", str(cert_path)
155
362
  ]
156
363
  success = self.run_command(cert_cmd, f"Creating {name} certificate")
157
-
158
364
  # Clean up CSR
159
365
  if csr_path.exists():
160
366
  csr_path.unlink()
161
-
162
367
  return success
163
-
164
368
  def create_legacy_certificates(self) -> bool:
165
369
  """Create legacy certificate files for compatibility."""
166
370
  legacy_files = [
167
- ("client.crt", "client.key", "client"),
168
371
  ("client_admin.crt", "client_admin.key", "admin"),
169
372
  ("admin.crt", "admin.key", "admin"),
170
373
  ("user.crt", "user.key", "user"),
171
374
  ("readonly.crt", "readonly.key", "readonly")
172
375
  ]
173
-
174
376
  success = True
175
377
  for cert_file, key_file, source_name in legacy_files:
176
378
  cert_path = self.certs_dir / cert_file
177
379
  key_path = self.certs_dir / key_file
178
-
179
380
  if not cert_path.exists() or not key_path.exists():
180
381
  source_cert = self.certs_dir / f"{source_name}_cert.pem"
181
382
  source_key = self.certs_dir / f"{source_name}_key.pem"
182
-
183
383
  if source_cert.exists() and source_key.exists():
184
384
  self.run_command(["cp", str(source_cert), str(cert_path)], f"Creating {cert_file}")
185
385
  self.run_command(["cp", str(source_key), str(key_path)], f"Creating {key_file}")
186
386
  else:
187
387
  print(f"⚠️ Source certificate {source_name} not found for {cert_file}")
188
- success = False
189
-
190
- return success
191
-
388
+ # Don't fail the entire process for missing legacy certificates
389
+ continue
390
+ return True # Always return True for legacy certificates
192
391
  def validate_certificates(self) -> bool:
193
392
  """Validate all created certificates."""
194
393
  print("\n🔍 Validating certificates...")
195
-
196
394
  cert_files = [
197
395
  "ca_cert.pem",
198
396
  "server_cert.pem",
@@ -202,7 +400,6 @@ class SimpleCertificateCreator:
202
400
  "guest_cert.pem",
203
401
  "proxy_cert.pem"
204
402
  ]
205
-
206
403
  success = True
207
404
  for cert_file in cert_files:
208
405
  cert_path = self.certs_dir / cert_file
@@ -220,78 +417,68 @@ class SimpleCertificateCreator:
220
417
  success = False
221
418
  else:
222
419
  print(f"⚠️ {cert_file}: Not found")
223
-
224
420
  return success
225
-
226
421
  def create_all(self) -> bool:
227
422
  """Create all certificates."""
228
423
  print("🔐 Creating All Certificates for Security Testing")
229
424
  print("=" * 60)
230
-
231
425
  success = True
232
-
233
426
  # 1. Create CA certificate
234
427
  if not self.create_ca_certificate():
235
428
  success = False
236
429
  print("❌ Cannot continue without CA certificate")
237
430
  return False
238
-
239
431
  # 2. Create server certificate
240
432
  if not self.create_server_certificate():
241
433
  success = False
242
-
243
434
  # 3. Create client certificates
244
435
  print("\n👥 Creating client certificates...")
245
436
  client_certs = [
246
- ("admin", "admin-client"),
247
- ("user", "user-client"),
248
- ("readonly", "readonly-client"),
249
- ("guest", "guest-client"),
250
- ("proxy", "proxy-client")
437
+ ("admin", "admin-client", ["admin"], ["read", "write", "execute", "delete", "admin", "register", "unregister", "heartbeat", "discover"]),
438
+ ("user", "user-client", ["user"], ["read", "execute", "register", "unregister", "heartbeat", "discover"]),
439
+ ("readonly", "readonly-client", ["readonly"], ["read", "discover"]),
440
+ ("guest", "guest-client", ["guest"], ["read", "discover"]),
441
+ ("proxy", "proxy-client", ["proxy"], ["register", "unregister", "heartbeat", "discover"])
251
442
  ]
252
-
253
- for name, common_name in client_certs:
254
- if not self.create_client_certificate(name, common_name):
443
+ for name, common_name, roles, permissions in client_certs:
444
+ if not self.create_client_certificate(name, common_name, roles, permissions):
255
445
  success = False
256
-
257
446
  # 4. Create legacy certificates
258
447
  print("\n🔄 Creating legacy certificates...")
259
448
  if not self.create_legacy_certificates():
260
449
  success = False
261
-
262
450
  # 5. Validate certificates
263
451
  if not self.validate_certificates():
264
452
  success = False
265
-
266
453
  # Print summary
267
454
  print("\n" + "=" * 60)
268
455
  print("📊 CERTIFICATE CREATION SUMMARY")
269
456
  print("=" * 60)
270
-
271
457
  if success:
272
458
  print("✅ All certificates created successfully!")
273
459
  print(f"📁 Certificates directory: {self.certs_dir}")
274
460
  print(f"🔑 Keys directory: {self.keys_dir}")
275
461
  print("\n📋 Created certificates:")
276
-
277
462
  cert_files = list(self.certs_dir.glob("*.pem")) + list(self.certs_dir.glob("*.crt"))
278
463
  for cert_file in sorted(cert_files):
279
464
  print(f" - {cert_file.name}")
280
-
281
465
  key_files = list(self.keys_dir.glob("*.pem")) + list(self.keys_dir.glob("*.key"))
282
466
  for key_file in sorted(key_files):
283
467
  print(f" - {key_file.name}")
284
468
  else:
285
469
  print("❌ Some certificates failed to create")
286
470
  print("Check the error messages above")
287
-
288
471
  return success
289
-
290
-
291
472
  def main():
292
473
  """Main function."""
293
- creator = SimpleCertificateCreator()
294
-
474
+ parser = argparse.ArgumentParser(description="Create certificates for testing")
475
+ parser.add_argument("--certs-dir", help="Directory for certificates")
476
+ parser.add_argument("--keys-dir", help="Directory for keys")
477
+ args = parser.parse_args()
478
+ creator = SimpleCertificateCreator(
479
+ certs_dir=args.certs_dir,
480
+ keys_dir=args.keys_dir
481
+ )
295
482
  try:
296
483
  success = creator.create_all()
297
484
  sys.exit(0 if success else 1)
@@ -301,7 +488,5 @@ def main():
301
488
  except Exception as e:
302
489
  print(f"\n❌ Certificate creation failed: {e}")
303
490
  sys.exit(1)
304
-
305
-
306
491
  if __name__ == "__main__":
307
492
  main()
@@ -1,49 +1,35 @@
1
1
  #!/usr/bin/env python3
2
2
  """
3
3
  Debug Request State - Проверка request.state
4
-
5
4
  Этот скрипт проверяет, как middleware устанавливает информацию о пользователе в request.state.
6
-
7
5
  Author: Vasiliy Zdanovskiy
8
6
  email: vasilyvz@gmail.com
9
7
  """
10
-
11
8
  import asyncio
12
9
  import json
13
10
  import sys
14
11
  from pathlib import Path
15
-
16
12
  # Add project root to path
17
13
  project_root = Path(__file__).parent.parent.parent
18
14
  sys.path.insert(0, str(project_root))
19
-
20
15
  from fastapi import FastAPI, Request
21
16
  from fastapi.testclient import TestClient
22
17
  from mcp_proxy_adapter.api.app import create_app
23
-
24
-
25
18
  async def debug_request_state():
26
19
  """Debug request state handling."""
27
-
28
20
  print("🔍 ОТЛАДКА REQUEST.STATE")
29
21
  print("=" * 50)
30
-
31
22
  # Create test app with proper configuration
32
23
  config_path = project_root / "mcp_proxy_adapter" / "examples" / "server_configs" / "config_http_token.json"
33
-
34
24
  with open(config_path) as f:
35
25
  config = json.load(f)
36
-
37
26
  # Override global config for testing
38
27
  import mcp_proxy_adapter.config
39
28
  mcp_proxy_adapter.config.config = config
40
-
41
29
  app = create_app(config)
42
30
  client = TestClient(app)
43
-
44
31
  print("📋 1. ТЕСТИРОВАНИЕ БЕЗ АУТЕНТИФИКАЦИИ")
45
32
  print("-" * 30)
46
-
47
33
  # Test without authentication
48
34
  response = client.post("/cmd", json={
49
35
  "jsonrpc": "2.0",
@@ -51,15 +37,12 @@ async def debug_request_state():
51
37
  "params": {"message": "test"},
52
38
  "id": 1
53
39
  })
54
-
55
40
  print(f"Status: {response.status_code}")
56
41
  print(f"Response: {response.json()}")
57
-
58
42
  print("\n📋 2. ТЕСТИРОВАНИЕ С ADMIN ТОКЕНОМ")
59
43
  print("-" * 30)
60
-
61
44
  # Test with admin token
62
- response = client.post("/cmd",
45
+ response = client.post("/cmd",
63
46
  json={
64
47
  "jsonrpc": "2.0",
65
48
  "method": "echo",
@@ -68,15 +51,12 @@ async def debug_request_state():
68
51
  },
69
52
  headers={"X-API-Key": "test-token-123"}
70
53
  )
71
-
72
54
  print(f"Status: {response.status_code}")
73
55
  print(f"Response: {response.json()}")
74
-
75
56
  print("\n📋 3. ТЕСТИРОВАНИЕ С USER ТОКЕНОМ")
76
57
  print("-" * 30)
77
-
78
58
  # Test with user token
79
- response = client.post("/cmd",
59
+ response = client.post("/cmd",
80
60
  json={
81
61
  "jsonrpc": "2.0",
82
62
  "method": "echo",
@@ -85,15 +65,12 @@ async def debug_request_state():
85
65
  },
86
66
  headers={"X-API-Key": "user-token-456"}
87
67
  )
88
-
89
68
  print(f"Status: {response.status_code}")
90
69
  print(f"Response: {response.json()}")
91
-
92
70
  print("\n📋 4. ТЕСТИРОВАНИЕ С READONLY ТОКЕНОМ")
93
71
  print("-" * 30)
94
-
95
72
  # Test with readonly token
96
- response = client.post("/cmd",
73
+ response = client.post("/cmd",
97
74
  json={
98
75
  "jsonrpc": "2.0",
99
76
  "method": "echo",
@@ -102,15 +79,12 @@ async def debug_request_state():
102
79
  },
103
80
  headers={"X-API-Key": "readonly-token-123"}
104
81
  )
105
-
106
82
  print(f"Status: {response.status_code}")
107
83
  print(f"Response: {response.json()}")
108
-
109
84
  print("\n📋 5. ТЕСТИРОВАНИЕ ROLE_TEST КОМАНДЫ")
110
85
  print("-" * 30)
111
-
112
86
  # Test role_test command with readonly token
113
- response = client.post("/cmd",
87
+ response = client.post("/cmd",
114
88
  json={
115
89
  "jsonrpc": "2.0",
116
90
  "method": "role_test",
@@ -119,26 +93,20 @@ async def debug_request_state():
119
93
  },
120
94
  headers={"X-API-Key": "readonly-token-123"}
121
95
  )
122
-
123
96
  print(f"Status: {response.status_code}")
124
97
  print(f"Response: {response.json()}")
125
-
126
98
  print("\n📋 6. АНАЛИЗ ПРОБЛЕМЫ")
127
99
  print("-" * 30)
128
-
129
100
  print("🔍 ПРОБЛЕМА: Readonly роль получает доступ к командам")
130
101
  print("\n📋 ВОЗМОЖНЫЕ ПРИЧИНЫ:")
131
102
  print("1. Framework middleware не устанавливает user info в request.state")
132
103
  print("2. Нет проверки прав на уровне middleware")
133
104
  print("3. Команды не проверяют права доступа")
134
105
  print("4. Интеграция между middleware и командами не работает")
135
-
136
106
  print("\n📋 РЕКОМЕНДАЦИИ:")
137
107
  print("1. Добавить CommandPermissionMiddleware")
138
108
  print("2. Убедиться, что framework middleware устанавливает user info")
139
109
  print("3. Добавить проверку прав в команды")
140
110
  print("4. Проверить интеграцию middleware")
141
-
142
-
143
111
  if __name__ == "__main__":
144
112
  asyncio.run(debug_request_state())