mcp-security-framework 1.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 +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.1.dist-info}/METADATA +2 -1
  34. mcp_security_framework-1.1.1.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.1.dist-info}/WHEEL +0 -0
  57. {mcp_security_framework-1.1.0.dist-info → mcp_security_framework-1.1.1.dist-info}/entry_points.txt +0 -0
  58. {mcp_security_framework-1.1.0.dist-info → mcp_security_framework-1.1.1.dist-info}/top_level.txt +0 -0
@@ -23,100 +23,116 @@ Version: 1.0.0
23
23
  License: MIT
24
24
  """
25
25
 
26
- import os
27
26
  import json
28
27
  import logging
29
- import tempfile
28
+ import os
30
29
  import shutil
31
- from typing import Dict, List, Any, Optional
30
+ import tempfile
32
31
  from datetime import datetime, timedelta, timezone
32
+ from typing import Any, Dict, List, Optional
33
33
 
34
- from fastapi import FastAPI, HTTPException, Depends, Request, Response, status
34
+ from fastapi import Depends, FastAPI, HTTPException, Request, Response, status
35
35
  from fastapi.middleware.cors import CORSMiddleware
36
- from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
36
+ from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
37
37
  from pydantic import BaseModel
38
38
 
39
+ from mcp_security_framework.constants import (
40
+ AUTH_METHODS,
41
+ DEFAULT_SECURITY_HEADERS,
42
+ ErrorCodes,
43
+ )
39
44
  from mcp_security_framework.core.security_manager import SecurityManager
40
45
  from mcp_security_framework.schemas.config import (
41
- SecurityConfig, AuthConfig, PermissionConfig, SSLConfig,
42
- CertificateConfig, RateLimitConfig, LoggingConfig
46
+ AuthConfig,
47
+ CertificateConfig,
48
+ LoggingConfig,
49
+ PermissionConfig,
50
+ RateLimitConfig,
51
+ SecurityConfig,
52
+ SSLConfig,
43
53
  )
44
54
  from mcp_security_framework.schemas.models import (
45
- AuthResult, ValidationResult, CertificatePair, CertificateInfo,
46
- AuthStatus, ValidationStatus, AuthMethod
47
- )
48
- from mcp_security_framework.constants import (
49
- DEFAULT_SECURITY_HEADERS, AUTH_METHODS, ErrorCodes
55
+ AuthMethod,
56
+ AuthResult,
57
+ AuthStatus,
58
+ CertificateInfo,
59
+ CertificatePair,
60
+ ValidationResult,
61
+ ValidationStatus,
50
62
  )
51
63
 
52
64
 
53
65
  class FastAPISecurityExample:
54
66
  """
55
67
  Comprehensive FastAPI Security Example
56
-
68
+
57
69
  This class demonstrates ALL capabilities of the MCP Security Framework
58
70
  with a real FastAPI application, serving as a complete integration test.
59
71
  """
60
-
72
+
61
73
  def __init__(self, config_path: Optional[str] = None):
62
74
  """
63
75
  Initialize the FastAPI security example.
64
-
76
+
65
77
  Args:
66
78
  config_path: Optional path to configuration file
