mcp-security-framework 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. mcp_security_framework/__init__.py +96 -0
  2. mcp_security_framework/cli/__init__.py +18 -0
  3. mcp_security_framework/cli/cert_cli.py +511 -0
  4. mcp_security_framework/cli/security_cli.py +791 -0
  5. mcp_security_framework/constants.py +209 -0
  6. mcp_security_framework/core/__init__.py +61 -0
  7. mcp_security_framework/core/auth_manager.py +1011 -0
  8. mcp_security_framework/core/cert_manager.py +1663 -0
  9. mcp_security_framework/core/permission_manager.py +735 -0
  10. mcp_security_framework/core/rate_limiter.py +602 -0
  11. mcp_security_framework/core/security_manager.py +943 -0
  12. mcp_security_framework/core/ssl_manager.py +735 -0
  13. mcp_security_framework/examples/__init__.py +75 -0
  14. mcp_security_framework/examples/django_example.py +615 -0
  15. mcp_security_framework/examples/fastapi_example.py +472 -0
  16. mcp_security_framework/examples/flask_example.py +506 -0
  17. mcp_security_framework/examples/gateway_example.py +803 -0
  18. mcp_security_framework/examples/microservice_example.py +690 -0
  19. mcp_security_framework/examples/standalone_example.py +576 -0
  20. mcp_security_framework/middleware/__init__.py +250 -0
  21. mcp_security_framework/middleware/auth_middleware.py +292 -0
  22. mcp_security_framework/middleware/fastapi_auth_middleware.py +447 -0
  23. mcp_security_framework/middleware/fastapi_middleware.py +757 -0
  24. mcp_security_framework/middleware/flask_auth_middleware.py +465 -0
  25. mcp_security_framework/middleware/flask_middleware.py +591 -0
  26. mcp_security_framework/middleware/mtls_middleware.py +439 -0
  27. mcp_security_framework/middleware/rate_limit_middleware.py +403 -0
  28. mcp_security_framework/middleware/security_middleware.py +507 -0
  29. mcp_security_framework/schemas/__init__.py +109 -0
  30. mcp_security_framework/schemas/config.py +694 -0
  31. mcp_security_framework/schemas/models.py +709 -0
  32. mcp_security_framework/schemas/responses.py +686 -0
  33. mcp_security_framework/tests/__init__.py +0 -0
  34. mcp_security_framework/utils/__init__.py +121 -0
  35. mcp_security_framework/utils/cert_utils.py +525 -0
  36. mcp_security_framework/utils/crypto_utils.py +475 -0
  37. mcp_security_framework/utils/validation_utils.py +571 -0
  38. mcp_security_framework-0.1.0.dist-info/METADATA +411 -0
  39. mcp_security_framework-0.1.0.dist-info/RECORD +76 -0
  40. mcp_security_framework-0.1.0.dist-info/WHEEL +5 -0
  41. mcp_security_framework-0.1.0.dist-info/entry_points.txt +3 -0
  42. mcp_security_framework-0.1.0.dist-info/top_level.txt +2 -0
  43. tests/__init__.py +0 -0
  44. tests/test_cli/__init__.py +0 -0
  45. tests/test_cli/test_cert_cli.py +379 -0
  46. tests/test_cli/test_security_cli.py +657 -0
  47. tests/test_core/__init__.py +0 -0
  48. tests/test_core/test_auth_manager.py +582 -0
  49. tests/test_core/test_cert_manager.py +795 -0
  50. tests/test_core/test_permission_manager.py +395 -0
  51. tests/test_core/test_rate_limiter.py +626 -0
  52. tests/test_core/test_security_manager.py +841 -0
  53. tests/test_core/test_ssl_manager.py +532 -0
  54. tests/test_examples/__init__.py +8 -0
  55. tests/test_examples/test_fastapi_example.py +264 -0
  56. tests/test_examples/test_flask_example.py +238 -0
  57. tests/test_examples/test_standalone_example.py +292 -0
  58. tests/test_integration/__init__.py +0 -0
  59. tests/test_integration/test_auth_flow.py +502 -0
  60. tests/test_integration/test_certificate_flow.py +527 -0
  61. tests/test_integration/test_fastapi_integration.py +341 -0
  62. tests/test_integration/test_flask_integration.py +398 -0
  63. tests/test_integration/test_standalone_integration.py +493 -0
  64. tests/test_middleware/__init__.py +0 -0
  65. tests/test_middleware/test_fastapi_middleware.py +523 -0
  66. tests/test_middleware/test_flask_middleware.py +582 -0
  67. tests/test_middleware/test_security_middleware.py +493 -0
  68. tests/test_schemas/__init__.py +0 -0
  69. tests/test_schemas/test_config.py +811 -0
  70. tests/test_schemas/test_models.py +879 -0
  71. tests/test_schemas/test_responses.py +1054 -0
  72. tests/test_schemas/test_serialization.py +493 -0
  73. tests/test_utils/__init__.py +0 -0
  74. tests/test_utils/test_cert_utils.py +510 -0
  75. tests/test_utils/test_crypto_utils.py +603 -0
  76. tests/test_utils/test_validation_utils.py +477 -0
