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,582 @@
1
+ """
2
+ Tests for Authentication Manager Module
3
+
4
+ This module contains comprehensive tests for the AuthManager class,
5
+ covering all authentication methods and edge cases.
6
+
7
+ Test Coverage:
8
+ - API key authentication
9
+ - JWT token authentication and creation
10
+ - Certificate-based authentication
11
+ - Error handling and edge cases
12
+ - Configuration validation
13
+ - Integration with PermissionManager
14
+
15
+ Author: MCP Security Team
16
+ Version: 1.0.0
17
+ License: MIT
18
+ """
19
+
20
+ from datetime import datetime, timedelta, timezone
21
+ from unittest.mock import MagicMock, Mock, patch
22
+
23
+ import pytest
24
+
25
+ from mcp_security_framework.core.auth_manager import (
26
+ AuthenticationConfigurationError,
27
+ AuthenticationError,
28
+ AuthManager,
29
+ CertificateValidationError,
30
+ JWTValidationError,
31
+ )
32
+ from mcp_security_framework.core.permission_manager import PermissionManager
33
+ from mcp_security_framework.schemas.config import AuthConfig
34
+ from mcp_security_framework.schemas.models import AuthResult, AuthStatus
35
+
36
+
37
+ class TestAuthManager:
38
+ """Test suite for AuthManager class."""
39
+
40
+ def setup_method(self):
41
+ """Set up test fixtures before each test method."""
42
+ # Create mock permission manager
43
+ self.mock_permission_manager = Mock(spec=PermissionManager)
44
+ # Configure mock to return default roles
45
+ self.mock_permission_manager.get_user_roles.return_value = ["user"]
46
+
47
+ # Create test configuration
48
+ self.auth_config = AuthConfig(
49
+ api_keys={"test_api_key_123": "test_user"},
50
+ jwt_secret="test_jwt_secret_key_32_chars_long",
51
+ jwt_expiry_hours=1,
52
+ ca_cert_file=None,
53
+ )
54
+
55
+ # Create AuthManager instance
56
+ self.auth_manager = AuthManager(self.auth_config, self.mock_permission_manager)
57
+
58
+ def teardown_method(self):
59
+ """Clean up after each test method."""
60
+ # Clear caches
61
+ self.auth_manager.clear_token_cache()
62
+ self.auth_manager.clear_session_store()
63
+
64
+ def test_init_success(self):
65
+ """Test successful AuthManager initialization."""
66
+ assert self.auth_manager.config == self.auth_config
67
+ assert self.auth_manager.permission_manager == self.mock_permission_manager
68
+ assert self.auth_manager._api_keys == {"test_user": "test_api_key_123"}
69
+ assert self.auth_manager._jwt_secret == "test_jwt_secret_key_32_chars_long"
70
+ assert isinstance(self.auth_manager._token_cache, dict)
71
+ assert isinstance(self.auth_manager._session_store, dict)
72
+
73
+ def test_init_without_config(self):
74
+ """Test AuthManager initialization without config."""
75
+ with pytest.raises(AuthenticationConfigurationError) as exc_info:
76
+ AuthManager(None, self.mock_permission_manager)
77
+ assert "Authentication configuration is required" in str(exc_info.value)
78
+
79
+ def test_init_without_permission_manager(self):
80
+ """Test AuthManager initialization without permission manager."""
81
+ with pytest.raises(AuthenticationConfigurationError) as exc_info:
82
+ AuthManager(self.auth_config, None)
83
+ assert "Permission manager is required" in str(exc_info.value)
84
+
85
+ def test_init_with_short_jwt_secret(self):
86
+ """Test AuthManager initialization with short JWT secret."""
87
+ short_config = AuthConfig(
88
+ api_keys={"test_api_key_123": "test_user"},
89
+ jwt_secret="short",
90
+ jwt_expiry_hours=1,
91
+ )
92
+
93
+ with pytest.raises(AuthenticationConfigurationError) as exc_info:
94
+ AuthManager(short_config, self.mock_permission_manager)
95
+ assert "JWT secret must be at least 16 characters" in str(exc_info.value)
96
+
97
+ def test_init_with_generated_jwt_secret(self):
98
+ """Test AuthManager initialization with auto-generated JWT secret."""
99
+ config_without_secret = AuthConfig(
100
+ api_keys={"test_api_key_123": "test_user"},
101
+ jwt_secret=None,
102
+ jwt_expiry_hours=1,
103
+ )
104
+
105
+ auth_manager = AuthManager(config_without_secret, self.mock_permission_manager)
106
+ assert len(auth_manager._jwt_secret) >= 32
107
+
108
+ def test_authenticate_api_key_success(self):
109
+ """Test successful API key authentication."""
110
+ # Mock user roles
111
+ with patch.object(
112
+ self.auth_manager, "_get_user_roles", return_value=["user", "admin"]
113
+ ):
114
+ result = self.auth_manager.authenticate_api_key("test_api_key_123")
115
+
116
+ assert result.is_valid is True
117
+ assert result.status == AuthStatus.SUCCESS
118
+ assert result.username == "test_user"
119
+ assert result.roles == ["user", "admin"]
120
+ assert result.auth_method == "api_key"
121
+ assert result.error_code is None
122
+ assert result.error_message is None
123
+ assert result.auth_timestamp is not None
124
+
125
+ def test_authenticate_api_key_empty_key(self):
126
+ """Test API key authentication with empty key."""
127
+ result = self.auth_manager.authenticate_api_key("")
128
+
129
+ assert result.is_valid is False
130
+ assert result.status == AuthStatus.INVALID
131
+ assert result.auth_method == "api_key"
132
+ assert result.error_code == -32001
133
+ assert "API key is required" in result.error_message
134
+
135
+ def test_authenticate_api_key_none_key(self):
136
+ """Test API key authentication with None key."""
137
+ result = self.auth_manager.authenticate_api_key(None)
138
+
139
+ assert result.is_valid is False
140
+ assert result.status == AuthStatus.INVALID
141
+ assert result.auth_method == "api_key"
142
+ assert result.error_code == -32001
143
+ assert "API key is required" in result.error_message
144
+
145
+ def test_authenticate_api_key_invalid_format(self):
146
+ """Test API key authentication with invalid format."""
147
+ with patch(
148
+ "mcp_security_framework.utils.crypto_utils.validate_api_key_format",
149
+ return_value=False,
150
+ ):
151
+ result = self.auth_manager.authenticate_api_key("short")
152
+
153
+ assert result.is_valid is False
154
+ assert result.status == AuthStatus.INVALID
155
+ assert result.auth_method == "api_key"
156
+ assert result.error_code == -32002
157
+ assert "Invalid API key format" in result.error_message
158
+
159
+ def test_authenticate_api_key_not_found(self):
160
+ """Test API key authentication with non-existent key."""
161
+ result = self.auth_manager.authenticate_api_key("non_existent_key")
162
+
163
+ assert result.is_valid is False
164
+ assert result.status == AuthStatus.INVALID
165
+ assert result.auth_method == "api_key"
166
+ assert result.error_code == -32003
167
+ assert "Invalid API key" in result.error_message
168
+
169
+ def test_authenticate_api_key_roles_error(self):
170
+ """Test API key authentication when role retrieval fails."""
171
+ with patch.object(
172
+ self.auth_manager, "_get_user_roles", side_effect=Exception("Role error")
173
+ ):
174
+ result = self.auth_manager.authenticate_api_key("test_api_key_123")
175
+
176
+ assert result.is_valid is False
177
+ assert result.status == AuthStatus.FAILED
178
+ assert result.auth_method == "api_key"
179
+ assert result.error_code == -32004
180
+ assert "Failed to retrieve user roles" in result.error_message
181
+
182
+ def test_authenticate_jwt_token_success(self):
183
+ """Test successful JWT token authentication."""
184
+ # Create a valid JWT token
185
+ user_data = {"username": "test_user", "roles": ["user", "admin"]}
186
+ token = self.auth_manager.create_jwt_token(user_data)
187
+
188
+ # Authenticate with the token
189
+ result = self.auth_manager.authenticate_jwt_token(token)
190
+
191
+ assert result.is_valid is True
192
+ assert result.status == AuthStatus.SUCCESS
193
+ assert result.username == "test_user"
194
+ assert result.roles == ["user", "admin"]
195
+ assert result.auth_method == "jwt"
196
+ assert result.error_code is None
197
+ assert result.error_message is None
198
+ assert result.auth_timestamp is not None
199
+ assert result.token_expiry is not None
200
+
201
+ def test_authenticate_jwt_token_empty_token(self):
202
+ """Test JWT authentication with empty token."""
203
+ result = self.auth_manager.authenticate_jwt_token("")
204
+
205
+ assert result.is_valid is False
206
+ assert result.status == AuthStatus.INVALID
207
+ assert result.auth_method == "jwt"
208
+ assert result.error_code == -32001
209
+ assert "JWT token is required" in result.error_message
210
+
211
+ def test_authenticate_jwt_token_none_token(self):
212
+ """Test JWT authentication with None token."""
213
+ result = self.auth_manager.authenticate_jwt_token(None)
214
+
215
+ assert result.is_valid is False
216
+ assert result.status == AuthStatus.INVALID
217
+ assert result.auth_method == "jwt"
218
+ assert result.error_code == -32001
219
+ assert "JWT token is required" in result.error_message
220
+
221
+ def test_authenticate_jwt_token_invalid_token(self):
222
+ """Test JWT authentication with invalid token."""
223
+ result = self.auth_manager.authenticate_jwt_token("invalid.jwt.token")
224
+
225
+ assert result.is_valid is False
226
+ assert result.status == AuthStatus.INVALID
227
+ assert result.auth_method == "jwt"
228
+ assert result.error_code == -32003
229
+ assert "Invalid JWT token" in result.error_message
230
+
231
+ def test_authenticate_jwt_token_expired_token(self):
232
+ """Test JWT authentication with expired token."""
233
+ # Create an expired token
234
+ expired_payload = {
235
+ "username": "test_user",
236
+ "roles": ["user"],
237
+ "iat": int((datetime.now(timezone.utc) - timedelta(hours=2)).timestamp()),
238
+ "exp": int((datetime.now(timezone.utc) - timedelta(hours=1)).timestamp()),
239
+ }
240
+
241
+ import jwt
242
+
243
+ expired_token = jwt.encode(
244
+ expired_payload, self.auth_manager._jwt_secret, algorithm="HS256"
245
+ )
246
+
247
+ result = self.auth_manager.authenticate_jwt_token(expired_token)
248
+
249
+ assert result.is_valid is False
250
+ assert result.status == AuthStatus.EXPIRED
251
+ assert result.auth_method == "jwt"
252
+ assert result.error_code == -32002
253
+ assert "JWT token has expired" in result.error_message
254
+
255
+ def test_authenticate_jwt_token_missing_username(self):
256
+ """Test JWT authentication with token missing username."""
257
+ # Create token without username
258
+ payload = {
259
+ "roles": ["user"],
260
+ "iat": int(datetime.now(timezone.utc).timestamp()),
261
+ "exp": int((datetime.now(timezone.utc) + timedelta(hours=1)).timestamp()),
262
+ }
263
+
264
+ import jwt
265
+
266
+ token = jwt.encode(payload, self.auth_manager._jwt_secret, algorithm="HS256")
267
+
268
+ result = self.auth_manager.authenticate_jwt_token(token)
269
+
270
+ assert result.is_valid is False
271
+ assert result.status == AuthStatus.INVALID
272
+ assert result.auth_method == "jwt"
273
+ assert result.error_code == -32004
274
+ assert "JWT token missing username" in result.error_message
275
+
276
+ def test_authenticate_jwt_token_cached_result(self):
277
+ """Test JWT authentication with cached result."""
278
+ # Create a valid token
279
+ user_data = {"username": "test_user", "roles": ["user"]}
280
+ token = self.auth_manager.create_jwt_token(user_data)
281
+
282
+ # First authentication
283
+ result1 = self.auth_manager.authenticate_jwt_token(token)
284
+
285
+ # Second authentication (should use cache)
286
+ result2 = self.auth_manager.authenticate_jwt_token(token)
287
+
288
+ assert result1.is_valid is True
289
+ assert result2.is_valid is True
290
+ assert result1.username == result2.username
291
+ assert result1.roles == result2.roles
292
+
293
+ def test_authenticate_certificate_success(self):
294
+ """Test successful certificate authentication."""
295
+ # Test with invalid certificate format (should fail gracefully)
296
+ cert_pem = "invalid_certificate_data"
297
+
298
+ result = self.auth_manager.authenticate_certificate(cert_pem)
299
+
300
+ assert result.is_valid is False
301
+ assert result.status == AuthStatus.INVALID
302
+ assert result.auth_method == "certificate"
303
+ assert result.error_code == -32002
304
+ assert "Invalid certificate format" in result.error_message
305
+
306
+ def test_authenticate_certificate_empty_cert(self):
307
+ """Test certificate authentication with empty certificate."""
308
+ result = self.auth_manager.authenticate_certificate("")
309
+
310
+ assert result.is_valid is False
311
+ assert result.status == AuthStatus.INVALID
312
+ assert result.auth_method == "certificate"
313
+ assert result.error_code == -32001
314
+ assert "Certificate is required" in result.error_message
315
+
316
+ def test_authenticate_certificate_invalid_format(self):
317
+ """Test certificate authentication with invalid format."""
318
+ result = self.auth_manager.authenticate_certificate("invalid_certificate")
319
+
320
+ assert result.is_valid is False
321
+ assert result.status == AuthStatus.INVALID
322
+ assert result.auth_method == "certificate"
323
+ assert result.error_code == -32002
324
+ assert "Invalid certificate format" in result.error_message
325
+
326
+ def test_authenticate_certificate_missing_username(self):
327
+ """Test certificate authentication with missing username."""
328
+ # Test with invalid certificate format (should fail before username check)
329
+ cert_pem = "invalid_certificate_data"
330
+
331
+ result = self.auth_manager.authenticate_certificate(cert_pem)
332
+
333
+ assert result.is_valid is False
334
+ assert result.status == AuthStatus.INVALID
335
+ assert result.auth_method == "certificate"
336
+ assert result.error_code == -32002
337
+ assert "Invalid certificate format" in result.error_message
338
+
339
+ def test_create_jwt_token_success(self):
340
+ """Test successful JWT token creation."""
341
+ user_data = {
342
+ "username": "test_user",
343
+ "roles": ["user", "admin"],
344
+ "permissions": ["read:users", "write:posts"],
345
+ }
346
+
347
+ token = self.auth_manager.create_jwt_token(user_data)
348
+
349
+ assert isinstance(token, str)
350
+ assert len(token) > 0
351
+
352
+ # Verify token can be decoded
353
+ import jwt
354
+
355
+ payload = jwt.decode(
356
+ token,
357
+ self.auth_manager._jwt_secret,
358
+ algorithms=["HS256"],
359
+ options={"verify_aud": False},
360
+ )
361
+
362
+ assert payload["username"] == "test_user"
363
+ assert payload["roles"] == ["user", "admin"]
364
+ assert payload["permissions"] == ["read:users", "write:posts"]
365
+ assert "iat" in payload
366
+ assert "exp" in payload
367
+ assert "sub" in payload
368
+ assert "iss" in payload
369
+
370
+ def test_create_jwt_token_with_additional_data(self):
371
+ """Test JWT token creation with additional user data."""
372
+ user_data = {
373
+ "username": "test_user",
374
+ "roles": ["user"],
375
+ "additional_data": {"email": "test@example.com", "department": "IT"},
376
+ }
377
+
378
+ token = self.auth_manager.create_jwt_token(user_data)
379
+
380
+ # Verify token can be decoded
381
+ import jwt
382
+
383
+ payload = jwt.decode(
384
+ token,
385
+ self.auth_manager._jwt_secret,
386
+ algorithms=["HS256"],
387
+ options={"verify_aud": False},
388
+ )
389
+
390
+ assert payload["username"] == "test_user"
391
+ assert payload["user_data"]["email"] == "test@example.com"
392
+ assert payload["user_data"]["department"] == "IT"
393
+
394
+ def test_create_jwt_token_invalid_user_data(self):
395
+ """Test JWT token creation with invalid user data."""
396
+ with pytest.raises(JWTValidationError) as exc_info:
397
+ self.auth_manager.create_jwt_token(None)
398
+ assert "User data must be provided" in str(exc_info.value)
399
+
400
+ with pytest.raises(JWTValidationError) as exc_info:
401
+ self.auth_manager.create_jwt_token({})
402
+ assert "User data dictionary cannot be empty" in str(exc_info.value)
403
+
404
+ with pytest.raises(JWTValidationError) as exc_info:
405
+ self.auth_manager.create_jwt_token({"roles": ["user"]})
406
+ assert "Username is required in user data" in str(exc_info.value)
407
+
408
+ def test_validate_jwt_token_valid(self):
409
+ """Test JWT token validation with valid token."""
410
+ user_data = {"username": "test_user", "roles": ["user"]}
411
+ token = self.auth_manager.create_jwt_token(user_data)
412
+
413
+ is_valid = self.auth_manager.validate_jwt_token(token)
414
+ assert is_valid is True
415
+
416
+ def test_validate_jwt_token_invalid(self):
417
+ """Test JWT token validation with invalid token."""
418
+ is_valid = self.auth_manager.validate_jwt_token("invalid.token")
419
+ assert is_valid is False
420
+
421
+ is_valid = self.auth_manager.validate_jwt_token("")
422
+ assert is_valid is False
423
+
424
+ is_valid = self.auth_manager.validate_jwt_token(None)
425
+ assert is_valid is False
426
+
427
+ def test_add_api_key_success(self):
428
+ """Test successful API key addition."""
429
+ success = self.auth_manager.add_api_key("new_user", "new_api_key_456789")
430
+
431
+ assert success is True
432
+ assert "new_user" in self.auth_manager._api_keys
433
+ assert self.auth_manager._api_keys["new_user"] == "new_api_key_456789"
434
+
435
+ def test_add_api_key_invalid_input(self):
436
+ """Test API key addition with invalid input."""
437
+ success = self.auth_manager.add_api_key("", "valid_key")
438
+ assert success is False
439
+
440
+ success = self.auth_manager.add_api_key("user", "")
441
+ assert success is False
442
+
443
+ success = self.auth_manager.add_api_key(None, "valid_key")
444
+ assert success is False
445
+
446
+ def test_add_api_key_invalid_format(self):
447
+ """Test API key addition with invalid format."""
448
+ with patch(
449
+ "mcp_security_framework.core.auth_manager.validate_api_key_format",
450
+ return_value=False,
451
+ ):
452
+ success = self.auth_manager.add_api_key("user", "invalid_key")
453
+ assert success is False
454
+
455
+ def test_remove_api_key_success(self):
456
+ """Test successful API key removal."""
457
+ # Add a key first
458
+ self.auth_manager.add_api_key("temp_user", "temp_key_123456789")
459
+ assert "temp_user" in self.auth_manager._api_keys
460
+
461
+ # Remove the key
462
+ success = self.auth_manager.remove_api_key("temp_user")
463
+ assert success is True
464
+ assert "temp_user" not in self.auth_manager._api_keys
465
+
466
+ def test_remove_api_key_not_found(self):
467
+ """Test API key removal for non-existent user."""
468
+ success = self.auth_manager.remove_api_key("non_existent_user")
469
+ assert success is False
470
+
471
+ def test_clear_token_cache(self):
472
+ """Test token cache clearing."""
473
+ # Add a token to cache
474
+ user_data = {"username": "test_user", "roles": ["user"]}
475
+ token = self.auth_manager.create_jwt_token(user_data)
476
+ self.auth_manager.authenticate_jwt_token(token)
477
+
478
+ assert len(self.auth_manager._token_cache) > 0
479
+
480
+ # Clear cache
481
+ self.auth_manager.clear_token_cache()
482
+ assert len(self.auth_manager._token_cache) == 0
483
+
484
+ def test_clear_session_store(self):
485
+ """Test session store clearing."""
486
+ # Add a session
487
+ self.auth_manager._session_store["test_session"] = {"user": "test"}
488
+
489
+ assert len(self.auth_manager._session_store) > 0
490
+
491
+ # Clear session store
492
+ self.auth_manager.clear_session_store()
493
+ assert len(self.auth_manager._session_store) == 0
494
+
495
+ def test_get_user_roles(self):
496
+ """Test user roles retrieval."""
497
+ roles = self.auth_manager._get_user_roles("test_user")
498
+ assert isinstance(roles, list)
499
+ assert "user" in roles
500
+
501
+ def test_extract_username_from_certificate(self):
502
+ """Test username extraction from certificate."""
503
+ from cryptography import x509
504
+ from cryptography.x509.oid import NameOID
505
+
506
+ # Create a mock certificate
507
+ mock_cert = Mock(spec=x509.Certificate)
508
+ mock_cn = Mock()
509
+ mock_cn.value = "test_user"
510
+ mock_cert.subject.get_attributes_for_oid.return_value = [mock_cn]
511
+
512
+ username = self.auth_manager._extract_username_from_certificate(mock_cert)
513
+ assert username == "test_user"
514
+
515
+ def test_is_token_expired(self):
516
+ """Test token expiration check."""
517
+ # Create a non-expired result
518
+ non_expired_result = AuthResult(
519
+ is_valid=True,
520
+ status=AuthStatus.SUCCESS,
521
+ username="test_user",
522
+ roles=["user"],
523
+ auth_method="jwt",
524
+ token_expiry=datetime.now(timezone.utc) + timedelta(hours=1),
525
+ )
526
+
527
+ assert self.auth_manager._is_token_expired(non_expired_result) is False
528
+
529
+ # Create an expired result
530
+ expired_result = AuthResult(
531
+ is_valid=True,
532
+ status=AuthStatus.SUCCESS,
533
+ username="test_user",
534
+ roles=["user"],
535
+ auth_method="jwt",
536
+ token_expiry=datetime.now(timezone.utc) - timedelta(hours=1),
537
+ )
538
+
539
+ assert self.auth_manager._is_token_expired(expired_result) is True
540
+
541
+ # Test with no expiration
542
+ no_expiry_result = AuthResult(
543
+ is_valid=True,
544
+ status=AuthStatus.SUCCESS,
545
+ username="test_user",
546
+ roles=["user"],
547
+ auth_method="jwt",
548
+ )
549
+
550
+ assert self.auth_manager._is_token_expired(no_expiry_result) is False
551
+
552
+
553
+ class TestAuthManagerExceptions:
554
+ """Test suite for AuthManager exception classes."""
555
+
556
+ def test_authentication_configuration_error(self):
557
+ """Test AuthenticationConfigurationError."""
558
+ error = AuthenticationConfigurationError("Test error", -32001)
559
+ assert error.message == "Test error"
560
+ assert error.error_code == -32001
561
+ assert str(error) == "Test error"
562
+
563
+ def test_authentication_error(self):
564
+ """Test AuthenticationError."""
565
+ error = AuthenticationError("Auth failed", -32002)
566
+ assert error.message == "Auth failed"
567
+ assert error.error_code == -32002
568
+ assert str(error) == "Auth failed"
569
+
570
+ def test_jwt_validation_error(self):
571
+ """Test JWTValidationError."""
572
+ error = JWTValidationError("JWT invalid", -32003)
573
+ assert error.message == "JWT invalid"
574
+ assert error.error_code == -32003
575
+ assert str(error) == "JWT invalid"
576
+
577
+ def test_certificate_validation_error(self):
578
+ """Test CertificateValidationError."""
579
+ error = CertificateValidationError("Cert invalid", -32004)
580
+ assert error.message == "Cert invalid"
581
+ assert error.error_code == -32004
582
+ assert str(error) == "Cert invalid"