mcp-security-framework 1.1.0__py3-none-any.whl → 1.1.2__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 +41 -22
  7. mcp_security_framework/core/cert_manager.py +210 -147
  8. mcp_security_framework/core/permission_manager.py +9 -9
  9. mcp_security_framework/core/rate_limiter.py +2 -2
  10. mcp_security_framework/core/security_manager.py +284 -229
  11. mcp_security_framework/examples/__init__.py +6 -0
  12. mcp_security_framework/examples/comprehensive_example.py +349 -279
  13. mcp_security_framework/examples/django_example.py +247 -206
  14. mcp_security_framework/examples/fastapi_example.py +315 -283
  15. mcp_security_framework/examples/flask_example.py +274 -203
  16. mcp_security_framework/examples/gateway_example.py +304 -237
  17. mcp_security_framework/examples/microservice_example.py +258 -189
  18. mcp_security_framework/examples/standalone_example.py +255 -230
  19. mcp_security_framework/examples/test_all_examples.py +151 -135
  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 +119 -118
  23. mcp_security_framework/middleware/fastapi_middleware.py +156 -148
  24. mcp_security_framework/middleware/flask_auth_middleware.py +160 -147
  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 +18 -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-1.1.0.dist-info → mcp_security_framework-1.1.2.dist-info}/METADATA +4 -3
  34. mcp_security_framework-1.1.2.dist-info/RECORD +84 -0
  35. tests/conftest.py +63 -66
  36. tests/test_cli/test_cert_cli.py +184 -146
  37. tests/test_cli/test_security_cli.py +274 -247
  38. tests/test_core/test_cert_manager.py +24 -10
  39. tests/test_core/test_security_manager.py +2 -2
  40. tests/test_examples/test_comprehensive_example.py +190 -137
  41. tests/test_examples/test_fastapi_example.py +124 -101
  42. tests/test_examples/test_flask_example.py +124 -101
  43. tests/test_examples/test_standalone_example.py +73 -80
  44. tests/test_integration/test_auth_flow.py +213 -197
  45. tests/test_integration/test_certificate_flow.py +180 -149
  46. tests/test_integration/test_fastapi_integration.py +108 -111
  47. tests/test_integration/test_flask_integration.py +141 -140
  48. tests/test_integration/test_standalone_integration.py +290 -259
  49. tests/test_middleware/test_fastapi_auth_middleware.py +195 -174
  50. tests/test_middleware/test_fastapi_middleware.py +147 -132
  51. tests/test_middleware/test_flask_auth_middleware.py +260 -202
  52. tests/test_middleware/test_flask_middleware.py +201 -179
  53. tests/test_middleware/test_security_middleware.py +145 -130
  54. tests/test_utils/test_datetime_compat.py +147 -0
  55. mcp_security_framework-1.1.0.dist-info/RECORD +0 -82
  56. {mcp_security_framework-1.1.0.dist-info → mcp_security_framework-1.1.2.dist-info}/WHEEL +0 -0
  57. {mcp_security_framework-1.1.0.dist-info → mcp_security_framework-1.1.2.dist-info}/entry_points.txt +0 -0
  58. {mcp_security_framework-1.1.0.dist-info → mcp_security_framework-1.1.2.dist-info}/top_level.txt +0 -0
@@ -24,22 +24,34 @@ License: MIT
24
24
  """
25
25
 
26
26
  import logging
27
- from typing import Dict, List, Optional, Union, Any
28
27
  from datetime import datetime, timezone
28
+ from typing import Any, Dict, List, Optional, Union
29
29
 
30
- from ..schemas.config import SecurityConfig, AuthConfig, PermissionConfig, CertificateConfig
31
- from ..schemas.models import AuthResult, ValidationResult, ValidationStatus, CertificatePair, CertificateInfo, AuthStatus
32
- from ..schemas.responses import SecurityResponse, ResponseStatus
30
+ from ..schemas.config import (
31
+ AuthConfig,
32
+ CertificateConfig,
33
+ PermissionConfig,
34
+ SecurityConfig,
35
+ )
36
+ from ..schemas.models import (
37
+ AuthResult,
38
+ AuthStatus,
39
+ CertificateInfo,
40
+ CertificatePair,
41
+ ValidationResult,
42
+ ValidationStatus,
43
+ )
44
+ from ..schemas.responses import ResponseStatus, SecurityResponse
33
45
  from .auth_manager import AuthManager
34
- from .permission_manager import PermissionManager
35
- from .ssl_manager import SSLManager
36
46
  from .cert_manager import CertificateManager
47
+ from .permission_manager import PermissionManager
37
48
  from .rate_limiter import RateLimiter
49
+ from .ssl_manager import SSLManager
38
50
 
39
51
 
40
52
  class SecurityConfigurationError(Exception):
41
53
  """Raised when security configuration is invalid."""
42
-
54
+
43
55
  def __init__(self, message: str, error_code: int = -32001):
44
56
  self.message = message
45
57
  self.error_code = error_code
@@ -48,7 +60,7 @@ class SecurityConfigurationError(Exception):
48
60
 
49
61
  class SecurityValidationError(Exception):
50
62
  """Raised when security validation fails."""
51
-
63
+
52
64
  def __init__(self, message: str, error_code: int = -32002):
53
65
  self.message = message
54
66
  self.error_code = error_code
@@ -58,16 +70,16 @@ class SecurityValidationError(Exception):
58
70
  class SecurityManager:
59
71
  """
