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