67
79
  """
68
80
  self.config = self._load_config(config_path)
69
81
  self.security_manager = SecurityManager(self.config)
70
82
  self.logger = logging.getLogger(__name__)
71
-
83
+
72
84
  # Create FastAPI app
73
85
  self.app = FastAPI(
74
86
  title="MCP Security Framework - FastAPI Example",
75
87
  description="Comprehensive security framework demonstration with FastAPI",
76
- version="1.0.0"
88
+ version="1.0.0",
77
89
  )
78
-
90
+
79
91
  # Setup security middleware
80
92
  self._setup_security_middleware()
81
-
93
+
82
94
  # Setup routes
83
95
  self._setup_routes()
84
-
96
+
85
97
  # Test data
86
98
  self.test_api_key = "admin_key_123"
87
99
  self.test_jwt_token = self._create_test_jwt_token()
88
100
  self.test_certificate = self._create_test_certificate()
89
-
101
+
90
102
  self.logger.info("FastAPI Security Example initialized successfully")
91
-
103
+
92
104
  def _load_config(self, config_path: Optional[str] = None) -> SecurityConfig:
93
105
  """Load security configuration."""
94
106
  if config_path and os.path.exists(config_path):
95
- with open(config_path, 'r') as f:
107
+ with open(config_path, "r") as f:
96
108
  config_data = json.load(f)
97
109
  return SecurityConfig(**config_data)
98
-
110
+
99
111
  # Create comprehensive configuration
100
112
  return SecurityConfig(
101
113
  auth=AuthConfig(
102
114
  enabled=True,
103
- methods=[AUTH_METHODS["API_KEY"], AUTH_METHODS["JWT"], AUTH_METHODS["CERTIFICATE"]],
115
+ methods=[
116
+ AUTH_METHODS["API_KEY"],
117
+ AUTH_METHODS["JWT"],
118
+ AUTH_METHODS["CERTIFICATE"],
119
+ ],
104
120
  api_keys={
105
121
  "admin_key_123": {"username": "admin", "roles": ["admin", "user"]},
106
122
  "user_key_456": {"username": "user", "roles": ["user"]},
107
- "readonly_key_789": {"username": "readonly", "roles": ["readonly"]}
123
+ "readonly_key_789": {"username": "readonly", "roles": ["readonly"]},
108
124
  },
109
125
  jwt_secret="your-super-secret-jwt-key-change-in-production-12345",
110
126
  jwt_algorithm="HS256",
111
127
  jwt_expiry_hours=24,
112
128
  public_paths=["/health", "/metrics", "/docs", "/openapi.json"],
113
- security_headers=DEFAULT_SECURITY_HEADERS
129
+ security_headers=DEFAULT_SECURITY_HEADERS,
114
130
  ),
115
131
  permissions=PermissionConfig(
116
132
  enabled=True,
117
133
  roles_file="config/roles.json",
118
134
  default_role="user",
119
- hierarchy_enabled=True
135
+ hierarchy_enabled=True,
120
136
  ),
121
137
  ssl=SSLConfig(
122
138
  enabled=False, # Disable for example
@@ -124,14 +140,14 @@ class FastAPISecurityExample:
124
140
  key_file=None,
125
141
  ca_cert_file=None,
126
142
  verify_mode="CERT_REQUIRED",
127
- min_version="TLSv1.2"
143
+ min_version="TLSv1.2",
128
144
  ),
129
145
  certificates=CertificateConfig(
130
146
  enabled=False, # Disable for example
131
147
  ca_cert_path=None,
132
148
  ca_key_path=None,
133
149
  cert_validity_days=365,
134
- key_size=2048
150
+ key_size=2048,
135
151
  ),
136
152
  rate_limit=RateLimitConfig(
137
153
  enabled=True,
@@ -140,7 +156,7 @@ class FastAPISecurityExample:
140
156
  burst_limit=2,
141
157
  window_size_seconds=60,
142
158
  storage_backend="memory",
143
- cleanup_interval=300
159
+ cleanup_interval=300,
144
160
  ),
145
161
  logging=LoggingConfig(
146
162
  enabled=True,
@@ -150,24 +166,29 @@ class FastAPISecurityExample:
150
166
  max_file_size=10,
151
167
  backup_count=5,
152
168
  console_output=True,
153
- json_format=False
169
+ json_format=False,
154
170
  ),
155
171
  debug=True,
156
172
  environment="test",
157
- version="1.0.0"
173
+ version="1.0.0",
158
174
  )
159
-
175
+
160
176
  def _create_test_jwt_token(self) -> str:
161
177
  """Create a test JWT token."""
162
178
  import jwt
179
+
163
180
  payload = {
164
181
  "username": "test_user",
165
182
  "roles": ["user"],
166
- "exp": datetime.now(timezone.utc) + timedelta(hours=1)
183
+ "exp": datetime.now(timezone.utc) + timedelta(hours=1),
167
184
  }
168
- jwt_secret = self.config.auth.jwt_secret.get_secret_value() if self.config.auth.jwt_secret else "default-jwt-secret-for-testing"
185
+ jwt_secret = (
186
+ self.config.auth.jwt_secret.get_secret_value()
187
+ if self.config.auth.jwt_secret
188
+ else "default-jwt-secret-for-testing"
189
+ )
169
190
  return jwt.encode(payload, jwt_secret, algorithm="HS256")
170
-
191
+
171
192
  def _create_test_certificate(self) -> str:
172
193
  """Create a test certificate."""
173
194
  return """-----BEGIN CERTIFICATE-----
@@ -182,9 +203,10 @@ eSBMdGQwHhcNMTkwMzI2MTIzMzQ5WhcNMjAwMzI1MTIzMzQ5WjBFMQswCQYDVQQG
182
203
  EwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lk
183
204
  Z2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
