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
@@ -33,36 +33,35 @@ License: MIT
33
33
 
34
34
  from typing import Optional
35
35
 
36
- from .security_middleware import SecurityMiddleware, SecurityMiddlewareError
37
- from .fastapi_middleware import FastAPISecurityMiddleware, FastAPIMiddlewareError
38
- from .flask_middleware import FlaskSecurityMiddleware, FlaskMiddlewareError
39
- from .auth_middleware import AuthMiddleware, AuthMiddlewareError
40
- from .rate_limit_middleware import RateLimitMiddleware, RateLimitMiddlewareError
41
- from .mtls_middleware import MTLSMiddleware, MTLSMiddlewareError
42
-
43
36
  from ..core.security_manager import SecurityManager
44
37
  from ..schemas.config import SecurityConfig
38
+ from .auth_middleware import AuthMiddleware, AuthMiddlewareError
39
+ from .fastapi_middleware import FastAPIMiddlewareError, FastAPISecurityMiddleware
40
+ from .flask_middleware import FlaskMiddlewareError, FlaskSecurityMiddleware
41
+ from .mtls_middleware import MTLSMiddleware, MTLSMiddlewareError
42
+ from .rate_limit_middleware import RateLimitMiddleware, RateLimitMiddlewareError
43
+ from .security_middleware import SecurityMiddleware, SecurityMiddlewareError
45
44
 
46
45
 
47
46
  def create_fastapi_security_middleware(
48
- security_manager: SecurityManager
47
+ security_manager: SecurityManager,
49
48
  ) -> FastAPISecurityMiddleware:
50
49
  """
51
50
  Create FastAPI security middleware.
52
-
51
+
53
52
  Args:
54
53
  security_manager (SecurityManager): Security manager instance
55
-
54
+
56
55
  Returns:
57
56
  FastAPISecurityMiddleware: Configured FastAPI security middleware
58
-
57
+
59
58
  Raises:
60
59
  FastAPIMiddlewareError: If middleware creation fails
61
-
60
+
62
61
  Example:
63
62
  >>> from mcp_security_framework.middleware import create_fastapi_security_middleware
64
63
  >>> from fastapi import FastAPI
65
- >>>
64
+ >>>
66
65
  >>> app = FastAPI()
67
66
  >>> security_manager = SecurityManager(config)
68
67
  >>> middleware = create_fastapi_security_middleware(security_manager)
@@ -72,24 +71,24 @@ def create_fastapi_security_middleware(
72
71
 
73
72
 
74
73
  def create_flask_security_middleware(
75
- security_manager: SecurityManager
74
+ security_manager: SecurityManager,
76
75
  ) -> FlaskSecurityMiddleware:
77
76
  """
78
77
  Create Flask security middleware.
79
-
78
+
80
79
  Args:
81
80
  security_manager (SecurityManager): Security manager instance
82
-
81
+
83
82
  Returns:
84
83
  FlaskSecurityMiddleware: Configured Flask security middleware
85
-
84
+
86
85
  Raises:
87
86
  FlaskMiddlewareError: If middleware creation fails
88
-
87
+
89
88
  Example:
90
89
  >>> from mcp_security_framework.middleware import create_flask_security_middleware
91
90
  >>> from flask import Flask
92
- >>>
91
+ >>>
93
92
  >>> app = Flask(__name__)
94
93
  >>> security_manager = SecurityManager(config)
95
94
  >>> middleware = create_flask_security_middleware(security_manager)
