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.
- mcp_security_framework/__init__.py +26 -15
- mcp_security_framework/cli/__init__.py +1 -1
- mcp_security_framework/cli/cert_cli.py +233 -197
- mcp_security_framework/cli/security_cli.py +324 -234
- mcp_security_framework/constants.py +21 -27
- mcp_security_framework/core/auth_manager.py +41 -22
- mcp_security_framework/core/cert_manager.py +210 -147
- mcp_security_framework/core/permission_manager.py +9 -9
- mcp_security_framework/core/rate_limiter.py +2 -2
- mcp_security_framework/core/security_manager.py +284 -229
- mcp_security_framework/examples/__init__.py +6 -0
- mcp_security_framework/examples/comprehensive_example.py +349 -279
- mcp_security_framework/examples/django_example.py +247 -206
- mcp_security_framework/examples/fastapi_example.py +315 -283
- mcp_security_framework/examples/flask_example.py +274 -203
- mcp_security_framework/examples/gateway_example.py +304 -237
- mcp_security_framework/examples/microservice_example.py +258 -189
- mcp_security_framework/examples/standalone_example.py +255 -230
- mcp_security_framework/examples/test_all_examples.py +151 -135
- mcp_security_framework/middleware/__init__.py +46 -55
- mcp_security_framework/middleware/auth_middleware.py +62 -63
- mcp_security_framework/middleware/fastapi_auth_middleware.py +119 -118
- mcp_security_framework/middleware/fastapi_middleware.py +156 -148
- mcp_security_framework/middleware/flask_auth_middleware.py +160 -147
- mcp_security_framework/middleware/flask_middleware.py +183 -157
- mcp_security_framework/middleware/mtls_middleware.py +106 -117
- mcp_security_framework/middleware/rate_limit_middleware.py +105 -101
- mcp_security_framework/middleware/security_middleware.py +109 -124
- mcp_security_framework/schemas/config.py +2 -1
- mcp_security_framework/schemas/models.py +18 -6
- mcp_security_framework/utils/cert_utils.py +14 -8
- mcp_security_framework/utils/datetime_compat.py +116 -0
- {mcp_security_framework-1.1.0.dist-info → mcp_security_framework-1.1.1.dist-info}/METADATA +2 -1
- mcp_security_framework-1.1.1.dist-info/RECORD +84 -0
- tests/conftest.py +63 -66
- tests/test_cli/test_cert_cli.py +184 -146
- tests/test_cli/test_security_cli.py +274 -247
- tests/test_core/test_cert_manager.py +24 -10
- tests/test_core/test_security_manager.py +2 -2
- tests/test_examples/test_comprehensive_example.py +190 -137
- tests/test_examples/test_fastapi_example.py +124 -101
- tests/test_examples/test_flask_example.py +124 -101
- tests/test_examples/test_standalone_example.py +73 -80
- tests/test_integration/test_auth_flow.py +213 -197
- tests/test_integration/test_certificate_flow.py +180 -149
- tests/test_integration/test_fastapi_integration.py +108 -111
- tests/test_integration/test_flask_integration.py +141 -140
- tests/test_integration/test_standalone_integration.py +290 -259
- tests/test_middleware/test_fastapi_auth_middleware.py +195 -174
- tests/test_middleware/test_fastapi_middleware.py +147 -132
- tests/test_middleware/test_flask_auth_middleware.py +260 -202
- tests/test_middleware/test_flask_middleware.py +201 -179
- tests/test_middleware/test_security_middleware.py +145 -130
- tests/test_utils/test_datetime_compat.py +147 -0
- mcp_security_framework-1.1.0.dist-info/RECORD +0 -82
- {mcp_security_framework-1.1.0.dist-info → mcp_security_framework-1.1.1.dist-info}/WHEEL +0 -0
- {mcp_security_framework-1.1.0.dist-info → mcp_security_framework-1.1.1.dist-info}/entry_points.txt +0 -0
- {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
|
28
|
+
import os
|
30
29
|
import shutil
|
31
|
-
|
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,
|
34
|
+
from fastapi import Depends, FastAPI, HTTPException, Request, Response, status
|
35
35
|
from fastapi.middleware.cors import CORSMiddleware
|
36
|
-
from fastapi.security import
|
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
|
-
|
42
|
-
CertificateConfig,
|
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
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
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,
|
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=[
|
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 =
|
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
|
-
|
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
|
-
|
214
|
-
|
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(
|
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
|
-
|
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(
|
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
|
-
|
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
|
-
|
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
|
-
|
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,
|
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,
|
386
|
-
return {
|
387
|
-
|
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,
|
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,
|
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,
|
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,
|
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
|
-
|
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(
|
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
|
-
|
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
|
-
|
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(
|
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
|
-
|
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
|
-
|
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
|
-
|
612
|
-
|
613
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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(
|
850
|
-
|
851
|
-
|
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(
|
855
|
-
|
856
|
-
|
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(
|
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(
|
864
|
-
|
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(
|
868
|
-
|
869
|
-
|
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
|
-
|
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(
|
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")
|