184
205
  -----END CERTIFICATE-----"""
185
-
206
+
186
207
  def _setup_security_middleware(self):
187
208
  """Setup security middleware for FastAPI."""
209
+
188
210
  @self.app.middleware("http")
189
211
  async def security_middleware(request: Request, call_next):
190
212
  """Security middleware for request processing."""
@@ -193,132 +215,134 @@ Z2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
193
215
  response = await call_next(request)
194
216
  self._add_security_headers(response)
195
217
  return response
196
-
218
+
197
219
  # Rate limiting check
198
220
  if not self._check_rate_limit(request):
199
221
  return Response(
200
- content=json.dumps({
201
- "error": "Rate limit exceeded",
202
- "error_code": -32003
203
- }),
222
+ content=json.dumps(
223
+ {"error": "Rate limit exceeded", "error_code": -32003}
224
+ ),
204
225
  status_code=status.HTTP_429_TOO_MANY_REQUESTS,
205
- media_type="application/json"
226
+ media_type="application/json",
206
227
  )
207
-
228
+
208
229
  # Authentication check
209
230
  auth_result = await self._authenticate_request(request)
210
231
  if not auth_result.is_valid:
211
232
  return Response(
212
- content=json.dumps({
213
- "error": auth_result.error_message,
214
- "error_code": auth_result.error_code
215
- }),
233
+ content=json.dumps(
234
+ {
235
+ "error": auth_result.error_message,
236
+ "error_code": auth_result.error_code,
237
+ }
238
+ ),
216
239
  status_code=status.HTTP_401_UNAUTHORIZED,
217
- media_type="application/json"
240
+ media_type="application/json",
218
241
  )
219
-
242
+
220
243
  # Authorization check (for protected endpoints)
221
- if request.url.path.startswith("/admin") or request.url.path.startswith("/api/v1"):
244
+ if request.url.path.startswith("/admin") or request.url.path.startswith(
245
+ "/api/v1"
246
+ ):
222
247
  if not self._check_permissions(request, auth_result):
223
248
  return Response(
224
- content=json.dumps({
225
- "error": "Insufficient permissions",
226
- "error_code": -32004
227
- }),
249
+ content=json.dumps(
250
+ {"error": "Insufficient permissions", "error_code": -32004}
251
+ ),
228
252
  status_code=status.HTTP_403_FORBIDDEN,
229
- media_type="application/json"
253
+ media_type="application/json",
230
254
  )
231
-
255
+
232
256
  # Add user info to request state
233
257
  request.state.user_info = {
234
258
  "username": auth_result.username,
235
259
  "roles": auth_result.roles,
236
260
  "permissions": auth_result.permissions,
237
- "auth_method": auth_result.auth_method.value
261
+ "auth_method": auth_result.auth_method.value,
238
262
  }
239
-
263
+
240
264
  # Process request
241
265
  response = await call_next(request)
242
-
266
+
243
267
  # Add security headers
244
268
  self._add_security_headers(response)
245
-
269
+
246
270
  return response
247
-
271
+
248
272
  def _is_public_path(self, path: str) -> bool:
249
273
  """Check if path is public."""
250
- return any(path.startswith(public_path) for public_path in self.config.auth.public_paths)
251
-
274
+ return any(
275
+ path.startswith(public_path)
276
+ for public_path in self.config.auth.public_paths
277
+ )
278
+
252
279
  def _check_rate_limit(self, request: Request) -> bool:
253
280
  """Check rate limit for request."""
254
281
  identifier = request.client.host if request.client else "unknown"
255
282
  return self.security_manager.check_rate_limit(identifier)
256
-
283
+
257
284
  async def _authenticate_request(self, request: Request) -> AuthResult:
258
285
  """Authenticate request."""
259
286
  # Check for API key in headers
260
287
  api_key = request.headers.get("X-API-Key")
261
288
  if api_key:
262
- return self.security_manager.authenticate_user({
263
- "method": "api_key",
264
- "api_key": api_key
265
- })
266
-
289
+ return self.security_manager.authenticate_user(
290
+ {"method": "api_key", "api_key": api_key}
291
+ )
292
+
267
293
  # Check for JWT token in Authorization header
268
294
  auth_header = request.headers.get("Authorization")
269
295
  if auth_header and auth_header.startswith("Bearer "):
270
296
  token = auth_header[7:]
271
- return self.security_manager.authenticate_user({
272
- "method": "jwt",
273
- "token": token
274
- })
275
-
297
+ return self.security_manager.authenticate_user(
298
+ {"method": "jwt", "token": token}
299
+ )
300
+
276
301
  # Check for certificate in headers (for mTLS)
277
302
  cert_header = request.headers.get("X-Client-Cert")
278
303
  if cert_header:
279
- return self.security_manager.authenticate_user({
280
- "method": "certificate",
281
- "certificate": cert_header
282
- })
283
-
304
+ return self.security_manager.authenticate_user(
305
+ {"method": "certificate", "certificate": cert_header}
306
+ )
307
+
284
308
  # Return failed authentication
285
309
  return AuthResult(
286
310
  is_valid=False,
287
311
  status=AuthStatus.INVALID,
288
312
  auth_method=AuthMethod.UNKNOWN,
289
313
  error_code=-32001,
290
- error_message="No authentication credentials provided"
314
+ error_message="No authentication credentials provided",
291
315
  )
292
-
316
+
293
317
  def _check_permissions(self, request: Request, auth_result: AuthResult) -> bool:
294
318
  """Check permissions for request."""
295
319
  # Determine required permissions based on endpoint
296
320
  required_permissions = []
297
-
321
+
298
322
  if request.url.path.startswith("/admin"):
299
323
  required_permissions = ["admin"]
300
324
  elif request.url.path.startswith("/api/v1/users"):
301
325
  required_permissions = ["read:own"] # Use read:own instead of read:users
302
326
  elif request.url.path.startswith("/api/v1/data"):
303
327
  required_permissions = ["read:own"] # Use read:own instead of read:data
304
-
328
+
305
329
  if required_permissions:
306
330
  result = self.security_manager.check_permissions(
307
331
  auth_result.roles, required_permissions
308
332
  )
309
333
  return result.is_valid
310
-
334
+
311
335
  return True
312
-
336
+
313
337
  def _add_security_headers(self, response: Response):
314
338
  """Add security headers to response."""
315
339
  if self.config.auth.security_headers:
316
340
  for header, value in self.config.auth.security_headers.items():
317
341
  response.headers[header] = value
318
-
342
+
319
343
  def _setup_routes(self):
320
344
  """Setup FastAPI routes."""
321
-
345
+
322
346
  # Health check endpoint
323
347
  @self.app.get("/health")
324
348
  async def health_check():
@@ -327,9 +351,9 @@ Z2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
327
351
  "status": "healthy",
328
352
  "framework": "FastAPI",
329
353
  "security_enabled": True,
330
- "timestamp": datetime.now(timezone.utc).isoformat()
354
+ "timestamp": datetime.now(timezone.utc).isoformat(),
331
355
  }
332
-
356
+
333
357
  # Metrics endpoint
334
358
  @self.app.get("/metrics")
335
359
  async def get_metrics():
@@ -338,9 +362,9 @@ Z2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
338
362
  return {
339
363
  "framework": "FastAPI",
340
364
  "metrics": metrics,
341
- "timestamp": datetime.now(timezone.utc).isoformat()
365
+ "timestamp": datetime.now(timezone.utc).isoformat(),
342
366
  }
343
-
367
+
344
368
  # Security status endpoint
345
369
  @self.app.get("/security/status")
346
370
  async def get_security_status():
@@ -349,9 +373,9 @@ Z2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
349
373
  return {
350
374
  "framework": "FastAPI",
351
375
  "status": status.dict(),
352
- "timestamp": datetime.now(timezone.utc).isoformat()
376
+ "timestamp": datetime.now(timezone.utc).isoformat(),
353
377
  }
354
-
378
+
355
379
  # Security audit endpoint
356
380
  @self.app.get("/security/audit")
357
381
  async def get_security_audit():
@@ -360,177 +384,174 @@ Z2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
360
384
  return {
361
385
  "framework": "FastAPI",
362
386
  "audit": audit,
363
- "timestamp": datetime.now(timezone.utc).isoformat()
387
+ "timestamp": datetime.now(timezone.utc).isoformat(),
364
388
  }
365
-
389
+
366
390
  # Admin endpoints (require admin permissions)
367
391
  @self.app.get("/admin/users")
368
392
  async def get_users(request: Request):
369
393
  """Get all users (admin only)."""
370
- user_info = getattr(request.state, 'user_info', {})
394
+ user_info = getattr(request.state, "user_info", {})
371
395
  return {
372
396
  "message": "Users list",
373
397
  "user": user_info,
374
398
  "users": [
375
399
  {"id": 1, "username": "admin", "roles": ["admin"]},
376
400
  {"id": 2, "username": "user", "roles": ["user"]},
377
- {"id": 3, "username": "readonly", "roles": ["readonly"]}
378
- ]
401
+ {"id": 3, "username": "readonly", "roles": ["readonly"]},
402
+ ],
379
403
  }
380
-
404
+
381
405
  # API endpoints (require specific permissions)
382
406
  @self.app.get("/api/v1/users/me")
383
407
  async def get_current_user(request: Request):
384
408
  """Get current user info."""
385
- user_info = getattr(request.state, 'user_info', {})
386
- return {
387
- "message": "Current user info",
388
- "user": user_info
389
- }
390
-
409
+ user_info = getattr(request.state, "user_info", {})
410
+ return {"message": "Current user info", "user": user_info}
411
+
391
412
  @self.app.get("/api/v1/data")
392
413
  async def get_data(request: Request):
393
414
  """Get data (requires read:data permission)."""
394
- user_info = getattr(request.state, 'user_info', {})
415
+ user_info = getattr(request.state, "user_info", {})
395
416
  return {
396
417
  "message": "Data retrieved successfully",
397
418
  "user": user_info,
398
419
  "data": [
399
420
  {"id": 1, "name": "Sample Data 1"},
400
421
  {"id": 2, "name": "Sample Data 2"},
401
- {"id": 3, "name": "Sample Data 3"}
402
- ]
422
+ {"id": 3, "name": "Sample Data 3"},
423
+ ],
403
424
  }
404
-
425
+
405
426
  # Authentication test endpoints
406
427
  @self.app.post("/auth/test-api-key")
407
428
  async def test_api_key_auth(request: Request):
408
429
  """Test API key authentication."""
409
- user_info = getattr(request.state, 'user_info', {})
430
+ user_info = getattr(request.state, "user_info", {})
410
431
  return {
411
432
  "message": "API key authentication successful",
412
433
  "user": user_info,
413
- "auth_method": "api_key"
434
+ "auth_method": "api_key",
414
435
  }
415
-
436
+
416
437
  @self.app.post("/auth/test-jwt")
417
438
  async def test_jwt_auth(request: Request):
418
439
  """Test JWT authentication."""
419
- user_info = getattr(request.state, 'user_info', {})
440
+ user_info = getattr(request.state, "user_info", {})
420
441
  return {
421
442
  "message": "JWT authentication successful",
422
443
  "user": user_info,
423
- "auth_method": "jwt"
444
+ "auth_method": "jwt",
424
445
  }
425
-
446
+
426
447
  # Rate limiting test endpoint
427
448
  @self.app.get("/rate-limit-test")
428
449
  async def rate_limit_test(request: Request):
429
450
  """Test rate limiting."""
430
- user_info = getattr(request.state, 'user_info', {})
451
+ user_info = getattr(request.state, "user_info", {})
431
452
  return {
432
453
  "message": "Rate limit test successful",
433
454
  "user": user_info,
434
- "timestamp": datetime.now(timezone.utc).isoformat()
455
+ "timestamp": datetime.now(timezone.utc).isoformat(),
435
456
  }
436
-
457
+
437
458
  def demonstrate_authentication(self) -> Dict[str, Any]:
438
459
  """
