mcp-security-framework 0.1.0__py3-none-any.whl → 1.1.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 (58) hide show
  1. mcp_security_framework/__init__.py +26 -15
  2. mcp_security_framework/cli/__init__.py +1 -1
  3. mcp_security_framework/cli/cert_cli.py +233 -197
  4. mcp_security_framework/cli/security_cli.py +324 -234
  5. mcp_security_framework/constants.py +21 -27
  6. mcp_security_framework/core/auth_manager.py +49 -20
  7. mcp_security_framework/core/cert_manager.py +398 -104
  8. mcp_security_framework/core/permission_manager.py +13 -9
  9. mcp_security_framework/core/rate_limiter.py +10 -0
  10. mcp_security_framework/core/security_manager.py +286 -229
  11. mcp_security_framework/examples/__init__.py +6 -0
  12. mcp_security_framework/examples/comprehensive_example.py +954 -0
  13. mcp_security_framework/examples/django_example.py +276 -202
  14. mcp_security_framework/examples/fastapi_example.py +897 -393
  15. mcp_security_framework/examples/flask_example.py +311 -200
  16. mcp_security_framework/examples/gateway_example.py +373 -214
  17. mcp_security_framework/examples/microservice_example.py +337 -172
  18. mcp_security_framework/examples/standalone_example.py +719 -478
  19. mcp_security_framework/examples/test_all_examples.py +572 -0
  20. mcp_security_framework/middleware/__init__.py +46 -55
  21. mcp_security_framework/middleware/auth_middleware.py +62 -63
  22. mcp_security_framework/middleware/fastapi_auth_middleware.py +179 -110
  23. mcp_security_framework/middleware/fastapi_middleware.py +156 -148
  24. mcp_security_framework/middleware/flask_auth_middleware.py +267 -107
  25. mcp_security_framework/middleware/flask_middleware.py +183 -157
  26. mcp_security_framework/middleware/mtls_middleware.py +106 -117
  27. mcp_security_framework/middleware/rate_limit_middleware.py +105 -101
  28. mcp_security_framework/middleware/security_middleware.py +109 -124
  29. mcp_security_framework/schemas/config.py +2 -1
  30. mcp_security_framework/schemas/models.py +19 -6
  31. mcp_security_framework/utils/cert_utils.py +14 -8
  32. mcp_security_framework/utils/datetime_compat.py +116 -0
  33. {mcp_security_framework-0.1.0.dist-info → mcp_security_framework-1.1.1.dist-info}/METADATA +2 -1
  34. mcp_security_framework-1.1.1.dist-info/RECORD +84 -0
  35. tests/conftest.py +303 -0
  36. tests/test_cli/test_cert_cli.py +194 -174
  37. tests/test_cli/test_security_cli.py +274 -247
  38. tests/test_core/test_cert_manager.py +33 -19
  39. tests/test_core/test_security_manager.py +2 -2
  40. tests/test_examples/test_comprehensive_example.py +613 -0
  41. tests/test_examples/test_fastapi_example.py +290 -169
  42. tests/test_examples/test_flask_example.py +304 -162
  43. tests/test_examples/test_standalone_example.py +106 -168
  44. tests/test_integration/test_auth_flow.py +214 -198
  45. tests/test_integration/test_certificate_flow.py +181 -150
  46. tests/test_integration/test_fastapi_integration.py +140 -149
  47. tests/test_integration/test_flask_integration.py +144 -141
  48. tests/test_integration/test_standalone_integration.py +331 -300
  49. tests/test_middleware/test_fastapi_auth_middleware.py +745 -0
  50. tests/test_middleware/test_fastapi_middleware.py +147 -132
  51. tests/test_middleware/test_flask_auth_middleware.py +696 -0
  52. tests/test_middleware/test_flask_middleware.py +201 -179
  53. tests/test_middleware/test_security_middleware.py +151 -130
  54. tests/test_utils/test_datetime_compat.py +147 -0
  55. mcp_security_framework-0.1.0.dist-info/RECORD +0 -76
  56. {mcp_security_framework-0.1.0.dist-info → mcp_security_framework-1.1.1.dist-info}/WHEEL +0 -0
  57. {mcp_security_framework-0.1.0.dist-info → mcp_security_framework-1.1.1.dist-info}/entry_points.txt +0 -0
  58. {mcp_security_framework-0.1.0.dist-info → mcp_security_framework-1.1.1.dist-info}/top_level.txt +0 -0
