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,493 @@
1
+ """
2
+ Serialization Tests Module
3
+
4
+ This module provides comprehensive tests for serialization and deserialization
5
+ of all data models in the MCP Security Framework. It tests JSON serialization,
6
+ model validation, and data consistency.
7
+
8
+ Test Classes:
9
+ TestConfigSerialization: Tests for configuration model serialization
10
+ TestModelSerialization: Tests for data model serialization
11
+ TestResponseSerialization: Tests for response model serialization
12
+
13
+ Author: MCP Security Team
14
+ Version: 1.0.0
15
+ License: MIT
16
+ """
17
+
18
+ from datetime import datetime, timezone
19
+ from typing import Any, Dict
20
+
21
+ from mcp_security_framework.schemas.config import (
22
+ AuthConfig,
23
+ AuthMethod,
24
+ CertificateConfig,
25
+ LoggingConfig,
26
+ LogLevel,
27
+ PermissionConfig,
28
+ RateLimitConfig,
29
+ SecurityConfig,
30
+ SSLConfig,
31
+ TLSVersion,
32
+ )
33
+ from mcp_security_framework.schemas.models import (
34
+ AuthResult,
35
+ AuthStatus,
36
+ CertificateInfo,
37
+ CertificateType,
38
+ RateLimitStatus,
39
+ ValidationResult,
40
+ ValidationStatus,
41
+ )
42
+ from mcp_security_framework.schemas.responses import (
43
+ ErrorCode,
44
+ ErrorResponse,
45
+ ResponseStatus,
46
+ SecurityResponse,
47
+ SuccessResponse,
48
+ )
49
+
50
+
51
+ class TestConfigSerialization:
52
+ """Test suite for configuration model serialization."""
53
+
54
+ def test_ssl_config_serialization(self):
55
+ """Test SSLConfig serialization and deserialization."""
56
+ config = SSLConfig(
57
+ enabled=False, # Disabled to avoid file validation
58
+ cert_file=None,
59
+ key_file=None,
60
+ ca_cert_file=None,
61
+ verify_mode="CERT_REQUIRED",
62
+ min_tls_version=TLSVersion.TLS_1_2,
63
+ max_tls_version=TLSVersion.TLS_1_3,
64
+ cipher_suite="ECDHE-RSA-AES256-GCM-SHA384",
65
+ check_hostname=True,
66
+ check_expiry=True,
67
+ expiry_warning_days=30,
68
+ )
69
+
70
+ # Test model_dump
71
+ data = config.model_dump()
72
+ assert data["enabled"] is False
73
+ assert data["cert_file"] is None
74
+ assert data["key_file"] is None
75
+ assert data["verify_mode"] == "CERT_REQUIRED"
76
+ assert data["min_tls_version"] == "TLSv1.2"
77
+ assert data["max_tls_version"] == "TLSv1.3"
78
+
79
+ # Test model_dump_json
80
+ json_str = config.model_dump_json()
81
+ assert isinstance(json_str, str)
82
+ assert "TLSv1.2" in json_str
83
+ assert "CERT_REQUIRED" in json_str
84
+
85
+ # Test deserialization
86
+ parsed_config = SSLConfig.model_validate_json(json_str)
87
+ assert parsed_config.enabled == config.enabled
88
+ assert parsed_config.cert_file == config.cert_file
89
+ assert parsed_config.min_tls_version == config.min_tls_version
90
+
91
+ def test_auth_config_serialization(self):
92
+ """Test AuthConfig serialization and deserialization."""
93
+ config = AuthConfig(
94
+ enabled=True,
95
+ methods=[AuthMethod.API_KEY, AuthMethod.JWT],
96
+ api_keys={"admin": "admin_key_123", "user": "user_key_456"},
97
+ jwt_secret="secret_key",
98
+ jwt_expiry_hours=24,
99
+ jwt_algorithm="HS256",
100
+ public_paths=["/docs", "/health"],
101
+ require_auth_for_all=True,
102
+ default_role="guest",
103
+ )
104
+
105
+ # Test model_dump
106
+ data = config.model_dump()
107
+ assert data["enabled"] is True
108
+ assert data["methods"] == ["api_key", "jwt"]
109
+ assert data["api_keys"]["admin"] == "admin_key_123"
110
+ assert data["jwt_algorithm"] == "HS256"
111
+
112
+ # Test model_dump_json
113
+ json_str = config.model_dump_json()
114
+ assert isinstance(json_str, str)
115
+ assert "admin_key_123" in json_str
116
+ assert "api_key" in json_str
117
+
118
+ # Test deserialization
119
+ parsed_config = AuthConfig.model_validate_json(json_str)
120
+ assert parsed_config.enabled == config.enabled
121
+ assert parsed_config.methods == config.methods
122
+ assert parsed_config.api_keys == config.api_keys
123
+
124
+ def test_security_config_serialization(self):
125
+ """Test SecurityConfig serialization and deserialization."""
126
+ config = SecurityConfig(
127
+ ssl=SSLConfig(enabled=False), # Disabled to avoid file validation
128
+ auth=AuthConfig(enabled=True, methods=[AuthMethod.API_KEY]),
129
+ certificates=CertificateConfig(cert_storage_path="./certs"),
130
+ permissions=PermissionConfig(
131
+ roles_file=None
132
+ ), # Set to None to avoid file validation
133
+ rate_limit=RateLimitConfig(enabled=True, default_requests_per_minute=100),
134
+ logging=LoggingConfig(level=LogLevel.INFO),
135
+ )
136
+
137
+ # Test model_dump
138
+ data = config.model_dump()
139
+ assert data["ssl"]["enabled"] is False
140
+ assert data["auth"]["enabled"] is True
141
+ assert data["certificates"]["cert_storage_path"] == "./certs"
142
+ assert data["permissions"]["roles_file"] is None
143
+ assert data["rate_limit"]["default_requests_per_minute"] == 100
144
+
145
+ # Test model_dump_json
146
+ json_str = config.model_dump_json()
147
+ assert isinstance(json_str, str)
148
+
149
+ # Test deserialization
150
+ parsed_config = SecurityConfig.model_validate_json(json_str)
151
+ assert parsed_config.ssl.enabled == config.ssl.enabled
152
+ assert parsed_config.auth.enabled == config.auth.enabled
153
+ assert (
154
+ parsed_config.certificates.cert_storage_path
155
+ == config.certificates.cert_storage_path
156
+ )
157
+
158
+
159
+ class TestModelSerialization:
160
+ """Test suite for data model serialization."""
161
+
162
+ def test_auth_result_serialization(self):
163
+ """Test AuthResult serialization and deserialization."""
164
+ auth_result = AuthResult(
165
+ is_valid=True,
166
+ status=AuthStatus.SUCCESS,
167
+ username="test_user",
168
+ user_id="user_123",
169
+ roles=["admin", "user"],
170
+ permissions={"read", "write", "delete"},
171
+ auth_method=AuthMethod.API_KEY,
172
+ auth_timestamp=datetime.now(timezone.utc),
173
+ error_code=None,
174
+ error_message=None,
175
+ metadata={"ip": "192.168.1.1", "user_agent": "test-agent"},
176
+ )
177
+
178
+ # Test model_dump
179
+ data = auth_result.model_dump()
180
+ assert data["is_valid"] is True
181
+ assert data["status"] == "success"
182
+ assert data["username"] == "test_user"
183
+ assert data["roles"] == ["admin", "user"]
184
+ assert data["auth_method"] == "api_key"
185
+ assert "ip" in data["metadata"]
186
+
187
+ # Test model_dump_json
188
+ json_str = auth_result.model_dump_json()
189
+ assert isinstance(json_str, str)
190
+ assert "test_user" in json_str
191
+ assert "admin" in json_str
192
+
193
+ # Test deserialization
194
+ parsed_result = AuthResult.model_validate_json(json_str)
195
+ assert parsed_result.is_valid == auth_result.is_valid
196
+ assert parsed_result.status == auth_result.status
197
+ assert parsed_result.username == auth_result.username
198
+ assert parsed_result.roles == auth_result.roles
199
+
200
+ def test_validation_result_serialization(self):
201
+ """Test ValidationResult serialization and deserialization."""
202
+ validation_result = ValidationResult(
203
+ is_valid=True,
204
+ status=ValidationStatus.VALID,
205
+ field_name="permissions",
206
+ value=["read", "write"],
207
+ error_code=None,
208
+ error_message=None,
209
+ warnings=[],
210
+ metadata={"resource": "/api/data", "action": "GET"},
211
+ )
212
+
213
+ # Test model_dump
214
+ data = validation_result.model_dump()
215
+ assert data["is_valid"] is True
216
+ assert data["status"] == "valid"
217
+ assert data["field_name"] == "permissions"
218
+ assert data["value"] == ["read", "write"]
219
+ assert data["metadata"]["resource"] == "/api/data"
220
+
221
+ # Test model_dump_json
222
+ json_str = validation_result.model_dump_json()
223
+ assert isinstance(json_str, str)
224
+ assert "read" in json_str
225
+ assert "write" in json_str
226
+
227
+ # Test deserialization
228
+ parsed_result = ValidationResult.model_validate_json(json_str)
229
+ assert parsed_result.is_valid == validation_result.is_valid
230
+ assert parsed_result.status == validation_result.status
231
+ assert parsed_result.field_name == validation_result.field_name
232
+
233
+ def test_certificate_info_serialization(self):
234
+ """Test CertificateInfo serialization and deserialization."""
235
+ cert_info = CertificateInfo(
236
+ subject={"CN": "test.example.com", "O": "Test Org"},
237
+ issuer={"CN": "Test CA", "O": "Test CA Org"},
238
+ serial_number="1234567890",
239
+ not_before=datetime.now(timezone.utc),
240
+ not_after=datetime.now(timezone.utc),
241
+ certificate_type=CertificateType.SERVER,
242
+ is_expired=False,
243
+ is_revoked=False,
244
+ revocation_reason=None,
245
+ roles=["server"],
246
+ permissions={"ssl"},
247
+ key_usage=["digitalSignature", "keyEncipherment"],
248
+ extended_key_usage=["serverAuth"],
249
+ signature_algorithm="sha256WithRSAEncryption",
250
+ public_key_algorithm="rsaEncryption",
251
+ key_size=2048,
252
+ )
253
+
254
+ # Test model_dump
255
+ data = cert_info.model_dump()
256
+ assert data["subject"]["CN"] == "test.example.com"
257
+ assert data["issuer"]["CN"] == "Test CA"
258
+ assert data["serial_number"] == "1234567890"
259
+ assert data["roles"] == ["server"]
260
+ assert data["key_size"] == 2048
261
+
262
+ # Test model_dump_json
263
+ json_str = cert_info.model_dump_json()
264
+ assert isinstance(json_str, str)
265
+ assert "test.example.com" in json_str
266
+ assert "Test CA" in json_str
267
+
268
+ # Test deserialization
269
+ parsed_info = CertificateInfo.model_validate_json(json_str)
270
+ assert parsed_info.subject["CN"] == cert_info.subject["CN"]
271
+ assert parsed_info.issuer["CN"] == cert_info.issuer["CN"]
272
+ assert parsed_info.key_size == cert_info.key_size
273
+
274
+ def test_rate_limit_status_serialization(self):
275
+ """Test RateLimitStatus serialization and deserialization."""
276
+ now = datetime.now(timezone.utc)
277
+ rate_limit_status = RateLimitStatus(
278
+ identifier="user:test_user",
279
+ current_count=50,
280
+ limit=100,
281
+ window_start=now,
282
+ window_end=now,
283
+ window_size_seconds=60,
284
+ is_exceeded=False,
285
+ remaining_requests=50,
286
+ reset_time=now,
287
+ )
288
+
289
+ # Test model_dump
290
+ data = rate_limit_status.model_dump()
291
+ assert data["identifier"] == "user:test_user"
292
+ assert data["current_count"] == 50
293
+ assert data["limit"] == 100
294
+ assert data["is_exceeded"] is False
295
+ assert data["remaining_requests"] == 50
296
+
297
+ # Test model_dump_json
298
+ json_str = rate_limit_status.model_dump_json()
299
+ assert isinstance(json_str, str)
300
+ assert "test_user" in json_str
301
+ assert "50" in json_str
302
+
303
+ # Test deserialization
304
+ parsed_status = RateLimitStatus.model_validate_json(json_str)
305
+ assert parsed_status.identifier == rate_limit_status.identifier
306
+ assert parsed_status.current_count == rate_limit_status.current_count
307
+ assert parsed_status.remaining_requests == rate_limit_status.remaining_requests
308
+
309
+
310
+ class TestResponseSerialization:
311
+ """Test suite for response model serialization."""
312
+
313
+ def test_security_response_serialization(self):
314
+ """Test SecurityResponse serialization and deserialization."""
315
+ response = SecurityResponse[Dict[str, Any]](
316
+ status=ResponseStatus.SUCCESS,
317
+ message="Operation completed successfully",
318
+ data={"result": "success", "count": 5},
319
+ timestamp=datetime.now(timezone.utc),
320
+ request_id="req_123",
321
+ metadata={"version": "1.0.0", "environment": "production"},
322
+ )
323
+
324
+ # Test model_dump
325
+ data = response.model_dump()
326
+ assert data["status"] == "success"
327
+ assert data["message"] == "Operation completed successfully"
328
+ assert data["data"]["result"] == "success"
329
+ assert data["data"]["count"] == 5
330
+ assert data["metadata"]["version"] == "1.0.0"
331
+
332
+ # Test model_dump_json
333
+ json_str = response.model_dump_json()
334
+ assert isinstance(json_str, str)
335
+ assert "success" in json_str
336
+ assert "Operation completed successfully" in json_str
337
+
338
+ # Test deserialization
339
+ parsed_response = SecurityResponse.model_validate_json(json_str)
340
+ assert parsed_response.status == response.status
341
+ assert parsed_response.message == response.message
342
+ assert parsed_response.data["result"] == response.data["result"]
343
+
344
+ def test_error_response_serialization(self):
345
+ """Test ErrorResponse serialization and deserialization."""
346
+ error_response = ErrorResponse(
347
+ status=ResponseStatus.ERROR,
348
+ message="Authentication failed",
349
+ error_code=ErrorCode.AUTHENTICATION_FAILED,
350
+ error_type="AuthenticationError",
351
+ http_status_code=401,
352
+ details="Invalid credentials for user test_user",
353
+ timestamp=datetime.now(timezone.utc),
354
+ request_id="req_456",
355
+ )
356
+
357
+ # Test model_dump
358
+ data = error_response.model_dump()
359
+ assert data["status"] == "error"
360
+ assert data["message"] == "Authentication failed"
361
+ assert data["error_code"] == "AUTHENTICATION_FAILED"
362
+ assert data["http_status_code"] == 401
363
+ assert "test_user" in data["details"]
364
+
365
+ # Test model_dump_json
366
+ json_str = error_response.model_dump_json()
367
+ assert isinstance(json_str, str)
368
+ assert "Authentication failed" in json_str
369
+ assert "AUTHENTICATION_FAILED" in json_str
370
+
371
+ # Test deserialization
372
+ parsed_response = ErrorResponse.model_validate_json(json_str)
373
+ assert parsed_response.status == error_response.status
374
+ assert parsed_response.error_code == error_response.error_code
375
+ assert parsed_response.http_status_code == error_response.http_status_code
376
+
377
+ def test_success_response_serialization(self):
378
+ """Test SuccessResponse serialization and deserialization."""
379
+ success_response = SuccessResponse[Dict[str, Any]](
380
+ status=ResponseStatus.SUCCESS,
381
+ message="Data retrieved successfully",
382
+ data={"items": [{"id": 1, "name": "item1"}, {"id": 2, "name": "item2"}]},
383
+ timestamp=datetime.now(timezone.utc),
384
+ request_id="req_789",
385
+ )
386
+
387
+ # Test model_dump
388
+ data = success_response.model_dump()
389
+ assert data["status"] == "success"
390
+ assert data["message"] == "Data retrieved successfully"
391
+ assert len(data["data"]["items"]) == 2
392
+
393
+ # Test model_dump_json
394
+ json_str = success_response.model_dump_json()
395
+ assert isinstance(json_str, str)
396
+ assert "Data retrieved successfully" in json_str
397
+ assert "item1" in json_str
398
+ assert "item2" in json_str
399
+
400
+ # Test deserialization
401
+ parsed_response = SuccessResponse.model_validate_json(json_str)
402
+ assert parsed_response.status == success_response.status
403
+ assert parsed_response.message == success_response.message
404
+ assert len(parsed_response.data["items"]) == 2
405
+
406
+
407
+ class TestEdgeCases:
408
+ """Test suite for edge cases in serialization."""
409
+
410
+ def test_empty_data_serialization(self):
411
+ """Test serialization with empty data."""
412
+ auth_result = AuthResult(
413
+ is_valid=False,
414
+ status=AuthStatus.FAILED,
415
+ username=None,
416
+ user_id=None,
417
+ roles=[],
418
+ permissions=set(),
419
+ auth_method=None,
420
+ auth_timestamp=datetime.now(timezone.utc),
421
+ error_code=-32001,
422
+ error_message="Authentication failed",
423
+ metadata={},
424
+ )
425
+
426
+ json_str = auth_result.model_dump_json()
427
+ parsed_result = AuthResult.model_validate_json(json_str)
428
+
429
+ assert parsed_result.is_valid is False
430
+ assert parsed_result.status == AuthStatus.FAILED
431
+ assert parsed_result.username is None
432
+ assert parsed_result.roles == []
433
+ assert parsed_result.error_code == -32001
434
+
435
+ def test_nested_object_serialization(self):
436
+ """Test serialization of nested objects."""
437
+ config = SecurityConfig(
438
+ ssl=SSLConfig(enabled=False), # Disabled to avoid file validation
439
+ auth=AuthConfig(
440
+ enabled=True,
441
+ methods=[AuthMethod.API_KEY],
442
+ api_keys={"admin": "admin_key"},
443
+ ),
444
+ certificates=CertificateConfig(cert_storage_path="./certs"),
445
+ permissions=PermissionConfig(
446
+ roles_file=None
447
+ ), # Set to None to avoid file validation
448
+ rate_limit=RateLimitConfig(enabled=True, default_requests_per_minute=100),
449
+ logging=LoggingConfig(level=LogLevel.INFO),
450
+ )
451
+
452
+ json_str = config.model_dump_json()
453
+ parsed_config = SecurityConfig.model_validate_json(json_str)
454
+
455
+ assert parsed_config.ssl.enabled is False
456
+ assert parsed_config.auth.enabled is True
457
+ assert parsed_config.auth.api_keys["admin"] == "admin_key"
458
+ assert parsed_config.rate_limit.default_requests_per_minute == 100
459
+
460
+ def test_datetime_serialization(self):
461
+ """Test datetime serialization and deserialization."""
462
+ timestamp = datetime.now(timezone.utc)
463
+
464
+ auth_result = AuthResult(
465
+ is_valid=True,
466
+ status=AuthStatus.SUCCESS,
467
+ username="test_user",
468
+ auth_timestamp=timestamp,
469
+ roles=["user"],
470
+ )
471
+
472
+ json_str = auth_result.model_dump_json()
473
+ parsed_result = AuthResult.model_validate_json(json_str)
474
+
475
+ # Check that datetime is properly serialized and deserialized
476
+ assert parsed_result.auth_timestamp is not None
477
+ assert isinstance(parsed_result.auth_timestamp, datetime)
478
+
479
+ def test_enum_serialization(self):
480
+ """Test enum serialization and deserialization."""
481
+ auth_result = AuthResult(
482
+ is_valid=True,
483
+ status=AuthStatus.SUCCESS,
484
+ username="test_user",
485
+ auth_method=AuthMethod.JWT,
486
+ roles=["user"],
487
+ )
488
+
489
+ json_str = auth_result.model_dump_json()
490
+ parsed_result = AuthResult.model_validate_json(json_str)
491
+
492
+ assert parsed_result.auth_method == AuthMethod.JWT
493
+ assert parsed_result.auth_method == "jwt"
File without changes