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
@@ -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 StandaloneExample
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
@@ -37,358 +42,376 @@ class TestStandaloneIntegration:
37
42
  "enabled": True,
38
43
  "methods": ["api_key"],
39
44
  "api_keys": {
40
- "admin_key_123": "admin",
41
- "user_key_456": "user",
42
- "readonly_key_789": "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
45
+ "admin_key_123": {"username": "admin", "roles": ["admin", "user"]},
46
+ "user_key_456": {"username": "user", "roles": ["user"]},
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", "write", "delete", "admin"],
75
- "description": "Administrator role"
66
+ "permissions": ["read", "write", "delete", "admin", "*"],
67
+ "description": "Administrator role",
76
68
  },
77
69
  "user": {
78
70
  "permissions": ["read", "write"],
79
- "description": "Regular user role"
71
+ "description": "Regular user role",
80
72
  },
81
73
  "readonly": {
82
74
  "permissions": ["read"],
83
- "description": "Read-only user role"
84
- }
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
- example = StandaloneExample(config_path=self.config_path)
111
-
102
+ example = StandaloneSecurityExample(config_path=self.config_path)
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
- example = StandaloneExample(config_path=self.config_path)
124
-
115
+ example = StandaloneSecurityExample(config_path=self.config_path)
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
- })
142
- assert "data" in result
143
- assert result["user"]["username"] == "admin"
144
-
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
+ )
138
+ assert result["success"] is True
139
+ assert result["auth_result"]["username"] == "admin"
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
- })
152
- assert "data" in result
153
- assert result["user"]["username"] == "user"
154
-
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
+ )
150
+ assert result["success"] is True
151
+ assert result["auth_result"]["username"] == "user"
152
+
155
153
  def test_standalone_authorization_flow(self):
156
154
  """Test complete authorization flow in standalone application."""
157
- example = StandaloneExample(config_path=self.config_path)
158
-
155
+ example = StandaloneSecurityExample(config_path=self.config_path)
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
- })
166
- assert "data" in result
167
- # The _execute_action method returns generic data, not specific users
168
- assert "data" in result["data"]
169
-
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
+ assert result["success"] is True
167
+ assert result["auth_result"]["username"] == "admin"
168
+
170
169
  # Test regular user access to admin-only operation (should be denied)
171
- # Note: Since roles are not loaded properly in test config, this may succeed
172
- result = example.process_request({
173
- "credentials": {"api_key": "user_key_456"},
174
- "action": "read",
175
- "resource": "/api/v1/admin/users",
176
- "identifier": "test_client"
177
- })
178
- # Check that request is processed (may succeed due to missing role configuration)
179
- assert "data" in result or "error" in result
180
-
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
+ )
178
+ # Check that request is processed
179
+ assert isinstance(result, dict)
180
+ assert "success" in result
181
+
181
182
  # Test readonly user access to write operation (should be denied)
182
- result = example.process_request({
183
- "credentials": {"api_key": "readonly_key_789"},
184
- "action": "write",
185
- "resource": "/api/v1/data",
186
- "data": {"name": "test", "value": "test_value"},
187
- "identifier": "test_client"
188
- })
189
- # Check that request is processed (may succeed due to missing role configuration)
190
- assert "data" in result or "error" in result
191
-
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
+ )
192
+ # Check that request is processed
193
+ assert isinstance(result, dict)
194
+ assert "success" in result
195
+
192
196
  def test_standalone_rate_limiting(self):
193
197
  """Test rate limiting in standalone application."""
194
- example = StandaloneExample(config_path=self.config_path)
195
-
198
+ example = StandaloneSecurityExample(config_path=self.config_path)
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
- # Note: Rate limiting behavior may vary, so we just check that requests are processed
209
- 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
+ )
210
217
  assert processed_requests > 0, "Some requests should be processed successfully"
211
-
218
+
212
219
  def test_standalone_ssl_integration(self):
213
220
  """Test SSL/TLS integration in standalone application."""
214
221
  # Create config with SSL enabled
215
222
  ssl_config = self.test_config.copy()
216
- ssl_config["ssl"] = {
217
- "enabled": False # Disable SSL for testing
218
- }
219
-
223
+ ssl_config["ssl"] = {"enabled": False} # Disable SSL for testing
224
+
220
225
  # Create temporary SSL config file
221
- ssl_config_fd, ssl_config_path = tempfile.mkstemp(suffix='.json')
222
- 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:
223
228
  json.dump(ssl_config, f)
224
-
229
+
225
230
  try:
226
231
  # Mock SSL context creation to avoid file requirements
227
- 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:
228
235
  mock_ssl.return_value = MagicMock()
229
-
230
- example = StandaloneExample(config_path=ssl_config_path)
231
-
236
+
237
+ example = StandaloneSecurityExample(config_path=ssl_config_path)
238
+
232
239
  # Test that SSL is configured