@@ -25,13 +25,13 @@ import ssl
25
25
  from abc import ABC, abstractmethod
26
26
  from typing import Any, Dict, List, Optional, Union
27
27
 
28
+ from ..schemas.models import AuthMethod, AuthResult, AuthStatus
28
29
  from .security_middleware import SecurityMiddleware, SecurityMiddlewareError
29
- from ..schemas.models import AuthResult, AuthStatus, AuthMethod
30
30
 
31
31
 
32
32
  class MTLSMiddlewareError(SecurityMiddlewareError):
33
33
  """Raised when mTLS middleware encounters an error."""
34
-
34
+
35
35
  def __init__(self, message: str, error_code: int = -32037):
36
36
  self.message = message
37
37
  self.error_code = error_code
@@ -41,18 +41,18 @@ class MTLSMiddlewareError(SecurityMiddlewareError):
41
41
  class MTLSMiddleware(SecurityMiddleware):
42
42
  """
43
43
  mTLS (Mutual TLS) Middleware Class
44
-
44
+
45
45
  This class provides mTLS-specific middleware that focuses on mutual
46
46
  TLS authentication and certificate validation. It's designed for
47
47
  scenarios where client certificates are used for authentication.
48
-
48
+
49
49
  The MTLSMiddleware implements:
50
50
  - mTLS authentication processing
51
51
  - Client certificate validation
52
52
  - Certificate chain verification
53
53
  - Certificate-based role extraction
54
54
  - mTLS event logging
55
-
55
+
56
56
  Key Responsibilities:
57
57
  - Process requests through mTLS authentication pipeline
58
58
  - Validate client certificates
@@ -60,82 +60,82 @@ class MTLSMiddleware(SecurityMiddleware):
60
60
  - Extract roles and permissions from certificates
61
61
  - Handle mTLS-specific error scenarios
62
62
  - Log mTLS authentication events
63
-
63
+
64
64
  Attributes:
65
65
  Inherits all attributes from SecurityMiddleware
66
66
  _certificate_cache (Dict): Cache for certificate validation results
67
67
  _ca_certificates (List): List of trusted CA certificates
68
-
68
+
69
69
  Example:
70
70
  >>> from mcp_security_framework.middleware import MTLSMiddleware
71
- >>>
71
+ >>>
72
72
  >>> security_manager = SecurityManager(config)
73
73
  >>> mtls_middleware = MTLSMiddleware(security_manager)
74
74
  >>> app.add_middleware(mtls_middleware)
75
-
75
+
76
76
  Note:
77
77
  This middleware requires proper SSL/TLS configuration on the
78
78
  server to handle client certificates.
79
79
  """
80
-
80
+
81
81
  def __init__(self, security_manager):
82
82
  """
83
83
  Initialize mTLS Middleware.
84
-
84
+
85
85
  Args:
86
86
  security_manager: Security manager instance containing
87
87
  all security components and configuration.
88
-
88
+
89
89
  Raises:
90
90
  MTLSMiddlewareError: If initialization fails
91
91
  """
92
92
  super().__init__(security_manager)
93
93
  self.logger = logging.getLogger(f"{__name__}.{self.__class__.__name__}")
94
-
94
+
95
95
  # Initialize certificate cache
96
96
  self._certificate_cache: Dict[str, Dict[str, Any]] = {}
97
-
97
+
98
98
  # Load CA certificates if configured
99
99
  self._ca_certificates = self._load_ca_certificates()
100
-
100
+
101
101
  self.logger.info(
102
102
  "mTLS middleware initialized",
103
- extra={"ca_certificates_count": len(self._ca_certificates)}
103
+ extra={"ca_certificates_count": len(self._ca_certificates)},
104
104
  )
105
-
105
+
106
106
  @abstractmethod
107
107
  def __call__(self, request: Any, call_next: Any) -> Any:
108
108
  """
109
109
  Process request through mTLS middleware.
110
-
110
+
111
111
  This method implements the mTLS authentication processing
112
112
  pipeline, focusing on client certificate validation.
113
-
113
+
114
114
  Args:
115
115
  request: Framework-specific request object
116
116
  call_next: Framework-specific call_next function
117
-
117
+
118
118
  Returns:
119
119
  Framework-specific response object
120
-
120
+
121
121
  Raises:
122
122
  MTLSMiddlewareError: If mTLS processing fails
123
123
  """
