mcp-security-framework 0.1.0__py3-none-any.whl → 1.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. mcp_security_framework/__init__.py +26 -15
  2. mcp_security_framework/cli/__init__.py +1 -1
  3. mcp_security_framework/cli/cert_cli.py +233 -197
  4. mcp_security_framework/cli/security_cli.py +324 -234
  5. mcp_security_framework/constants.py +21 -27
  6. mcp_security_framework/core/auth_manager.py +49 -20
  7. mcp_security_framework/core/cert_manager.py +398 -104
  8. mcp_security_framework/core/permission_manager.py +13 -9
  9. mcp_security_framework/core/rate_limiter.py +10 -0
  10. mcp_security_framework/core/security_manager.py +286 -229
  11. mcp_security_framework/examples/__init__.py +6 -0
  12. mcp_security_framework/examples/comprehensive_example.py +954 -0
  13. mcp_security_framework/examples/django_example.py +276 -202
  14. mcp_security_framework/examples/fastapi_example.py +897 -393
  15. mcp_security_framework/examples/flask_example.py +311 -200
  16. mcp_security_framework/examples/gateway_example.py +373 -214
  17. mcp_security_framework/examples/microservice_example.py +337 -172
  18. mcp_security_framework/examples/standalone_example.py +719 -478
  19. mcp_security_framework/examples/test_all_examples.py +572 -0
  20. mcp_security_framework/middleware/__init__.py +46 -55
  21. mcp_security_framework/middleware/auth_middleware.py +62 -63
  22. mcp_security_framework/middleware/fastapi_auth_middleware.py +179 -110
  23. mcp_security_framework/middleware/fastapi_middleware.py +156 -148
  24. mcp_security_framework/middleware/flask_auth_middleware.py +267 -107
  25. mcp_security_framework/middleware/flask_middleware.py +183 -157
  26. mcp_security_framework/middleware/mtls_middleware.py +106 -117
  27. mcp_security_framework/middleware/rate_limit_middleware.py +105 -101
  28. mcp_security_framework/middleware/security_middleware.py +109 -124
  29. mcp_security_framework/schemas/config.py +2 -1
  30. mcp_security_framework/schemas/models.py +19 -6
  31. mcp_security_framework/utils/cert_utils.py +14 -8
  32. mcp_security_framework/utils/datetime_compat.py +116 -0
  33. {mcp_security_framework-0.1.0.dist-info → mcp_security_framework-1.1.1.dist-info}/METADATA +2 -1
  34. mcp_security_framework-1.1.1.dist-info/RECORD +84 -0
  35. tests/conftest.py +303 -0
  36. tests/test_cli/test_cert_cli.py +194 -174
  37. tests/test_cli/test_security_cli.py +274 -247
  38. tests/test_core/test_cert_manager.py +33 -19
  39. tests/test_core/test_security_manager.py +2 -2
  40. tests/test_examples/test_comprehensive_example.py +613 -0
  41. tests/test_examples/test_fastapi_example.py +290 -169
  42. tests/test_examples/test_flask_example.py +304 -162
  43. tests/test_examples/test_standalone_example.py +106 -168
  44. tests/test_integration/test_auth_flow.py +214 -198
  45. tests/test_integration/test_certificate_flow.py +181 -150
  46. tests/test_integration/test_fastapi_integration.py +140 -149
  47. tests/test_integration/test_flask_integration.py +144 -141
  48. tests/test_integration/test_standalone_integration.py +331 -300
  49. tests/test_middleware/test_fastapi_auth_middleware.py +745 -0
  50. tests/test_middleware/test_fastapi_middleware.py +147 -132
  51. tests/test_middleware/test_flask_auth_middleware.py +696 -0
  52. tests/test_middleware/test_flask_middleware.py +201 -179
  53. tests/test_middleware/test_security_middleware.py +151 -130
  54. tests/test_utils/test_datetime_compat.py +147 -0
  55. mcp_security_framework-0.1.0.dist-info/RECORD +0 -76
  56. {mcp_security_framework-0.1.0.dist-info → mcp_security_framework-1.1.1.dist-info}/WHEEL +0 -0
  57. {mcp_security_framework-0.1.0.dist-info → mcp_security_framework-1.1.1.dist-info}/entry_points.txt +0 -0
  58. {mcp_security_framework-0.1.0.dist-info → mcp_security_framework-1.1.1.dist-info}/top_level.txt +0 -0
@@ -62,16 +62,17 @@ HTTP_NOT_FOUND = 404
62
62
  HTTP_TOO_MANY_REQUESTS = 429
63
63
  HTTP_INTERNAL_SERVER_ERROR = 500
