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,75 @@
1
+ """
2
+ Examples Module
3
+
4
+ This module contains comprehensive examples of how to implement
5
+ the MCP Security Framework with real server configurations.
6
+
7
+ The examples demonstrate:
8
+ - Complete implementation of abstract methods
9
+ - Real-world server configurations
10
+ - Production-ready security setups
11
+ - Integration with popular web frameworks
12
+
13
+ Author: MCP Security Team
14
+ Version: 1.0.0
15
+ License: MIT
16
+ """
17
+
18
+ # Import examples conditionally to avoid import errors when dependencies are missing
19
+ try:
20
+ from .fastapi_example import FastAPIExample
21
+ _FASTAPI_AVAILABLE = True
22
+ except ImportError:
23
+ _FASTAPI_AVAILABLE = False
24
+ FastAPIExample = None
25
+
26
+ try:
27
+ from .flask_example import FlaskExample
28
+ _FLASK_AVAILABLE = True
29
+ except ImportError:
30
+ _FLASK_AVAILABLE = False
31
+ FlaskExample = None
32
+
33
+ try:
34
+ from .django_example import DjangoExample
35
+ _DJANGO_AVAILABLE = True
36
+ except ImportError:
37
+ _DJANGO_AVAILABLE = False
38
+ DjangoExample = None
39
+
40
+ try:
41
+ from .standalone_example import StandaloneExample
42
+ _STANDALONE_AVAILABLE = True
43
+ except ImportError:
44
+ _STANDALONE_AVAILABLE = False
45
+ StandaloneExample = None
46
+
47
+ try:
48
+ from .microservice_example import MicroserviceExample
49
+ _MICROSERVICE_AVAILABLE = True
50
+ except ImportError:
51
+ _MICROSERVICE_AVAILABLE = False
52
+ MicroserviceExample = None
53
+
54
+ try:
55
+ from .gateway_example import APIGatewayExample
56
+ _GATEWAY_AVAILABLE = True
57
+ except ImportError:
58
+ _GATEWAY_AVAILABLE = False
59
+ APIGatewayExample = None
60
+
61
+ # Build __all__ list with only available examples
62
+ __all__ = []
63
+
64
+ if _FASTAPI_AVAILABLE:
65
+ __all__.append("FastAPIExample")
66
+ if _FLASK_AVAILABLE:
67
+ __all__.append("FlaskExample")
68
+ if _DJANGO_AVAILABLE:
69
+ __all__.append("DjangoExample")
70
+ if _STANDALONE_AVAILABLE:
71
+ __all__.append("StandaloneExample")
72
+ if _MICROSERVICE_AVAILABLE:
73
+ __all__.append("MicroserviceExample")
74
+ if _GATEWAY_AVAILABLE:
75
+ __all__.append("APIGatewayExample")
@@ -0,0 +1,615 @@
1
+ """
2
+ Django Example Implementation
3
+
4
+ This module provides a complete example of how to implement the MCP Security Framework
5
+ with Django, including all abstract method implementations for real server usage.
6
+
7
+ The example demonstrates:
8
+ - Complete Django application with security middleware
9
+ - Real-world authentication and authorization
10
+ - Rate limiting implementation
11
+ - Certificate-based authentication
12
+ - Production-ready security headers
13
+ - Comprehensive error handling
14
+
15
+ Author: MCP Security Team
16
+ Version: 1.0.0
17
+ License: MIT
18
+ """
19
+
20
+ import os
21
+ import json
22
+ import logging
23
+ from typing import Dict, List, Any, Optional
24
+ from datetime import datetime, timedelta
25
+
26
+ from django.http import HttpRequest, HttpResponse, JsonResponse
27
+ from django.views.decorators.csrf import csrf_exempt
28
+ from django.views.decorators.http import require_http_methods
29
+ from django.middleware.base import BaseMiddleware
30
+ from django.conf import settings
31
+ from django.urls import path, include
32
+ from django.contrib.auth.models import User
33
+ from django.contrib.auth.decorators import login_required, permission_required
34
+ from django.core.exceptions import PermissionDenied
35
+ from django.utils.decorators import method_decorator
36
+ from django.views import View
37
+
38
+ from mcp_security_framework.core.security_manager import SecurityManager
39
+ from mcp_security_framework.core.auth_manager import AuthManager
40
+ from mcp_security_framework.core.ssl_manager import SSLManager
41
+ from mcp_security_framework.core.permission_manager import PermissionManager
42
+ from mcp_security_framework.core.rate_limiter import RateLimiter
43
+ from mcp_security_framework.schemas.config import SecurityConfig, AuthConfig, SSLConfig
44
+ from mcp_security_framework.schemas.models import AuthResult, AuthStatus, AuthMethod
45
+ from mcp_security_framework.constants import (
46
+ DEFAULT_CLIENT_IP, DEFAULT_SECURITY_HEADERS, AUTH_METHODS,
47
+ ErrorCodes, HTTP_UNAUTHORIZED, HTTP_FORBIDDEN, HTTP_TOO_MANY_REQUESTS
48
+ )
49
+
50
+
51
+ class DjangoSecurityMiddleware(BaseMiddleware):
52
+ """
53
+ Django Security Middleware Implementation
54
+
55
+ This middleware provides comprehensive security features for Django applications
56
+ including authentication, authorization, rate limiting, and security headers.
57
+ """
58
+
59
+ def __init__(self, get_response):
60
+ """Initialize middleware with security configuration."""
61
+ super().__init__(get_response)
62
+ self.config = self._load_config()
63
+ self.security_manager = SecurityManager(self.config)
64
+ self.logger = logging.getLogger(__name__)
65
+
66
+ def _load_config(self) -> SecurityConfig:
67
+ """Load security configuration."""
68
+ config_path = getattr(settings, 'SECURITY_CONFIG_PATH', None)
69
+
70
+ if config_path and os.path.exists(config_path):
71
+ with open(config_path, 'r') as f:
72
+ config_data = json.load(f)
73
+ return SecurityConfig(**config_data)
74
+
75
+ # Create production-ready default configuration
76
+ return SecurityConfig(
77
+ auth=AuthConfig(
78
+ enabled=True,
79
+ methods=[AUTH_METHODS["API_KEY"], AUTH_METHODS["JWT"], AUTH_METHODS["CERTIFICATE"]],
80
+ api_keys={
81
+ "admin_key_123": {"username": "admin", "roles": ["admin", "user"]},
82
+ "user_key_456": {"username": "user", "roles": ["user"]},
83
+ "readonly_key_789": {"username": "readonly", "roles": ["readonly"]}
84
+ },
85
+ jwt_secret="your-super-secret-jwt-key-change-in-production",
86
+ jwt_algorithm="HS256",
87
+ jwt_expiry_hours=24,
88
+ public_paths=["/health/", "/metrics/", "/admin/"],
89
+ security_headers=DEFAULT_SECURITY_HEADERS
90
+ ),
91
+ ssl=SSLConfig(
92
+ enabled=True,
93
+ cert_file="certs/server.crt",
94
+ key_file="certs/server.key",
95
+ ca_cert_file="certs/ca.crt",
96
+ verify_mode="CERT_REQUIRED",
97
+ min_version="TLSv1.2"
98
+ ),
99
+ rate_limit={
100
+ "enabled": True,
101
+ "default_requests_per_minute": 60,
102
+ "default_requests_per_hour": 1000,
103
+ "burst_limit": 2,
104
+ "window_size_seconds": 60,
105
+ "storage_backend": "redis",
106
+ "redis_config": {
107
+ "host": "localhost",
108
+ "port": 6379,
109
+ "db": 0,
110
+ "password": None
111
+ },
112
+ "exempt_paths": ["/health/", "/metrics/", "/admin/"],
113
+ "exempt_roles": ["admin"]
114
+ },
115
+ permissions={
116
+ "enabled": True,
117
+ "roles_file": "config/roles.json",
118
+ "default_role": "user",
119
+ "hierarchy_enabled": True
120
+ },
121
+ logging={
122
+ "enabled": True,
123
+ "level": "INFO",
124
+ "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
125
+ "file_path": "logs/security.log",
126
+ "max_file_size": 10,
127
+ "backup_count": 5,
128
+ "console_output": True,
129
+ "json_format": False
130
+ }
131
+ )
132
+
133
+ def __call__(self, request):
134
+ """Process request through security middleware."""
135
+ # Check if path is public
136
+ if self._is_public_path(request.path):
137
+ return self.get_response(request)
138
+
139
+ # Rate limiting check
140
+ if not self._check_rate_limit(request):
141
+ return self._rate_limit_response()
142
+
143
+ # Authentication check
144
+ auth_result = self._authenticate_request(request)
145
+ if not auth_result.is_valid:
146
+ return self._auth_error_response(auth_result)
147
+
148
+ # Authorization check
149
+ if not self._check_permissions(request, auth_result):
150
+ return self._permission_error_response()
151
+
152
+ # Add user info to request
153
+ request.user_info = {
154
+ "username": auth_result.username,
155
+ "roles": auth_result.roles,
156
+ "permissions": auth_result.permissions,
157
+ "auth_method": auth_result.auth_method
158
+ }
159
+
160
+ # Process request
161
+ response = self.get_response(request)
162
+
163
+ # Add security headers
164
+ self._add_security_headers(response)
165
+
166
+ return response
167
+
168
+ def _is_public_path(self, path: str) -> bool:
169
+ """Check if path is public (bypasses authentication)."""
170
+ return any(path.startswith(public_path) for public_path in self.config.auth.public_paths)
171
+
172
+ def _check_rate_limit(self, request: HttpRequest) -> bool:
173
+ """Check if request is within rate limits."""
174
+ if not self.config.rate_limit.enabled:
175
+ return True
176
+
177
+ identifier = self._get_rate_limit_identifier(request)
178
+ return self.security_manager.rate_limiter.check_rate_limit(identifier)
179
+
180
+ def _get_rate_limit_identifier(self, request: HttpRequest) -> str:
181
+ """Get rate limit identifier from request."""
182
+ # Try to get IP from headers
183
+ forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
184
+ if forwarded_for:
185
+ return forwarded_for.split(',')[0].strip()
186
+
187
+ real_ip = request.META.get('HTTP_X_REAL_IP')
188
+ if real_ip:
189
+ return real_ip
190
+
191
+ # Fall back to remote address
192
+ return request.META.get('REMOTE_ADDR', DEFAULT_CLIENT_IP)
193
+
194
+ def _authenticate_request(self, request: HttpRequest) -> AuthResult:
195
+ """Authenticate the request using configured methods."""
196
+ if not self.config.auth.enabled:
197
+ return AuthResult(
198
+ is_valid=True,
199
+ status=AuthStatus.SUCCESS,
200
+ username="anonymous",
201
+ roles=[],
202
+ auth_method=None
203
+ )
204
+
205
+ # Try each authentication method in order
206
+ for method in self.config.auth.methods:
207
+ auth_result = self._try_auth_method(request, method)
208
+ if auth_result.is_valid:
209
+ return auth_result
210
+
211
+ # All authentication methods failed
212
+ return AuthResult(
213
+ is_valid=False,
214
+ status=AuthStatus.FAILED,
215
+ username=None,
216
+ roles=[],
217
+ auth_method=None,
218
+ error_code=ErrorCodes.AUTHENTICATION_ERROR,
219
+ error_message="All authentication methods failed"
220
+ )
221
+
222
+ def _try_auth_method(self, request: HttpRequest, method: str) -> AuthResult:
223
+ """Try authentication using specific method."""
224
+ try:
225
+ if method == AUTH_METHODS["API_KEY"]:
226
+ return self._try_api_key_auth(request)
227
+ elif method == AUTH_METHODS["JWT"]:
228
+ return self._try_jwt_auth(request)
229
+ elif method == AUTH_METHODS["CERTIFICATE"]:
230
+ return self._try_certificate_auth(request)
231
+ else:
232
+ return AuthResult(
233
+ is_valid=False,
234
+ status=AuthStatus.FAILED,
235
+ username=None,
236
+ roles=[],
237
+ auth_method=None,
238
+ error_code=ErrorCodes.AUTH_METHOD_NOT_SUPPORTED,
239
+ error_message=f"Unsupported authentication method: {method}"
240
+ )
241
+ except Exception as e:
242
+ self.logger.error(f"Authentication method {method} failed: {str(e)}")
243
+ return AuthResult(
244
+ is_valid=False,
245
+ status=AuthStatus.FAILED,
246
+ username=None,
247
+ roles=[],
248
+ auth_method=None,
249
+ error_code=ErrorCodes.AUTHENTICATION_ERROR,
250
+ error_message=str(e)
251
+ )
252
+
253
+ def _try_api_key_auth(self, request: HttpRequest) -> AuthResult:
254
+ """Try API key authentication."""
255
+ # Try to get API key from headers
256
+ api_key = request.META.get('HTTP_X_API_KEY')
257
+ if not api_key:
258
+ # Try Authorization header
259
+ auth_header = request.META.get('HTTP_AUTHORIZATION', '')
260
+ if auth_header.startswith('Bearer '):
261
+ api_key = auth_header[7:] # Remove "Bearer " prefix
262
+
263
+ if not api_key:
264
+ return AuthResult(
265
+ is_valid=False,
266
+ status=AuthStatus.FAILED,
267
+ username=None,
268
+ roles=[],
269
+ auth_method=AuthMethod.API_KEY,
270
+ error_code=ErrorCodes.API_KEY_NOT_FOUND,
271
+ error_message="API key not found in request"
272
+ )
273
+
274
+ return self.security_manager.auth_manager.authenticate_api_key(api_key)
275
+
276
+ def _try_jwt_auth(self, request: HttpRequest) -> AuthResult:
277
+ """Try JWT authentication."""
278
+ # Try to get JWT token from Authorization header
279
+ auth_header = request.META.get('HTTP_AUTHORIZATION', '')
280
+ if not auth_header.startswith('Bearer '):
281
+ return AuthResult(
282
+ is_valid=False,
283
+ status=AuthStatus.FAILED,
284
+ username=None,
285
+ roles=[],
286
+ auth_method=AuthMethod.JWT,
287
+ error_code=ErrorCodes.JWT_VALIDATION_ERROR,
288
+ error_message="JWT token not found in Authorization header"
289
+ )
290
+
291
+ token = auth_header[7:] # Remove "Bearer " prefix
292
+ return self.security_manager.auth_manager.authenticate_jwt_token(token)
293
+
294
+ def _try_certificate_auth(self, request: HttpRequest) -> AuthResult:
295
+ """Try certificate authentication."""
296
+ # In Django, certificate authentication would typically be handled
297
+ # at the web server level (nginx, Apache) and passed via headers
298
+ client_cert = request.META.get('SSL_CLIENT_CERT')
299
+ if not client_cert:
300
+ return AuthResult(
301
+ is_valid=False,
302
+ status=AuthStatus.FAILED,
303
+ username=None,
304
+ roles=[],
305
+ auth_method=AuthMethod.CERTIFICATE,
306
+ error_code=ErrorCodes.CERTIFICATE_AUTH_ERROR,
307
+ error_message="Client certificate not found"
308
+ )
309
+
310
+ return self.security_manager.auth_manager.authenticate_certificate(client_cert)
311
+
312
+ def _check_permissions(self, request: HttpRequest, auth_result: AuthResult) -> bool:
313
+ """Check if user has required permissions for the request."""
314
+ if not self.config.permissions.enabled:
315
+ return True
316
+
317
+ # Get required permissions based on request
318
+ required_permissions = self._get_required_permissions(request)
319
+ if not required_permissions:
320
+ return True # No specific permissions required
321
+
322
+ return self.security_manager.permission_manager.validate_access(
323
+ auth_result.roles, required_permissions
324
+ )
325
+
326
+ def _get_required_permissions(self, request: HttpRequest) -> List[str]:
327
+ """Get required permissions for the request."""
328
+ # This would be implemented based on your permission system
329
+ # For now, return basic permissions based on HTTP method
330
+ method_permissions = {
331
+ 'GET': ['read'],
332
+ 'POST': ['write'],
333
+ 'PUT': ['write'],
334
+ 'PATCH': ['write'],
335
+ 'DELETE': ['delete']
336
+ }
337
+
338
+ return method_permissions.get(request.method, [])
339
+
340
+ def _add_security_headers(self, response: HttpResponse):
341
+ """Add security headers to response."""
342
+ for header_name, header_value in self.config.auth.security_headers.items():
343
+ response[header_name] = header_value
344
+
345
+ def _rate_limit_response(self) -> HttpResponse:
346
+ """Create rate limit exceeded response."""
347
+ return JsonResponse({
348
+ "error": "Rate limit exceeded",
349
+ "message": "Too many requests, please try again later",
350
+ "error_code": ErrorCodes.RATE_LIMIT_EXCEEDED_ERROR
351
+ }, status=HTTP_TOO_MANY_REQUESTS)
352
+
353
+ def _auth_error_response(self, auth_result: AuthResult) -> HttpResponse:
354
+ """Create authentication error response."""
355
+ return JsonResponse({
356
+ "error": "Authentication failed",
357
+ "message": auth_result.error_message or "Invalid credentials",
358
+ "error_code": auth_result.error_code,
359
+ "auth_method": auth_result.auth_method
360
+ }, status=HTTP_UNAUTHORIZED)
361
+
362
+ def _permission_error_response(self) -> HttpResponse:
363
+ """Create permission denied response."""
364
+ return JsonResponse({
365
+ "error": "Permission denied",
366
+ "message": "Insufficient permissions to access this resource",
367
+ "error_code": ErrorCodes.PERMISSION_DENIED_ERROR
368
+ }, status=HTTP_FORBIDDEN)
369
+
370
+
371
+ # Django Views
372
+ class HealthCheckView(View):
373
+ """Health check endpoint."""
374
+
375
+ def get(self, request):
376
+ """Handle GET request."""
377
+ return JsonResponse({
378
+ "status": "healthy",
379
+ "timestamp": datetime.utcnow().isoformat(),
380
+ "version": "1.0.0"
381
+ })
382
+
383
+
384
+ class MetricsView(View):
385
+ """Metrics endpoint."""
386
+
387
+ def get(self, request):
388
+ """Handle GET request."""
389
+ return JsonResponse({
390
+ "requests_total": 1000,
391
+ "requests_per_minute": 60,
392
+ "active_connections": 25,
393
+ "uptime_seconds": 3600
394
+ })
395
+
396
+
397
+ class UserProfileView(View):
398
+ """User profile endpoint."""
399
+
400
+ def get(self, request):
401
+ """Handle GET request."""
402
+ user_info = getattr(request, 'user_info', None)
403
+ if not user_info:
404
+ return JsonResponse({"error": "User not authenticated"}, status=401)
405
+
406
+ return JsonResponse({
407
+ "username": user_info.get("username"),
408
+ "roles": user_info.get("roles", []),
409
+ "permissions": user_info.get("permissions", []),
410
+ "last_login": datetime.utcnow().isoformat()
411
+ })
412
+
413
+
414
+ class AdminUsersView(View):
415
+ """Admin users endpoint."""
416
+
417
+ def get(self, request):
418
+ """Handle GET request."""
419
+ user_info = getattr(request, 'user_info', None)
420
+ if not user_info or "admin" not in user_info.get("roles", []):
421
+ return JsonResponse({"error": "Admin access required"}, status=403)
422
+
423
+ return JsonResponse({
424
+ "users": [
425
+ {"username": "admin", "roles": ["admin"], "status": "active"},
426
+ {"username": "user", "roles": ["user"], "status": "active"},
427
+ {"username": "readonly", "roles": ["readonly"], "status": "active"}
428
+ ]
429
+ })
430
+
431
+
432
+ class DataView(View):
433
+ """Data endpoint."""
434
+
435
+ def get(self, request, data_id):
436
+ """Handle GET request."""
437
+ user_info = getattr(request, 'user_info', None)
438
+ if not user_info:
439
+ return JsonResponse({"error": "Authentication required"}, status=401)
440
+
441
+ return JsonResponse({
442
+ "id": data_id,
443
+ "data": {"example": "data"},
444
+ "created_by": "user",
445
+ "created_at": "2024-01-01T00:00:00Z"
446
+ })
447
+
448
+ def post(self, request):
449
+ """Handle POST request."""
450
+ user_info = getattr(request, 'user_info', None)
451
+ if not user_info:
452
+ return JsonResponse({"error": "Authentication required"}, status=401)
453
+
454
+ if "readonly" in user_info.get("roles", []):
455
+ return JsonResponse({"error": "Write permission required"}, status=403)
456
+
457
+ # Process request data
458
+ data = json.loads(request.body) if request.body else {}
459
+
460
+ return JsonResponse({
461
+ "id": "data_123",
462
+ "created_by": user_info.get("username"),
463
+ "data": data,
464
+ "created_at": datetime.utcnow().isoformat()
465
+ })
466
+
467
+
468
+ # URL patterns
469
+ urlpatterns = [
470
+ path('health/', HealthCheckView.as_view(), name='health'),
471
+ path('metrics/', MetricsView.as_view(), name='metrics'),
472
+ path('api/v1/users/me/', UserProfileView.as_view(), name='user_profile'),
473
+ path('api/v1/admin/users/', AdminUsersView.as_view(), name='admin_users'),
474
+ path('api/v1/data/', DataView.as_view(), name='data'),
475
+ path('api/v1/data/<str:data_id>/', DataView.as_view(), name='data_detail'),
476
+ ]
477
+
478
+
479
+ # Django Example Application
480
+ class DjangoExample:
481
+ """
482
+ Complete Django Example with Security Framework Implementation
483
+
484
+ This class demonstrates a production-ready Django application
485
+ with comprehensive security features.
486
+ """
487
+
488
+ def __init__(self, config_path: Optional[str] = None):
489
+ """
490
+ Initialize Django example with security configuration.
491
+
492
+ Args:
493
+ config_path: Path to security configuration file
494
+ """
495
+ self.config_path = config_path
496
+ self.logger = logging.getLogger(__name__)
497
+
498
+ def setup_django_settings(self):
499
+ """Setup Django settings with security configuration."""
500
+ # This would be called in your Django settings.py
501
+ settings.SECURITY_CONFIG_PATH = self.config_path
502
+
503
+ # Add security middleware
504
+ if 'mcp_security_framework.examples.django_example.DjangoSecurityMiddleware' not in settings.MIDDLEWARE:
505
+ settings.MIDDLEWARE.insert(0, 'mcp_security_framework.examples.django_example.DjangoSecurityMiddleware')
506
+
507
+ # Security settings
508
+ settings.SECURE_SSL_REDIRECT = True
509
+ settings.SECURE_HSTS_SECONDS = 31536000
510
+ settings.SECURE_HSTS_INCLUDE_SUBDOMAINS = True
511
+ settings.SECURE_HSTS_PRELOAD = True
512
+ settings.SECURE_CONTENT_TYPE_NOSNIFF = True
513
+ settings.SECURE_BROWSER_XSS_FILTER = True
514
+ settings.X_FRAME_OPTIONS = 'DENY'
515
+ settings.SESSION_COOKIE_SECURE = True
516
+ settings.CSRF_COOKIE_SECURE = True
517
+
518
+ def create_superuser(self, username: str, email: str, password: str):
519
+ """Create Django superuser."""
520
+ try:
521
+ if not User.objects.filter(username=username).exists():
522
+ User.objects.create_superuser(username, email, password)
523
+ self.logger.info(f"Created superuser: {username}")
524
+ else:
525
+ self.logger.info(f"Superuser {username} already exists")
526
+ except Exception as e:
527
+ self.logger.error(f"Failed to create superuser: {str(e)}")
528
+
529
+ def get_security_status(self) -> Dict[str, Any]:
530
+ """Get security framework status."""
531
+ return {
532
+ "framework": "Django",
533
+ "middleware_enabled": True,
534
+ "ssl_enabled": True,
535
+ "auth_enabled": True,
536
+ "rate_limiting_enabled": True,
537
+ "permissions_enabled": True,
538
+ "timestamp": datetime.utcnow().isoformat()
539
+ }
540
+
541
+
542
+ # Example usage and testing
543
+ class DjangoExampleTest:
544
+ """Test class for Django example functionality."""
545
+
546
+ @staticmethod
547
+ def test_middleware_creation():
548
+ """Test middleware creation."""
549
+ middleware = DjangoSecurityMiddleware(lambda request: None)
550
+ assert middleware.config is not None
551
+ assert middleware.security_manager is not None
552
+
553
+ print("✅ Middleware creation test passed")
554
+
555
+ @staticmethod
556
+ def test_public_path_check():
557
+ """Test public path checking."""
558
+ middleware = DjangoSecurityMiddleware(lambda request: None)
559
+
560
+ # Test public paths
561
+ assert middleware._is_public_path("/health/")
562
+ assert middleware._is_public_path("/metrics/")
563
+ assert middleware._is_public_path("/admin/")
564
+
565
+ # Test private paths
566
+ assert not middleware._is_public_path("/api/v1/users/")
567
+ assert not middleware._is_public_path("/private/")
568
+
569
+ print("✅ Public path check test passed")
570
+
571
+ @staticmethod
572
+ def test_rate_limit_identifier():
573
+ """Test rate limit identifier extraction."""
574
+ middleware = DjangoSecurityMiddleware(lambda request: None)
575
+
576
+ # Mock request
577
+ class MockRequest:
578
+ def __init__(self):
579
+ self.META = {}
580
+
581
+ request = MockRequest()
582
+
583
+ # Test X-Forwarded-For
584
+ request.META['HTTP_X_FORWARDED_FOR'] = '192.168.1.1, 10.0.0.1'
585
+ assert middleware._get_rate_limit_identifier(request) == '192.168.1.1'
586
+
587
+ # Test X-Real-IP
588
+ request.META = {'HTTP_X_REAL_IP': '192.168.1.100'}
589
+ assert middleware._get_rate_limit_identifier(request) == '192.168.1.100'
590
+
591
+ # Test REMOTE_ADDR
592
+ request.META = {'REMOTE_ADDR': '127.0.0.1'}
593
+ assert middleware._get_rate_limit_identifier(request) == '127.0.0.1'
594
+
595
+ print("✅ Rate limit identifier test passed")
596
+
597
+
598
+ if __name__ == "__main__":
599
+ # Run tests
600
+ print("Running Django Example Tests...")
601
+ DjangoExampleTest.test_middleware_creation()
602
+ DjangoExampleTest.test_public_path_check()
603
+ DjangoExampleTest.test_rate_limit_identifier()
604
+
605
+ # Example usage
606
+ print("\nExample Usage:")
607
+ example = DjangoExample()
608
+ example.setup_django_settings()
609
+
610
+ # Create superuser
611
+ example.create_superuser("admin", "admin@example.com", "secure_password")
612
+
613
+ # Get security status
614
+ status = example.get_security_status()
615
+ print(f"Security status: {status}")