233
240
  assert example.config.ssl.enabled is False # SSL disabled for testing
234
-
241
+
235
242
  finally:
236
243
  os.unlink(ssl_config_path)
237
-
244
+
238
245
  def test_standalone_error_handling(self):
239
246
  """Test error handling in standalone application."""
240
- example = StandaloneExample(config_path=self.config_path)
241
-
247
+ example = StandaloneSecurityExample(config_path=self.config_path)
248
+
242
249
  # Test invalid API key
243
- result = example.process_request({
244
- "credentials": {"api_key": "invalid_key"},
245
- "action": "read",
246
- "resource": "/api/v1/users/me",
247
- "identifier": "test_client"
248
- })
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
+ )
249
258
  assert "error" in result
250
259
  assert "authentication" in result["error"].lower()
251
-
260
+
252
261
  # Test malformed request
253
- result = example.process_request({
254
- "credentials": {"api_key": "admin_key_123456789012345"},
255
- "action": "write",
256
- "resource": "/api/v1/data",
257
- "data": {"invalid": "data"},
258
- "identifier": "test_client"
259
- })
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
+ )
260
271
  assert "error" in result
261
-
272
+
262
273
  def test_standalone_data_operations(self):
263
274
  """Test data operations with security."""
264
- example = StandaloneExample(config_path=self.config_path)
265
-
275
+ example = StandaloneSecurityExample(config_path=self.config_path)
276
+
266
277
  # Create data
267
- create_result = example.process_request({
268
- "credentials": {"api_key": "admin_key_123"},
269
- "action": "write",
270
- "resource": "/api/v1/data",
271
- "data": {"name": "test_item", "value": "test_value"},
272
- "identifier": "test_client"
273
- })
274
- assert "data" in create_result
275
- # The _execute_action method doesn't generate IDs, it just returns the data
276
- assert "data" in create_result["data"]
277
-
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
+ )
287
+ assert create_result["success"] is True
288
+ # The data is returned in the result
289
+ assert create_result["data"] == {"name": "test_item", "value": "test_value"}
290
+
278
291
  # Retrieve data (simulate retrieval since _execute_action doesn't generate IDs)
279
- get_result = example.process_request({
280
- "credentials": {"api_key": "admin_key_123"},
281
- "action": "read",
282
- "resource": "/api/v1/data/test_item",
283
- "identifier": "test_client"
284
- })
285
- assert "data" in get_result
286
- # The _execute_action method returns generic data
287
- assert "data" in get_result["data"]
288
-
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
+ )
300
+ assert get_result["success"] is True
301
+ # The result contains the request information
302
+ assert get_result["resource"] == "/api/v1/data/test_item"
303
+
289
304
  def test_standalone_configuration_validation(self):
290
305
  """Test configuration validation in standalone application."""
291
306
  # Test with invalid configuration
292
- invalid_config = {
293
- "auth": {
294
- "enabled": True,
295
- "methods": ["invalid_method"]
296
- }
297
- }
298
-
299
- invalid_config_fd, invalid_config_path = tempfile.mkstemp(suffix='.json')
300
- 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:
301
311
  json.dump(invalid_config, f)
302
-
312
+
303
313
  try:
304
314
  # Should raise validation error
305
315
  with pytest.raises(Exception):
306
- StandaloneExample(config_path=invalid_config_path)
316
+ StandaloneSecurityExample(config_path=invalid_config_path)
307
317
  finally:
308
318
  os.unlink(invalid_config_path)
309
-
319
+
310
320
  def test_standalone_performance_benchmark(self):
311
321
  """Test performance of standalone application."""
312
- example = StandaloneExample(config_path=self.config_path)
313
-
322
+ example = StandaloneSecurityExample(config_path=self.config_path)
323
+
314
324
  import time
315
-
325
+
316
326
  # Benchmark simple request
317
327
  start_time = time.time()
318
328
  for _ in range(100):
319
- result = example.process_request({
320
- "credentials": {"api_key": "user_key_456"},
321
- "action": "read",
322
- "resource": "/api/v1/users/me",
323
- "identifier": "test_client"
324
- })
325
- assert "data" in result
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
+ )
337
+ assert result["success"] is True
326
338
  end_time = time.time()
327
-
339
+
328
340
  avg_time = (end_time - start_time) / 100
329
- assert avg_time < 0.01, f"Request processing too slow: {avg_time:.4f}s per request"
330
-
341
+ assert (
342
+ avg_time < 0.01
343
+ ), f"Request processing too slow: {avg_time:.4f}s per request"
344
+
331
345
  # Benchmark authenticated request
332
346
  start_time = time.time()
333
347
  for _ in range(50):