124
124
  pass
125
-
125
+
126
126
  def _authenticate_mtls(self, request: Any) -> AuthResult:
127
127
  """
128
128
  Perform mTLS authentication.
129
-
129
+
130
130
  This method handles mutual TLS authentication by validating
131
131
  client certificates and extracting user information.
132
-
132
+
133
133
  Args:
134
134
  request: Framework-specific request object
135
-
135
+
136
136
  Returns:
137
137
  AuthResult: Authentication result with user information
138
-
138
+
139
139
  Raises:
140
140
  MTLSMiddlewareError: If mTLS authentication fails
141
141
  """
@@ -150,9 +150,9 @@ class MTLSMiddleware(SecurityMiddleware):
150
150
  roles=[],
151
151
  auth_method=AuthMethod.CERTIFICATE,
152
152
  error_code=-32038,
153
- error_message="No client certificate provided"
153
+ error_message="No client certificate provided",
154
154
  )
155
-
155
+
156
156
  # Validate client certificate
157
157
  cert_validation = self._validate_client_certificate(client_cert)
158
158
  if not cert_validation["is_valid"]:
@@ -163,119 +163,113 @@ class MTLSMiddleware(SecurityMiddleware):
163
163
  roles=[],
164
164
  auth_method=AuthMethod.CERTIFICATE,
165
165
  error_code=-32039,
166
- error_message=cert_validation["error_message"]
166
+ error_message=cert_validation["error_message"],
167
167
  )
168
-
168
+
169
169
  # Extract user information from certificate
170
170
  user_info = self._extract_user_info_from_certificate(client_cert)
171
-
171
+
172
172
  # Extract roles from certificate
173
173
  roles = self._extract_roles_from_certificate(client_cert)
174
-
174
+
175
175
  self.logger.info(
176
176
  "mTLS authentication successful",
177
177
  extra={
178
178
  "username": user_info["username"],
179
179
  "subject": user_info["subject"],
180
180
  "issuer": user_info["issuer"],
181
- "roles": roles
182
- }
181
+ "roles": roles,
182
+ },
183
183
  )
184
-
184
+
185
185
  return AuthResult(
186
186
  is_valid=True,
187
187
  status=AuthStatus.SUCCESS,
188
188
  username=user_info["username"],
189
189
  roles=roles,
190
- auth_method=AuthMethod.CERTIFICATE
190
+ auth_method=AuthMethod.CERTIFICATE,
191
191
  )
192
-
192
+
193
193
  except Exception as e:
194
194
  self.logger.error(
195
- "mTLS authentication failed",
196
- extra={"error": str(e)},
197
- exc_info=True
195
+ "mTLS authentication failed", extra={"error": str(e)}, exc_info=True
198
196
  )
199
197
  raise MTLSMiddlewareError(
200
- f"mTLS authentication failed: {str(e)}",
201
- error_code=-32040
198
+ f"mTLS authentication failed: {str(e)}", error_code=-32040
202
199
  )
203
-
200
+
204
201
  def _get_client_certificate(self, request: Any) -> Optional[str]:
205
202
  """
206
203
  Get client certificate from request.
207
-
204
+
208
205
  Args:
209
206
  request: Framework-specific request object
210
-
207
+
211
208
  Returns:
212
209
  Optional[str]: Client certificate in PEM format if available
213
210
  """
214
211
  # This should be implemented by framework-specific subclasses
215
212
  # to extract the client certificate from the request
216
213
  return None
217
-
214
+
218
215
  def _validate_client_certificate(self, cert_pem: str) -> Dict[str, Any]:
219
216
  """
220
217
  Validate client certificate.
221
-
218
+
222
219
  Args:
223
220
  cert_pem (str): Client certificate in PEM format
224
-
221
+
225
222
  Returns:
226
223
  Dict[str, Any]: Validation result with status and details
227
224
  """
228
225
  try:
229
226
  # Use security manager's certificate validation
230
227
  is_valid = self.security_manager.cert_manager.validate_certificate_chain(
231
- cert_pem,
232
- self.config.ssl.ca_cert_file if self.config.ssl else None
228
+ cert_pem, self.config.ssl.ca_cert_file if self.config.ssl else None
233
229
  )
234
-
230
+
235
231
  if is_valid:
236
- return {
237
- "is_valid": True,
238
- "error_message": ""
239
- }
232
+ return {"is_valid": True, "error_message": ""}
240
233
  else:
241
234
  return {
242
235
  "is_valid": False,
243
- "error_message": "Certificate validation failed"
236
+ "error_message": "Certificate validation failed",
244
237
  }
245
-
238
+
246
239
  except Exception as e:
247
240
  return {
248
241
  "is_valid": False,
249
- "error_message": f"Certificate validation error: {str(e)}"
242
+ "error_message": f"Certificate validation error: {str(e)}",
250
243
  }
251
-
244
+
252
245
  def _extract_user_info_from_certificate(self, cert_pem: str) -> Dict[str, str]:
253
246
  """
254
247
  Extract user information from certificate.
255
-
248
+
256
249
  Args:
257
250
  cert_pem (str): Client certificate in PEM format
258
-
251
+
259
252
  Returns:
260
253
  Dict[str, str]: User information extracted from certificate
261
254
  """
262
255
  try:
263
256
  # Use security manager's certificate utilities
264
- cert_info = self.security_manager.cert_manager.get_certificate_info(cert_pem)
265
-
257
+ cert_info = self.security_manager.cert_manager.get_certificate_info(
258
+ cert_pem
259
+ )
260
+
266
261
  return {
267
262
  "username": cert_info.get("common_name", "unknown"),
268
263
  "subject": cert_info.get("subject", ""),
269
264
  "issuer": cert_info.get("issuer", ""),
270
265
  "serial_number": cert_info.get("serial_number", ""),
271
266
  "valid_from": str(cert_info.get("valid_from", "")),
272
- "valid_until": str(cert_info.get("valid_until", ""))
267
+ "valid_until": str(cert_info.get("valid_until", "")),
273
268
  }
274
-
269
+
275
270
  except Exception as e:
276
271
  self.logger.error(
277
- "Failed to extract user info from certificate",
278
- extra={"error": str(e)}
272
+ "Failed to extract user info from certificate", extra={"error": str(e)}
279
273
  )
280
274
  return {
281
275
  "username": "unknown",
@@ -283,61 +277,59 @@ class MTLSMiddleware(SecurityMiddleware):
283
277
  "issuer": "",
284
278
  "serial_number": "",
285
279
  "valid_from": "",
286
- "valid_until": ""
280
+ "valid_until": "",
287
281
  }
288
-
282
+
289
283
  def _extract_roles_from_certificate(self, cert_pem: str) -> List[str]:
290
284
  """
291
285
  Extract roles from certificate.
292
-
286
+
293
287
  Args:
294
288
  cert_pem (str): Client certificate in PEM format
295
-
289
+
296
290
  Returns:
297
291
  List[str]: List of roles extracted from certificate
298
292
  """
299
293
  try:
300
294
  # Use security manager's certificate utilities
301
- roles = self.security_manager.cert_manager.extract_roles_from_certificate(cert_pem)
295
+ roles = self.security_manager.cert_manager.extract_roles_from_certificate(
296
+ cert_pem
297
+ )
302
298
  return roles
303
-
299
+
304
300
  except Exception as e:
305
301
  self.logger.error(
306
- "Failed to extract roles from certificate",
307
- extra={"error": str(e)}
302
+ "Failed to extract roles from certificate", extra={"error": str(e)}
308
303
  )
309
304
  return []
310
-
305
+
311
306
  def _load_ca_certificates(self) -> List[str]:
312
307
  """
313
308
  Load trusted CA certificates.
314
-
309
+
315
310
  Returns:
316
311
  List[str]: List of CA certificates in PEM format
317
312
  """
318
313
  ca_certs = []
319
-
314
+
320
315
  try:
321
316
  if self.config.ssl and self.config.ssl.ca_cert_file:
322
317
  # Load CA certificate from file
323
- with open(self.config.ssl.ca_cert_file, 'r') as f:
318
+ with open(self.config.ssl.ca_cert_file, "r") as f:
324
319
  ca_certs.append(f.read())
325
-
320
+
326
321
  except Exception as e:
327
- self.logger.error(
328
- "Failed to load CA certificates",
329
- extra={"error": str(e)}
330
- )
331
-
322
+ self.logger.error("Failed to load CA certificates", extra={"error": str(e)})
323
+
332
324
  return ca_certs