439
460
  Demonstrate ALL authentication methods.
440
-
461
+
441
462
  Returns:
442
463
  Dict with authentication test results
443
464
  """
444
465
  self.logger.info("Demonstrating authentication capabilities...")
445
-
466
+
446
467
  results = {
447
468
  "api_key_auth": {},
448
469
  "jwt_auth": {},
449
470
  "certificate_auth": {},
450
- "failed_auth": {}
471
+ "failed_auth": {},
451
472
  }
452
-
473
+
453
474
  # 1. API Key Authentication
454
475
  try:
455
- auth_result = self.security_manager.authenticate_user({
456
- "method": "api_key",
457
- "api_key": self.test_api_key
458
- })
476
+ auth_result = self.security_manager.authenticate_user(
477
+ {"method": "api_key", "api_key": self.test_api_key}
478
+ )
459
479
  results["api_key_auth"] = {
460
480
  "success": auth_result.is_valid,
461
481
  "username": auth_result.username,
462
482
  "roles": auth_result.roles,
463
- "auth_method": auth_result.auth_method.value
483
+ "auth_method": auth_result.auth_method.value,
464
484
  }
465
- self.logger.info(f"API Key auth: {auth_result.username} - {auth_result.roles}")
485
+ self.logger.info(
486
+ f"API Key auth: {auth_result.username} - {auth_result.roles}"
487
+ )
466
488
  except Exception as e:
467
489
  results["api_key_auth"] = {"error": str(e)}
468
-
490
+
469
491
  # 2. JWT Authentication
470
492
  try:
471
- auth_result = self.security_manager.authenticate_user({
472
- "method": "jwt",
473
- "token": self.test_jwt_token
474
- })
493
+ auth_result = self.security_manager.authenticate_user(
494
+ {"method": "jwt", "token": self.test_jwt_token}
495
+ )
475
496
  results["jwt_auth"] = {
476
497
  "success": auth_result.is_valid,
477
498
  "username": auth_result.username,
478
499
  "roles": auth_result.roles,
479
- "auth_method": auth_result.auth_method.value
500
+ "auth_method": auth_result.auth_method.value,
480
501
  }
481
502
  self.logger.info(f"JWT auth: {auth_result.username} - {auth_result.roles}")
482
503
  except Exception as e:
483
504
  results["jwt_auth"] = {"error": str(e)}
484
-
505
+
485
506
  # 3. Certificate Authentication
486
507
  try:
487
- auth_result = self.security_manager.authenticate_user({
488
- "method": "certificate",
489
- "certificate": self.test_certificate
490
- })
508
+ auth_result = self.security_manager.authenticate_user(
509
+ {"method": "certificate", "certificate": self.test_certificate}
510
+ )
491
511
  results["certificate_auth"] = {
492
512
  "success": auth_result.is_valid,
493
513
  "username": auth_result.username,
494
514
  "roles": auth_result.roles,
495
- "auth_method": auth_result.auth_method.value
515
+ "auth_method": auth_result.auth_method.value,
496
516
  }
497
- self.logger.info(f"Certificate auth: {auth_result.username} - {auth_result.roles}")
517
+ self.logger.info(
518
+ f"Certificate auth: {auth_result.username} - {auth_result.roles}"
519
+ )
498
520
  except Exception as e:
499
521
  results["certificate_auth"] = {"error": str(e)}
500
-
522
+
501
523
  # 4. Failed Authentication
502
524
  try:
503
- auth_result = self.security_manager.authenticate_user({
504
- "method": "api_key",
505
- "api_key": "invalid_key"
506
- })
525
+ auth_result = self.security_manager.authenticate_user(
526
+ {"method": "api_key", "api_key": "invalid_key"}
527
+ )
507
528
  results["failed_auth"] = {
508
529
  "success": auth_result.is_valid,
509
530
  "error_message": auth_result.error_message,
510
- "error_code": auth_result.error_code
531
+ "error_code": auth_result.error_code,
511
532
  }
512
533
  self.logger.info(f"Failed auth test: {auth_result.error_message}")
513
534
  except Exception as e:
514
535
  results["failed_auth"] = {"error": str(e)}
515
-
536
+
516
537
  return results
517
-
538
+
518
539
  def demonstrate_authorization(self) -> Dict[str, Any]:
519
540
  """
