mcp-security-framework 1.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 +41 -22
  7. mcp_security_framework/core/cert_manager.py +210 -147
  8. mcp_security_framework/core/permission_manager.py +9 -9
  9. mcp_security_framework/core/rate_limiter.py +2 -2
  10. mcp_security_framework/core/security_manager.py +284 -229
  11. mcp_security_framework/examples/__init__.py +6 -0
  12. mcp_security_framework/examples/comprehensive_example.py +349 -279
  13. mcp_security_framework/examples/django_example.py +247 -206
  14. mcp_security_framework/examples/fastapi_example.py +315 -283
  15. mcp_security_framework/examples/flask_example.py +274 -203
  16. mcp_security_framework/examples/gateway_example.py +304 -237
  17. mcp_security_framework/examples/microservice_example.py +258 -189
  18. mcp_security_framework/examples/standalone_example.py +255 -230
  19. mcp_security_framework/examples/test_all_examples.py +151 -135
  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 +119 -118
  23. mcp_security_framework/middleware/fastapi_middleware.py +156 -148
  24. mcp_security_framework/middleware/flask_auth_middleware.py +160 -147
  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 +18 -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-1.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 +63 -66
  36. tests/test_cli/test_cert_cli.py +184 -146
  37. tests/test_cli/test_security_cli.py +274 -247
  38. tests/test_core/test_cert_manager.py +24 -10
  39. tests/test_core/test_security_manager.py +2 -2
  40. tests/test_examples/test_comprehensive_example.py +190 -137
  41. tests/test_examples/test_fastapi_example.py +124 -101
  42. tests/test_examples/test_flask_example.py +124 -101
  43. tests/test_examples/test_standalone_example.py +73 -80
  44. tests/test_integration/test_auth_flow.py +213 -197
  45. tests/test_integration/test_certificate_flow.py +180 -149
  46. tests/test_integration/test_fastapi_integration.py +108 -111
  47. tests/test_integration/test_flask_integration.py +141 -140
  48. tests/test_integration/test_standalone_integration.py +290 -259
  49. tests/test_middleware/test_fastapi_auth_middleware.py +195 -174
  50. tests/test_middleware/test_fastapi_middleware.py +147 -132
  51. tests/test_middleware/test_flask_auth_middleware.py +260 -202
  52. tests/test_middleware/test_flask_middleware.py +201 -179
  53. tests/test_middleware/test_security_middleware.py +145 -130
  54. tests/test_utils/test_datetime_compat.py +147 -0
  55. mcp_security_framework-1.1.0.dist-info/RECORD +0 -82
  56. {mcp_security_framework-1.1.0.dist-info → mcp_security_framework-1.1.1.dist-info}/WHEEL +0 -0
  57. {mcp_security_framework-1.1.0.dist-info → mcp_security_framework-1.1.1.dist-info}/entry_points.txt +0 -0
  58. {mcp_security_framework-1.1.0.dist-info → mcp_security_framework-1.1.1.dist-info}/top_level.txt +0 -0
