185 lines
No EOL
7 KiB
Python
185 lines
No EOL
7 KiB
Python
import unittest
|
|
import time
|
|
import json
|
|
import base64
|
|
import hmac
|
|
import hashlib
|
|
from unittest.mock import patch, MagicMock
|
|
from security.rbac_engine import RBACEngine, Role, ClientCertInfo, RoleBoundary
|
|
from cryptography.fernet import Fernet
|
|
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
|
from cryptography.hazmat.primitives import hashes
|
|
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
|
from datetime import datetime, timedelta
|
|
|
|
class TestRBACNegativeScenarios(unittest.TestCase):
|
|
def setUp(self):
|
|
self.encryption_key = Fernet.generate_key()
|
|
self.rbac = RBACEngine(self.encryption_key)
|
|
|
|
# Setup test certificates
|
|
self.cert_fingerprints = {
|
|
"valid_cert": "valid_fingerprint",
|
|
"untrusted_cert": "untrusted_fingerprint"
|
|
}
|
|
self.rbac.trusted_cert_fingerprints.add(self.cert_fingerprints["valid_cert"])
|
|
|
|
def test_tampered_ou_claim(self):
|
|
"""Test validation fails with tampered OU claim signature"""
|
|
# Create a valid signed OU claim
|
|
valid_claim = self.rbac.create_signed_ou_claim(Role.DEVELOPER)
|
|
|
|
# Tamper with the signature
|
|
role_name, signature = valid_claim.split(':')
|
|
tampered_signature = signature[:-1] + 'x' # Change last character
|
|
tampered_claim = f"{role_name}:{tampered_signature}"
|
|
|
|
cert_info = ClientCertInfo(
|
|
subject={'CN': 'tampered_cert', 'OU': tampered_claim},
|
|
fingerprint=self.cert_fingerprints["valid_cert"],
|
|
raw_cert=object()
|
|
)
|
|
|
|
self.assertFalse(self.rbac.validate_permission(
|
|
resource="tasks",
|
|
action="create",
|
|
client_cert_info=cert_info
|
|
))
|
|
|
|
def test_certificate_pinning_failure(self):
|
|
"""Test validation fails with untrusted certificate"""
|
|
cert_info = ClientCertInfo(
|
|
subject={'CN': 'untrusted_cert', 'OU': 'developer'},
|
|
fingerprint=self.cert_fingerprints["untrusted_cert"],
|
|
raw_cert=object()
|
|
)
|
|
|
|
self.assertFalse(self.rbac.validate_permission(
|
|
resource="tasks",
|
|
action="create",
|
|
client_cert_info=cert_info
|
|
))
|
|
|
|
def test_role_assignment_boundary_violation(self):
|
|
"""Test role assignment fails with boundary violation"""
|
|
# Try to assign ADMIN role to non-admin domain
|
|
self.assertFalse(self.rbac.assign_role(
|
|
user="hacker@example.com",
|
|
role=Role.ADMIN,
|
|
domain="example.com"
|
|
))
|
|
|
|
# Try to assign DEVELOPER role to external domain
|
|
self.assertFalse(self.rbac.assign_role(
|
|
user="hacker@external.org",
|
|
role=Role.DEVELOPER,
|
|
domain="external.org"
|
|
))
|
|
|
|
def test_audit_log_tampering(self):
|
|
"""Test audit log integrity verification fails with tampered entries"""
|
|
# Generate valid audit entries
|
|
valid_entries = []
|
|
for i in range(3):
|
|
entry = {
|
|
"sequence": i+1,
|
|
"timestamp": datetime.now().isoformat(),
|
|
"user": f"user{i}",
|
|
"resource": "test",
|
|
"action": "read",
|
|
"allowed": True,
|
|
"reason": "test",
|
|
"auth_method": "username",
|
|
"previous_hash": valid_entries[-1]["integrity_hash"] if valid_entries else None
|
|
}
|
|
entry_json = json.dumps(entry, sort_keys=True)
|
|
entry["integrity_hash"] = hmac.new(
|
|
self.rbac.hmac_key,
|
|
entry_json.encode(),
|
|
hashlib.sha256
|
|
).hexdigest()
|
|
valid_entries.append(entry)
|
|
|
|
# Tamper with an entry
|
|
tampered_entries = valid_entries.copy()
|
|
tampered_entries[1]["allowed"] = False # Change the outcome
|
|
|
|
self.assertFalse(self.rbac.verify_audit_log_integrity(tampered_entries))
|
|
|
|
def test_performance_under_brute_force(self):
|
|
"""Test performance under repeated failed authentication attempts"""
|
|
# Setup test with many invalid certificates
|
|
invalid_certs = []
|
|
for i in range(100):
|
|
cert_info = ClientCertInfo(
|
|
subject={'CN': f'brute_force_{i}', 'OU': 'invalid'},
|
|
fingerprint=f"invalid_fingerprint_{i}",
|
|
raw_cert=object()
|
|
)
|
|
invalid_certs.append(cert_info)
|
|
|
|
# Measure validation time
|
|
start_time = time.time()
|
|
for cert in invalid_certs:
|
|
self.rbac.validate_permission(
|
|
resource="tasks",
|
|
action="create",
|
|
client_cert_info=cert
|
|
)
|
|
elapsed_time = time.time() - start_time
|
|
|
|
# Verify performance is acceptable (under 1 second for 100 attempts)
|
|
self.assertLess(elapsed_time, 1.0,
|
|
"Performance degraded under brute force attacks")
|
|
|
|
def test_missing_authentication_context(self):
|
|
"""Test validation fails when no authentication context is provided"""
|
|
self.assertFalse(self.rbac.validate_permission(
|
|
resource="tasks",
|
|
action="read"
|
|
))
|
|
|
|
def test_invalid_permission_combinations(self):
|
|
"""Test invalid permission combinations are rejected"""
|
|
# Try to access non-existent resource
|
|
self.assertFalse(self.rbac.validate_permission(
|
|
user="admin_user@admin.example.com",
|
|
resource="nonexistent",
|
|
action="read"
|
|
))
|
|
|
|
# Try to perform non-existent action
|
|
self.assertFalse(self.rbac.validate_permission(
|
|
user="admin_user@admin.example.com",
|
|
resource="admin",
|
|
action="nonexistent"
|
|
))
|
|
|
|
def test_circular_inheritance(self):
|
|
"""Test circular role inheritance is prevented"""
|
|
# Create circular inheritance: A -> B -> C -> A
|
|
self.assertTrue(self.rbac.define_role_inheritance("A", "B"))
|
|
self.assertTrue(self.rbac.define_role_inheritance("B", "C"))
|
|
self.assertFalse(self.rbac.define_role_inheritance("C", "A"))
|
|
|
|
def test_boundary_violation_through_inheritance(self):
|
|
"""Test inheritance cannot bypass boundary restrictions"""
|
|
# Try to inherit RESTRICTED role permissions in GLOBAL context
|
|
self.rbac.define_role_boundary("RESTRICTED_ROLE", RoleBoundary.RESTRICTED)
|
|
self.rbac.define_role_boundary("GLOBAL_ROLE", RoleBoundary.GLOBAL)
|
|
self.assertFalse(self.rbac.define_role_inheritance("GLOBAL_ROLE", "RESTRICTED_ROLE"))
|
|
|
|
def test_admin_role_inheritance_validation(self):
|
|
"""Test admin role cannot inherit from non-admin roles"""
|
|
self.assertFalse(self.rbac.define_role_inheritance(Role.ADMIN, Role.DEVELOPER))
|
|
|
|
def test_permission_composition_abuse(self):
|
|
"""Test invalid permission composition attempts"""
|
|
# Try to compose permissions across boundary levels
|
|
self.assertFalse(self.rbac.compose_permissions(
|
|
"INTERNAL:read",
|
|
"RESTRICTED:write"
|
|
))
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main() |