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,502 @@
1
+ """
2
+ Authentication Flow Integration Tests
3
+
4
+ This module contains integration tests for complete authentication and
5
+ authorization flows using the MCP Security Framework. Tests cover API key
6
+ authentication, JWT authentication, role-based access control, and
7
+ permission management.
8
+
9
+ Author: MCP Security Team
10
+ Version: 1.0.0
11
+ License: MIT
12
+ """
13
+
14
+ import json
15
+ import tempfile
16
+ import os
17
+ from unittest.mock import patch, MagicMock
18
+ from typing import Dict, Any
19
+ from datetime import datetime, timedelta
20
+
21
+ import pytest
22
+ import jwt
23
+
24
+ from mcp_security_framework.core.auth_manager import AuthManager
25
+ from mcp_security_framework.core.permission_manager import PermissionManager
26
+ from mcp_security_framework.core.security_manager import SecurityManager, SecurityValidationError
27
+ from mcp_security_framework.schemas.config import (
28
+ SecurityConfig, AuthConfig, PermissionConfig, RateLimitConfig, SSLConfig, CertificateConfig
29
+ )
30
+ from mcp_security_framework.schemas.responses import AuthResult, ValidationResult
31
+
32
+
33
+ class TestAuthFlowIntegration:
34
+ """Integration tests for complete authentication and authorization flows."""
35
+
36
+ def setup_method(self):
37
+ """Set up test fixtures before each test method."""
38
+ # Create temporary roles file
39
+ self.roles_fd, self.roles_path = tempfile.mkstemp(suffix='.json')
40
+ self.roles_config = {
41
+ "roles": {
42
+ "admin": {
43
+ "permissions": ["read", "write", "delete", "admin"],
44
+ "description": "Administrator role",
45
+ "inherits": ["user", "moderator"]
46
+ },
47
+ "user": {
48
+ "permissions": ["read", "write"],
49
+ "description": "Regular user role"
50
+ },
51
+ "readonly": {
52
+ "permissions": ["read"],
53
+ "description": "Read-only user role"
54
+ },
55
+ "moderator": {
56
+ "permissions": ["read", "write", "moderate"],
57
+ "description": "Moderator role",
58
+ "inherits": ["user"]
59
+ }
60
+ }
61
+ }
62
+
63
+ with os.fdopen(self.roles_fd, 'w') as f:
64
+ json.dump(self.roles_config, f)
65
+
66
+ # Create authentication configuration
67
+ self.auth_config = AuthConfig(
68
+ enabled=True,
69
+ methods=["api_key", "jwt"],
70
+ api_keys={
71
+ "admin_key_123456789012345": "admin",
72
+ "user_key_456789012345678": "user",
73
+ "readonly_key_789012345678": "readonly",
74
+ "moderator_key_101234567890": "moderator"
75
+ },
76
+ user_roles={
77
+ "admin": ["admin"],
78
+ "user": ["user"],
79
+ "readonly": ["readonly"],
80
+ "moderator": ["moderator"]
81
+ },
82
+ jwt_secret="test_jwt_secret_key_for_integration_tests",
83
+ jwt_algorithm="HS256",
84
+ jwt_expiry_hours=24
85
+ )
86
+
87
+ # Create permission configuration
88
+ self.permission_config = PermissionConfig(
89
+ enabled=True,
90
+ roles_file=self.roles_path
91
+ )
92
+
93
+ # Create security configuration
94
+ self.security_config = SecurityConfig(
95
+ auth=self.auth_config,
96
+ permissions=self.permission_config,
97
+ rate_limit=RateLimitConfig(enabled=True, default_requests_per_minute=100),
98
+ ssl=SSLConfig(enabled=False),
99
+ certificates=CertificateConfig(enabled=False)
100
+ )
101
+
102
+ # Create security manager
103
+ self.security_manager = SecurityManager(self.security_config)
104
+
105
+ def teardown_method(self):
106
+ """Clean up after each test method."""
107
+ if hasattr(self, 'roles_path') and os.path.exists(self.roles_path):
108
+ os.unlink(self.roles_path)
109
+
110
+ def test_complete_api_key_authentication_flow(self):
111
+ """Test complete API key authentication flow."""
112
+ # Test valid API key authentication
113
+ auth_result = self.security_manager.auth_manager.authenticate_api_key("admin_key_123456789012345")
114
+
115
+ assert auth_result.is_valid is True
116
+ assert auth_result.username == "admin"
117
+ assert "admin" in auth_result.roles
118
+ assert auth_result.auth_method == "api_key"
119
+
120
+ # Test invalid API key
121
+ auth_result = self.security_manager.auth_manager.authenticate_api_key("short")
122
+
123
+ assert auth_result.is_valid is False
124
+ assert auth_result.error_code == -32002
125
+
126
+ # Test missing API key
127
+ auth_result = self.security_manager.auth_manager.authenticate_api_key("")
128
+
129
+ assert auth_result.is_valid is False
130
+ assert auth_result.error_code == -32001
131
+
132
+ def test_complete_jwt_authentication_flow(self):
133
+ """Test complete JWT authentication flow."""
134
+ # Create JWT token
135
+ payload = {
136
+ "username": "admin",
137
+ "roles": ["admin"],
138
+ "exp": datetime.utcnow() + timedelta(hours=24)
139
+ }
140
+
141
+ token = jwt.encode(
142
+ payload,
143
+ self.auth_config.jwt_secret.get_secret_value(),
144
+ algorithm=self.auth_config.jwt_algorithm
145
+ )
146
+
147
+ # Test valid JWT authentication
148
+ auth_result = self.security_manager.authenticate_user({
149
+ "method": "jwt",
150
+ "token": token
151
+ })
152
+
153
+ assert auth_result.is_valid is True
154
+ assert auth_result.username == "admin"
155
+ assert "admin" in auth_result.roles
156
+ assert auth_result.auth_method == "jwt"
157
+
158
+ # Test expired JWT token
159
+ expired_payload = {
160
+ "username": "admin",
161
+ "roles": ["admin"],
162
+ "exp": datetime.utcnow() - timedelta(hours=1)
163
+ }
164
+
165
+ expired_token = jwt.encode(
166
+ expired_payload,
167
+ self.auth_config.jwt_secret.get_secret_value(),
168
+ algorithm=self.auth_config.jwt_algorithm
169
+ )
170
+
171
+ auth_result = self.security_manager.authenticate_user({
172
+ "method": "jwt",
173
+ "token": expired_token
174
+ })
175
+
176
+ assert auth_result.is_valid is False
177
+ assert auth_result.error_code == -32002 # JWT token expired error
178
+
179
+ # Test invalid JWT token
180
+ auth_result = self.security_manager.authenticate_user({
181
+ "method": "jwt",
182
+ "token": "invalid_token"
183
+ })
184
+
185
+ assert auth_result.is_valid is False
186
+ assert auth_result.error_code == -32003 # Invalid JWT token error
187
+
188
+ def test_complete_authorization_flow(self):
189
+ """Test complete authorization flow."""
190
+ # Test admin permissions
191
+ auth_result = self.security_manager.authenticate_user({
192
+ "method": "api_key",
193
+ "api_key": "admin_key_123456789012345"
194
+ })
195
+
196
+ assert auth_result.is_valid is True
197
+
198
+ # Check admin permissions
199
+ perm_result = self.security_manager.check_permissions(
200
+ auth_result.roles,
201
+ ["read", "write", "delete", "admin"]
202
+ )
203
+
204
+ assert perm_result.is_valid is True
205
+ assert set(perm_result.granted_permissions) == {"read", "write", "delete", "admin", "moderate"}
206
+
207
+ # Test user permissions
208
+ auth_result = self.security_manager.auth_manager.authenticate_api_key("user_key_456789012345678")
209
+
210
+ assert auth_result.is_valid is True
211
+
212
+ # Check user permissions
213
+ perm_result = self.security_manager.check_permissions(
214
+ auth_result.roles,
215
+ ["read", "write"]
216
+ )
217
+
218
+ assert perm_result.is_valid is True
219
+ assert set(perm_result.granted_permissions) == {"read", "write"}
220
+
221
+ # Test user denied admin permissions
222
+ perm_result = self.security_manager.check_permissions(
223
+ auth_result.roles,
224
+ ["admin"]
225
+ )
226
+
227
+ assert perm_result.is_valid is False
228
+ assert perm_result.denied_permissions == ["admin"]
229
+
230
+ # Test readonly permissions
231
+ auth_result = self.security_manager.auth_manager.authenticate_api_key("readonly_key_789012345678")
232
+
233
+ assert auth_result.is_valid is True
234
+
235
+ # Check readonly permissions
236
+ perm_result = self.security_manager.check_permissions(
237
+ auth_result.roles,
238
+ ["read"]
239
+ )
240
+
241
+ assert perm_result.is_valid is True
242
+ assert perm_result.granted_permissions == ["read"]
243
+
244
+ # Test readonly denied write permissions
245
+ perm_result = self.security_manager.check_permissions(
246
+ auth_result.roles,
247
+ ["write"]
248
+ )
249
+
250
+ assert perm_result.is_valid is False
251
+ assert perm_result.denied_permissions == ["write"]
252
+
253
+ def test_role_hierarchy_flow(self):
254
+ """Test role hierarchy inheritance flow."""
255
+ # Test admin role (inherits from user and guest)
256
+ auth_result = self.security_manager.auth_manager.authenticate_api_key("admin_key_123456789012345")
257
+
258
+ assert auth_result.is_valid is True
259
+ assert "admin" in auth_result.roles
260
+ # Admin inherits from user and guest through hierarchy
261
+
262
+ # Check inherited permissions (admin has all permissions including moderate from moderator)
263
+ perm_result = self.security_manager.check_permissions(
264
+ auth_result.roles,
265
+ ["read", "write", "moderate", "admin"]
266
+ )
267
+
268
+ assert perm_result.is_valid is True
269
+ assert set(perm_result.granted_permissions) == {"read", "write", "moderate", "admin", "delete"}
270
+ assert "read" in perm_result.granted_permissions
271
+ assert "write" in perm_result.granted_permissions
272
+ assert "moderate" in perm_result.granted_permissions
273
+
274
+ def test_rate_limiting_integration_flow(self):
275
+ """Test rate limiting integration with authentication."""
276
+ # Test rate limiting for authenticated user
277
+ user_identifier = "user_key_456789012345678"
278
+
279
+ # Make multiple requests to trigger rate limiting
280
+ for i in range(105): # Exceed default limit
281
+ rate_limit_result = self.security_manager.check_rate_limit(user_identifier)
282
+
283
+ # Rate limiting should work
284
+ assert isinstance(rate_limit_result, bool)
285
+
286
+ # Test rate limiting reset
287
+ # Note: In real implementation, this would depend on time window
288
+ # For testing, we'll just verify the mechanism works
289
+
290
+ def test_multi_method_authentication_flow(self):
291
+ """Test authentication with multiple methods."""
292
+ # Test API key first, then JWT
293
+ auth_result = self.security_manager.auth_manager.authenticate_api_key("admin_key_123456789012345")
294
+
295
+ # Should use API key (first method)
296
+ assert auth_result.is_valid is True
297
+ assert auth_result.auth_method == "api_key"
298
+
299
+ # Test JWT when API key is invalid
300
+ auth_result = self.security_manager.authenticate_user({
301
+ "method": "api_key",
302
+ "api_key": "invalid_key"
303
+ })
304
+
305
+ # Should fail (both methods invalid)
306
+ assert auth_result.is_valid is False
307
+
308
+ def test_session_management_flow(self):
309
+ """Test session management flow."""
310
+ # Create session for user
311
+ auth_result = self.security_manager.authenticate_user({
312
+ "method": "api_key",
313
+ "api_key": "user_key_456789012345678"
314
+ })
315
+
316
+ assert auth_result.is_valid is True
317
+
318
+ # Simulate session persistence
319
+ session_data = {
320
+ "user_id": auth_result.username,
321
+ "roles": auth_result.roles,
322
+ "permissions": auth_result.permissions,
323
+ "created_at": datetime.utcnow().isoformat()
324
+ }
325
+
326
+ # Verify session data
327
+ assert session_data["user_id"] == "user"
328
+ assert "user" in session_data["roles"]
329
+ assert "read" in session_data["permissions"]
330
+ assert "write" in session_data["permissions"]
331
+
332
+ def test_error_handling_flow(self):
333
+ """Test error handling in authentication flow."""
334
+ # Test with malformed headers
335
+ auth_result = self.security_manager.authenticate_user({
336
+ "method": "api_key",
337
+ "api_key": "" # Empty API key
338
+ })
339
+
340
+ assert auth_result.is_valid is False
341
+ assert auth_result.error_code == -32001
342
+
343
+ # Test with invalid JWT format
344
+ auth_result = self.security_manager.authenticate_user({
345
+ "method": "jwt",
346
+ "token": "InvalidFormat token"
347
+ })
348
+
349
+ assert auth_result.is_valid is False
350
+ assert auth_result.error_code == -32003
351
+
352
+ # Test with unsupported authentication method
353
+ with pytest.raises(SecurityValidationError) as exc_info:
354
+ self.security_manager.authenticate_user({
355
+ "method": "custom",
356
+ "custom_token": "custom_token"
357
+ })
358
+
359
+ assert "Unsupported authentication method: custom" in str(exc_info.value)
360
+
361
+ def test_performance_benchmark_flow(self):
362
+ """Test performance of authentication flow."""
363
+ import time
364
+
365
+ # Benchmark API key authentication
366
+ start_time = time.time()
367
+ for i in range(1000):
368
+ auth_result = self.security_manager.authenticate_user({
369
+ "method": "api_key",
370
+ "api_key": "admin_key_123456789012345"
371
+ })
372
+ assert auth_result.is_valid is True
373
+ end_time = time.time()
374
+
375
+ avg_time = (end_time - start_time) / 1000
376
+ assert avg_time < 0.001, f"API key auth too slow: {avg_time:.6f}s per request"
377
+
378
+ # Benchmark permission checking
379
+ auth_result = self.security_manager.authenticate_user({
380
+ "method": "api_key",
381
+ "api_key": "admin_key_123456789012345"
382
+ })
383
+
384
+ start_time = time.time()
385
+ for i in range(1000):
386
+ perm_result = self.security_manager.check_permissions(
387
+ auth_result.roles,
388
+ ["read", "write", "delete"]
389
+ )
390
+ assert perm_result.is_valid is True
391
+ end_time = time.time()
392
+
393
+ avg_time = (end_time - start_time) / 1000
394
+ assert avg_time < 0.001, f"Permission check too slow: {avg_time:.6f}s per request"
395
+
396
+ def test_security_audit_flow(self):
397
+ """Test security audit flow."""
398
+ # Perform security audit
399
+ audit_result = self.security_manager.perform_security_audit()
400
+
401
+ # Verify audit results
402
+ assert audit_result is not None
403
+ assert "authentication" in audit_result
404
+ assert "authorization" in audit_result
405
+ assert "rate_limiting" in audit_result
406
+
407
+ # Check authentication audit
408
+ auth_audit = audit_result["authentication"]
409
+ assert auth_audit["enabled"] is True
410
+ assert "api_key" in auth_audit["methods"]
411
+ assert "jwt" in auth_audit["methods"]
412
+
413
+ # Check authorization audit
414
+ authz_audit = audit_result["authorization"]
415
+ assert authz_audit["enabled"] is True
416
+ assert authz_audit["roles_count"] >= 4 # admin, user, readonly, moderator
417
+
418
+ # Check rate limiting audit
419
+ rate_audit = audit_result["rate_limiting"]
420
+ assert rate_audit["enabled"] is True
421
+
422
+ def test_configuration_validation_flow(self):
423
+ """Test configuration validation flow."""
424
+ # Test valid configuration
425
+ validation_result = self.security_manager.validate_configuration()
426
+ assert validation_result.is_valid is True
427
+
428
+ # Test with invalid configuration (missing API keys)
429
+ invalid_auth_config = AuthConfig(
430
+ enabled=True,
431
+ methods=["api_key"],
432
+ api_keys={}, # Empty API keys
433
+ jwt_secret="test_secret_long_enough_for_validation"
434
+ )
435
+
436
+ invalid_config = SecurityConfig(
437
+ auth=invalid_auth_config,
438
+ permissions=self.permission_config,
439
+ rate_limit=RateLimitConfig(enabled=True, default_requests_per_minute=100),
440
+ ssl=SSLConfig(enabled=False),
441
+ certificates=CertificateConfig(enabled=False)
442
+ )
443
+
444
+ invalid_manager = SecurityManager(invalid_config)
445
+ validation_result = invalid_manager.validate_configuration()
446
+ assert validation_result.is_valid is False
447
+
448
+ def test_logging_and_monitoring_flow(self):
449
+ """Test logging and monitoring flow."""
450
+ # Perform authentication with logging
451
+ auth_result = self.security_manager.authenticate_user({
452
+ "method": "api_key",
453
+ "api_key": "admin_key_123456789012345"
454
+ })
455
+
456
+ assert auth_result.is_valid is True
457
+
458
+ # Check that logging is configured
459
+ assert hasattr(self.security_manager.auth_manager, 'logger')
460
+ assert self.security_manager.auth_manager.logger is not None
461
+
462
+ assert hasattr(self.security_manager.permission_manager, 'logger')
463
+ assert self.security_manager.permission_manager.logger is not None
464
+
465
+ # Get security metrics
466
+ metrics = self.security_manager.get_security_metrics()
467
+
468
+ assert metrics is not None
469
+ assert "authentication_attempts" in metrics
470
+ assert "successful_authentications" in metrics
471
+ assert "failed_authentications" in metrics
472
+ assert "permission_checks" in metrics
473
+ assert "rate_limit_violations" in metrics
474
+
475
+ def test_integration_with_external_systems_flow(self):
476
+ """Test integration with external systems flow."""
477
+ # Test with external user store (mocked)
478
+ with patch('mcp_security_framework.core.auth_manager.AuthManager._validate_external_user') as mock_validate:
479
+ mock_validate.return_value = True
480
+
481
+ auth_result = self.security_manager.authenticate_user({
482
+ "method": "api_key",
483
+ "api_key": "external_user_key"
484
+ })
485
+
486
+ # Should handle external authentication gracefully
487
+ assert auth_result.is_valid is False # Key not in config
488
+ assert auth_result.error_code == -32003
489
+
490
+ # Test with external permission store (mocked)
491
+ with patch('mcp_security_framework.core.permission_manager.PermissionManager._load_external_permissions') as mock_load:
492
+ mock_load.return_value = {"external_role": {"permissions": ["external_perm"]}}
493
+
494
+ # Should integrate with external permission systems
495
+ perm_result = self.security_manager.check_permissions(
496
+ ["external_role"],
497
+ ["external_perm"]
498
+ )
499
+
500
+ # In this case, external permissions would be loaded
501
+ # but the test role doesn't exist in our config
502
+ assert perm_result.is_valid is False