520
541
  Demonstrate authorization capabilities.
521
-
542
+
522
543
  Returns:
523
544
  Dict with authorization test results
524
545
  """
525
546
  self.logger.info("Demonstrating authorization capabilities...")
526
-
547
+
527
548
  results = {
528
549
  "admin_permissions": {},
529
550
  "user_permissions": {},
530
551
  "readonly_permissions": {},
531
- "denied_permissions": {}
552
+ "denied_permissions": {},
532
553
  }
533
-
554
+
534
555
  # 1. Admin permissions
535
556
  try:
536
557
  result = self.security_manager.check_permissions(
@@ -538,12 +559,12 @@ Z2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
538
559
  )
539
560
  results["admin_permissions"] = {
540
561
  "success": result.is_valid,
541
- "status": result.status.value
562
+ "status": result.status.value,
542
563
  }
543
564
  self.logger.info(f"Admin permissions: {result.is_valid}")
544
565
  except Exception as e:
545
566
  results["admin_permissions"] = {"error": str(e)}
546
-
567
+
547
568
  # 2. User permissions
548
569
  try:
549
570
  result = self.security_manager.check_permissions(
@@ -551,138 +572,122 @@ Z2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
551
572
  )
552
573
  results["user_permissions"] = {
553
574
  "success": result.is_valid,
554
- "status": result.status.value
575
+ "status": result.status.value,
555
576
  }
556
577
  self.logger.info(f"User permissions: {result.is_valid}")
557
578
  except Exception as e:
558
579
  results["user_permissions"] = {"error": str(e)}
559
-
580
+
560
581
  # 3. Readonly permissions
561
582
  try:
562
- result = self.security_manager.check_permissions(
563
- ["readonly"], ["read"]
564
- )
583
+ result = self.security_manager.check_permissions(["readonly"], ["read"])
565
584
  results["readonly_permissions"] = {
566
585
  "success": result.is_valid,
567
- "status": result.status.value
586
+ "status": result.status.value,
568
587
  }
569
588
  self.logger.info(f"Readonly permissions: {result.is_valid}")
570
589
  except Exception as e:
571
590
  results["readonly_permissions"] = {"error": str(e)}
572
-
591
+
573
592
  # 4. Denied permissions
574
593
  try:
575
- result = self.security_manager.check_permissions(
576
- ["readonly"], ["delete"]
577
- )
594
+ result = self.security_manager.check_permissions(["readonly"], ["delete"])
578
595
  results["denied_permissions"] = {
579
596
  "success": result.is_valid,
580
597
  "status": result.status.value,
581
- "error_message": result.error_message
598
+ "error_message": result.error_message,
582
599
  }
583
600
  self.logger.info(f"Denied permissions: {result.is_valid}")
584
601
  except Exception as e:
585
602
  results["denied_permissions"] = {"error": str(e)}
586
-
603
+
587
604
  return results
588
-
605
+
589
606
  def demonstrate_rate_limiting(self) -> Dict[str, Any]:
590
607
  """
591
608
  Demonstrate rate limiting capabilities.
592
-
609
+
593
610
  Returns:
594
611
  Dict with rate limiting test results