@@ -99,83 +98,81 @@ def create_flask_security_middleware(
99
98
 
100
99
 
101
100
  def create_auth_middleware(
102
- security_manager: SecurityManager,
103
- framework: str = "fastapi",
104
- cache_ttl: int = 300
101
+ security_manager: SecurityManager, framework: str = "fastapi", cache_ttl: int = 300
105
102
  ) -> AuthMiddleware:
106
103
  """
107
104
  Create authentication-only middleware for specified framework.
108
-
105
+
109
106
  Args:
110
107
  security_manager (SecurityManager): Security manager instance
111
108
  framework (str): Target framework ("fastapi", "flask", "django")
112
109
  cache_ttl (int): Cache TTL in seconds (default: 300)
113
-
110
+
114
111
  Returns:
115
112
  AuthMiddleware: Framework-specific authentication middleware
116
-
113
+
117
114
  Raises:
118
115
  ValueError: If framework is not supported
119
116
  AuthMiddlewareError: If middleware creation fails
120
-
117
+
121
118
  Example:
122
119
  >>> from mcp_security_framework.middleware import create_auth_middleware
123
- >>>
120
+ >>>
124
121
  >>> security_manager = SecurityManager(config)
125
122
  >>> auth_middleware = create_auth_middleware(security_manager, "fastapi")
126
123
  """
127
124
  if framework == "fastapi":
128
125
  from .fastapi_auth_middleware import FastAPIAuthMiddleware
126
+
129
127
  return FastAPIAuthMiddleware(security_manager.config, security_manager)
130
128
  elif framework == "flask":
131
129
  from .flask_auth_middleware import FlaskAuthMiddleware
130
+
132
131
  return FlaskAuthMiddleware(security_manager.config, security_manager)
133
132
  else:
134
133
  raise ValueError(f"Unsupported framework: {framework}")
135
134
 
136
135
 
137
136
  def create_rate_limit_middleware(
138
- security_manager: SecurityManager
137
+ security_manager: SecurityManager,
139
138
  ) -> RateLimitMiddleware:
140
139
  """
141
140
  Create rate limiting middleware.
142
-
141
+
143
142
  Args:
144
143
  security_manager (SecurityManager): Security manager instance
145
-
144
+
146
145
  Returns:
147
146
  RateLimitMiddleware: Configured rate limiting middleware
148
-
147
+
149
148
  Raises:
150
149
  RateLimitMiddlewareError: If middleware creation fails
151
-
150
+
152
151
  Example:
153
152
  >>> from mcp_security_framework.middleware import create_rate_limit_middleware
154
- >>>
153
+ >>>
155
154
  >>> security_manager = SecurityManager(config)
156
155
  >>> rate_limit_middleware = create_rate_limit_middleware(security_manager)
157
156
  """
158
157
  return RateLimitMiddleware(security_manager)
159
158
 
160
159
 
161
- def create_mtls_middleware(
162
- security_manager: SecurityManager
163
- ) -> MTLSMiddleware:
160
+ def create_mtls_middleware(security_manager: SecurityManager) -> MTLSMiddleware:
164
161
  """
165
162
  Create mTLS middleware.
166
-
163
+
167
164
  Args:
168
165
  security_manager (SecurityManager): Security manager instance
169
-
166
+
170
167
  Returns:
171
168
  MTLSMiddleware: Configured mTLS middleware
172
-
169
+
173
170
  Raises:
174
171
  MTLSMiddlewareError: If middleware creation fails
175
-
172
+
176
173
  Example:
177
174
  >>> from mcp_security_framework.middleware import create_mtls_middleware
178
- >>>
175
+ >>>
179
176
  >>> security_manager = SecurityManager(config)
180
177
  >>> mtls_middleware = create_mtls_middleware(security_manager)
181
178
  """
@@ -183,38 +180,36 @@ def create_mtls_middleware(
183
180
 
184
181
 
185
182
  def create_security_middleware(
186
- security_manager: SecurityManager,
187
- framework: str = "fastapi"
183
+ security_manager: SecurityManager, framework: str = "fastapi"
188
184
  ) -> SecurityMiddleware:
189
185
  """
190
186
  Create security middleware for specified framework.
191
-
187
+
192
188
  Args:
193
189
  security_manager (SecurityManager): Security manager instance
194
190
  framework (str): Target framework ("fastapi", "flask", etc.)
195
-
191
+
196
192
  Returns:
197
193
  SecurityMiddleware: Configured security middleware
198
-
194
+
199
195
  Raises:
200
196
  SecurityMiddlewareError: If middleware creation fails
201
-
197
+
202
198
  Example:
203
199
  >>> from mcp_security_framework.middleware import create_security_middleware
204
- >>>
200
+ >>>
205
201
  >>> security_manager = SecurityManager(config)
206
202
  >>> middleware = create_security_middleware(security_manager, "fastapi")
207
203
  """
208
204
  framework = framework.lower()
209
-
205
+
210
206
  if framework == "fastapi":
211
207
  return create_fastapi_security_middleware(security_manager)
212
208
  elif framework == "flask":
213
209
  return create_flask_security_middleware(security_manager)
214
210
  else:
215
211
  raise SecurityMiddlewareError(
216
- f"Unsupported framework: {framework}",
217
- error_code=-32041
212
+ f"Unsupported framework: {framework}", error_code=-32041
218
213
  )
219
214
 
220
215
 
@@ -223,15 +218,12 @@ __all__ = [
223
218
  # Base classes
224
219
  "SecurityMiddleware",
225
220
  "SecurityMiddlewareError",
226
-
227
221
  # FastAPI middleware
228
222
  "FastAPISecurityMiddleware",
229
223
  "FastAPIMiddlewareError",
230
-
231
224
  # Flask middleware
232
225
  "FlaskSecurityMiddleware",
233
226
  "FlaskMiddlewareError",
234
-
235
227
  # Specialized middleware
236
228
  "AuthMiddleware",
237
229
  "AuthMiddlewareError",
@@ -239,7 +231,6 @@ __all__ = [
239
231
  "RateLimitMiddlewareError",
240
232
  "MTLSMiddleware",
241
233
  "MTLSMiddlewareError",
242
-
243
234
  # Factory functions
244
235
  "create_fastapi_security_middleware",
245
236
  "create_flask_security_middleware",
@@ -24,13 +24,13 @@ import logging
24
24
  from abc import ABC, abstractmethod
25
25
  from typing import Any, Dict, List, Optional
26
26
 
27
- from .security_middleware import SecurityMiddleware, SecurityMiddlewareError
28
27
  from ..schemas.models import AuthResult, AuthStatus
28
+ from .security_middleware import SecurityMiddleware, SecurityMiddlewareError
29
29
 
30
30
 
31
31
  class AuthMiddlewareError(SecurityMiddlewareError):
32
32
  """Raised when authentication middleware encounters an error."""
33
-
33
+
34
34
  def __init__(self, message: str, error_code: int = -32032):
35
35
  self.message = message
36
36
  self.error_code = error_code
@@ -40,100 +40,99 @@ class AuthMiddlewareError(SecurityMiddlewareError):
40
40
  class AuthMiddleware(SecurityMiddleware):
41
41
  """
42
42
  Authentication-Only Middleware Class
43
-
43
+
44
44
  This class provides authentication-only middleware that focuses
45
45
  solely on user authentication without performing authorization
46
46
  checks. It's useful for scenarios where authentication and
47
47
  authorization are handled separately.
48
-
48
+
49
49
  The AuthMiddleware implements:
50
50
  - Authentication-only request processing
51
51
  - Multiple authentication method support
52
52
  - Authentication result caching
53
53
  - Authentication event logging
54
54
  - Framework-agnostic design
55
-
55
+
56
56
  Key Responsibilities:
57
57
  - Process requests through authentication pipeline only
58
58
  - Handle multiple authentication methods
59
59
  - Cache authentication results for performance
60
60
  - Log authentication events and failures
61
61
  - Provide authentication status to downstream components
62
-
62
+
63
63
  Attributes:
64
64
  Inherits all attributes from SecurityMiddleware
65
65
  _auth_cache (Dict): Cache for authentication results
66
66
  _cache_ttl (int): Time-to-live for cached results
67
-
67
+
68
68
  Example:
69
69
  >>> from mcp_security_framework.middleware import AuthMiddleware
70
- >>>
70
+ >>>
71
71
  >>> security_manager = SecurityManager(config)
72
72
  >>> auth_middleware = AuthMiddleware(security_manager)
73
73
  >>> app.add_middleware(auth_middleware)
74
-
74
+
75
75
  Note:
76
76
  This middleware only handles authentication. Authorization
77
77
  should be handled separately by other middleware or
78
78
  application logic.
79
79
  """
80
-
80
+
81
81
  def __init__(self, security_manager, cache_ttl: int = 300):
82
82
  """
83
83
  Initialize Authentication-Only Middleware.
84
-
84
+
85
85
  Args:
86
86
  security_manager: Security manager instance containing
87
87
  all security components and configuration.
88
88
  cache_ttl (int): Time-to-live for cached authentication
89
89
  results in seconds. Defaults to 300 seconds (5 minutes).
90
-
90
+
91
91
  Raises:
92
92
  AuthMiddlewareError: If initialization fails
93
93
  """
94
94
  super().__init__(security_manager)
95
95
  self.logger = logging.getLogger(f"{__name__}.{self.__class__.__name__}")
96
96
  self._cache_ttl = cache_ttl
97
-
97
+
98
98
  self.logger.info(
99
- "Authentication middleware initialized",
100
- extra={"cache_ttl": cache_ttl}
99
+ "Authentication middleware initialized", extra={"cache_ttl": cache_ttl}
101
100
  )
102
-
101
+
103
102
  @abstractmethod
104
103
  def __call__(self, request: Any, call_next: Any) -> Any:
105
104
  """
106
105
  Process request through authentication middleware.
107
-
106
+
108
107
  This method implements the authentication-only processing
109
108
  pipeline, focusing solely on user authentication.
110
-
109
+
111
110
  Args:
112
111
  request: Framework-specific request object
113
112
  call_next: Framework-specific call_next function
114
-
113
+
115
114
  Returns:
116
115
  Framework-specific response object
117
-
116
+
118
117
  Raises:
119
118
  AuthMiddlewareError: If authentication processing fails
120
119
  """
121
120
  pass
122
-
121
+
123
122
  def _authenticate_only(self, request: Any) -> AuthResult:
124
123
  """
125
124
  Perform authentication-only processing.
126
-
125
+
127
126
  This method handles authentication without authorization
128
127
  checks, making it suitable for scenarios where auth and
129
128
  authz are separated.
130
-
129
+
131
130
  Args:
132
131
  request: Framework-specific request object
133
-
132
+
134
133
  Returns:
135
134
  AuthResult: Authentication result with user information
136
-
135
+
137
136
  Raises:
138
137
  AuthMiddlewareError: If authentication process fails
139
138
  """
@@ -144,9 +143,9 @@ class AuthMiddleware(SecurityMiddleware):
144
143
  status=AuthStatus.SUCCESS,
145
144
  username="anonymous",
146
145
  roles=[],
147
- auth_method=None
146
+ auth_method=None,
148
147
  )
149
-
148
+
150
149
  # Check cache first
151
150
  cache_key = self._get_cache_key(request)
152
151
  if cache_key in self._auth_cache:
@@ -154,33 +153,33 @@ class AuthMiddleware(SecurityMiddleware):
154
153
  if self._is_cache_valid(cached_result):
155
154
  self.logger.debug(
156
155
  "Using cached authentication result",
157
- extra={"username": cached_result.username}
156
+ extra={"username": cached_result.username},
158
157
  )
159
158
  return cached_result
160
-
159
+
161
160
  # Try each authentication method in order
162
161
  for method in self.config.auth.methods:
163
162
  auth_result = self._try_auth_method(request, method)
164
163
  if auth_result.is_valid:
165
164
  # Cache successful authentication result
166
165
  self._cache_auth_result(cache_key, auth_result)
167
-
166
+
168
167
  self.logger.info(
169
168
  "Authentication successful",
170
169
  extra={
171
170
  "username": auth_result.username,
172
171
  "auth_method": auth_result.auth_method,
173
- "user_roles": auth_result.roles
174
- }
172
+ "user_roles": auth_result.roles,
173
+ },
175
174
  )
176
175
  return auth_result
177
-
176
+
178
177
  # All authentication methods failed
179
178
  self.logger.warning(
180
179
  "All authentication methods failed",
181
- extra={"auth_methods": self.config.auth.methods}
180
+ extra={"auth_methods": self.config.auth.methods},
182
181
  )
183
-
182
+
184
183
  failed_result = AuthResult(
185
184
  is_valid=False,
186
185
  status=AuthStatus.FAILED,
@@ -188,31 +187,28 @@ class AuthMiddleware(SecurityMiddleware):
188
187
  roles=[],
189
188
  auth_method=None,
190
189
  error_code=-32033,
191
- error_message="All authentication methods failed"
190
+ error_message="All authentication methods failed",
192
191
  )
193
-
192
+
194
193
  # Cache failed result briefly to prevent repeated attempts
195
194
  self._cache_auth_result(cache_key, failed_result, ttl=60)
196
195
  return failed_result
197
-
196
+
198
197
  except Exception as e:
199
198
  self.logger.error(
200
- "Authentication process failed",
201
- extra={"error": str(e)},
202
- exc_info=True
199
+ "Authentication process failed", extra={"error": str(e)}, exc_info=True
203
200
  )
204
201
  raise AuthMiddlewareError(
205
- f"Authentication process failed: {str(e)}",
206
- error_code=-32034
202
+ f"Authentication process failed: {str(e)}", error_code=-32034
207
203
  )
208
-
204
+
209
205
  def _get_cache_key(self, request: Any) -> str:
210
206
  """
211
207
  Generate cache key for authentication result.
212
-
208
+
213
209
  Args:
214
210
  request: Framework-specific request object
215
-
211
+
216
212
  Returns:
217
213
  str: Cache key for authentication result
218
214
  """
@@ -220,25 +216,27 @@ class AuthMiddleware(SecurityMiddleware):
220
216
  ip = self._get_rate_limit_identifier(request)
221
217
  user_agent = self._get_user_agent(request)
222
218
  return f"auth:{ip}:{user_agent}"
223
-
219
+
224
220
  def _is_cache_valid(self, auth_result: AuthResult) -> bool:
225
221
  """
226
222
  Check if cached authentication result is still valid.
227
-
223
+
228
224
  Args:
229
225
  auth_result (AuthResult): Cached authentication result
230
-
226
+
231
227
  Returns:
232
228
  bool: True if cache is valid, False otherwise
233
229
  """
234
230
  # For now, assume cache is valid if it exists
235
231
  # In a real implementation, you might check timestamps
236
232
  return True
237
-
238
- def _cache_auth_result(self, cache_key: str, auth_result: AuthResult, ttl: int = None) -> None:
233
+
234
+ def _cache_auth_result(
235
+ self, cache_key: str, auth_result: AuthResult, ttl: int = None
236
+ ) -> None:
239
237
  """
240
238
  Cache authentication result.
241
-
239
+
242
240
  Args:
243
241
  cache_key (str): Cache key for the result
244
242
  auth_result (AuthResult): Authentication result to cache
@@ -246,33 +244,34 @@ class AuthMiddleware(SecurityMiddleware):
246
244
  """
247
245
  if ttl is None:
248
246
  ttl = self._cache_ttl
249
-
247
+
250
248
  # In a real implementation, you would store with timestamp
251
249
  self._auth_cache[cache_key] = auth_result
252
-
250
+
253
251
  def _clear_auth_cache(self) -> None:
254
252
  """Clear all cached authentication results."""
255
253
  self._auth_cache.clear()
256
254
  self.logger.info("Authentication cache cleared")
257
-
255
+
258
256
  def _get_user_agent(self, request: Any) -> str:
259
257
  """
260
258
  Get user agent from request.
261
-
259
+
262
260
  Args:
263
261
  request: Framework-specific request object
264
-
262
+
265
263
  Returns:
266
264
  str: User agent string
267
265
  """
268
266
  # This should be implemented by framework-specific subclasses
269
267
  return "unknown"
270
-
271
- def _log_auth_event(self, event_type: str, auth_result: AuthResult,
272
- request_details: Dict[str, Any]) -> None:
268
+
269
+ def _log_auth_event(
270
+ self, event_type: str, auth_result: AuthResult, request_details: Dict[str, Any]
271
+ ) -> None:
273
272
  """
274
273
  Log authentication event.
275
-
274
+
276
275
  Args:
277
276
  event_type (str): Type of authentication event
278
277
  auth_result (AuthResult): Authentication result
@@ -287,6 +286,6 @@ class AuthMiddleware(SecurityMiddleware):
287
286
  "is_valid": auth_result.is_valid,
288
287
  "error_code": auth_result.error_code,
289
288
  "error_message": auth_result.error_message,
290
- **request_details
291
- }
289
+ **request_details,
290
+ },
292
291
  )