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,686 @@
1
+ """
2
+ Response Models Module
3
+
4
+ This module provides comprehensive response models for all API responses,
5
+ error handling, and validation responses used throughout the MCP Security
6
+ Framework. It includes standardized response formats with proper HTTP
7
+ status codes and error handling.
8
+
9
+ Key Features:
10
+ - Standardized API response formats
11
+ - Comprehensive error handling models
12
+ - HTTP status code integration
13
+ - Validation response models
14
+ - Success response models
15
+ - Consistent error message formatting
16
+
17
+ Classes:
18
+ SecurityResponse: Base response model
19
+ ErrorResponse: Error response model
20
+ SuccessResponse: Success response model
21
+ ValidationResponse: Validation response model
22
+ AuthResponse: Authentication response model
23
+ CertificateResponse: Certificate response model
24
+ PermissionResponse: Permission response model
25
+ RateLimitResponse: Rate limiting response model
26
+
27
+ Author: MCP Security Team
28
+ Version: 1.0.0
29
+ License: MIT
30
+ """
31
+
32
+ from datetime import datetime
33
+ from enum import Enum
34
+ from typing import Any, Dict, Generic, List, Optional, TypeVar
35
+
36
+ from pydantic import BaseModel, Field, field_validator, model_validator
37
+
38
+ from .models import AuthResult, CertificateInfo, RateLimitStatus, ValidationResult
39
+
40
+
41
+ class ResponseStatus(str, Enum):
42
+ """Response status enumeration."""
43
+
44
+ SUCCESS = "success"
45
+ ERROR = "error"
46
+ WARNING = "warning"
47
+ INFO = "info"
48
+
49
+
50
+ class SecurityStatus(str, Enum):
51
+ """Security status enumeration."""
52
+
53
+ HEALTHY = "healthy"
54
+ WARNING = "warning"
55
+ ERROR = "error"
56
+ DEGRADED = "degraded"
57
+ UNKNOWN = "unknown"
58
+
59
+
60
+ class ErrorCode(str, Enum):
61
+ """Error code enumeration."""
62
+
63
+ # Authentication errors
64
+ AUTHENTICATION_FAILED = "AUTHENTICATION_FAILED"
65
+ INVALID_CREDENTIALS = "INVALID_CREDENTIALS"
66
+ TOKEN_EXPIRED = "TOKEN_EXPIRED"
67
+ INVALID_TOKEN = "INVALID_TOKEN"
68
+ INSUFFICIENT_PERMISSIONS = "INSUFFICIENT_PERMISSIONS"
69
+
70
+ # Certificate errors
71
+ CERTIFICATE_INVALID = "CERTIFICATE_INVALID"
72
+ CERTIFICATE_EXPIRED = "CERTIFICATE_EXPIRED"
73
+ CERTIFICATE_REVOKED = "CERTIFICATE_REVOKED"
74
+ CERTIFICATE_CHAIN_INVALID = "CERTIFICATE_CHAIN_INVALID"
75
+ CERTIFICATE_NOT_FOUND = "CERTIFICATE_NOT_FOUND"
76
+
77
+ # Rate limiting errors
78
+ RATE_LIMIT_EXCEEDED = "RATE_LIMIT_EXCEEDED"
79
+ TOO_MANY_REQUESTS = "TOO_MANY_REQUESTS"
80
+
81
+ # Configuration errors
82
+ CONFIGURATION_ERROR = "CONFIGURATION_ERROR"
83
+ INVALID_CONFIGURATION = "INVALID_CONFIGURATION"
84
+ MISSING_CONFIGURATION = "MISSING_CONFIGURATION"
85
+
86
+ # Validation errors
87
+ VALIDATION_ERROR = "VALIDATION_ERROR"
88
+ INVALID_INPUT = "INVALID_INPUT"
89
+ MISSING_REQUIRED_FIELD = "MISSING_REQUIRED_FIELD"
90
+
91
+ # System errors
92
+ INTERNAL_ERROR = "INTERNAL_ERROR"
93
+ SERVICE_UNAVAILABLE = "SERVICE_UNAVAILABLE"
94
+ DATABASE_ERROR = "DATABASE_ERROR"
95
+ NETWORK_ERROR = "NETWORK_ERROR"
96
+
97
+ # Security errors
98
+ SECURITY_VIOLATION = "SECURITY_VIOLATION"
99
+ ACCESS_DENIED = "ACCESS_DENIED"
100
+ FORBIDDEN = "FORBIDDEN"
101
+ UNAUTHORIZED = "UNAUTHORIZED"
102
+
103
+
104
+ # Generic type for response data
105
+ T = TypeVar("T")
106
+
107
+
108
+ class SecurityResponse(BaseModel, Generic[T]):
109
+ """
110
+ Base Security Response Model
111
+
112
+ This is the base response model that provides a standardized
113
+ format for all API responses in the MCP Security Framework.
114
+
115
+ Attributes:
116
+ status: Response status (success, error, warning, info)
117
+ message: Human-readable response message
118
+ data: Response data payload
119
+ timestamp: Response timestamp
120
+ request_id: Unique request identifier
121
+ version: API version
122
+ metadata: Additional response metadata
123
+ """
124
+
125
+ status: ResponseStatus = Field(..., description="Response status")
126
+ message: str = Field(..., description="Human-readable response message")
127
+ data: Optional[T] = Field(default=None, description="Response data payload")
128
+ timestamp: datetime = Field(
129
+ default_factory=datetime.utcnow, description="Response timestamp"
130
+ )
131
+ request_id: Optional[str] = Field(
132
+ default=None, description="Unique request identifier"
133
+ )
134
+ version: str = Field(default="1.0.0", description="API version")
135
+ metadata: Dict[str, Any] = Field(
136
+ default_factory=dict, description="Additional response metadata"
137
+ )
138
+
139
+ @field_validator("message")
140
+ @classmethod
141
+ def validate_message(cls, v):
142
+ """Validate response message."""
143
+ if len(v.strip()) == 0:
144
+ raise ValueError("Response message cannot be empty")
145
+ return v.strip()
146
+
147
+ @property
148
+ def is_success(self) -> bool:
149
+ """Check if response indicates success."""
150
+ return self.status == ResponseStatus.SUCCESS
151
+
152
+ @property
153
+ def is_error(self) -> bool:
154
+ """Check if response indicates error."""
155
+ return self.status == ResponseStatus.ERROR
156
+
157
+
158
+ class ErrorResponse(SecurityResponse[None]):
159
+ """
160
+ Error Response Model
161
+
162
+ This model represents error responses with detailed error
163
+ information including error codes, HTTP status codes, and
164
+ additional error context.
165
+
166
+ Attributes:
167
+ error_code: Specific error code
168
+ http_status_code: HTTP status code
169
+ details: Detailed error information
170
+ field_errors: Field-specific validation errors
171
+ stack_trace: Stack trace for debugging (optional)
172
+ retry_after: Retry after time in seconds
173
+ error_type: Type of error
174
+ """
175
+
176
+ error_code: ErrorCode = Field(..., description="Specific error code")
177
+ http_status_code: int = Field(..., ge=400, le=599, description="HTTP status code")
178
+ details: Optional[str] = Field(
179
+ default=None, description="Detailed error information"
180
+ )
181
+ field_errors: Dict[str, List[str]] = Field(
182
+ default_factory=dict, description="Field-specific validation errors"
183
+ )
184
+ stack_trace: Optional[str] = Field(
185
+ default=None, description="Stack trace for debugging"
186
+ )
187
+ retry_after: Optional[int] = Field(
188
+ default=None, ge=0, description="Retry after time in seconds"
189
+ )
190
+ error_type: str = Field(default="SecurityError", description="Type of error")
191
+
192
+ @field_validator("status")
193
+ @classmethod
194
+ def validate_error_status(cls, v):
195
+ """Validate that error responses have error status."""
196
+ if v != ResponseStatus.ERROR:
197
+ raise ValueError("Error responses must have ERROR status")
198
+ return v
199
+
200
+ @field_validator("http_status_code")
201
+ @classmethod
202
+ def validate_http_status_code(cls, v):
203
+ """Validate HTTP status code for errors."""
204
+ if v < 400 or v > 599:
205
+ raise ValueError(
206
+ "Error responses must have HTTP status code between 400 and 599"
207
+ )
208
+ return v
209
+
210
+ @model_validator(mode="after")
211
+ def validate_error_response(self):
212
+ """Validate error response consistency."""
213
+ if self.status != ResponseStatus.ERROR:
214
+ raise ValueError("Error responses must have ERROR status")
215
+
216
+ # Validate error code and HTTP status code consistency
217
+ if (
218
+ self.error_code == ErrorCode.AUTHENTICATION_FAILED
219
+ and self.http_status_code != 401
220
+ ):
221
+ raise ValueError("Authentication failed should have HTTP status 401")
222
+
223
+ if (
224
+ self.error_code == ErrorCode.INSUFFICIENT_PERMISSIONS
225
+ and self.http_status_code != 403
226
+ ):
227
+ raise ValueError("Insufficient permissions should have HTTP status 403")
228
+
229
+ if (
230
+ self.error_code == ErrorCode.RATE_LIMIT_EXCEEDED
231
+ and self.http_status_code != 429
232
+ ):
233
+ raise ValueError("Rate limit exceeded should have HTTP status 429")
234
+
235
+ return self
236
+
237
+ @classmethod
238
+ def create_authentication_error(
239
+ cls, message: str, details: Optional[str] = None
240
+ ) -> "ErrorResponse":
241
+ """Create authentication error response."""
242
+ return cls(
243
+ status=ResponseStatus.ERROR,
244
+ message=message,
245
+ error_code=ErrorCode.AUTHENTICATION_FAILED,
246
+ http_status_code=401,
247
+ details=details,
248
+ error_type="AuthenticationError",
249
+ )
250
+
251
+ @classmethod
252
+ def create_permission_error(
253
+ cls, message: str, details: Optional[str] = None
254
+ ) -> "ErrorResponse":
255
+ """Create permission error response."""
256
+ return cls(
257
+ status=ResponseStatus.ERROR,
258
+ message=message,
259
+ error_code=ErrorCode.INSUFFICIENT_PERMISSIONS,
260
+ http_status_code=403,
261
+ details=details,
262
+ error_type="PermissionError",
263
+ )
264
+
265
+ @classmethod
266
+ def create_rate_limit_error(
267
+ cls, message: str, retry_after: Optional[int] = None
268
+ ) -> "ErrorResponse":
269
+ """Create rate limit error response."""
270
+ return cls(
271
+ status=ResponseStatus.ERROR,
272
+ message=message,
273
+ error_code=ErrorCode.RATE_LIMIT_EXCEEDED,
274
+ http_status_code=429,
275
+ retry_after=retry_after,
276
+ error_type="RateLimitError",
277
+ )
278
+
279
+ @classmethod
280
+ def create_validation_error(
281
+ cls, message: str, field_errors: Dict[str, List[str]]
282
+ ) -> "ErrorResponse":
283
+ """Create validation error response."""
284
+ return cls(
285
+ status=ResponseStatus.ERROR,
286
+ message=message,
287
+ error_code=ErrorCode.VALIDATION_ERROR,
288
+ http_status_code=400,
289
+ field_errors=field_errors,
290
+ error_type="ValidationError",
291
+ )
292
+
293
+
294
+ class SuccessResponse(SecurityResponse[T]):
295
+ """
296
+ Success Response Model
297
+
298
+ This model represents successful responses with data payload
299
+ and optional success metadata.
300
+
301
+ Attributes:
302
+ data: Response data payload
303
+ total_count: Total count for paginated responses
304
+ page: Current page number
305
+ page_size: Page size
306
+ has_more: Whether there are more pages
307
+ """
308
+
309
+ data: T = Field(..., description="Response data payload")
310
+ total_count: Optional[int] = Field(
311
+ default=None, ge=0, description="Total count for paginated responses"
312
+ )
313
+ page: Optional[int] = Field(default=None, ge=1, description="Current page number")
314
+ page_size: Optional[int] = Field(default=None, ge=1, description="Page size")
315
+ has_more: Optional[bool] = Field(
316
+ default=None, description="Whether there are more pages"
317
+ )
318
+
319
+ @field_validator("status")
320
+ @classmethod
321
+ def validate_success_status(cls, v):
322
+ """Validate that success responses have success status."""
323
+ if v != ResponseStatus.SUCCESS:
324
+ raise ValueError("Success responses must have SUCCESS status")
325
+ return v
326
+
327
+ @model_validator(mode="after")
328
+ def validate_success_response(self):
329
+ """Validate success response consistency."""
330
+ if self.status != ResponseStatus.SUCCESS:
331
+ raise ValueError("Success responses must have SUCCESS status")
332
+
333
+ if self.data is None:
334
+ raise ValueError("Success responses must have data")
335
+
336
+ return self
337
+
338
+ @classmethod
339
+ def create_success(
340
+ cls, data: T, message: str = "Operation completed successfully"
341
+ ) -> "SuccessResponse[T]":
342
+ """Create success response."""
343
+ return cls(status=ResponseStatus.SUCCESS, message=message, data=data)
344
+
345
+
346
+ class ValidationResponse(SecurityResponse[ValidationResult]):
347
+ """
348
+ Validation Response Model
349
+
350
+ This model represents validation responses with detailed
351
+ validation results and field-specific error information.
352
+
353
+ Attributes:
354
+ validation_result: Validation result object
355
+ field_errors: Field-specific validation errors
356
+ warnings: List of validation warnings
357
+ suggestions: List of improvement suggestions
358
+ """
359
+
360
+ validation_result: ValidationResult = Field(
361
+ ..., description="Validation result object"
362
+ )
363
+ field_errors: Dict[str, List[str]] = Field(
364
+ default_factory=dict, description="Field-specific validation errors"
365
+ )
366
+ warnings: List[str] = Field(
367
+ default_factory=list, description="List of validation warnings"
368
+ )
369
+ suggestions: List[str] = Field(
370
+ default_factory=list, description="List of improvement suggestions"
371
+ )
372
+
373
+ @field_validator("status")
374
+ @classmethod
375
+ def validate_validation_status(cls, v):
376
+ """Validate validation response status."""
377
+ # This validation will be handled by model_validator
378
+ return v
379
+
380
+ @model_validator(mode="after")
381
+ def validate_validation_response(self):
382
+ """Validate validation response consistency."""
383
+ if self.validation_result.is_valid and self.status != ResponseStatus.SUCCESS:
384
+ raise ValueError("Valid validation must have SUCCESS status")
385
+
386
+ if not self.validation_result.is_valid and self.status != ResponseStatus.ERROR:
387
+ raise ValueError("Invalid validation must have ERROR status")
388
+
389
+ return self
390
+
391
+ @classmethod
392
+ def create_validation_success(
393
+ cls, validation_result: ValidationResult
394
+ ) -> "ValidationResponse":
395
+ """Create successful validation response."""
396
+ return cls(
397
+ status=ResponseStatus.SUCCESS,
398
+ message="Validation completed successfully",
399
+ validation_result=validation_result,
400
+ )
401
+
402
+ @classmethod
403
+ def create_validation_error(
404
+ cls, validation_result: ValidationResult, field_errors: Dict[str, List[str]]
405
+ ) -> "ValidationResponse":
406
+ """Create validation error response."""
407
+ return cls(
408
+ status=ResponseStatus.ERROR,
409
+ message="Validation failed",
410
+ validation_result=validation_result,
411
+ field_errors=field_errors,
412
+ )
413
+
414
+
415
+ class AuthResponse(SecurityResponse[AuthResult]):
416
+ """
417
+ Authentication Response Model
418
+
419
+ This model represents authentication responses with detailed
420
+ authentication results and user information.
421
+
422
+ Attributes:
423
+ auth_result: Authentication result object
424
+ user_info: Additional user information
425
+ session_info: Session information
426
+ token_info: Token information
427
+ """
428
+
429
+ auth_result: AuthResult = Field(..., description="Authentication result object")
430
+ user_info: Dict[str, Any] = Field(
431
+ default_factory=dict, description="Additional user information"
432
+ )
433
+ session_info: Dict[str, Any] = Field(
434
+ default_factory=dict, description="Session information"
435
+ )
436
+ token_info: Dict[str, Any] = Field(
437
+ default_factory=dict, description="Token information"
438
+ )
439
+
440
+ @field_validator("status")
441
+ @classmethod
442
+ def validate_auth_status(cls, v):
443
+ """Validate authentication response status."""
444
+ # This validation will be handled by model_validator
445
+ return v
446
+
447
+ @model_validator(mode="after")
448
+ def validate_auth_response(self):
449
+ """Validate authentication response consistency."""
450
+ if self.auth_result.is_valid and self.status != ResponseStatus.SUCCESS:
451
+ raise ValueError("Successful authentication must have SUCCESS status")
452
+
453
+ if not self.auth_result.is_valid and self.status != ResponseStatus.ERROR:
454
+ raise ValueError("Failed authentication must have ERROR status")
455
+
456
+ return self
457
+
458
+ @classmethod
459
+ def create_auth_success(
460
+ cls, auth_result: AuthResult, user_info: Optional[Dict[str, Any]] = None
461
+ ) -> "AuthResponse":
462
+ """Create successful authentication response."""
463
+ return cls(
464
+ status=ResponseStatus.SUCCESS,
465
+ message="Authentication successful",
466
+ auth_result=auth_result,
467
+ user_info=user_info or {},
468
+ )
469
+
470
+ @classmethod
471
+ def create_auth_error(cls, auth_result: AuthResult) -> "AuthResponse":
472
+ """Create authentication error response."""
473
+ return cls(
474
+ status=ResponseStatus.ERROR,
475
+ message=auth_result.error_message or "Authentication failed",
476
+ auth_result=auth_result,
477
+ )
478
+
479
+
480
+ class CertificateResponse(SecurityResponse[CertificateInfo]):
481
+ """
482
+ Certificate Response Model
483
+
484
+ This model represents certificate-related responses with
485
+ detailed certificate information and validation results.
486
+
487
+ Attributes:
488
+ certificate_info: Certificate information object
489
+ validation_result: Certificate validation result
490
+ chain_info: Certificate chain information
491
+ expiry_info: Certificate expiry information
492
+ """
493
+
494
+ certificate_info: CertificateInfo = Field(
495
+ ..., description="Certificate information object"
496
+ )
497
+ validation_result: Optional[ValidationResult] = Field(
498
+ default=None, description="Certificate validation result"
499
+ )
500
+ chain_info: Dict[str, Any] = Field(
501
+ default_factory=dict, description="Certificate chain information"
502
+ )
503
+ expiry_info: Dict[str, Any] = Field(
504
+ default_factory=dict, description="Certificate expiry information"
505
+ )
506
+
507
+ @model_validator(mode="after")
508
+ def validate_certificate_response(self):
509
+ """Validate certificate response consistency."""
510
+ if (
511
+ self.validation_result
512
+ and not self.validation_result.is_valid
513
+ and self.status == ResponseStatus.SUCCESS
514
+ ):
515
+ raise ValueError(
516
+ "Invalid certificate validation cannot have SUCCESS status"
517
+ )
518
+
519
+ return self
520
+
521
+ @classmethod
522
+ def create_certificate_success(
523
+ cls,
524
+ certificate_info: CertificateInfo,
525
+ validation_result: Optional[ValidationResult] = None,
526
+ ) -> "CertificateResponse":
527
+ """Create successful certificate response."""
528
+ return cls(
529
+ status=ResponseStatus.SUCCESS,
530
+ message="Certificate information retrieved successfully",
531
+ certificate_info=certificate_info,
532
+ validation_result=validation_result,
533
+ )
534
+
535
+
536
+ class PermissionResponse(SecurityResponse[Dict[str, Any]]):
537
+ """
538
+ Permission Response Model
539
+
540
+ This model represents permission-related responses with
541
+ user roles, permissions, and access control information.
542
+
543
+ Attributes:
544
+ user_roles: List of user roles
545
+ user_permissions: Set of user permissions
546
+ effective_permissions: Effective permissions after inheritance
547
+ access_granted: Whether access is granted
548
+ required_permissions: Required permissions for the operation
549
+ missing_permissions: Missing permissions
550
+ """
551
+
552
+ user_roles: List[str] = Field(
553
+ default_factory=list, description="List of user roles"
554
+ )
555
+ user_permissions: set = Field(
556
+ default_factory=set, description="Set of user permissions"
557
+ )
558
+ effective_permissions: set = Field(
559
+ default_factory=set, description="Effective permissions after inheritance"
560
+ )
561
+ access_granted: bool = Field(..., description="Whether access is granted")
562
+ required_permissions: List[str] = Field(
563
+ default_factory=list, description="Required permissions for the operation"
564
+ )
565
+ missing_permissions: List[str] = Field(
566
+ default_factory=list, description="Missing permissions"
567
+ )
568
+
569
+ @model_validator(mode="after")
570
+ def validate_permission_response(self):
571
+ """Validate permission response consistency."""
572
+ if self.access_granted and self.status != ResponseStatus.SUCCESS:
573
+ raise ValueError("Granted access must have SUCCESS status")
574
+
575
+ if not self.access_granted and self.status != ResponseStatus.ERROR:
576
+ raise ValueError("Denied access must have ERROR status")
577
+
578
+ return self
579
+
580
+ @classmethod
581
+ def create_permission_granted(
582
+ cls,
583
+ user_roles: List[str],
584
+ user_permissions: set,
585
+ required_permissions: List[str],
586
+ ) -> "PermissionResponse":
587
+ """Create permission granted response."""
588
+ return cls(
589
+ status=ResponseStatus.SUCCESS,
590
+ message="Access granted",
591
+ user_roles=user_roles,
592
+ user_permissions=user_permissions,
593
+ effective_permissions=user_permissions,
594
+ access_granted=True,
595
+ required_permissions=required_permissions,
596
+ missing_permissions=[],
597
+ )
598
+
599
+ @classmethod
600
+ def create_permission_denied(
601
+ cls,
602
+ user_roles: List[str],
603
+ user_permissions: set,
604
+ required_permissions: List[str],
605
+ ) -> "PermissionResponse":
606
+ """Create permission denied response."""
607
+ missing_permissions = [
608
+ perm for perm in required_permissions if perm not in user_permissions
609
+ ]
610
+ return cls(
611
+ status=ResponseStatus.ERROR,
612
+ message="Access denied - insufficient permissions",
613
+ user_roles=user_roles,
614
+ user_permissions=user_permissions,
615
+ effective_permissions=user_permissions,
616
+ access_granted=False,
617
+ required_permissions=required_permissions,
618
+ missing_permissions=missing_permissions,
619
+ )
620
+
621
+
622
+ class RateLimitResponse(SecurityResponse[RateLimitStatus]):
623
+ """
624
+ Rate Limit Response Model
625
+
626
+ This model represents rate limiting responses with current
627
+ rate limit status and usage information.
628
+
629
+ Attributes:
630
+ rate_limit_status: Rate limit status object
631
+ usage_percentage: Current usage percentage
632
+ reset_time: Time when rate limit resets
633
+ retry_after: Retry after time in seconds
634
+ """
635
+
636
+ rate_limit_status: RateLimitStatus = Field(
637
+ ..., description="Rate limit status object"
638
+ )
639
+ usage_percentage: float = Field(..., ge=0.0, description="Current usage percentage")
640
+ reset_time: datetime = Field(..., description="Time when rate limit resets")
641
+ retry_after: Optional[int] = Field(
642
+ default=None, ge=0, description="Retry after time in seconds"
643
+ )
644
+
645
+ @model_validator(mode="after")
646
+ def validate_rate_limit_response(self):
647
+ """Validate rate limit response consistency."""
648
+ is_exceeded = self.rate_limit_status.is_exceeded
649
+
650
+ if is_exceeded and self.status != ResponseStatus.ERROR:
651
+ raise ValueError("Exceeded rate limit must have ERROR status")
652
+
653
+ if not is_exceeded and self.status != ResponseStatus.SUCCESS:
654
+ raise ValueError("Within rate limit must have SUCCESS status")
655
+
656
+ return self
657
+
658
+ @classmethod
659
+ def create_rate_limit_status(
660
+ cls, rate_limit_status: RateLimitStatus
661
+ ) -> "RateLimitResponse":
662
+ """Create rate limit status response."""
663
+ is_exceeded = rate_limit_status.is_exceeded
664
+ return cls(
665
+ status=ResponseStatus.ERROR if is_exceeded else ResponseStatus.SUCCESS,
666
+ message="Rate limit exceeded" if is_exceeded else "Rate limit status",
667
+ rate_limit_status=rate_limit_status,
668
+ usage_percentage=rate_limit_status.utilization_percentage,
669
+ reset_time=rate_limit_status.reset_time,
670
+ retry_after=rate_limit_status.seconds_until_reset if is_exceeded else None,
671
+ )
672
+
673
+
674
+ __all__ = [
675
+ "ResponseStatus",
676
+ "SecurityStatus",
677
+ "ErrorCode",
678
+ "SecurityResponse",
679
+ "ErrorResponse",
680
+ "SuccessResponse",
681
+ "ValidationResponse",
682
+ "AuthResponse",
683
+ "CertificateResponse",
684
+ "PermissionResponse",
685
+ "RateLimitResponse",
686
+ ]
File without changes