595
612
  """
596
613
  self.logger.info("Demonstrating rate limiting capabilities...")
597
-
598
- results = {
599
- "rate_limit_checks": [],
600
- "rate_limit_exceeded": False
601
- }
602
-
614
+
615
+ results = {"rate_limit_checks": [], "rate_limit_exceeded": False}
616
+
603
617
  identifier = "test_user_123"
604
-
618
+
605
619
  # Test rate limiting
606
620
  for i in range(5):
607
621
  try:
608
622
  allowed = self.security_manager.check_rate_limit(identifier)
609
- results["rate_limit_checks"].append({
610
- "request": i + 1,
611
- "allowed": allowed
612
- })
613
- self.logger.info(f"Rate limit check {i+1}: {'Allowed' if allowed else 'Blocked'}")
614
-
623
+ results["rate_limit_checks"].append(
624
+ {"request": i + 1, "allowed": allowed}
625
+ )
626
+ self.logger.info(
627
+ f"Rate limit check {i+1}: {'Allowed' if allowed else 'Blocked'}"
628
+ )
629
+
615
630
  if not allowed:
616
631
  results["rate_limit_exceeded"] = True
617
632
  break
618
-
633
+
619
634
  except Exception as e:
620
- results["rate_limit_checks"].append({
621
- "request": i + 1,
622
- "error": str(e)
623
- })
624
-
635
+ results["rate_limit_checks"].append({"request": i + 1, "error": str(e)})
636
+
625
637
  return results
626
-
638
+
627
639
  def demonstrate_security_validation(self) -> Dict[str, Any]:
628
640
  """
629
641
  Demonstrate security validation capabilities.
630
-
642
+
631
643
  Returns:
632
644
  Dict with validation test results
633
645
  """
634
646
  self.logger.info("Demonstrating security validation capabilities...")
635
-
636
- results = {
637
- "request_validation": {},
638
- "configuration_validation": {}
639
- }
640
-
647
+
648
+ results = {"request_validation": {}, "configuration_validation": {}}
649
+
641
650
  # 1. Request validation
642
651
  try:
643
652
  request_data = {
644
653
  "api_key": self.test_api_key,
645
654
  "required_permissions": ["read", "write"],
646
- "client_ip": "192.168.1.100"
655
+ "client_ip": "192.168.1.100",
647
656
  }
648
-
657
+
649
658
  result = self.security_manager.validate_request(request_data)
650
659
  results["request_validation"] = {
651
660
  "success": result.is_valid,
652
- "status": result.status.value
661
+ "status": result.status.value,
653
662
  }
654
663
  self.logger.info(f"Request validation: {result.is_valid}")
655
664
  except Exception as e:
656
665
  results["request_validation"] = {"error": str(e)}
657
-
666
+
658
667
  # 2. Configuration validation
659
668
  try:
660
669
  result = self.security_manager.validate_configuration()
661
670
  results["configuration_validation"] = {
662
671
  "success": result.is_valid,
663
- "status": result.status.value
672
+ "status": result.status.value,
664
673
  }
665
674
  self.logger.info(f"Configuration validation: {result.is_valid}")
666
675
  except Exception as e:
667
676
  results["configuration_validation"] = {"error": str(e)}
668
-
677
+
669
678
  return results
670
-
679
+
671
680
  def demonstrate_security_monitoring(self) -> Dict[str, Any]:
672
681
  """
673
682
  Demonstrate security monitoring capabilities.
674
-
683
+
675
684
  Returns:
676
685
  Dict with monitoring test results
677
686
  """
678
687
  self.logger.info("Demonstrating security monitoring capabilities...")
679
-
680
- results = {
681
- "security_status": {},
682
- "security_metrics": {},
683
- "security_audit": {}
684
- }
685
-
688
+
689
+ results = {"security_status": {}, "security_metrics": {}, "security_audit": {}}
690
+
686
691
  # 1. Security status
687
692
  try:
688
693
  status = self.security_manager.get_security_status()
@@ -690,24 +695,24 @@ Z2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
690
695
  "status": status.status.value,
691
696
  "message": status.message,
692
697
  "version": status.version,
693
- "metadata": status.metadata
698
+ "metadata": status.metadata,
694
699
  }
695
700
  self.logger.info("Security status retrieved successfully")
696
701
  except Exception as e:
697
702
  results["security_status"] = {"error": str(e)}
698
-
703
+
699
704
  # 2. Security metrics
700
705
  try:
701
706
  metrics = self.security_manager.get_security_metrics()
702
707
  results["security_metrics"] = {
703
708
  "authentication_attempts": metrics.get("authentication_attempts", 0),
704
709
  "security_events": metrics.get("security_events", 0),
705
- "uptime_seconds": metrics.get("uptime_seconds", 0)
710
+ "uptime_seconds": metrics.get("uptime_seconds", 0),
706
711
  }
707
712
  self.logger.info("Security metrics retrieved successfully")
708
713
  except Exception as e:
709
714
  results["security_metrics"] = {"error": str(e)}
710
-
715
+
711
716
  # 3. Security audit
712
717
  try:
713
718
  audit = self.security_manager.perform_security_audit()
@@ -715,23 +720,23 @@ Z2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
715
720
  "authentication": audit.get("authentication", {}),
716
721
  "authorization": audit.get("authorization", {}),
717
722
  "rate_limiting": audit.get("rate_limiting", {}),
718
- "ssl": audit.get("ssl", {})
723
+ "ssl": audit.get("ssl", {}),
719
724
  }
720
725
  self.logger.info("Security audit completed successfully")
721
726
  except Exception as e:
722
727
  results["security_audit"] = {"error": str(e)}
723
-
728
+
724
729
  return results
725
-
730
+
726
731
  def run_comprehensive_demo(self) -> Dict[str, Any]:
727
732
  """
728
733
  Run comprehensive demonstration of ALL framework capabilities.