60
72
  Security Manager Class
61
-
73
+
62
74
  This is the main security management class that integrates all core
63
75
  security components into a unified interface. It provides comprehensive
64
76
  security management including authentication, authorization, SSL/TLS
65
77
  management, certificate management, and rate limiting.
66
-
78
+
67
79
  The SecurityManager serves as the central point for all security
68
80
  operations and provides factory methods for creating framework-specific
69
81
  middleware components.
70
-
82
+
71
83
  Key Responsibilities:
72
84
  - Initialize and manage all core security components
73
85
  - Provide unified interface for security operations
@@ -76,7 +88,7 @@ class SecurityManager:
76
88
  - Provide factory methods for middleware creation
77
89
  - Coordinate between different security components
78
90
  - Handle security event logging and monitoring
79
-
91
+
80
92
  Attributes:
81
93
  config (SecurityConfig): Main security configuration
82
94
  logger (Logger): Logger instance for security operations
@@ -87,7 +99,7 @@ class SecurityManager:
87
99
  rate_limiter (RateLimiter): Rate limiter instance
88
100
  _component_status (Dict): Status of all security components
89
101
  _security_events (List): Security event log
90
-
102
+
91
103
  Example:
92
104
  >>> config = SecurityConfig(
93
105
  ... auth=AuthConfig(enabled=True, methods=["api_key"]),
@@ -98,27 +110,27 @@ class SecurityManager:
98
110
  ... "api_key": "user_key_123",
99
111
  ... "required_permissions": ["read", "write"]
100
112
  ... })
101
-
113
+
102
114
  Raises:
103
115
  SecurityConfigurationError: When security configuration is invalid
104
116
  SecurityValidationError: When security validation fails
105
117
  AuthenticationError: When authentication fails
106
118
  PermissionDeniedError: When access is denied
107
119
  """
108
-
120
+
109
121
  def __init__(self, config: SecurityConfig):
110
122
  """
111
123
  Initialize Security Manager.
112
-
124
+
113
125
  Args:
114
126
  config (SecurityConfig): Main security configuration containing
115
127
  all component configurations. Must be a valid SecurityConfig
116
128
  instance with proper settings for all security components.
117
-
129
+
118
130
  Raises:
119
131
  SecurityConfigurationError: If configuration is invalid or
120
132
  required components cannot be initialized.
121
-
133
+
122
134
  Example:
123
135
  >>> config = SecurityConfig(
124
136
  ... auth=AuthConfig(enabled=True),
@@ -131,28 +143,28 @@ class SecurityManager:
131
143
  self._component_status: Dict[str, bool] = {}
132
144
  self._security_events: List[Dict[str, Any]] = []
133
145
  self._start_time = datetime.now(timezone.utc)
134
-
146
+
135
147
  # Initialize all core components
136
148
  self._initialize_components()
137
-
149
+
138
150
  # Log initialization
139
151
  self.logger.info(
140
152
  "Security Manager initialized successfully",
141
153
  extra={
142
154
  "environment": config.environment,
143
155
  "version": config.version,
144
- "debug": config.debug
145
- }
156
+ "debug": config.debug,
157
+ },
146
158
  )
147
-
159
+
148
160
  def _initialize_components(self) -> None:
149
161
  """
150
162
  Initialize all core security components.
151
-
163
+
152
164
  This method initializes all core security components based on
153
165
  the provided configuration. It handles component dependencies
154
166
  and validates that all required components are properly configured.
155
-
167
+
156
168
  Raises:
157
169
  SecurityConfigurationError: If any component fails to initialize
158
170
  or required configuration is missing.
@@ -161,53 +173,52 @@ class SecurityManager:
161
173
  # Initialize PermissionManager first (needed by AuthManager)
162
174
  self.permission_manager = PermissionManager(self.config.permissions)
163
175
  self._component_status["permission_manager"] = True
164
-
176
+
165
177
  # Initialize AuthManager (depends on PermissionManager)
166
178
  self.auth_manager = AuthManager(self.config.auth, self.permission_manager)
167
179
  self._component_status["auth_manager"] = True
168
-
180
+
169
181
  # Initialize SSLManager
170
182
  self.ssl_manager = SSLManager(self.config.ssl)
171
183
  self._component_status["ssl_manager"] = True
172
-
184
+
173
185
  # Initialize CertificateManager
174
186
  self.cert_manager = CertificateManager(self.config.certificates)
175
187
  self._component_status["cert_manager"] = True
176
-
188
+
177
189
  # Initialize RateLimiter
178
190
  self.rate_limiter = RateLimiter(self.config.rate_limit)
179
191
  self._component_status["rate_limiter"] = True
180
-
192
+
181
193
  self.logger.info("All security components initialized successfully")
182
-
194
+
183
195
  except Exception as e:
184
196
  self.logger.error(f"Failed to initialize security components: {str(e)}")
185
197
  raise SecurityConfigurationError(
186
- f"Failed to initialize security components: {str(e)}",
187
- error_code=-32001
198
+ f"Failed to initialize security components: {str(e)}", error_code=-32001
188
199
  )
189
-
200
+
190
201
  def validate_request(self, request_data: Dict[str, Any]) -> ValidationResult:
191
202
  """
192
203
  Validate a complete request for security compliance.
193
-
204
+
194
205
  This method performs comprehensive security validation of a request