64
64
 
65
+
65
66
  # Error Codes
66
67
  class ErrorCodes:
67
68
  """Error codes for the MCP Security Framework."""
68
-
69
+
69
70
  # SSL/TLS Errors (-32001 to -32009)
70
71
  SSL_CONFIGURATION_ERROR = -32001
71
72
  CERTIFICATE_VALIDATION_ERROR = -32002
72
73
  SSL_CONTEXT_CREATION_ERROR = -32003
73
74
  SSL_HANDSHAKE_ERROR = -32004
74
-
75
+
75
76
  # Authentication Errors (-32010 to -32019)
76
77
  AUTHENTICATION_ERROR = -32010
77
78
  AUTHENTICATION_CONFIGURATION_ERROR = -32011
@@ -80,46 +81,47 @@ class ErrorCodes:
80
81
  CERTIFICATE_AUTH_ERROR = -32014
81
82
  BASIC_AUTH_ERROR = -32015
82
83
  AUTH_METHOD_NOT_SUPPORTED = -32016
83
-
84
+
84
85
  # Authorization Errors (-32020 to -32029)
85
86
  PERMISSION_DENIED_ERROR = -32020
86
87
  INSUFFICIENT_PERMISSIONS = -32021
87
88
  ROLE_NOT_FOUND = -32022
88
89
  PERMISSION_NOT_FOUND = -32023
89
-
90
+
90
91
  # Rate Limiting Errors (-32030 to -32039)
91
92
  RATE_LIMIT_EXCEEDED_ERROR = -32030
92
93
  RATE_LIMIT_CONFIGURATION_ERROR = -32031
93
94
  RATE_LIMIT_STORAGE_ERROR = -32032
94
-
95
+
95
96
  # Middleware Errors (-32040 to -32049)
96
97
  SECURITY_MIDDLEWARE_ERROR = -32040
97
98
  AUTH_MIDDLEWARE_ERROR = -32041
98
99
  MTLS_MIDDLEWARE_ERROR = -32042
99
100
  RATE_LIMIT_MIDDLEWARE_ERROR = -32043
100
-
101
+
101
102
  # Certificate Management Errors (-32050 to -32059)
102
103
  CERTIFICATE_GENERATION_ERROR = -32050
103
104
  CERTIFICATE_REVOCATION_ERROR = -32051
104
105
  CERTIFICATE_STORAGE_ERROR = -32052
105
106
  CA_CONFIGURATION_ERROR = -32053
106
-
107
+
107
108
  # Crypto Errors (-32060 to -32069)
108
109
  CRYPTO_ERROR = -32060
109
110
  KEY_GENERATION_ERROR = -32061
110
111
  HASHING_ERROR = -32062
111
112
  ENCRYPTION_ERROR = -32063
112
-
113
+
113
114
  # Configuration Errors (-32070 to -32079)
114
115
  CONFIGURATION_ERROR = -32070
115
116
  VALIDATION_ERROR = -32071
116
117
  SERIALIZATION_ERROR = -32072
117
-
118
+
118
119
  # General Errors (-32080 to -32099)
119
120
  GENERAL_ERROR = -32080
120
121
  NOT_IMPLEMENTED_ERROR = -32081
121
122
  UNSUPPORTED_OPERATION_ERROR = -32082
122
123
 
124
+
123
125
  # Security Headers