333
-
325
+
334
326
  def _verify_certificate_chain(self, cert_pem: str) -> bool:
335
327
  """
336
328
  Verify certificate chain against trusted CAs.
337
-
329
+
338
330
  Args:
339
331
  cert_pem (str): Client certificate in PEM format
340
-
332
+
341
333
  Returns:
342
334
  bool: True if chain is valid, False otherwise
343
335
  """
@@ -345,21 +337,20 @@ class MTLSMiddleware(SecurityMiddleware):
345
337
  # This would implement certificate chain verification
346
338
  # against the loaded CA certificates
347
339
  return True
348
-
340
+
349
341
  except Exception as e:
350
342
  self.logger.error(
351
- "Certificate chain verification failed",
352
- extra={"error": str(e)}
343
+ "Certificate chain verification failed", extra={"error": str(e)}
353
344
  )
354
345
  return False
355
-
346
+
356
347
  def _check_certificate_revocation(self, cert_pem: str) -> bool:
357
348
  """
358
349
  Check if certificate is revoked.
359
-
350
+
360
351
  Args:
361
352
  cert_pem (str): Client certificate in PEM format
362
-
353
+
363
354
  Returns:
364
355
  bool: True if certificate is not revoked, False otherwise
365
356
  """
@@ -367,19 +358,22 @@ class MTLSMiddleware(SecurityMiddleware):
367
358
  # This would implement CRL or OCSP checking
368
359
  # For now, assume certificate is not revoked
369
360
  return True
370
-
361
+
371
362
  except Exception as e:
372
363
  self.logger.error(
373
- "Certificate revocation check failed",
374
- extra={"error": str(e)}
364
+ "Certificate revocation check failed", extra={"error": str(e)}
375
365
  )
376
366
  return False
377
-
378
- def _log_mtls_event(self, event_type: str, cert_info: Dict[str, Any],
379
- request_details: Dict[str, Any]) -> None:
367
+
368
+ def _log_mtls_event(
369
+ self,
370
+ event_type: str,
371
+ cert_info: Dict[str, Any],
372
+ request_details: Dict[str, Any],
373
+ ) -> None:
380
374
  """
381
375
  Log mTLS event.
382
-
376
+
383
377
  Args:
384
378
  event_type (str): Type of mTLS event
385
379
  cert_info (Dict[str, Any]): Certificate information
@@ -393,47 +387,42 @@ class MTLSMiddleware(SecurityMiddleware):
393
387
  "subject": cert_info.get("subject", ""),
394
388
  "issuer": cert_info.get("issuer", ""),
395
389
  "serial_number": cert_info.get("serial_number", ""),
396
- **request_details
397
- }
390
+ **request_details,
391
+ },
398
392
  )
399
-
393
+
400
394
  def get_certificate_info(self, cert_pem: str) -> Dict[str, Any]:
401
395
  """
402
396
  Get detailed certificate information.
403
-
397
+
404
398
  Args:
405
399
  cert_pem (str): Certificate in PEM format
406
-
400
+
407
401
  Returns:
408
402
  Dict[str, Any]: Detailed certificate information
409
403
  """
410
404
  try:
411
405
  return self.security_manager.cert_manager.get_certificate_info(cert_pem)
412
406
  except Exception as e:
413
- self.logger.error(
414
- "Failed to get certificate info",
415
- extra={"error": str(e)}
416
- )
407
+ self.logger.error("Failed to get certificate info", extra={"error": str(e)})
417
408
  return {"error": str(e)}
418
-
409
+
419
410
  def validate_certificate_chain(self, cert_pem: str) -> bool:
420
411
  """
421
412
  Validate certificate chain.
422
-
413
+
423
414
  Args:
424
415
  cert_pem (str): Certificate in PEM format
425
-
416
+
426
417
  Returns:
427
418
  bool: True if chain is valid, False otherwise
428
419
  """
429
420
  try:
430
421
  return self.security_manager.cert_manager.validate_certificate_chain(
431
- cert_pem,
432
- self.config.ssl.ca_cert_file if self.config.ssl else None
422
+ cert_pem, self.config.ssl.ca_cert_file if self.config.ssl else None
433
423
  )
434
424
  except Exception as e:
435
425
  self.logger.error(
436
- "Certificate chain validation failed",
437
- extra={"error": str(e)}
426
+ "Certificate chain validation failed", extra={"error": str(e)}
438
427
  )
439
428
  return False