141 lines
No EOL
5.2 KiB
Python
141 lines
No EOL
5.2 KiB
Python
import unittest
|
|
import ssl
|
|
from web_interface import app
|
|
from security.audit import SecureAudit
|
|
from security.rbac_engine import RBACEngine
|
|
|
|
class TestWebInterfaceSecurity(unittest.TestCase):
|
|
def setUp(self):
|
|
self.client = app.test_client()
|
|
self.audit = SecureAudit(self.rbac)
|
|
self.rbac = RBACEngine()
|
|
|
|
def test_tls_configuration(self):
|
|
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_3)
|
|
self.assertIn('AES256-GCM', context.get_ciphers()[0]['name'])
|
|
|
|
def test_security_headers(self):
|
|
response = self.client.get('/permissions/validate')
|
|
self.assertEqual(response.headers['X-Frame-Options'], 'SAMEORIGIN')
|
|
self.assertEqual(response.headers['X-Content-Type-Options'], 'nosniff')
|
|
|
|
def test_rate_limiting(self):
|
|
for _ in range(10):
|
|
response = self.client.post('/tasks')
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
response = self.client.post('/tasks')
|
|
self.assertEqual(response.status_code, 429)
|
|
|
|
def test_audit_logging(self):
|
|
with self.assertLogs('audit', level='INFO') as cm:
|
|
self.client.post('/tasks')
|
|
self.assertIn('task_add', cm.output[0])
|
|
|
|
def test_rbac_integration(self):
|
|
response = self.client.post('/tasks')
|
|
self.assertIn(response.status_code, [401, 403])
|
|
|
|
def test_batch_integrity_verification(self):
|
|
"""Verify cryptographic integrity of batched entries"""
|
|
# Generate test operations
|
|
test_ops = [
|
|
{'operation': 'task_add', 'data': 'test1', 'user': 'user1', 'status': 'completed'},
|
|
{'operation': 'task_add', 'data': 'test2', 'user': 'user2', 'status': 'failed'}
|
|
]
|
|
|
|
# Process batch
|
|
with self.assertLogs('audit', level='INFO') as cm:
|
|
for op in test_ops:
|
|
self.audit.log_operation(**op)
|
|
|
|
# Verify integrity
|
|
logs = [record.getMessage() for record in cm.records]
|
|
self.assertEqual(len(logs), 2) # Should be 2 entries
|
|
self.assertIn('integrity_hash=', logs[0]) # First entry has hash
|
|
self.assertIn('prev_hash=', logs[1]) # Second entry references first
|
|
|
|
def test_timer_flush_security(self):
|
|
"""Verify timer-based flush maintains security properties"""
|
|
# Setup
|
|
test_op = {'operation': 'task_add', 'data': 'test', 'user': 'user1', 'status': 'completed'}
|
|
|
|
# Log operation and force timer flush
|
|
with self.assertLogs('audit', level='INFO') as cm:
|
|
self.audit.log_operation(**test_op)
|
|
self.audit._flush_batch() # Force flush
|
|
|
|
# Verify
|
|
self.assertIn('Batch flushed', cm.output[0])
|
|
self.assertIn('integrity_hash=', cm.output[0])
|
|
|
|
def test_size_flush_security(self):
|
|
"""Verify size-based flush maintains security properties"""
|
|
# Setup
|
|
test_ops = [
|
|
{'operation': 'task_add', 'data': f'test{i}', 'user': f'user{i}', 'status': 'completed'}
|
|
for i in range(10) # Batch size limit
|
|
]
|
|
|
|
# Log operations (should trigger size-based flush)
|
|
with self.assertLogs('audit', level='INFO') as cm:
|
|
for op in test_ops:
|
|
self.audit.log_operation(**op)
|
|
|
|
# Verify flush occurred and has integrity
|
|
self.assertIn('Batch size limit reached', cm.output[-1])
|
|
self.assertIn('integrity_hash=', cm.output[-1])
|
|
|
|
def test_rbac_batch_notifications(self):
|
|
"""Verify RBAC notifications for batched operations"""
|
|
# Setup test user with permissions
|
|
self.rbac.grant_permission('user1', 'batch_operations')
|
|
|
|
# Test operation
|
|
test_op = {'operation': 'task_add', 'data': 'test', 'user': 'user1', 'status': 'completed'}
|
|
|
|
# Log operation and verify notification
|
|
with self.assertLogs('rbac', level='INFO') as cm:
|
|
self.audit.log_operation(**test_op)
|
|
self.audit._flush_batch()
|
|
|
|
# Verify notification
|
|
self.assertIn('Batch operation notification', cm.output[0])
|
|
self.assertIn('user1', cm.output[0])
|
|
|
|
def test_thread_safety(self):
|
|
"""Verify thread-safe operation during concurrent access"""
|
|
import threading
|
|
|
|
# Shared test data
|
|
test_ops = [
|
|
{'operation': 'task_add', 'data': f'test{i}', 'user': f'user{i}', 'status': 'completed'}
|
|
for i in range(20)
|
|
]
|
|
results = []
|
|
|
|
# Worker function
|
|
def worker(op):
|
|
try:
|
|
self.audit.log_operation(**op)
|
|
results.append(True)
|
|
except Exception:
|
|
results.append(False)
|
|
|
|
# Create and start threads
|
|
threads = []
|
|
for op in test_ops:
|
|
t = threading.Thread(target=worker, args=(op,))
|
|
threads.append(t)
|
|
t.start()
|
|
|
|
# Wait for completion
|
|
for t in threads:
|
|
t.join()
|
|
|
|
# Verify all operations succeeded
|
|
self.assertTrue(all(results))
|
|
self.assertEqual(len(results), len(test_ops))
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main() |