124
126
  DEFAULT_SECURITY_HEADERS = {
125
127
  "X-Content-Type-Options": "nosniff",
@@ -127,7 +129,7 @@ DEFAULT_SECURITY_HEADERS = {
127
129
  "X-XSS-Protection": "1; mode=block",
128
130
  "Strict-Transport-Security": "max-age=31536000; includeSubDomains",
129
131
  "Content-Security-Policy": "default-src 'self'",
130
- "Referrer-Policy": "strict-origin-when-cross-origin"
132
+ "Referrer-Policy": "strict-origin-when-cross-origin",
131
133
  }
132
134
 
133
135
  # Authentication Methods
@@ -136,29 +138,21 @@ AUTH_METHODS = {
136
138
  "JWT": "jwt",
137
139
  "CERTIFICATE": "certificate",
138
140
  "BASIC": "basic",
139
- "OAUTH2": "oauth2"
141
+ "OAUTH2": "oauth2",
140
142
  }
141
143
 
142
144
  # Storage Backends
143
- STORAGE_BACKENDS = {
144
- "MEMORY": "memory",
145
- "REDIS": "redis",
146
- "DATABASE": "database"
147
- }
145
+ STORAGE_BACKENDS = {"MEMORY": "memory", "REDIS": "redis", "DATABASE": "database"}
148
146
 
149
147
  # Hash Algorithms
150
- HASH_ALGORITHMS = {
151
- "SHA256": "sha256",
152
- "SHA512": "sha512",
153
- "MD5": "md5"
154
- }
148
+ HASH_ALGORITHMS = {"SHA256": "sha256", "SHA512": "sha512", "MD5": "md5"}
155
149
 
156
150
  # TLS Versions
157
151
  TLS_VERSIONS = {
158
152
  "TLSv1.0": "TLSv1.0",
159
153
  "TLSv1.1": "TLSv1.1",
160
154
  "TLSv1.2": "TLSv1.2",
161
- "TLSv1.3": "TLSv1.3"
155
+ "TLSv1.3": "TLSv1.3",
162
156
  }
163
157
 
164
158
  # Certificate Revocation Reasons
@@ -169,7 +163,7 @@ CERTIFICATE_REVOCATION_REASONS = {
169
163
  "AFFILIATION_CHANGED": "affiliation_changed",
170
164
  "SUPERSEDED": "superseded",
171
165
  "CESSATION_OF_OPERATION": "cessation_of_operation",
172
- "CERTIFICATE_HOLD": "certificate_hold"
166
+ "CERTIFICATE_HOLD": "certificate_hold",
173
167
  }
174
168
 
175
169
  # Log Levels
@@ -178,7 +172,7 @@ LOG_LEVELS = {
178
172
  "INFO": "INFO",
179
173
  "WARNING": "WARNING",
180
174
  "ERROR": "ERROR",
181
- "CRITICAL": "CRITICAL"
175
+ "CRITICAL": "CRITICAL",
182
176
  }
183
177
 
184
178
  # Time Constants (in seconds)
@@ -188,7 +182,7 @@ TIME_CONSTANTS = {
188
182
  "DAY": 86400,
189
183
  "WEEK": 604800,
190
184
  "MONTH": 2592000, # 30 days
191
- "YEAR": 31536000 # 365 days
185
+ "YEAR": 31536000, # 365 days
192
186
  }
193
187
 
194
188
  # Cache Keys
@@ -196,7 +190,7 @@ CACHE_KEY_PREFIXES = {
196
190
  "AUTH": "auth",
197
191
  "RATE_LIMIT": "rate_limit",
198
192
  "PERMISSION": "permission",
199
- "CERTIFICATE": "certificate"
193
+ "CERTIFICATE": "certificate",
200
194
  }
201
195
 
202
196
  # Environment Variables
@@ -205,5 +199,5 @@ ENV_VARS = {
205
199
  "DEFAULT_SERVER_HOST": "DEFAULT_SERVER_HOST",
206
200
  "DEFAULT_SERVER_PORT": "DEFAULT_SERVER_PORT",
207
201
  "LOG_LEVEL": "LOG_LEVEL",
208
- "ENVIRONMENT": "ENVIRONMENT"
202
+ "ENVIRONMENT": "ENVIRONMENT",
209
203
  }
@@ -26,7 +26,7 @@ License: MIT
26
26
  import logging
27
27
  import time
28
28
  from datetime import datetime, timedelta, timezone
29
- from typing import Dict, List, Optional, Union, Any
29
+ from typing import Any, Dict, List, Optional, Union
30
30
 
31
31
  import jwt
32
32
  from cryptography import x509
@@ -47,6 +47,9 @@ from ..utils.crypto_utils import (
47
47
  validate_api_key_format,
48
48
  verify_password,
49
49
  )
50
+ from ..utils.datetime_compat import (
51
+ get_not_valid_after_utc,
52
+ )
50
53
 
51
54
 
52
55
  class AuthManager:
@@ -136,7 +139,9 @@ class AuthManager:
136
139
  self._api_keys[username] = key
137
140
  self._api_key_metadata[key] = value
138
141
  else:
139
- self.logger.warning(f"Invalid API key format for key {key}: {value}")
142
+ self.logger.warning(
143
+ f"Invalid API key format for key {key}: {value}"
144
+ )
140
145
  else:
141
146
  self._api_keys = {}
142
147
  self._api_key_metadata = {}
@@ -160,6 +165,16 @@ class AuthManager:
160
165
  },
161
166
  )
162
167
 
168
+ @property
169
+ def is_auth_enabled(self) -> bool:
170
+ """
171
+ Check if authentication is enabled.
172
+
173
+ Returns:
174
+ bool: True if authentication is enabled, False otherwise
175
+ """
176
+ return self.config.enabled
177
+
163
178
  def authenticate_api_key(self, api_key: str) -> AuthResult:
164
179
  """
165
180
  Authenticate user using API key.
@@ -277,16 +292,24 @@ class AuthManager:
277
292
  user_permissions = set()
278
293
  if self.permission_manager:
279
294
  try:
280
- permissions_result = self.permission_manager.get_effective_permissions(user_roles)
295
+ permissions_result = (
296
+ self.permission_manager.get_effective_permissions(user_roles)
297
+ )
281
298
  # Handle both set and mock objects
282
- if hasattr(permissions_result, '__iter__') and not isinstance(permissions_result, str):
299
+ if hasattr(permissions_result, "__iter__") and not isinstance(
300
+ permissions_result, str
301
+ ):
283
302
  user_permissions = set(permissions_result)
284
303
  else:
285
304
  user_permissions = set()
286
305
  except Exception as e:
287
306
  self.logger.warning(
288
307
  "Failed to get user permissions",
289
- extra={"username": username, "roles": user_roles, "error": str(e)},
308
+ extra={
309
+ "username": username,
310
+ "roles": user_roles,
311
+ "error": str(e),
312
+ },
290
313
  )
291
314
 
292
315
  # Create successful authentication result
@@ -448,9 +471,13 @@ class AuthManager:
448
471
  user_permissions = set()
449
472
  if self.permission_manager:
450
473
  try:
451
- permissions_result = self.permission_manager.get_effective_permissions(roles)
474
+ permissions_result = (
475
+ self.permission_manager.get_effective_permissions(roles)
476
+ )
452
477
  # Handle both set and mock objects
453
- if hasattr(permissions_result, '__iter__') and not isinstance(permissions_result, str):
478
+ if hasattr(permissions_result, "__iter__") and not isinstance(
479
+ permissions_result, str
480
+ ):
454
481
  user_permissions = set(permissions_result)
455
482
  else:
456
483
  user_permissions = set()
@@ -568,7 +595,7 @@ class AuthManager:
568
595
 
569
596
  # Check certificate expiration
570
597
  now = datetime.now(timezone.utc)
571
- if cert.not_valid_after.replace(tzinfo=timezone.utc) < now:
598
+ if get_not_valid_after_utc(cert) < now:
572
599
  return AuthResult(
573
600
  is_valid=False,
574
601
  status=AuthStatus.EXPIRED,
@@ -626,7 +653,7 @@ class AuthManager:
626
653
  roles=roles,
627
654
  auth_method="certificate",
628
655
  auth_timestamp=datetime.now(timezone.utc),
629
- token_expiry=cert.not_valid_after.replace(tzinfo=timezone.utc),
656
+ token_expiry=get_not_valid_after_utc(cert),
630
657
  )
631
658
 
632
659
  self.logger.info(
@@ -896,37 +923,39 @@ class AuthManager:
896
923
  def _get_user_roles(self, username: str) -> List[str]:
897
924
  """
898
925
  Get user roles from configuration.
899
-
926
+
900
927
  This method retrieves user roles from the authentication configuration.
901
928
  It checks both the user_roles mapping and the permission manager.
902
-
929
+
903
930
  Args:
904
931
  username (str): Username to get roles for
905
-
932
+
906
933
  Returns:
907
934
  List[str]: List of user roles
908
935
  """
909
936
  # Check user_roles mapping first
910
937
  if self.config.user_roles and username in self.config.user_roles:
911
938
  return self.config.user_roles[username]
912
-
939
+
913
940
  # Fallback to permission manager
914
941
  if self.permission_manager:
915
942
  return self.permission_manager.get_user_roles(username)
916
-
943
+
917
944
  return []
918
945
 
919
- def _validate_external_user(self, username: str, credentials: Dict[str, Any]) -> bool:
946
+ def _validate_external_user(
947
+ self, username: str, credentials: Dict[str, Any]
948
+ ) -> bool:
920
949
  """
921
950
  Validate user against external authentication system.
922
-
951
+
923
952
  This method provides a hook for integrating with external
924
953
  authentication systems (LDAP, Active Directory, etc.).
925
-
954
+
926
955
  Args:
927
956
  username (str): Username to validate
928
957
  credentials (Dict[str, Any]): User credentials
929
-
958
+
930
959
  Returns:
931
960
  bool: True if user is valid in external system
932
961
  """
@@ -934,9 +963,9 @@ class AuthManager:
934
963
  # In a real implementation, this would connect to external auth systems
935
964
  self.logger.debug(
936
965
  "External user validation called",
937
- extra={"username": username, "method": "external"}
966
+ extra={"username": username, "method": "external"},
938
967
  )
939
-
968
+
940
969
  # For now, return False to indicate external validation not implemented
941
970
  return False
942
971