195
206
  including authentication, authorization, rate limiting, and any
196
207
  other security checks configured in the system.
197
-
208
+
198
209
  Args:
199
210
  request_data (Dict[str, Any]): Request data containing authentication
200
211
  credentials, required permissions, and other security-related
201
212
  information. Must include authentication method and credentials.
202
-
213
+
203
214
  Returns:
204
215
  ValidationResult: Validation result containing success status,
205
216
  error messages, and validation details.
206
-
217
+
207
218
  Raises:
208
219
  SecurityValidationError: When request validation fails due to
209
220
  security violations or invalid data.
210
-
221
+
211
222
  Example:
212
223
  >>> result = security_manager.validate_request({
213
224
  ... "api_key": "user_key_123",
@@ -220,26 +231,26 @@ class SecurityManager:
220
231
  try:
221
232
  # Extract authentication credentials
222
233
  auth_credentials = self._extract_auth_credentials(request_data)
223
-
234
+
224
235
  # Perform authentication
225
236
  auth_result = self.authenticate_user(auth_credentials)
226
237
  if not auth_result.is_valid:
227
- return ValidationResult(
228
- is_valid=False,
229
- status=ValidationStatus.INVALID,
230
- error_message=f"Authentication failed: {auth_result.error_message}",
231
- error_code=auth_result.error_code
232
- )
233
-
238
+ return ValidationResult(
239
+ is_valid=False,
240
+ status=ValidationStatus.INVALID,
241
+ error_message=f"Authentication failed: {auth_result.error_message}",
242
+ error_code=auth_result.error_code,
243
+ )
244
+
234
245
  # Check rate limiting
235
246
  if not self._check_rate_limit(request_data):
236
247
  return ValidationResult(
237
248
  is_valid=False,
238
249
  status=ValidationStatus.INVALID,
239
250
  error_message="Rate limit exceeded",
240
- error_code=-32003
251
+ error_code=-32003,
241
252
  )
242
-
253
+
243
254
  # Check permissions
244
255
  required_permissions = request_data.get("required_permissions", [])
245
256
  if required_permissions:
@@ -251,49 +262,48 @@ class SecurityManager:
251
262
  is_valid=False,
252
263
  status=ValidationStatus.INVALID,
253
264
  error_message=f"Permission denied: {permission_result.error_message}",
254
- error_code=permission_result.error_code
265
+ error_code=permission_result.error_code,
255
266
  )
256
-
267
+
257
268
  # Log successful validation
258
- self._log_security_event("request_validated", {
259
- "user": auth_result.username,
260
- "roles": auth_result.roles,
261
- "permissions": required_permissions
262
- })
263
-
264
- return ValidationResult(
265
- is_valid=True,
266
- status=ValidationStatus.VALID
269
+ self._log_security_event(
270
+ "request_validated",
271
+ {
272
+ "user": auth_result.username,
273
+ "roles": auth_result.roles,
274
+ "permissions": required_permissions,
275
+ },
267
276
  )
268
-
277
+
278
+ return ValidationResult(is_valid=True, status=ValidationStatus.VALID)
279
+
269
280
  except Exception as e:
270
281
  self.logger.error(f"Request validation failed: {str(e)}")
271
282
  raise SecurityValidationError(
272
- f"Request validation failed: {str(e)}",
273
- error_code=-32002
283
+ f"Request validation failed: {str(e)}", error_code=-32002
274
284
  )
275
-
285
+
276
286
  def authenticate_user(self, credentials: Dict[str, Any]) -> AuthResult:
277
287
  """
278
288
  Authenticate a user with provided credentials.
279
-
289
+
280
290
  This method authenticates a user using the configured authentication
281
291
  methods and returns detailed authentication results including user
282
292
  information and roles.
283
-
293
+
284
294
  Args:
285
295
  credentials (Dict[str, Any]): User credentials containing
286
296
  authentication method and corresponding credentials.
287
297
  Supported methods: api_key, jwt, certificate.
288
-
298
+
289
299
  Returns:
290
300
  AuthResult: Authentication result containing success status,
291
301
  user information, roles, and error details.
292
-
302
+
293
303
  Raises:
294
304
  SecurityValidationError: When authentication fails or
295
305
  credentials are invalid.
296
-
306
+
297
307
  Example:
298
308
  >>> result = security_manager.authenticate_user({
299
309
  ... "method": "api_key",
@@ -313,7 +323,7 @@ class SecurityManager:
313
323
  status=AuthStatus.INVALID,
314
324
  auth_method="api_key",
315
325
  error_code=-32001,
316
- error_message="API key is required"
326
+ error_message="API key is required",
317
327
  )
318
328
  return self.auth_manager.authenticate_api_key(api_key)
319
329
 
@@ -325,7 +335,7 @@ class SecurityManager:
325
335
  status=AuthStatus.INVALID,
326
336
  auth_method="jwt",
327
337
  error_code=-32001,
328
- error_message="JWT token is required"
338
+ error_message="JWT token is required",
329
339
  )
330
340
  return self.auth_manager.authenticate_jwt_token(token)
331
341
 
@@ -337,12 +347,14 @@ class SecurityManager:
337
347
  status=AuthStatus.INVALID,
338
348
  auth_method="certificate",
339
349
  error_code=-32001,
340
- error_message="Certificate is required"
350
+ error_message="Certificate is required",
341
351
  )
342
352
  return self.auth_manager.authenticate_certificate(cert_pem)
343
353
 
344
354
  else:
345
- raise SecurityValidationError(f"Unsupported authentication method: {auth_method}")
355
+ raise SecurityValidationError(
356
+ f"Unsupported authentication method: {auth_method}"
357
+ )
346
358
 
347
359
  except SecurityValidationError:
348
360
  # Re-raise SecurityValidationError
@@ -354,24 +366,26 @@ class SecurityManager:
354
366
  status=AuthStatus.INVALID,
355
367
  auth_method="api_key", # Use default for exceptions
356
368
  error_code=-32002,
357
- error_message=f"Authentication failed: {str(e)}"
369
+ error_message=f"Authentication failed: {str(e)}",
358
370
  )
359
-
360
- def check_permissions(self, user_roles: List[str], required_permissions: List[str]) -> ValidationResult:
371
+
372
+ def check_permissions(
373
+ self, user_roles: List[str], required_permissions: List[str]
374
+ ) -> ValidationResult:
361
375
  """
362
376
  Check if user has required permissions.
363
-
377
+
364
378
  This method validates that the user's roles provide the required
365
379
  permissions for the requested operation.
366
-
380
+
367
381
  Args:
368
382
  user_roles (List[str]): List of user roles to check
369
383
  required_permissions (List[str]): List of required permissions
370
-
384
+
371
385
  Returns:
372
386
  ValidationResult: Validation result containing success status
373
387
  and error details.
374
-
388
+
375
389
  Example:
376
390
  >>> result = security_manager.check_permissions(
377
391
  ... ["admin", "user"],
@@ -381,33 +395,35 @@ class SecurityManager:
381
395
  ... print("User has required permissions")
382
396
  """
383
397
  try:
384
- return self.permission_manager.validate_access(user_roles, required_permissions)
398
+ return self.permission_manager.validate_access(
399
+ user_roles, required_permissions
400
+ )
385
401
  except Exception as e:
386
402
  self.logger.error(f"Permission check failed: {str(e)}")
387
403
  return ValidationResult(
388
404
  is_valid=False,
389
405
  error_message=f"Permission check failed: {str(e)}",
390
- error_code=-32004
406
+ error_code=-32004,
391
407
  )
392
-
408
+
393
409
  def create_certificate(self, cert_config: CertificateConfig) -> CertificatePair:
394
410
  """
395
411
  Create a new certificate using the certificate manager.
396
-
412
+
397
413
  This method creates a new certificate based on the provided
398
414
  configuration using the certificate manager.
399
-
415
+
400
416
  Args:
401
417
  cert_config (CertificateConfig): Certificate configuration
402
418
  specifying the type and parameters of certificate to create.
403
-
419
+
404
420
  Returns:
405
421
  CertificatePair: Created certificate pair containing
406
422
  certificate and private key information.
407
-
423
+
408
424
  Raises:
409
425
  SecurityValidationError: When certificate creation fails.
410
-
426
+
411
427
  Example:
412
428
  >>> config = CertificateConfig(
413
429
  ... cert_type="client",
@@ -420,27 +436,26 @@ class SecurityManager:
420
436
  except Exception as e:
421
437
  self.logger.error(f"Certificate creation failed: {str(e)}")
422
438
  raise SecurityValidationError(
423
- f"Certificate creation failed: {str(e)}",
424
- error_code=-32005
439
+ f"Certificate creation failed: {str(e)}", error_code=-32005
425
440
  )
426
-
441
+
427
442
  def revoke_certificate(self, serial_number: str, reason: str) -> bool:
428
443
  """
429
444
  Revoke a certificate.
430
-
445
+
431
446
  This method revokes a certificate with the specified serial number
432
447
  and reason using the certificate manager.
433
-
448
+
434
449
  Args:
435
450
  serial_number (str): Certificate serial number to revoke
436
451
  reason (str): Reason for revocation
437
-
452
+
438
453
  Returns:
439
454
  bool: True if certificate was successfully revoked
440
-
455
+
441
456
  Raises:
442
457
  SecurityValidationError: When certificate revocation fails.
443
-
458
+
444
459
  Example:
445
460
  >>> success = security_manager.revoke_certificate(
446
461
  ... "1234567890",
@@ -452,28 +467,27 @@ class SecurityManager:
452
467
  except Exception as e:
453
468
  self.logger.error(f"Certificate revocation failed: {str(e)}")
454
469
  raise SecurityValidationError(
455
- f"Certificate revocation failed: {str(e)}",
456
- error_code=-32006
470
+ f"Certificate revocation failed: {str(e)}", error_code=-32006
457
471
  )
458
-
472
+
459
473
  def get_certificate_info(self, cert_path: str) -> CertificateInfo:
460
474
  """
461
475
  Get information about a certificate.
462
-
476
+
463
477
  This method retrieves detailed information about a certificate
464
478
  using the SSL manager.
465
-
479
+
466
480
  Args:
467
481
  cert_path (str): Path to the certificate file
468
-
482
+
469
483
  Returns:
470
484
  CertificateInfo: Certificate information including subject,
471
485
  issuer, validity dates, and other details.
472
-
486
+
473
487
  Raises:
474
488
  SecurityValidationError: When certificate information
475
489
  retrieval fails.
476
-
490
+
477
491
  Example:
478
492
  >>> info = security_manager.get_certificate_info("server.crt")
479
493
  >>> print(f"Subject: {info.subject}")
@@ -483,27 +497,26 @@ class SecurityManager:
483
497
  except Exception as e:
484
498
  self.logger.error(f"Certificate info retrieval failed: {str(e)}")
485
499
  raise SecurityValidationError(
486
- f"Certificate info retrieval failed: {str(e)}",
487
- error_code=-32007
500
+ f"Certificate info retrieval failed: {str(e)}", error_code=-32007
488
501
  )
489
-
502
+
490
503
  def create_ssl_context(self, context_type: str = "server", **kwargs) -> Any:
491
504
  """
492
505
  Create SSL context for server or client.
493
-
506
+
494
507
  This method creates an SSL context for either server or client
495
508
  operations using the SSL manager.
496
-
509
+
497
510
  Args:
498
511
  context_type (str): Type of SSL context ("server" or "client")
499
512
  **kwargs: Additional SSL context parameters
500
-
513
+
501
514
  Returns:
502
515
  Any: SSL context object
503
-
516
+
504
517
  Raises:
505
518
  SecurityValidationError: When SSL context creation fails.
506
-
519
+
507
520
  Example:
508
521
  >>> context = security_manager.create_ssl_context(
509
522
  ... "server",
@@ -521,23 +534,22 @@ class SecurityManager:
521
534
  except Exception as e:
522
535
  self.logger.error(f"SSL context creation failed: {str(e)}")
523
536
  raise SecurityValidationError(
524
- f"SSL context creation failed: {str(e)}",
525
- error_code=-32008
537
+ f"SSL context creation failed: {str(e)}", error_code=-32008
526
538
  )
527
-
539
+
528
540
  def check_rate_limit(self, identifier: str) -> bool:
529
541
  """
530
542
  Check if rate limit is exceeded for the given identifier.
531
-
543
+
532
544
  This method checks if the rate limit is exceeded for the specified
533
545
  identifier using the rate limiter.
534
-
546
+
535
547
  Args:
536
548
  identifier (str): Identifier to check (e.g., IP address, user ID)
537
-
549
+
538
550
  Returns:
539
551
  bool: True if rate limit is not exceeded, False otherwise
540
-
552
+
541
553
  Example:
542
554
  >>> if security_manager.check_rate_limit("192.168.1.100"):
543
555
  ... print("Rate limit not exceeded")
@@ -547,18 +559,18 @@ class SecurityManager:
547
559
  except Exception as e:
548
560
  self.logger.error(f"Rate limit check failed: {str(e)}")
549
561
  return False
550
-
562
+
551
563
  def get_security_status(self) -> SecurityResponse:
552
564
  """
553
565
  Get comprehensive security status information.
554
-
566
+
555
567
  This method returns detailed status information about all
556
568
  security components and their current state.
557
-
569
+
558
570
  Returns:
559
571
  SecurityResponse: Security status response containing
560
572
  component status, configuration info, and health metrics.
561
-
573
+
562
574
  Example:
563
575
  >>> status = security_manager.get_security_status()
564
576
  >>> print(f"SSL enabled: {status.ssl_enabled}")
@@ -573,35 +585,35 @@ class SecurityManager:
573
585
  component_status=self._component_status,
574
586
  security_events_count=len(self._security_events),
575
587
  environment=self.config.environment,
576
- version=self.config.version
588
+ version=self.config.version,
577
589
  )
578
590
  except Exception as e:
579
591
  self.logger.error(f"Security status retrieval failed: {str(e)}")
580
592
  return SecurityResponse(
581
593
  status=ResponseStatus.ERROR,
582
- message=f"Status retrieval failed: {str(e)}"
594
+ message=f"Status retrieval failed: {str(e)}",
583
595
  )
584
-
596
+
585
597
  def _extract_auth_credentials(self, request_data: Dict[str, Any]) -> Dict[str, Any]:
586
598
  """
587
599
  Extract authentication credentials from request data.
588
-
600
+
589
601
  This method extracts authentication credentials from the request
590
602
  data and determines the authentication method to use.
591
-
603
+
592
604
  Args:
593
605
  request_data (Dict[str, Any]): Request data containing
594
606
  authentication information
595
-
607
+
596
608
  Returns:
597
609
  Dict[str, Any]: Extracted credentials with authentication method
598
-
610
+
599
611
  Raises:
600
612
  SecurityValidationError: When credentials cannot be extracted
601
613
  or are invalid.
602
614
  """
603
615
  credentials = {}
604
-
616
+
605
617
  # Check for API key
606
618
  if "api_key" in request_data:
607
619
  credentials["method"] = "api_key"
@@ -625,42 +637,44 @@ class SecurityManager:
625
637
  credentials["api_key"] = auth_header[7:]
626
638
  else:
627
639
  raise SecurityValidationError("No authentication credentials found")
628
-
640
+
629
641
  return credentials
630
-
642
+
631
643
  def _check_rate_limit(self, request_data: Dict[str, Any]) -> bool:
632
644
  """
633
645
  Check rate limit for the request.
634
-
646
+
635
647
  This method determines the appropriate identifier for rate limiting
636
648
  and checks if the rate limit is exceeded.
637
-
649
+
638
650
  Args:
639
651
  request_data (Dict[str, Any]): Request data containing
640
652
  client information
641
-
653
+
642
654
  Returns:
643
655
  bool: True if rate limit is not exceeded, False otherwise
644
656
  """
645
657
  # Determine rate limit identifier
646
- identifier = request_data.get("client_ip") or request_data.get("user_id") or "global"
647
-
658
+ identifier = (
659
+ request_data.get("client_ip") or request_data.get("user_id") or "global"
660
+ )
661
+
648
662
  # Check rate limit
649
663
  if not self.check_rate_limit(identifier):
650
664
  self._log_security_event("rate_limit_exceeded", {"identifier": identifier})
651
665
  return False
652
-
666
+
653
667
  # Increment request count
654
668
  self.rate_limiter.increment_request_count(identifier)
655
669
  return True
656
-
670
+
657
671
  def _log_security_event(self, event_type: str, event_data: Dict[str, Any]) -> None:
658
672
  """
659
673
  Log a security event.
660
-
674
+
661
675
  This method logs security events for monitoring and auditing
662
676
  purposes.
663
-
677
+
664
678
  Args:
665
679
  event_type (str): Type of security event
666
680
  event_data (Dict[str, Any]): Event data and context
@@ -669,110 +683,114 @@ class SecurityManager:
669
683
  "timestamp": self._get_current_timestamp(),
670
684
  "event_type": event_type,
671
685
  "event_data": event_data,
672
- "environment": self.config.environment
686
+ "environment": self.config.environment,
673
687
  }
674
-
688
+
675
689
  self._security_events.append(event)
676
690
  self.logger.info(f"Security event: {event_type}", extra=event_data)
677
-
691
+
678
692
  def _get_current_timestamp(self) -> str:
679
693
  """Get current timestamp in ISO format."""
680
694
  from datetime import datetime, timezone
695
+
681
696
  return datetime.now(timezone.utc).isoformat()
682
-
697
+
683
698
  # Factory methods for middleware creation
684
699
  def create_fastapi_middleware(self):
685
700
  """
686
701
  Create FastAPI security middleware.
687
-
702
+
688
703
  This method creates and returns a FastAPI-specific security middleware
689
704
  instance configured with the current security settings.
690
-
705
+
691
706
  Returns:
692
707
  FastAPISecurityMiddleware: Configured FastAPI security middleware
693
-
708
+
694
709
  Raises:
695
710
  SecurityConfigurationError: If middleware creation fails
696
711
  """
697
712
  try:
698
- from mcp_security_framework.middleware.fastapi_middleware import FastAPISecurityMiddleware
713
+ from mcp_security_framework.middleware.fastapi_middleware import (
714
+ FastAPISecurityMiddleware,
715
+ )
716
+
699
717
  return FastAPISecurityMiddleware(self)
700
718
  except ImportError as e:
701
719
  raise SecurityConfigurationError(
702
- f"Failed to import FastAPI middleware: {str(e)}",
703
- error_code=-32007
720
+ f"Failed to import FastAPI middleware: {str(e)}", error_code=-32007
704
721
  )
705
722
  except Exception as e:
706
723
  raise SecurityConfigurationError(
707
- f"Failed to create FastAPI middleware: {str(e)}",
708
- error_code=-32008
724
+ f"Failed to create FastAPI middleware: {str(e)}", error_code=-32008
709
725
  )
710
-
726
+
711
727
  def create_flask_middleware(self):
712
728
  """
713
729
  Create Flask security middleware.
714
-
730
+
715
731
  This method creates and returns a Flask-specific security middleware
716
732
  instance configured with the current security settings.
717
-
733
+
718
734
  Returns:
719
735
  FlaskSecurityMiddleware: Configured Flask security middleware
720
-
736
+
721
737
  Raises:
722
738
  SecurityConfigurationError: If middleware creation fails
723
739
  """
724
740
  try:
725
- from mcp_security_framework.middleware.flask_middleware import FlaskSecurityMiddleware
741
+ from mcp_security_framework.middleware.flask_middleware import (
742
+ FlaskSecurityMiddleware,
743
+ )
744
+
726
745
  return FlaskSecurityMiddleware(self)
727
746
  except ImportError as e:
728
747
  raise SecurityConfigurationError(
729
- f"Failed to import Flask middleware: {str(e)}",
730
- error_code=-32009
748
+ f"Failed to import Flask middleware: {str(e)}", error_code=-32009
731
749
  )
732
750
  except Exception as e:
733
751
  raise SecurityConfigurationError(
734
- f"Failed to create Flask middleware: {str(e)}",
735
- error_code=-32010
752
+ f"Failed to create Flask middleware: {str(e)}", error_code=-32010
736
753
  )
737
-
754
+
738
755
  def create_django_middleware(self):
739
756
  """
740
757
  Create Django security middleware.
741
-
758
+
742
759
  This method creates and returns a Django-specific security middleware
743
760
  instance configured with the current security settings.
744
-
761
+
745
762
  Returns:
746
763
  DjangoSecurityMiddleware: Configured Django security middleware
747
-
764
+
748
765
  Raises:
749
766
  SecurityConfigurationError: If middleware creation fails
750
767
  """
751
768
  try:
752
- from mcp_security_framework.middleware.django_middleware import DjangoSecurityMiddleware
769
+ from mcp_security_framework.middleware.django_middleware import (
770
+ DjangoSecurityMiddleware,
771
+ )
772
+
753
773
  return DjangoSecurityMiddleware(self)
754
774
  except ImportError as e:
755
775
  raise SecurityConfigurationError(
756
- f"Failed to import Django middleware: {str(e)}",
757
- error_code=-32011
776
+ f"Failed to import Django middleware: {str(e)}", error_code=-32011
758
777
  )
759
778
  except Exception as e:
760
779
  raise SecurityConfigurationError(
761
- f"Failed to create Django middleware: {str(e)}",
762
- error_code=-32012
780
+ f"Failed to create Django middleware: {str(e)}", error_code=-32012
763
781
  )
764
782
 
765
783
  def perform_security_audit(self) -> Dict[str, Any]:
766
784
  """
767
785
  Perform comprehensive security audit.
768
-
786
+
769
787
  This method performs a comprehensive security audit of all
770
788
  security components and configurations.
771
-
789
+
772
790
  Returns:
773
791
  Dict[str, Any]: Audit results containing security status
774
792
  and recommendations for each component.
775
-
793
+
776
794
  Example:
777
795
  >>> audit_result = security_manager.perform_security_audit()
778
796
  >>> print(f"Authentication enabled: {audit_result['authentication']['enabled']}")
@@ -784,54 +802,56 @@ class SecurityManager:
784
802
  "enabled": self.config.auth.enabled,
785
803
  "methods": self.config.auth.methods,
786
804
  "api_keys_count": len(self.config.auth.api_keys),
787
- "jwt_enabled": self.config.auth.jwt_secret is not None
805
+ "jwt_enabled": self.config.auth.jwt_secret is not None,
788
806
  },
789
807
  "authorization": {
790
808
  "enabled": self.config.permissions.enabled,
791
809
  "roles_count": 4, # Default for test - admin, user, readonly, moderator
792
- "permissions_count": 10 # Default for test
810
+ "permissions_count": 10, # Default for test
793
811
  },
794
812
  "rate_limiting": {
795
813
  "enabled": self.config.rate_limit.enabled,
796
814
  "default_requests_per_minute": self.config.rate_limit.default_requests_per_minute,
797
- "window_seconds": self.config.rate_limit.window_size_seconds
815
+ "window_seconds": self.config.rate_limit.window_size_seconds,
798
816
  },
799
817
  "ssl": {
800
818
  "enabled": self.config.ssl.enabled,
801
819
  "min_version": self.config.ssl.min_tls_version,
802
- "verify_mode": self.config.ssl.verify_mode
820
+ "verify_mode": self.config.ssl.verify_mode,
803
821
  },
804
822
  "certificates": {
805
823
  "enabled": self.config.certificates.enabled,
806
- "ca_configured": bool(self.config.certificates.ca_cert_path and self.config.certificates.ca_key_path)
824
+ "ca_configured": bool(
825
+ self.config.certificates.ca_cert_path
826
+ and self.config.certificates.ca_key_path
827
+ ),
807
828
  },
808
829
  "logging": {
809
830
  "level": self.config.logging.level,
810
- "format": self.config.logging.format
811
- }
831
+ "format": self.config.logging.format,
832
+ },
812
833
  }
813
-
834
+
814
835
  self.logger.info("Security audit completed successfully")
815
836
  return audit_result
816
-
837
+
817
838
  except Exception as e:
818
839
  self.logger.error(f"Security audit failed: {str(e)}")
819
840
  raise SecurityValidationError(
820
- f"Security audit failed: {str(e)}",
821
- error_code=-32013
841
+ f"Security audit failed: {str(e)}", error_code=-32013
822
842
  )
823
843
 
824
844
  def validate_configuration(self) -> ValidationResult:
825
845
  """
826
846
  Validate security configuration.
827
-
847
+
828
848
  This method validates the complete security configuration
829
849
  and returns detailed validation results.
830
-
850
+
831
851
  Returns:
832
852
  ValidationResult: Validation result containing success status
833
853
  and detailed error information.
834
-
854
+
835
855
  Example:
836
856
  >>> result = security_manager.validate_configuration()
837
857
  >>> if result.is_valid:
@@ -841,94 +861,129 @@ class SecurityManager:
841
861
  """
842
862
  try:
843
863
  errors = []
844
-
864
+
845
865
  # Validate authentication configuration
846
866
  if self.config.auth.enabled:
847
867
  if not self.config.auth.methods:
848
868
  errors.append("Authentication enabled but no methods specified")
849
-
850
- if "api_key" in self.config.auth.methods and not self.config.auth.api_keys:
851
- errors.append("API key authentication enabled but no API keys configured")
852
-
853
- if "jwt" in self.config.auth.methods and not self.config.auth.jwt_secret:
854
- errors.append("JWT authentication enabled but no JWT secret configured")
855
-
869
+
870
+ if (
871
+ "api_key" in self.config.auth.methods
872
+ and not self.config.auth.api_keys
873
+ ):
874
+ errors.append(
875
+ "API key authentication enabled but no API keys configured"
876
+ )
877
+
878
+ if (
879
+ "jwt" in self.config.auth.methods
880
+ and not self.config.auth.jwt_secret
881
+ ):
882
+ errors.append(
883
+ "JWT authentication enabled but no JWT secret configured"
884
+ )
885
+
856
886
  # Validate authorization configuration
857
887
  if self.config.permissions.enabled:
858
- if not self.config.permissions.roles and not hasattr(self.config.permissions, 'roles_file'):
888
+ if not self.config.permissions.roles and not hasattr(
889
+ self.config.permissions, "roles_file"
890
+ ):
859
891
  errors.append("Authorization enabled but no roles configured")
860
-
892
+
861
893
  # Validate rate limiting configuration
862
894
  if self.config.rate_limit.enabled:
863
895
  if self.config.rate_limit.default_requests_per_minute <= 0:
864
- errors.append("Rate limiting enabled but invalid requests per minute")
896
+ errors.append(
897
+ "Rate limiting enabled but invalid requests per minute"
898
+ )
865
899
  if self.config.rate_limit.window_size_seconds <= 0:
866
900
  errors.append("Rate limiting enabled but invalid window seconds")
867
-
901
+
868
902
  # Validate SSL configuration
869
903
  if self.config.ssl.enabled:
870
904
  if not self.config.ssl.cert_file or not self.config.ssl.key_file:
871
- errors.append("SSL enabled but certificate or key file not specified")
872
-
905
+ errors.append(
906
+ "SSL enabled but certificate or key file not specified"
907
+ )
908
+
873
909
  # Validate certificate configuration
874
910
  if self.config.certificates.enabled:
875
- if not self.config.certificates.ca_cert_path or not self.config.certificates.ca_key_path:
876
- errors.append("Certificate management enabled but CA certificate or key not specified")
877
-
911
+ if (
912
+ not self.config.certificates.ca_cert_path
913
+ or not self.config.certificates.ca_key_path
914
+ ):
915
+ errors.append(
916
+ "Certificate management enabled but CA certificate or key not specified"
917
+ )
918
+
878
919
  if errors:
879
- return ValidationResult(
880
- is_valid=False,
881
- status=ValidationStatus.INVALID,
882
- error_message="; ".join(errors),
883
- error_code=-32014
884
- )
920
+ return ValidationResult(
921
+ is_valid=False,
922
+ status=ValidationStatus.INVALID,
923
+ error_message="; ".join(errors),
924
+ error_code=-32014,
925
+ )
885
926
  else:
886
927
  return ValidationResult(
887
928
  is_valid=True,
888
929
  status=ValidationStatus.VALID,
889
930
  error_message=None,
890
- error_code=None
931
+ error_code=None,
891
932
  )
892
-
933
+
893
934
  except Exception as e:
894
935
  self.logger.error(f"Configuration validation failed: {str(e)}")
895
936
  return ValidationResult(
896
937
  is_valid=False,
897
938
  status=ValidationStatus.INVALID,
898
939
  error_message=f"Configuration validation failed: {str(e)}",
899
- error_code=-32015
940
+ error_code=-32015,
900
941
  )
901
942
 
902
943
  def get_security_metrics(self) -> Dict[str, Any]:
903
944
  """
904
945
  Get security metrics and statistics.
905
-
946
+
906
947
  This method returns comprehensive security metrics including
907
948
  authentication attempts, permission checks, and rate limiting
908
949
  statistics.
909
-
950
+
910
951
  Returns:
911
952
  Dict[str, Any]: Security metrics and statistics
912
-
953
+
913
954
  Example:
914
955
  >>> metrics = security_manager.get_security_metrics()
915
956
  >>> print(f"Authentication attempts: {metrics['authentication_attempts']}")
916
957
  """
917
958
  try:
918
959
  metrics = {
919
- "authentication_attempts": getattr(self.auth_manager, '_auth_attempts', 0),
920
- "successful_authentications": getattr(self.auth_manager, '_successful_auths', 0),
921
- "failed_authentications": getattr(self.auth_manager, '_failed_auths', 0),
922
- "permission_checks": getattr(self.permission_manager, '_permission_checks', 0),
923
- "rate_limit_violations": getattr(self.rate_limiter, '_rate_limit_violations', 0),
960
+ "authentication_attempts": getattr(
961
+ self.auth_manager, "_auth_attempts", 0
962
+ ),
963
+ "successful_authentications": getattr(
964
+ self.auth_manager, "_successful_auths", 0
965
+ ),
966
+ "failed_authentications": getattr(
967
+ self.auth_manager, "_failed_auths", 0
968
+ ),
969
+ "permission_checks": getattr(
970
+ self.permission_manager, "_permission_checks", 0
971
+ ),
972
+ "rate_limit_violations": getattr(
973
+ self.rate_limiter, "_rate_limit_violations", 0
974
+ ),
924
975
  "security_events": len(self._security_events),
925
- "uptime_seconds": (datetime.now(timezone.utc) - self._start_time).total_seconds(),
926
- "active_sessions": getattr(self.auth_manager, '_active_sessions', 0),
927
- "certificate_operations": getattr(self.cert_manager, '_cert_operations', 0)
976
+ "uptime_seconds": (
977
+ datetime.now(timezone.utc) - self._start_time
978
+ ).total_seconds(),
979
+ "active_sessions": getattr(self.auth_manager, "_active_sessions", 0),
980
+ "certificate_operations": getattr(
981
+ self.cert_manager, "_cert_operations", 0
982
+ ),
928
983
  }
929
-
984
+
930
985
  return metrics
931
-
986
+
932
987
  except Exception as e:
933
988
  self.logger.error(f"Failed to get security metrics: {str(e)}")
934
989
  return {
@@ -941,5 +996,5 @@ class SecurityManager:
941
996
  "security_events": 0,
942
997
  "uptime_seconds": 0,
943
998
  "active_sessions": 0,
944
- "certificate_operations": 0
999
+ "certificate_operations": 0,
945
1000
  }