729
-
734
+
730
735
  Returns:
731
736
  Dict with all demonstration results
732
737
  """
733
738
  self.logger.info("Starting comprehensive security framework demonstration...")
734
-
739
+
735
740
  demo_results = {
736
741
  "timestamp": datetime.now(timezone.utc).isoformat(),
737
742
  "framework": "FastAPI",
@@ -740,90 +745,90 @@ Z2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
740
745
  "authorization": self.demonstrate_authorization(),
741
746
  "rate_limiting": self.demonstrate_rate_limiting(),
742
747
  "security_validation": self.demonstrate_security_validation(),
743
- "security_monitoring": self.demonstrate_security_monitoring()
748
+ "security_monitoring": self.demonstrate_security_monitoring(),
744
749
  }
745
-
750
+
746
751
  self.logger.info("Comprehensive demonstration completed successfully")
747
752
  return demo_results
748
753
 
749
754
 
750
755
  class FastAPIExampleTest:
751
756
  """Test class for FastAPI example."""
752
-
757
+
753
758
  def test_authentication(self):
754
759
  """Test authentication capabilities."""
755
760
  example = FastAPISecurityExample()
756
761
  results = example.demonstrate_authentication()
757
-
762
+
758
763
  # Verify API key authentication works
759
764
  assert results["api_key_auth"]["success"] == True
760
765
  assert results["api_key_auth"]["username"] == "admin"
761
766
  assert "admin" in results["api_key_auth"]["roles"]
762
-
767
+
763
768
  # Verify JWT authentication works
764
769
  assert results["jwt_auth"]["success"] == True
765
770
  assert results["jwt_auth"]["username"] == "test_user"
766
-
771
+
767
772
  # Verify failed authentication is handled
768
773
  assert results["failed_auth"]["success"] == False
769
-
774
+
770
775
  print("✅ Authentication tests passed")
771
-
776
+
772
777
  def test_authorization(self):
773
778
  """Test authorization capabilities."""
774
779
  example = FastAPISecurityExample()
775
780
  results = example.demonstrate_authorization()
776
-
781
+
777
782
  # Verify admin permissions work
778
783
  assert results["admin_permissions"]["success"] == True
779
-
784
+
780
785
  # Verify user permissions work
781
786
  assert results["user_permissions"]["success"] == True
782
-
787
+
783
788
  # Verify readonly permissions work
784
789
  assert results["readonly_permissions"]["success"] == True
785
-
790
+
786
791
  print("✅ Authorization tests passed")
787
-
792
+
788
793
  def test_rate_limiting(self):
789
794
  """Test rate limiting capabilities."""
790
795
  example = FastAPISecurityExample()
791
796
  results = example.demonstrate_rate_limiting()
792
-
797
+
793
798
  # Verify rate limiting checks work
794
799
  assert len(results["rate_limit_checks"]) > 0
795
800
  assert results["rate_limit_checks"][0]["allowed"] == True
796
-
801
+
797
802
  print("✅ Rate limiting tests passed")
798
-
803
+
799
804
  def test_security_validation(self):
800
805
  """Test security validation capabilities."""
801
806
  example = FastAPISecurityExample()
802
807
  results = example.demonstrate_security_validation()
803
-
808
+
804
809
  # Verify request validation works
805
810
  assert results["request_validation"]["success"] == True
806
-
811
+
807
812
  # Verify configuration validation works
808
813
  assert results["configuration_validation"]["success"] == True
809
-
814
+
810
815
  print("✅ Security validation tests passed")
811
-
816
+
812
817
  def test_security_monitoring(self):
813
818
  """Test security monitoring capabilities."""
814
819
  example = FastAPISecurityExample()
815
820
  results = example.demonstrate_security_monitoring()
816
-
821
+
817
822
  # Verify security status works
818
823
  assert "status" in results["security_status"]
819
824
  assert "message" in results["security_status"]
820
-
825
+
821
826
  # Verify security metrics work
822
827
  assert "authentication_attempts" in results["security_metrics"]
823
-
828
+
824
829
  # Verify security audit works
825
830
  assert "authentication" in results["security_audit"]
826
-
831
+
827
832
  print("✅ Security monitoring tests passed")
828
833
 
829
834
 
@@ -831,46 +836,70 @@ def main():
831
836
  """Main function to run the FastAPI example."""
832
837
  print("\n🚀 MCP Security Framework - FastAPI Example")
833
838
  print("=" * 60)
834
-
839
+
835
840
  # Create example instance
836
841
  example = FastAPISecurityExample()
837
-
842
+
838
843
  # Run comprehensive demonstration
839
844
  results = example.run_comprehensive_demo()
840
-
845
+
841
846
  # Print results
842
847
  print("\n📊 COMPREHENSIVE DEMONSTRATION RESULTS")
843
848
  print("=" * 60)
844
849
  print(f"Framework: {results['framework']}")
845
850
  print(f"Version: {results['version']}")
846
851
  print(f"Timestamp: {results['timestamp']}")
847
-
852
+
848
853
  print("\n🔐 AUTHENTICATION RESULTS:")
849
- print(f" API Key: {'✅' if results['authentication']['api_key_auth']['success'] else '❌'}")
850
- print(f" JWT: {'✅' if results['authentication']['jwt_auth']['success'] else '❌'}")
851
- print(f" Certificate: {'✅' if results['authentication']['certificate_auth']['success'] else '❌'}")
852
-
854
+ print(
855
+ f" API Key: {'✅' if results['authentication']['api_key_auth']['success'] else '❌'}"
856
+ )
857
+ print(
858
+ f" JWT: {'✅' if results['authentication']['jwt_auth']['success'] else '❌'}"
859
+ )
860
+ print(
861
+ f" Certificate: {'✅' if results['authentication']['certificate_auth']['success'] else '❌'}"
862
+ )
863
+
853
864
  print("\n🔑 AUTHORIZATION RESULTS:")
854
- print(f" Admin Permissions: {'✅' if results['authorization']['admin_permissions']['success'] else '❌'}")
855
- print(f" User Permissions: {'✅' if results['authorization']['user_permissions']['success'] else '❌'}")
856
- print(f" Readonly Permissions: {'✅' if results['authorization']['readonly_permissions']['success'] else '❌'}")
857
-
865
+ print(
866
+ f" Admin Permissions: {'✅' if results['authorization']['admin_permissions']['success'] else '❌'}"
867
+ )
868
+ print(
869
+ f" User Permissions: {'✅' if results['authorization']['user_permissions']['success'] else '❌'}"
870
+ )
871
+ print(
872
+ f" Readonly Permissions: {'✅' if results['authorization']['readonly_permissions']['success'] else '❌'}"
873
+ )
874
+
858
875
  print("\n⚡ RATE LIMITING RESULTS:")
859
876
  print(f" Rate Limit Checks: {len(results['rate_limiting']['rate_limit_checks'])}")
860
- print(f" Rate Limit Exceeded: {'❌' if results['rate_limiting']['rate_limit_exceeded'] else '✅'}")
861
-
877
+ print(
878
+ f" Rate Limit Exceeded: {'❌' if results['rate_limiting']['rate_limit_exceeded'] else '✅'}"
879
+ )
880
+
862
881
  print("\n🔒 SECURITY VALIDATION RESULTS:")
863
- print(f" Request Validation: {'✅' if results['security_validation']['request_validation']['success'] else '❌'}")
864
- print(f" Configuration Validation: {'✅' if results['security_validation']['configuration_validation']['success'] else '❌'}")
865
-
882
+ print(
883
+ f" Request Validation: {'✅' if results['security_validation']['request_validation']['success'] else '❌'}"
884
+ )
885
+ print(
886
+ f" Configuration Validation: {'✅' if results['security_validation']['configuration_validation']['success'] else '❌'}"
887
+ )
888
+
866
889
  print("\n📊 SECURITY MONITORING RESULTS:")
867
- print(f" Security Status: {'✅' if 'status' in results['security_monitoring']['security_status'] else '❌'}")
868
- print(f" Security Metrics: {'✅' if 'authentication_attempts' in results['security_monitoring']['security_metrics'] else '❌'}")
869
- print(f" Security Audit: {'✅' if 'authentication' in results['security_monitoring']['security_audit'] else '❌'}")
870
-
890
+ print(
891
+ f" Security Status: {'✅' if 'status' in results['security_monitoring']['security_status'] else '❌'}"
892
+ )
893
+ print(
894
+ f" Security Metrics: {'✅' if 'authentication_attempts' in results['security_monitoring']['security_metrics'] else '❌'}"
895
+ )
896
+ print(
897
+ f" Security Audit: {'✅' if 'authentication' in results['security_monitoring']['security_audit'] else '❌'}"
898
+ )
899
+
871
900
  print("\n🎉 ALL FRAMEWORK CAPABILITIES DEMONSTRATED SUCCESSFULLY!")
872
901
  print("=" * 60)
873
-
902
+
874
903
  print("\n🌐 FastAPI Application Ready!")
875
904
  print("Run with: uvicorn fastapi_example:example.app --reload")
876
905
  print("Available endpoints:")
@@ -895,50 +924,53 @@ if __name__ == "__main__":
895
924
  test.test_rate_limiting()
896
925
  test.test_security_validation()
897
926
  test.test_security_monitoring()
898
-
927
+
899
928
  print("\nExample Usage:")
900
929
  main()
901
-
930
+
902
931
  # Start server in background thread for testing
903
932
  print("\nStarting FastAPI Server in background...")
904
933
  example = FastAPISecurityExample()
905
-
934
+
935
+ import asyncio
906
936
  import threading
907
937
  import time
938
+
908
939
  import requests
909
940
  import uvicorn
910
- import asyncio
911
-
941
+
912
942
  # Start server in background thread
913
943
  def run_server():
914
944
  uvicorn.run(example.app, host="0.0.0.0", port=8000, log_level="error")
915
-
945
+
916
946
  server_thread = threading.Thread(target=run_server, daemon=True)
917
947
  server_thread.start()
918
-
948
+
919
949
  # Wait for server to start
920
950
  time.sleep(5)
921
-
951
+
922
952
  try:
923
953
  # Test server endpoints
924
954
  print("Testing FastAPI server endpoints...")
925
-
955
+
926
956
  # Test health endpoint
927
957
  response = requests.get("http://localhost:8000/health", timeout=5)
928
958
  print(f"Health endpoint: {response.status_code}")
929
-
959
+
930
960
  # Test metrics endpoint
931
961
  response = requests.get("http://localhost:8000/metrics", timeout=5)
932
962
  print(f"Metrics endpoint: {response.status_code}")
933
-
963
+
934
964
  # Test protected endpoint with API key
935
965
  headers = {"X-API-Key": "admin_key_123"}
936
- response = requests.get("http://localhost:8000/api/v1/users/me", headers=headers, timeout=5)
966
+ response = requests.get(
967
+ "http://localhost:8000/api/v1/users/me", headers=headers, timeout=5
968
+ )
937
969
  print(f"Protected endpoint: {response.status_code}")
938
-
970
+
939
971
  print("✅ FastAPI server testing completed successfully")
940
-
972
+
941
973
  except requests.exceptions.RequestException as e:
942
974
  print(f"⚠️ FastAPI server testing failed: {e}")
943
-
975
+
944
976
  print("FastAPI example completed")