ai-agent/tests/security/test_rbac_negative.py

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()