@@ -11,24 +11,29 @@ License: MIT
11
11
  """
12
12
 
13
13
  import json
14
- import tempfile
15
14
  import os
16
- from unittest.mock import patch, MagicMock
17
- from typing import Dict, Any
15
+ import tempfile
16
+ from typing import Any, Dict
17
+ from unittest.mock import MagicMock, patch
18
18
 
19
19
  import pytest
20
20
  from cryptography import x509
21
21
  from cryptography.hazmat.primitives import hashes, serialization
22
22
  from cryptography.hazmat.primitives.asymmetric import rsa
23
23
 
24
- from mcp_security_framework.examples.standalone_example import StandaloneSecurityExample
25
24
  from mcp_security_framework.core.security_manager import SecurityManager
26
- from mcp_security_framework.schemas.config import SecurityConfig, AuthConfig, RateLimitConfig, SSLConfig
25
+ from mcp_security_framework.examples.standalone_example import StandaloneSecurityExample
26
+ from mcp_security_framework.schemas.config import (
27
+ AuthConfig,
28
+ RateLimitConfig,
29
+ SecurityConfig,
30
+ SSLConfig,
31
+ )
27
32
 
28
33
 
29
34
  class TestStandaloneIntegration:
30
35
  """Integration tests for standalone applications with security framework."""
31
-
36
+
32
37
  def setup_method(self):
33
38
  """Set up test fixtures before each test method."""
34
39
  # Create temporary configuration
@@ -39,352 +44,371 @@ class TestStandaloneIntegration:
39
44
  "api_keys": {
40
45
  "admin_key_123": {"username": "admin", "roles": ["admin", "user"]},
41
46
  "user_key_456": {"username": "user", "roles": ["user"]},
42
- "readonly_key_789": {"username": "readonly", "roles": ["readonly"]}
43
- }
44
- },
45
- "rate_limit": {
46
- "enabled": True,
47
- "default_requests_per_minute": 100
48
- },
49
- "ssl": {
50
- "enabled": False
51
- },
52
- "permissions": {
53
- "enabled": True,
54
- "roles_file": "test_roles.json"
55
- },
56
- "certificates": {
57
- "enabled": False
47
+ "readonly_key_789": {"username": "readonly", "roles": ["readonly"]},
48
+ },
58
49
  },
59
- "logging": {
60
- "level": "INFO",
61
- "format": "standard"
62
- }
50
+ "rate_limit": {"enabled": True, "default_requests_per_minute": 100},
51
+ "ssl": {"enabled": False},
52
+ "permissions": {"enabled": True, "roles_file": "test_roles.json"},
53
+ "certificates": {"enabled": False},
54
+ "logging": {"level": "INFO", "format": "standard"},
63
55
  }
64
-
56
+
65
57
  # Create temporary config file
66
- self.config_fd, self.config_path = tempfile.mkstemp(suffix='.json')
67
- with os.fdopen(self.config_fd, 'w') as f:
58
+ self.config_fd, self.config_path = tempfile.mkstemp(suffix=".json")
59
+ with os.fdopen(self.config_fd, "w") as f:
68
60
  json.dump(self.test_config, f)
69
-
61
+
70
62
  # Create temporary roles file
71
63
  self.roles_config = {
72
64
  "roles": {
73
65
  "admin": {
74
- "permissions": ["read:own", "write:own", "delete:own", "admin", "*"],
75
- "description": "Administrator role"
66
+ "permissions": ["read", "write", "delete", "admin", "*"],
67
+ "description": "Administrator role",
76
68
  },
77
69
  "user": {
78
- "permissions": ["read:own", "write:own"],
79
- "description": "Regular user role"
70
+ "permissions": ["read", "write"],
71
+ "description": "Regular user role",
80
72
  },
81
73
  "readonly": {
82
- "permissions": ["read:own"],
83
- "description": "Read-only user role"
84
- }
74
+ "permissions": ["read"],
75
+ "description": "Read-only user role",
76
+ },
85
77
  }
86
78
  }
87
-
88
- self.roles_fd, self.roles_path = tempfile.mkstemp(suffix='.json')
89
- with os.fdopen(self.roles_fd, 'w') as f:
79
+
80
+ self.roles_fd, self.roles_path = tempfile.mkstemp(suffix=".json")
81
+ with os.fdopen(self.roles_fd, "w") as f:
90
82
  json.dump(self.roles_config, f)
91
-
83
+
92
84
  # Update config to use roles file
93
85
  self.test_config["permissions"]["roles_file"] = self.roles_path
94
-
86
+
95
87
  # Recreate config file with updated roles path
96
- with open(self.config_path, 'w') as f:
88
+ with open(self.config_path, "w") as f:
97
89
  json.dump(self.test_config, f)
98
-
90
+
99
91
  def teardown_method(self):
100
92
  """Clean up after each test method."""
101
93
  # Remove temporary files
102
- if hasattr(self, 'config_path') and os.path.exists(self.config_path):
94
+ if hasattr(self, "config_path") and os.path.exists(self.config_path):
103
95
  os.unlink(self.config_path)
104
- if hasattr(self, 'roles_path') and os.path.exists(self.roles_path):
96
+ if hasattr(self, "roles_path") and os.path.exists(self.roles_path):
105
97
  os.unlink(self.roles_path)
106
-
98
+
107
99
  def test_standalone_full_integration(self):
108
100
  """Test complete standalone integration with security framework."""
109
101
  # Create standalone example
110
102
  example = StandaloneSecurityExample(config_path=self.config_path)
111
-
103
+
112
104
  # Test that security manager is configured
113
105
  assert example.security_manager is not None
114
106
  assert isinstance(example.security_manager, SecurityManager)
115
-
107
+
116
108
  # Test that configuration is loaded
117
109
  assert example.config is not None
118
110
  assert example.config.auth.enabled is True
119
111
  assert example.config.rate_limit.enabled is True
120
-
112
+
121
113
  def test_standalone_authentication_flow(self):
122
114
  """Test complete authentication flow in standalone application."""
123
115
  example = StandaloneSecurityExample(config_path=self.config_path)
124
-
116
+
125
117
  # Test unauthenticated request
126
- result = example.process_request({
127
- "credentials": {},
128
- "action": "read",
129
- "resource": "/api/v1/users/me",
130
- "identifier": "test_client"
131
- })
118
+ result = example.process_request(
119
+ {
120
+ "credentials": {},
121
+ "action": "read",
122
+ "resource": "/api/v1/users/me",
123
+ "identifier": "test_client",
124
+ }
125
+ )
132
126
  assert "error" in result
133
127
  assert "authentication" in result["error"].lower()
134
-
128
+
135
129
  # Test authenticated request with valid API key
136
- result = example.process_request({
137
- "credentials": {"api_key": "admin_key_123"},
138
- "action": "read",
139
- "resource": "/api/v1/users/me",
140
- "identifier": "test_client"
141
- })
130
+ result = example.process_request(
131
+ {
132
+ "credentials": {"api_key": "admin_key_123"},
133
+ "action": "read",
134
+ "resource": "/api/v1/users/me",
135
+ "identifier": "test_client",
136
+ }
137
+ )
142
138
  assert result["success"] is True
143
139
  assert result["auth_result"]["username"] == "admin"
144
-
140
+
145
141
  # Test authenticated request with different user
146
- result = example.process_request({
147
- "credentials": {"api_key": "user_key_456"},
148
- "action": "read",
149
- "resource": "/api/v1/users/me",
150
- "identifier": "test_client"
151
- })
142
+ result = example.process_request(
143
+ {
144
+ "credentials": {"api_key": "user_key_456"},
145
+ "action": "read",
146
+ "resource": "/api/v1/users/me",
147
+ "identifier": "test_client",
148
+ }
149
+ )
152
150
  assert result["success"] is True
153
151
  assert result["auth_result"]["username"] == "user"
154
-
152
+
155
153
  def test_standalone_authorization_flow(self):
156
154
  """Test complete authorization flow in standalone application."""
157
155
  example = StandaloneSecurityExample(config_path=self.config_path)
158
-
156
+
159
157
  # Test admin access to admin-only operation
160
- result = example.process_request({
161
- "credentials": {"api_key": "admin_key_123"},
162
- "action": "read",
163
- "resource": "/api/v1/admin/users",
164
- "identifier": "test_client"
165
- })
158
+ result = example.process_request(
159
+ {
160
+ "credentials": {"api_key": "admin_key_123"},
161
+ "action": "read",
162
+ "resource": "/api/v1/admin/users",
163
+ "identifier": "test_client",
164
+ }
165
+ )
166
166
  assert result["success"] is True
167
167
  assert result["auth_result"]["username"] == "admin"
168
-
168
+
169
169
  # Test regular user access to admin-only operation (should be denied)
170
- result = example.process_request({
171
- "credentials": {"api_key": "user_key_456"},
172
- "action": "read",
173
- "resource": "/api/v1/admin/users",
174
- "identifier": "test_client"
175
- })
170
+ result = example.process_request(
171
+ {
172
+ "credentials": {"api_key": "user_key_456"},
173
+ "action": "read",
174
+ "resource": "/api/v1/admin/users",
175
+ "identifier": "test_client",
176
+ }
177
+ )
176
178
  # Check that request is processed
177
179
  assert isinstance(result, dict)
178
180
  assert "success" in result
179
-
181
+
180
182
  # Test readonly user access to write operation (should be denied)
181
- result = example.process_request({
182
- "credentials": {"api_key": "readonly_key_789"},
183
- "action": "write",
184
- "resource": "/api/v1/data",
185
- "data": {"name": "test", "value": "test_value"},
186
- "identifier": "test_client"
187
- })
183
+ result = example.process_request(
184
+ {
185
+ "credentials": {"api_key": "readonly_key_789"},
186
+ "action": "write",
187
+ "resource": "/api/v1/data",
188
+ "data": {"name": "test", "value": "test_value"},
189
+ "identifier": "test_client",
190
+ }
191
+ )
188
192
  # Check that request is processed
189
193
  assert isinstance(result, dict)
190
194
  assert "success" in result
191
-
195
+
192
196
  def test_standalone_rate_limiting(self):
193
197
  """Test rate limiting in standalone application."""
194
198
  example = StandaloneSecurityExample(config_path=self.config_path)
195
-
199
+
196
200
  # Make multiple requests to trigger rate limiting
197
201
  results = []
198
202
  for i in range(105): # Exceed the 100 requests per minute limit
199
- result = example.process_request({
200
- "credentials": {"api_key": "user_key_456"},
201
- "action": "read",
202
- "resource": "/api/v1/users/me",
203
- "identifier": "test_client"
204
- })
203
+ result = example.process_request(
204
+ {
205
+ "credentials": {"api_key": "user_key_456"},
206
+ "action": "read",
207
+ "resource": "/api/v1/users/me",
208
+ "identifier": "test_client",
209
+ }
210
+ )
205
211
  results.append(result)
206
-
212
+
207
213
  # Check that rate limiting is working (requests are processed)
208
- processed_requests = sum(1 for result in results if result.get("success") is True)
214
+ processed_requests = sum(
215
+ 1 for result in results if result.get("success") is True
216
+ )
209
217
  assert processed_requests > 0, "Some requests should be processed successfully"
210
-
218
+
211
219
  def test_standalone_ssl_integration(self):
212
220
  """Test SSL/TLS integration in standalone application."""
213
221
  # Create config with SSL enabled
214
222
  ssl_config = self.test_config.copy()
215
- ssl_config["ssl"] = {
216
- "enabled": False # Disable SSL for testing
217
- }
218
-
223
+ ssl_config["ssl"] = {"enabled": False} # Disable SSL for testing
224
+
219
225
  # Create temporary SSL config file
220
- ssl_config_fd, ssl_config_path = tempfile.mkstemp(suffix='.json')
221
- with os.fdopen(ssl_config_fd, 'w') as f:
226
+ ssl_config_fd, ssl_config_path = tempfile.mkstemp(suffix=".json")
227
+ with os.fdopen(ssl_config_fd, "w") as f:
222
228
  json.dump(ssl_config, f)
223
-
229
+
224
230
  try:
225
231
  # Mock SSL context creation to avoid file requirements
226
- with patch('mcp_security_framework.core.ssl_manager.SSLManager.create_server_context') as mock_ssl:
232
+ with patch(
233
+ "mcp_security_framework.core.ssl_manager.SSLManager.create_server_context"
234
+ ) as mock_ssl:
227
235
  mock_ssl.return_value = MagicMock()
228
-
236
+
229
237
  example = StandaloneSecurityExample(config_path=ssl_config_path)
230
-
238
+
231
239
  # Test that SSL is configured
232
240
  assert example.config.ssl.enabled is False # SSL disabled for testing
233
-
241
+
234
242
  finally:
235
243
  os.unlink(ssl_config_path)
236
-
244
+
237
245
  def test_standalone_error_handling(self):
238
246
  """Test error handling in standalone application."""
239
247
  example = StandaloneSecurityExample(config_path=self.config_path)
240
-
248
+
241
249
  # Test invalid API key
242
- result = example.process_request({
243
- "credentials": {"api_key": "invalid_key"},
244
- "action": "read",
245
- "resource": "/api/v1/users/me",
246
- "identifier": "test_client"
247
- })
250
+ result = example.process_request(
251
+ {
252
+ "credentials": {"api_key": "invalid_key"},
253
+ "action": "read",
254
+ "resource": "/api/v1/users/me",
255
+ "identifier": "test_client",
256
+ }
257
+ )
248
258
  assert "error" in result
249
259
  assert "authentication" in result["error"].lower()
250
-
260
+
251
261
  # Test malformed request
252
- result = example.process_request({
253
- "credentials": {"api_key": "admin_key_123456789012345"},
254
- "action": "write",
255
- "resource": "/api/v1/data",
256
- "data": {"invalid": "data"},
257
- "identifier": "test_client"
258
- })
262
+ result = example.process_request(
263
+ {
264
+ "credentials": {"api_key": "admin_key_123456789012345"},
265
+ "action": "write",
266
+ "resource": "/api/v1/data",
267
+ "data": {"invalid": "data"},
268
+ "identifier": "test_client",
269
+ }
270
+ )
259
271
  assert "error" in result
260
-
272
+
261
273
  def test_standalone_data_operations(self):
262
274
  """Test data operations with security."""
263
275
  example = StandaloneSecurityExample(config_path=self.config_path)
264
-
276
+
265
277
  # Create data
266
- create_result = example.process_request({
267
- "credentials": {"api_key": "admin_key_123"},
268
- "action": "write",
269
- "resource": "/api/v1/data",
270
- "data": {"name": "test_item", "value": "test_value"},
271
- "identifier": "test_client"
272
- })
278
+ create_result = example.process_request(
279
+ {
280
+ "credentials": {"api_key": "admin_key_123"},
281
+ "action": "write",
282
+ "resource": "/api/v1/data",
283
+ "data": {"name": "test_item", "value": "test_value"},
284
+ "identifier": "test_client",
285
+ }
286
+ )
273
287
  assert create_result["success"] is True
274
288
  # The data is returned in the result
275
289
  assert create_result["data"] == {"name": "test_item", "value": "test_value"}
276
-
290
+
277
291
  # Retrieve data (simulate retrieval since _execute_action doesn't generate IDs)
278
- get_result = example.process_request({
279
- "credentials": {"api_key": "admin_key_123"},
280
- "action": "read",
281
- "resource": "/api/v1/data/test_item",
282
- "identifier": "test_client"
283
- })
292
+ get_result = example.process_request(
293
+ {
294
+ "credentials": {"api_key": "admin_key_123"},
295
+ "action": "read",
296
+ "resource": "/api/v1/data/test_item",
297
+ "identifier": "test_client",
298
+ }
299
+ )
284
300
  assert get_result["success"] is True
285
301
  # The result contains the request information
286
302
  assert get_result["resource"] == "/api/v1/data/test_item"
287
-
303
+
288
304
  def test_standalone_configuration_validation(self):
289
305
  """Test configuration validation in standalone application."""
290
306
  # Test with invalid configuration
291
- invalid_config = {
292
- "auth": {
293
- "enabled": True,
294
- "methods": ["invalid_method"]
295
- }
296
- }
297
-
298
- invalid_config_fd, invalid_config_path = tempfile.mkstemp(suffix='.json')
299
- with os.fdopen(invalid_config_fd, 'w') as f:
307
+ invalid_config = {"auth": {"enabled": True, "methods": ["invalid_method"]}}
308
+
309
+ invalid_config_fd, invalid_config_path = tempfile.mkstemp(suffix=".json")
310
+ with os.fdopen(invalid_config_fd, "w") as f:
300
311
  json.dump(invalid_config, f)
301
-
312
+
302
313
  try:
303
314
  # Should raise validation error
304
315
  with pytest.raises(Exception):
305
316
  StandaloneSecurityExample(config_path=invalid_config_path)
306
317
  finally:
307
318
  os.unlink(invalid_config_path)
308
-
319
+
309
320
  def test_standalone_performance_benchmark(self):
310
321
  """Test performance of standalone application."""
311
322
  example = StandaloneSecurityExample(config_path=self.config_path)
312
-
323
+
313
324
  import time
314
-
325
+
315
326
  # Benchmark simple request
316
327
  start_time = time.time()
317
328
  for _ in range(100):
318
- result = example.process_request({
319
- "credentials": {"api_key": "user_key_456"},
320
- "action": "read",
321
- "resource": "/api/v1/users/me",
322
- "identifier": "test_client"
323
- })
329
+ result = example.process_request(
330
+ {
331
+ "credentials": {"api_key": "user_key_456"},
332
+ "action": "read",
333
+ "resource": "/api/v1/users/me",
334
+ "identifier": "test_client",
335
+ }
336
+ )
324
337
  assert result["success"] is True
325
338
  end_time = time.time()
326
-
339
+
327
340
  avg_time = (end_time - start_time) / 100
328
- assert avg_time < 0.01, f"Request processing too slow: {avg_time:.4f}s per request"
329
-
341
+ assert (
342
+ avg_time < 0.01
343
+ ), f"Request processing too slow: {avg_time:.4f}s per request"
344
+
330
345
  # Benchmark authenticated request
331
346
  start_time = time.time()
332
347
  for _ in range(50):
333
- result = example.process_request({
334
- "credentials": {"api_key": "user_key_456"},
335
- "action": "write",
336
- "resource": "/api/v1/data",
337
- "data": {"name": f"test_{_}", "value": f"value_{_}"},
338
- "identifier": "test_client"
339
- }
348
+ result = example.process_request(
349
+ {
350
+ "credentials": {"api_key": "user_key_456"},
351
+ "action": "write",
352
+ "resource": "/api/v1/data",
353
+ "data": {"name": f"test_{_}", "value": f"value_{_}"},
354
+ "identifier": "test_client",
355
+ }
340
356
  )
341
357
  assert result["success"] is True
342
358
  end_time = time.time()
343
-
359
+
344
360
  avg_time = (end_time - start_time) / 50
345
361
  assert avg_time < 0.02, f"Data operation too slow: {avg_time:.4f}s per request"
346
-
362
+
347
363
  def test_standalone_method_handling(self):
348
364
  """Test different HTTP method handling."""
349
365
  example = StandaloneSecurityExample(config_path=self.config_path)
350
366
  # Test GET method
351
- result = example.process_request({
352
- "credentials": {"api_key": "admin_key_123"},
353
- "action": "read",
354
- "resource": "/api/v1/users/me",
355
- "identifier": "test_client"
356
- })
367
+ result = example.process_request(
368
+ {
369
+ "credentials": {"api_key": "admin_key_123"},
370
+ "action": "read",
371
+ "resource": "/api/v1/users/me",
372
+ "identifier": "test_client",
373
+ }
374
+ )
357
375
  assert result["success"] is True
358
-
376
+
359
377
  # Test POST method
360
- result = example.process_request({
361
- "credentials": {"api_key": "admin_key_123"},
362
- "action": "write",
363
- "resource": "/api/v1/data",
364
- "data": {"name": "test", "value": "value"},
365
- "identifier": "test_client"
366
- })
378
+ result = example.process_request(
379
+ {
380
+ "credentials": {"api_key": "admin_key_123"},
381
+ "action": "write",
382
+ "resource": "/api/v1/data",
383
+ "data": {"name": "test", "value": "value"},
384
+ "identifier": "test_client",
385
+ }
386
+ )
367
387
  assert result["success"] is True
368
-
388
+
369
389
  # Test PUT method
370
- result = example.process_request({
371
- "credentials": {"api_key": "admin_key_123456789012345"},
372
- "action": "update",
373
- "resource": "/api/v1/data/1",
374
- "data": {"name": "updated", "value": "updated_value"},
375
- "identifier": "test_client"
376
- })
390
+ result = example.process_request(
391
+ {
392
+ "credentials": {"api_key": "admin_key_123456789012345"},
393
+ "action": "update",
394
+ "resource": "/api/v1/data/1",
395
+ "data": {"name": "updated", "value": "updated_value"},
396
+ "identifier": "test_client",
397
+ }
398
+ )
377
399
  # Should handle PUT method appropriately
378
-
400
+
379
401
  # Test DELETE method
380
- result = example.process_request({
381
- "credentials": {"api_key": "admin_key_123456789012345"},
382
- "action": "delete",
383
- "resource": "/api/v1/data/1",
384
- "identifier": "test_client"
385
- })
402
+ result = example.process_request(
403
+ {
404
+ "credentials": {"api_key": "admin_key_123456789012345"},
405
+ "action": "delete",
406
+ "resource": "/api/v1/data/1",
407
+ "identifier": "test_client",
408
+ }
409
+ )
386
410
  # Should handle DELETE method appropriately
387
-
411
+
388
412
  def test_standalone_path_routing(self):
389
413
  """Test path-based routing in standalone application."""
390
414
  example = StandaloneSecurityExample(config_path=self.config_path)
@@ -395,41 +419,45 @@ class TestStandaloneIntegration:
395
419
  "/api/v1/data",
396
420
  "/api/v1/data/123",
397
421
  "/health",
398
- "/metrics"
422
+ "/metrics",
399
423
  ]
400
-
424
+
401
425
  for path in paths:
402
- result = example.process_request({
403
- "credentials": {"api_key": "admin_key_123"},
404
- "action": "read",
405
- "resource": path,
406
- "identifier": "test_client"
407
- })
426
+ result = example.process_request(
427
+ {
428
+ "credentials": {"api_key": "admin_key_123"},
429
+ "action": "read",
430
+ "resource": path,
431
+ "identifier": "test_client",
432
+ }
433
+ )
408
434
  # Should handle all paths appropriately
409
435
  assert isinstance(result, dict)
410
-
436
+
411
437
  def test_standalone_header_processing(self):
412
438
  """Test header processing in standalone application."""
413
439
  example = StandaloneSecurityExample(config_path=self.config_path)
414
-
440
+
415
441
  # Test with different API key combinations
416
442
  api_key_combinations = [
417
443
  "admin_key_123",
418
444
  "user_key_456",
419
445
  "readonly_key_789",
420
- "admin_key_123"
446
+ "admin_key_123",
421
447
  ]
422
-
448
+
423
449
  for api_key in api_key_combinations:
424
- result = example.process_request({
425
- "credentials": {"api_key": api_key},
426
- "action": "read",
427
- "resource": "/api/v1/users/me",
428
- "identifier": "test_client"
429
- })
450
+ result = example.process_request(
451
+ {
452
+ "credentials": {"api_key": api_key},
453
+ "action": "read",
454
+ "resource": "/api/v1/users/me",
455
+ "identifier": "test_client",
456
+ }
457
+ )
430
458
  assert isinstance(result, dict)
431
459
  assert "success" in result
432
-
460
+
433
461
  def test_standalone_body_processing(self):
434
462
  """Test body processing in standalone application."""
435
463
  example = StandaloneSecurityExample(config_path=self.config_path)
@@ -440,54 +468,57 @@ class TestStandaloneIntegration:
440
468
  {"complex": {"nested": "data", "array": [1, 2, 3]}},
441
469
  {"empty": {}},
442
470
  {"string": "simple string"},
443
- {"number": 42, "boolean": True}
471
+ {"number": 42, "boolean": True},
444
472
  ]
445
-
473
+
446
474
  for data in data_combinations:
447
- result = example.process_request({
448
- "credentials": {"api_key": "admin_key_123"},
449
- "action": "write",
450
- "resource": "/api/v1/data",
451
- "data": data,
452
- "identifier": "test_client"
453
- })
475
+ result = example.process_request(
476
+ {
477
+ "credentials": {"api_key": "admin_key_123"},
478
+ "action": "write",
479
+ "resource": "/api/v1/data",
480
+ "data": data,
481
+ "identifier": "test_client",
482
+ }
483
+ )
454
484
  assert isinstance(result, dict)
455
-
485
+
456
486
  def test_standalone_security_manager_integration(self):
457
487
  """Test security manager integration in standalone application."""
458
488
  example = StandaloneSecurityExample(config_path=self.config_path)
459
-
489
+
460
490
  # Test that security manager methods are accessible
461
- assert hasattr(example.security_manager, 'authenticate_user')
462
- assert hasattr(example.security_manager, 'check_permissions')
463
- assert hasattr(example.security_manager, 'check_rate_limit')
464
-
491
+ assert hasattr(example.security_manager, "authenticate_user")
492
+ assert hasattr(example.security_manager, "check_permissions")
493
+ assert hasattr(example.security_manager, "check_rate_limit")
494
+
465
495
  # Test direct security manager usage
466
- auth_result = example.security_manager.authenticate_user({
467
- "method": "api_key",
468
- "api_key": "admin_key_123"
469
- })
496
+ auth_result = example.security_manager.authenticate_user(
497
+ {"method": "api_key", "api_key": "admin_key_123"}
498
+ )
470
499
  assert auth_result.is_valid
471
-
500
+
472
501
  # Test permission checking
473
502
  perm_result = example.security_manager.check_permissions(
474
503
  ["admin"], ["read:own", "write:own"]
475
504
  )
476
505
  assert perm_result.is_valid
477
-
506
+
478
507
  def test_standalone_logging_integration(self):
479
508
  """Test logging integration in standalone application."""
480
509
  example = StandaloneSecurityExample(config_path=self.config_path)
481
-
510
+
482
511
  # Test that logging is configured
483
- assert hasattr(example.security_manager, 'logger')
512
+ assert hasattr(example.security_manager, "logger")
484
513
  assert example.security_manager.logger is not None
485
-
514
+
486
515
  # Test that requests are processed (logging happens internally)
487
- result = example.process_request({
488
- "credentials": {"api_key": "admin_key_123"},
489
- "action": "read",
490
- "resource": "/api/v1/users/me",
491
- "identifier": "test_client"
492
- })
516
+ result = example.process_request(
517
+ {
518
+ "credentials": {"api_key": "admin_key_123"},
519
+ "action": "read",
520
+ "resource": "/api/v1/users/me",
521
+ "identifier": "test_client",
522
+ }
523
+ )
493
524
  assert result["success"] is True