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,403 @@
1
+ """
2
+ Rate Limit Middleware Module
3
+
4
+ This module provides specialized rate limiting middleware that focuses
5
+ solely on request rate limiting without authentication or authorization.
6
+
7
+ Key Features:
8
+ - Rate limiting-only processing
9
+ - Multiple rate limiting strategies
10
+ - Rate limit result caching
11
+ - Rate limit event logging
12
+ - Framework-agnostic design
13
+
14
+ Classes:
15
+ RateLimitMiddleware: Rate limiting-only middleware
16
+ RateLimitMiddlewareError: Rate limit middleware-specific error exception
17
+
18
+ Author: MCP Security Team
19
+ Version: 1.0.0
20
+ License: MIT
21
+ """
22
+
23
+ import logging
24
+ import time
25
+ from abc import ABC, abstractmethod
26
+ from typing import Any, Dict, List, Optional, Tuple
27
+
28
+ from .security_middleware import SecurityMiddleware, SecurityMiddlewareError
29
+
30
+
31
+ class RateLimitMiddlewareError(SecurityMiddlewareError):
32
+ """Raised when rate limit middleware encounters an error."""
33
+
34
+ def __init__(self, message: str, error_code: int = -32035):
35
+ self.message = message
36
+ self.error_code = error_code
37
+ super().__init__(self.message)
38
+
39
+
40
+ class RateLimitMiddleware(SecurityMiddleware):
41
+ """
42
+ Rate Limiting-Only Middleware Class
43
+
44
+ This class provides rate limiting-only middleware that focuses
45
+ solely on request rate limiting without performing authentication
46
+ or authorization checks. It's useful for scenarios where rate
47
+ limiting is handled separately from other security concerns.
48
+
49
+ The RateLimitMiddleware implements:
50
+ - Rate limiting-only request processing
51
+ - Multiple rate limiting strategies
52
+ - Rate limit result caching
53
+ - Rate limit event logging
54
+ - Framework-agnostic design
55
+
56
+ Key Responsibilities:
57
+ - Process requests through rate limiting pipeline only
58
+ - Handle multiple rate limiting strategies
59
+ - Cache rate limit results for performance
60
+ - Log rate limit events and violations
61
+ - Provide rate limit status to downstream components
62
+
63
+ Attributes:
64
+ Inherits all attributes from SecurityMiddleware
65
+ _rate_limit_cache (Dict): Cache for rate limit results
66
+ _rate_limit_strategies (Dict): Available rate limiting strategies
67
+
68
+ Example:
69
+ >>> from mcp_security_framework.middleware import RateLimitMiddleware
70
+ >>>
71
+ >>> security_manager = SecurityManager(config)
72
+ >>> rate_limit_middleware = RateLimitMiddleware(security_manager)
73
+ >>> app.add_middleware(rate_limit_middleware)
74
+
75
+ Note:
76
+ This middleware only handles rate limiting. Authentication and
77
+ authorization should be handled separately by other middleware
78
+ or application logic.
79
+ """
80
+
81
+ def __init__(self, security_manager):
82
+ """
83
+ Initialize Rate Limiting-Only Middleware.
84
+
85
+ Args:
86
+ security_manager: Security manager instance containing
87
+ all security components and configuration.
88
+
89
+ Raises:
90
+ RateLimitMiddlewareError: If initialization fails
91
+ """
92
+ super().__init__(security_manager)
93
+ self.logger = logging.getLogger(f"{__name__}.{self.__class__.__name__}")
94
+
95
+ # Initialize rate limiting strategies
96
+ self._rate_limit_strategies = {
97
+ "ip": self._rate_limit_by_ip,
98
+ "user": self._rate_limit_by_user,
99
+ "global": self._rate_limit_global,
100
+ "path": self._rate_limit_by_path,
101
+ "method": self._rate_limit_by_method
102
+ }
103
+
104
+ self.logger.info("Rate limit middleware initialized")
105
+
106
+ @abstractmethod
107
+ def __call__(self, request: Any, call_next: Any) -> Any:
108
+ """
109
+ Process request through rate limiting middleware.
110
+
111
+ This method implements the rate limiting-only processing
112
+ pipeline, focusing solely on request rate limiting.
113
+
114
+ Args:
115
+ request: Framework-specific request object
116
+ call_next: Framework-specific call_next function
117
+
118
+ Returns:
119
+ Framework-specific response object
120
+
121
+ Raises:
122
+ RateLimitMiddlewareError: If rate limiting processing fails
123
+ """
124
+ pass
125
+
126
+ def _check_rate_limit_only(self, request: Any) -> Tuple[bool, Dict[str, Any]]:
127
+ """
128
+ Perform rate limiting-only processing.
129
+
130
+ This method handles rate limiting without authentication
131
+ or authorization checks.
132
+
133
+ Args:
134
+ request: Framework-specific request object
135
+
136
+ Returns:
137
+ Tuple[bool, Dict[str, Any]]: (is_allowed, rate_limit_info)
138
+
139
+ Raises:
140
+ RateLimitMiddlewareError: If rate limiting process fails
141
+ """
142
+ try:
143
+ if not self.config.rate_limit.enabled:
144
+ return True, {"strategy": "disabled", "reason": "Rate limiting disabled"}
145
+
146
+ # Get rate limiting strategy from config
147
+ strategy = self.config.rate_limit.strategy if hasattr(self.config.rate_limit, 'strategy') else "ip"
148
+
149
+ if strategy not in self._rate_limit_strategies:
150
+ self.logger.warning(f"Unknown rate limiting strategy: {strategy}, using 'ip'")
151
+ strategy = "ip"
152
+
153
+ # Apply rate limiting strategy
154
+ is_allowed, rate_limit_info = self._rate_limit_strategies[strategy](request)
155
+
156
+ # Log rate limit event
157
+ self._log_rate_limit_event(request, is_allowed, rate_limit_info)
158
+
159
+ return is_allowed, rate_limit_info
160
+
161
+ except Exception as e:
162
+ self.logger.error(
163
+ "Rate limiting process failed",
164
+ extra={"error": str(e)},
165
+ exc_info=True
166
+ )
167
+ raise RateLimitMiddlewareError(
168
+ f"Rate limiting process failed: {str(e)}",
169
+ error_code=-32036
170
+ )
171
+
172
+ def _rate_limit_by_ip(self, request: Any) -> Tuple[bool, Dict[str, Any]]:
173
+ """
174
+ Rate limit by IP address.
175
+
176
+ Args:
177
+ request: Framework-specific request object
178
+
179
+ Returns:
180
+ Tuple[bool, Dict[str, Any]]: (is_allowed, rate_limit_info)
181
+ """
182
+ identifier = self._get_rate_limit_identifier(request)
183
+ is_allowed = self.security_manager.rate_limiter.check_rate_limit(identifier)
184
+
185
+ return is_allowed, {
186
+ "strategy": "ip",
187
+ "identifier": identifier,
188
+ "is_allowed": is_allowed
189
+ }
190
+
191
+ def _rate_limit_by_user(self, request: Any) -> Tuple[bool, Dict[str, Any]]:
192
+ """
193
+ Rate limit by user (requires authentication).
194
+
195
+ Args:
196
+ request: Framework-specific request object
197
+
198
+ Returns:
199
+ Tuple[bool, Dict[str, Any]]: (is_allowed, rate_limit_info)
200
+ """
201
+ # Try to get user identifier from request
202
+ user_id = self._get_user_identifier(request)
203
+ if not user_id:
204
+ # Fall back to IP-based rate limiting
205
+ return self._rate_limit_by_ip(request)
206
+
207
+ is_allowed = self.security_manager.rate_limiter.check_rate_limit(f"user:{user_id}")
208
+
209
+ return is_allowed, {
210
+ "strategy": "user",
211
+ "identifier": user_id,
212
+ "is_allowed": is_allowed
213
+ }
214
+
215
+ def _rate_limit_global(self, request: Any) -> Tuple[bool, Dict[str, Any]]:
216
+ """
217
+ Global rate limiting (all requests).
218
+
219
+ Args:
220
+ request: Framework-specific request object
221
+
222
+ Returns:
223
+ Tuple[bool, Dict[str, Any]]: (is_allowed, rate_limit_info)
224
+ """
225
+ is_allowed = self.security_manager.rate_limiter.check_rate_limit("global")
226
+
227
+ return is_allowed, {
228
+ "strategy": "global",
229
+ "identifier": "global",
230
+ "is_allowed": is_allowed
231
+ }
232
+
233
+ def _rate_limit_by_path(self, request: Any) -> Tuple[bool, Dict[str, Any]]:
234
+ """
235
+ Rate limit by request path.
236
+
237
+ Args:
238
+ request: Framework-specific request object
239
+
240
+ Returns:
241
+ Tuple[bool, Dict[str, Any]]: (is_allowed, rate_limit_info)
242
+ """
243
+ path = self._get_request_path(request)
244
+ identifier = f"path:{path}"
245
+ is_allowed = self.security_manager.rate_limiter.check_rate_limit(identifier)
246
+
247
+ return is_allowed, {
248
+ "strategy": "path",
249
+ "identifier": identifier,
250
+ "path": path,
251
+ "is_allowed": is_allowed
252
+ }
253
+
254
+ def _rate_limit_by_method(self, request: Any) -> Tuple[bool, Dict[str, Any]]:
255
+ """
256
+ Rate limit by HTTP method.
257
+
258
+ Args:
259
+ request: Framework-specific request object
260
+
261
+ Returns:
262
+ Tuple[bool, Dict[str, Any]]: (is_allowed, rate_limit_info)
263
+ """
264
+ method = self._get_request_method(request)
265
+ identifier = f"method:{method}"
266
+ is_allowed = self.security_manager.rate_limiter.check_rate_limit(identifier)
267
+
268
+ return is_allowed, {
269
+ "strategy": "method",
270
+ "identifier": identifier,
271
+ "method": method,
272
+ "is_allowed": is_allowed
273
+ }
274
+
275
+ def _get_user_identifier(self, request: Any) -> Optional[str]:
276
+ """
277
+ Get user identifier from request.
278
+
279
+ Args:
280
+ request: Framework-specific request object
281
+
282
+ Returns:
283
+ Optional[str]: User identifier if available, None otherwise
284
+ """
285
+ # This should be implemented by framework-specific subclasses
286
+ # For now, return None to indicate no user identifier available
287
+ return None
288
+
289
+ def _get_request_method(self, request: Any) -> str:
290
+ """
291
+ Get HTTP method from request.
292
+
293
+ Args:
294
+ request: Framework-specific request object
295
+
296
+ Returns:
297
+ str: HTTP method
298
+ """
299
+ # This should be implemented by framework-specific subclasses
300
+ return "GET"
301
+
302
+ def _log_rate_limit_event(self, request: Any, is_allowed: bool,
303
+ rate_limit_info: Dict[str, Any]) -> None:
304
+ """
305
+ Log rate limit event.
306
+
307
+ Args:
308
+ request: Framework-specific request object
309
+ is_allowed (bool): Whether request is allowed
310
+ rate_limit_info (Dict[str, Any]): Rate limit information
311
+ """
312
+ log_level = logging.WARNING if not is_allowed else logging.DEBUG
313
+
314
+ self.logger.log(
315
+ log_level,
316
+ f"Rate limit event: {'allowed' if is_allowed else 'blocked'}",
317
+ extra={
318
+ "event_type": "rate_limit",
319
+ "is_allowed": is_allowed,
320
+ "ip_address": self._get_rate_limit_identifier(request),
321
+ "path": self._get_request_path(request),
322
+ "method": self._get_request_method(request),
323
+ **rate_limit_info
324
+ }
325
+ )
326
+
327
+ def get_rate_limit_status(self, identifier: str) -> Dict[str, Any]:
328
+ """
329
+ Get current rate limit status for an identifier.
330
+
331
+ Args:
332
+ identifier (str): Rate limit identifier
333
+
334
+ Returns:
335
+ Dict[str, Any]: Rate limit status information
336
+ """
337
+ try:
338
+ status = self.security_manager.rate_limiter.get_rate_limit_status(identifier)
339
+ return {
340
+ "identifier": identifier,
341
+ "current_count": status.current_count,
342
+ "limit": status.limit,
343
+ "window_seconds": status.window_seconds,
344
+ "remaining": status.remaining,
345
+ "reset_time": status.reset_time
346
+ }
347
+ except Exception as e:
348
+ self.logger.error(
349
+ "Failed to get rate limit status",
350
+ extra={"identifier": identifier, "error": str(e)}
351
+ )
352
+ return {
353
+ "identifier": identifier,
354
+ "error": str(e)
355
+ }
356
+
357
+ def reset_rate_limit(self, identifier: str) -> bool:
358
+ """
359
+ Reset rate limit for an identifier.
360
+
361
+ Args:
362
+ identifier (str): Rate limit identifier
363
+
364
+ Returns:
365
+ bool: True if reset successful, False otherwise
366
+ """
367
+ try:
368
+ self.security_manager.rate_limiter.reset_rate_limit(identifier)
369
+ self.logger.info(
370
+ "Rate limit reset",
371
+ extra={"identifier": identifier}
372
+ )
373
+ return True
374
+ except Exception as e:
375
+ self.logger.error(
376
+ "Failed to reset rate limit",
377
+ extra={"identifier": identifier, "error": str(e)}
378
+ )
379
+ return False
380
+
381
+ def get_rate_limit_statistics(self) -> Dict[str, Any]:
382
+ """
383
+ Get rate limiting statistics.
384
+
385
+ Returns:
386
+ Dict[str, Any]: Rate limiting statistics
387
+ """
388
+ try:
389
+ # This would need to be implemented based on the rate limiter
390
+ # implementation to provide actual statistics
391
+ return {
392
+ "total_requests": 0,
393
+ "blocked_requests": 0,
394
+ "active_identifiers": 0,
395
+ "cache_hits": 0,
396
+ "cache_misses": 0
397
+ }
398
+ except Exception as e:
399
+ self.logger.error(
400
+ "Failed to get rate limit statistics",
401
+ extra={"error": str(e)}
402
+ )
403
+ return {"error": str(e)}