@@ -0,0 +1,507 @@
1
+ """
2
+ Security Middleware Module
3
+
4
+ This module provides the base SecurityMiddleware class that serves as the
5
+ foundation for all framework-specific security middleware implementations.
6
+
7
+ Key Features:
8
+ - Abstract base class for all security middleware
9
+ - Common security logic and request processing
10
+ - Framework-agnostic security operations
11
+ - Unified interface for authentication and authorization
12
+ - Rate limiting and security header management
13
+ - Security event logging and monitoring
14
+
15
+ Classes:
16
+ SecurityMiddleware: Abstract base class for security middleware
17
+ SecurityMiddlewareError: Middleware-specific error exception
18
+
19
+ Author: MCP Security Team
20
+ Version: 1.0.0
21
+ License: MIT
22
+ """
23
+
24
+ import logging
25
+ from abc import ABC, abstractmethod
26
+ from typing import Any, Dict, List, Optional, Union
27
+
28
+ from ..core.security_manager import SecurityManager
29
+ from ..schemas.config import SecurityConfig
30
+ from ..schemas.models import AuthResult, ValidationResult, ValidationStatus, AuthStatus
31
+ from ..schemas.responses import SecurityResponse, ResponseStatus
32
+
33
+
34
+ class SecurityMiddlewareError(Exception):
35
+ """Raised when security middleware encounters an error."""
36
+
37
+ def __init__(self, message: str, error_code: int = -32003):
38
+ self.message = message
39
+ self.error_code = error_code
40
+ super().__init__(self.message)
41
+
42
+
43
+ class SecurityMiddleware(ABC):
44
+ """
45
+ Abstract Security Middleware Class
46
+
47
+ This is the base class for all framework-specific security middleware
48
+ implementations. It provides common security logic and a unified
49
+ interface for request processing, authentication, authorization,
50
+ and rate limiting.
51
+
52
+ The SecurityMiddleware implements the security processing pipeline:
53
+ 1. Rate limiting check
54
+ 2. Public path validation
55
+ 3. Authentication
56
+ 4. Authorization
57
+ 5. Security headers addition
58
+ 6. Response processing
59
+
60
+ Key Responsibilities:
61
+ - Process incoming requests through security pipeline
62
+ - Handle authentication using multiple methods
63
+ - Validate user permissions and access rights
64
+ - Implement rate limiting and abuse prevention
65
+ - Add security headers to responses
66
+ - Log security events and violations
67
+ - Provide framework-specific request/response handling
68
+
69
+ Attributes:
70
+ security_manager (SecurityManager): Main security manager instance
71
+ config (SecurityConfig): Security configuration
72
+ logger (Logger): Logger instance for middleware operations
73
+ _public_paths (List[str]): List of public paths that bypass security
74
+ _rate_limit_cache (Dict): Cache for rate limiting data
75
+ _auth_cache (Dict): Cache for authentication results
76
+
77
+ Example:
78
+ >>> config = SecurityConfig(auth=AuthConfig(enabled=True))
79
+ >>> security_manager = SecurityManager(config)
80
+ >>> middleware = FastAPISecurityMiddleware(security_manager)
81
+ >>> app.add_middleware(middleware)
82
+
83
+ Note:
84
+ This is an abstract base class. Implementations must provide
85
+ framework-specific request/response handling methods.
86
+ """
87
+
88
+ def __init__(self, security_manager: SecurityManager):
89
+ """
90
+ Initialize Security Middleware.
91
+
92
+ Args:
93
+ security_manager (SecurityManager): Security manager instance
94
+ containing all security components and configuration.
95
+ Must be a properly initialized SecurityManager with
96
+ valid configuration.
97
+
98
+ Raises:
99
+ SecurityMiddlewareError: If security manager is invalid or
100
+ configuration is missing.
101
+
102
+ Example:
103
+ >>> security_manager = SecurityManager(config)
104
+ >>> middleware = FastAPISecurityMiddleware(security_manager)
105
+ """
106
+ if not isinstance(security_manager, SecurityManager):
107
+ raise SecurityMiddlewareError(
108
+ "Invalid security manager: must be SecurityManager instance",
109
+ error_code=-32003
110
+ )
111
+
112
+ self.security_manager = security_manager
113
+ self.config = security_manager.config
114
+ self.logger = logging.getLogger(f"{__name__}.{self.__class__.__name__}")
115
+
116
+ # Initialize caches and state
117
+ self._public_paths = self.config.auth.public_paths if self.config.auth else []
118
+ self._rate_limit_cache: Dict[str, Dict[str, Any]] = {}
119
+ self._auth_cache: Dict[str, AuthResult] = {}
120
+
121
+ self.logger.info(
122
+ "Security middleware initialized",
123
+ extra={
124
+ "middleware_type": self.__class__.__name__,
125
+ "auth_enabled": self.config.auth.enabled if self.config.auth else False,
126
+ "public_paths_count": len(self._public_paths)
127
+ }
128
+ )
129
+
130
+ @abstractmethod
131
+ def __call__(self, request: Any, call_next: Any) -> Any:
132
+ """
133
+ Process request through security middleware.
134
+
135
+ This is the main entry point for the middleware. It implements
136
+ the security processing pipeline and delegates framework-specific
137
+ operations to abstract methods.
138
+
139
+ Args:
140
+ request: Framework-specific request object
141
+ call_next: Framework-specific call_next function
142
+
143
+ Returns:
144
+ Framework-specific response object
145
+
146
+ Raises:
147
+ SecurityMiddlewareError: If security processing fails
148
+ AuthenticationError: If authentication fails
149
+ PermissionDeniedError: If authorization fails
150
+ RateLimitExceededError: If rate limit is exceeded
151
+ """
152
+ pass
153
+
154
+ def _check_rate_limit(self, request: Any) -> bool:
155
+ """
156
+ Check if request is within rate limits.
157
+
158
+ This method checks if the current request exceeds rate limits
159
+ based on the request identifier (IP, user, etc.).
160
+
161
+ Args:
162
+ request: Framework-specific request object
163
+
164
+ Returns:
165
+ bool: True if request is within rate limits, False otherwise
166
+
167
+ Raises:
168
+ SecurityMiddlewareError: If rate limiting check fails
169
+ """
170
+ try:
171
+ if not self.config.rate_limit.enabled:
172
+ return True
173
+
174
+ identifier = self._get_rate_limit_identifier(request)
175
+ if not identifier:
176
+ self.logger.warning("Could not determine rate limit identifier")
177
+ return True
178
+
179
+ # Check rate limit using security manager
180
+ is_allowed = self.security_manager.rate_limiter.check_rate_limit(identifier)
181
+
182
+ if not is_allowed:
183
+ self.logger.warning(
184
+ "Rate limit exceeded",
185
+ extra={
186
+ "identifier": identifier,
187
+ "rate_limit": self.config.rate_limit.default_requests_per_minute,
188
+ "window_seconds": self.config.rate_limit.window_size_seconds
189
+ }
190
+ )
191
+
192
+ return is_allowed
193
+
194
+ except Exception as e:
195
+ self.logger.error(
196
+ "Rate limit check failed",
197
+ extra={"error": str(e)},
198
+ exc_info=True
199
+ )
200
+ raise SecurityMiddlewareError(
201
+ f"Rate limit check failed: {str(e)}",
202
+ error_code=-32004
203
+ )
204
+
205
+ def _authenticate_request(self, request: Any) -> AuthResult:
206
+ """
207
+ Authenticate the request using configured methods.
208
+
209
+ This method attempts to authenticate the request using all
210
+ configured authentication methods in order of preference.
211
+
212
+ Args:
213
+ request: Framework-specific request object
214
+
215
+ Returns:
216
+ AuthResult: Authentication result with user information
217
+
218
+ Raises:
219
+ SecurityMiddlewareError: If authentication process fails
220
+ """
221
+ try:
222
+ if not self.config.auth.enabled:
223
+ return AuthResult(
224
+ is_valid=True,
225
+ status=AuthStatus.SUCCESS,
226
+ username="anonymous",
227
+ roles=[],
228
+ auth_method=None
229
+ )
230
+
231
+ # Try each authentication method in order
232
+ for method in self.config.auth.methods:
233
+ auth_result = self._try_auth_method(request, method)
234
+ # Handle async methods
235
+ if hasattr(auth_result, '__await__'):
236
+ import asyncio
237
+ try:
238
+ auth_result = asyncio.run(auth_result)
239
+ except RuntimeError:
240
+ # If we're already in an event loop, use create_task
241
+ loop = asyncio.get_event_loop()
242
+ auth_result = loop.run_until_complete(auth_result)
243
+
244
+ if auth_result.is_valid:
245
+ self.logger.info(
246
+ "Authentication successful",
247
+ extra={
248
+ "username": auth_result.username,
249
+ "auth_method": auth_result.auth_method,
250
+ "user_roles": auth_result.roles
251
+ }
252
+ )
253
+ return auth_result
254
+
255
+ # All authentication methods failed
256
+ self.logger.warning(
257
+ "All authentication methods failed",
258
+ extra={"auth_methods": self.config.auth.methods}
259
+ )
260
+
261
+ return AuthResult(
262
+ is_valid=False,
263
+ status=AuthStatus.FAILED,
264
+ username=None,
265
+ roles=[],
266
+ auth_method=None,
267
+ error_code=-32005,
268
+ error_message="All authentication methods failed"
269
+ )
270
+
271
+ except Exception as e:
272
+ self.logger.error(
273
+ "Authentication process failed",
274
+ extra={"error": str(e)},
275
+ exc_info=True
276
+ )
277
+ raise SecurityMiddlewareError(
278
+ f"Authentication process failed: {str(e)}",
279
+ error_code=-32006
280
+ )
281
+
282
+ def _validate_permissions(self, request: Any, auth_result: AuthResult) -> bool:
283
+ """
284
+ Validate user permissions for the requested resource.
285
+
286
+ This method checks if the authenticated user has the required
287
+ permissions to access the requested resource.
288
+
289
+ Args:
290
+ request: Framework-specific request object
291
+ auth_result (AuthResult): Authentication result with user info
292
+
293
+ Returns:
294
+ bool: True if user has required permissions, False otherwise
295
+
296
+ Raises:
297
+ SecurityMiddlewareError: If permission validation fails
298
+ """
299
+ try:
300
+ if not auth_result.is_valid:
301
+ return False
302
+
303
+ # Get required permissions for the request
304
+ required_permissions = self._get_required_permissions(request)
305
+ if not required_permissions:
306
+ # No specific permissions required
307
+ return True
308
+
309
+ # Check permissions using security manager
310
+ validation_result = self.security_manager.check_permissions(
311
+ auth_result.roles,
312
+ required_permissions
313
+ )
314
+
315
+ if not validation_result.is_valid:
316
+ self.logger.warning(
317
+ "Permission validation failed",
318
+ extra={
319
+ "username": auth_result.username,
320
+ "user_roles": auth_result.roles,
321
+ "required_permissions": required_permissions,
322
+ "error_message": validation_result.error_message
323
+ }
324
+ )
325
+
326
+ return validation_result.is_valid
327
+
328
+ except Exception as e:
329
+ self.logger.error(
330
+ "Permission validation failed",
331
+ extra={"error": str(e)},
332
+ exc_info=True
333
+ )
334
+ raise SecurityMiddlewareError(
335
+ f"Permission validation failed: {str(e)}",
336
+ error_code=-32007
337
+ )
338
+
339
+ def _is_public_path(self, request: Any) -> bool:
340
+ """
341
+ Check if the request path is public (bypasses security).
342
+
343
+ Args:
344
+ request: Framework-specific request object
345
+
346
+ Returns:
347
+ bool: True if path is public, False otherwise
348
+ """
349
+ try:
350
+ path = self._get_request_path(request)
351
+ if not path:
352
+ return False
353
+
354
+ # Check if path matches any public path pattern
355
+ for public_path in self._public_paths:
356
+ if path == public_path or path.startswith(public_path):
357
+ return True
358
+
359
+ return False
360
+
361
+ except Exception as e:
362
+ self.logger.error(
363
+ "Public path check failed",
364
+ extra={"error": str(e)},
365
+ exc_info=True
366
+ )
367
+ return False
368
+
369
+ def _add_security_headers(self, response: Any) -> None:
370
+ """
371
+ Add security headers to the response.
372
+
373
+ Args:
374
+ response: Framework-specific response object
375
+ """
376
+ try:
377
+ # Add standard security headers
378
+ headers = {
379
+ "X-Content-Type-Options": "nosniff",
380
+ "X-Frame-Options": "DENY",
381
+ "X-XSS-Protection": "1; mode=block",
382
+ "Strict-Transport-Security": "max-age=31536000; includeSubDomains",
383
+ "Content-Security-Policy": "default-src 'self'",
384
+ "Referrer-Policy": "strict-origin-when-cross-origin"
385
+ }
386
+
387
+ # Add custom security headers from config
388
+ if self.config.auth and self.config.auth.security_headers:
389
+ headers.update(self.config.auth.security_headers)
390
+
391
+ # Apply headers using framework-specific method
392
+ self._apply_security_headers(response, headers)
393
+
394
+ except Exception as e:
395
+ self.logger.error(
396
+ "Failed to add security headers",
397
+ extra={"error": str(e)},
398
+ exc_info=True
399
+ )
400
+
401
+ def _log_security_event(self, event_type: str, details: Dict[str, Any]) -> None:
402
+ """
403
+ Log security event for monitoring and auditing.
404
+
405
+ Args:
406
+ event_type (str): Type of security event
407
+ details (Dict[str, Any]): Event details
408
+ """
409
+ try:
410
+ self.logger.info(
411
+ f"Security event: {event_type}",
412
+ extra={
413
+ "event_type": event_type,
414
+ "timestamp": details.get("timestamp"),
415
+ "ip_address": details.get("ip_address"),
416
+ "username": details.get("username"),
417
+ "path": details.get("path"),
418
+ "method": details.get("method"),
419
+ **details
420
+ }
421
+ )
422
+ except Exception as e:
423
+ self.logger.error(
424
+ "Failed to log security event",
425
+ extra={"error": str(e)},
426
+ exc_info=True
427
+ )
428
+
429
+ # Abstract methods for framework-specific implementations
430
+
431
+ @abstractmethod
432
+ def _get_rate_limit_identifier(self, request: Any) -> str:
433
+ """
434
+ Get rate limit identifier from request.
435
+
436
+ Args:
437
+ request: Framework-specific request object
438
+
439
+ Returns:
440
+ str: Rate limit identifier (IP, user ID, etc.)
441
+ """
442
+ pass
443
+
444
+ @abstractmethod
445
+ def _get_request_path(self, request: Any) -> str:
446
+ """
447
+ Get request path from request object.
448
+
449
+ Args:
450
+ request: Framework-specific request object
451
+
452
+ Returns:
453
+ str: Request path
454
+ """
455
+ pass
456
+
457
+ @abstractmethod
458
+ def _get_required_permissions(self, request: Any) -> List[str]:
459
+ """
460
+ Get required permissions for the request.
461
+
462
+ Args:
463
+ request: Framework-specific request object
464
+
465
+ Returns:
466
+ List[str]: List of required permissions
467
+ """
468
+ pass
469
+
470
+ @abstractmethod
471
+ def _try_auth_method(self, request: Any, method: str) -> AuthResult:
472
+ """
473
+ Try authentication using specific method.
474
+
475
+ Args:
476
+ request: Framework-specific request object
477
+ method (str): Authentication method to try
478
+
479
+ Returns:
480
+ AuthResult: Authentication result
481
+ """
482
+ pass
483
+
484
+ @abstractmethod
485
+ def _apply_security_headers(self, response: Any, headers: Dict[str, str]) -> None:
486
+ """
487
+ Apply security headers to response.
488
+
489
+ Args:
490
+ response: Framework-specific response object
491
+ headers (Dict[str, str]): Headers to apply
492
+ """
493
+ pass
494
+
495
+ @abstractmethod
496
+ def _create_error_response(self, status_code: int, message: str) -> Any:
497
+ """
498
+ Create error response for security violations.
499
+
500
+ Args:
501
+ status_code (int): HTTP status code
502
+ message (str): Error message
503
+
504
+ Returns:
505
+ Framework-specific error response object
506
+ """
507
+ pass
@@ -0,0 +1,109 @@
1
+ """
2
+ MCP Security Framework Schemas Module
3
+
4
+ This module provides all data models and configuration schemas for the
5
+ MCP Security Framework. It includes configuration models, data models,
6
+ and response models used throughout the framework.
7
+
8
+ Key Components:
9
+ - Configuration models for all framework components
10
+ - Data models for authentication, certificates, and permissions
11
+ - Response models for API responses and validation results
12
+ - Type definitions and aliases for better code readability
13
+
14
+ Classes:
15
+ SecurityConfig: Main security configuration class
16
+ SSLConfig: SSL/TLS configuration settings
17
+ AuthConfig: Authentication configuration
18
+ CertificateConfig: Certificate management configuration
19
+ PermissionConfig: Role and permission configuration
20
+ RateLimitConfig: Rate limiting configuration
21
+ LoggingConfig: Logging configuration
22
+
23
+ Models:
24
+ AuthResult: Authentication result model
25
+ ValidationResult: Validation result model
26
+ CertificateInfo: Certificate information model
27
+ CertificatePair: Certificate and key pair model
28
+ RateLimitStatus: Rate limiting status model
29
+
30
+ Author: MCP Security Team
31
+ Version: 1.0.0
32
+ License: MIT
33
+ """
34
+
35
+ # Configuration imports
36
+ from .config import (
37
+ AuthConfig,
38
+ CAConfig,
39
+ CertificateConfig,
40
+ ClientCertConfig,
41
+ IntermediateCAConfig,
42
+ LoggingConfig,
43
+ PermissionConfig,
44
+ RateLimitConfig,
45
+ SecurityConfig,
46
+ ServerCertConfig,
47
+ SSLConfig,
48
+ )
49
+
50
+ # Type aliases
51
+ # Model imports
52
+ from .models import (
53
+ ApiKey,
54
+ AuthResult,
55
+ CertificateChain,
56
+ CertificateInfo,
57
+ CertificatePair,
58
+ CertificatePath,
59
+ PermissionName,
60
+ RateLimitStatus,
61
+ RoleName,
62
+ RolePermissions,
63
+ UserCredentials,
64
+ Username,
65
+ ValidationResult,
66
+ )
67
+
68
+ # Response imports
69
+ from .responses import (
70
+ ErrorResponse,
71
+ SecurityResponse,
72
+ SuccessResponse,
73
+ ValidationResponse,
74
+ )
75
+
76
+ __all__ = [
77
+ # Configuration classes
78
+ "SecurityConfig",
79
+ "SSLConfig",
80
+ "AuthConfig",
81
+ "CertificateConfig",
82
+ "PermissionConfig",
83
+ "RateLimitConfig",
84
+ "LoggingConfig",
85
+ "CAConfig",
86
+ "ClientCertConfig",
87
+ "ServerCertConfig",
88
+ "IntermediateCAConfig",
89
+ # Model classes
90
+ "AuthResult",
91
+ "ValidationResult",
92
+ "CertificateInfo",
93
+ "CertificatePair",
94
+ "RateLimitStatus",
95
+ "UserCredentials",
96
+ "RolePermissions",
97
+ "CertificateChain",
98
+ # Response classes
99
+ "SecurityResponse",
100
+ "ErrorResponse",
101
+ "SuccessResponse",
102
+ "ValidationResponse",
103
+ # Type aliases
104
+ "ApiKey",
105
+ "Username",
106
+ "RoleName",
107
+ "PermissionName",
108
+ "CertificatePath",
109
+ ]