334
- result = example.process_request({
335
- "credentials": {"api_key": "user_key_456"},
336
- "action": "write",
337
- "resource": "/api/v1/data",
338
- "data": {"name": f"test_{_}", "value": f"value_{_}"},
339
- "identifier": "test_client"
340
- }
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
+ }
341
356
  )
342
- assert "data" in result
357
+ assert result["success"] is True
343
358
  end_time = time.time()
344
-
359
+
345
360
  avg_time = (end_time - start_time) / 50
346
361
  assert avg_time < 0.02, f"Data operation too slow: {avg_time:.4f}s per request"
347
-
362
+
348
363
  def test_standalone_method_handling(self):
349
364
  """Test different HTTP method handling."""
350
- example = StandaloneExample(config_path=self.config_path)
365
+ example = StandaloneSecurityExample(config_path=self.config_path)
351
366
  # Test GET method
352
- result = example.process_request({
353
- "credentials": {"api_key": "admin_key_123"},
354
- "action": "read",
355
- "resource": "/api/v1/users/me",
356
- "identifier": "test_client"
357
- })
358
- assert "data" in result
359
-
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
+ )
375
+ assert result["success"] is True
376
+
360
377
  # Test POST method
361
- result = example.process_request({
362
- "credentials": {"api_key": "admin_key_123"},
363
- "action": "write",
364
- "resource": "/api/v1/data",
365
- "data": {"name": "test", "value": "value"},
366
- "identifier": "test_client"
367
- })
368
- assert "data" in result
369
-
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
+ )
387
+ assert result["success"] is True
388
+
370
389
  # Test PUT method
371
- result = example.process_request({
372
- "credentials": {"api_key": "admin_key_123456789012345"},
373
- "action": "update",
374
- "resource": "/api/v1/data/1",
375
- "data": {"name": "updated", "value": "updated_value"},
376
- "identifier": "test_client"
377
- })
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
+ )
378
399
  # Should handle PUT method appropriately
379
-
400
+
380
401
  # Test DELETE method
381
- result = example.process_request({
382
- "credentials": {"api_key": "admin_key_123456789012345"},
383
- "action": "delete",
384
- "resource": "/api/v1/data/1",
385
- "identifier": "test_client"
386
- })
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
+ )
387
410
  # Should handle DELETE method appropriately
388
-
411
+
389
412
  def test_standalone_path_routing(self):
390
413
  """Test path-based routing in standalone application."""
391
- example = StandaloneExample(config_path=self.config_path)
414
+ example = StandaloneSecurityExample(config_path=self.config_path)
392
415
  # Test different paths
393
416
  paths = [
394
417
  "/api/v1/users/me",
@@ -396,43 +419,48 @@ class TestStandaloneIntegration:
396
419
  "/api/v1/data",
397
420
  "/api/v1/data/123",
398
421
  "/health",
399
- "/metrics"
422
+ "/metrics",
400
423
  ]
401
-
424
+
402
425
  for path in paths:
403
- result = example.process_request({
404
- "credentials": {"api_key": "admin_key_123"},
405
- "action": "read",
406
- "resource": path,
407
- "identifier": "test_client"
408
- })
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
+ )
409
434
  # Should handle all paths appropriately
410
435
  assert isinstance(result, dict)
411
-
436
+
412
437
  def test_standalone_header_processing(self):
413
438
  """Test header processing in standalone application."""
414
- example = StandaloneExample(config_path=self.config_path)
415
-
439
+ example = StandaloneSecurityExample(config_path=self.config_path)
440
+
416
441
  # Test with different API key combinations
417
442
  api_key_combinations = [
418
443
  "admin_key_123",
419
444
  "user_key_456",
420
445
  "readonly_key_789",
421
- "admin_key_123"
446
+ "admin_key_123",
422
447
  ]
423
-
448
+
424
449
  for api_key in api_key_combinations:
425
- result = example.process_request({
426
- "credentials": {"api_key": api_key},
427
- "action": "read",
428
- "resource": "/api/v1/users/me",
429
- "identifier": "test_client"
430
- })
431
- assert "data" in result or "error" in result
432
-
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
+ )
458
+ assert isinstance(result, dict)
459
+ assert "success" in result
460
+
433
461
  def test_standalone_body_processing(self):
434
462
  """Test body processing in standalone application."""
435
- example = StandaloneExample(config_path=self.config_path)
463
+ example = StandaloneSecurityExample(config_path=self.config_path)
436
464
  # Test with different data types
437
465
  data_combinations = [
438
466
  None,
@@ -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
- example = StandaloneExample(config_path=self.config_path)
459
-
488
+ example = StandaloneSecurityExample(config_path=self.config_path)
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
- ["admin"], ["read", "write"]
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
- example = StandaloneExample(config_path=self.config_path)
481
-
509
+ example = StandaloneSecurityExample(config_path=self.config_path)
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
- })
493
- assert "data" in result
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
+ )
524
+ assert result["success"] is True