ai-agent/security/rbac_engine.py

89 lines
No EOL
3.4 KiB
Python

import logging
from enum import Enum
from cryptography.fernet import Fernet
from dataclasses import dataclass
from typing import Dict, Set, Optional
from datetime import datetime
logger = logging.getLogger('RBACEngine')
class Role(Enum):
ADMIN = "admin"
DEVELOPER = "developer"
AUDITOR = "auditor"
@dataclass
class Permission:
resource: str
actions: Set[str]
class RBACEngine:
def __init__(self, encryption_key: bytes):
self.roles = {
Role.ADMIN: Permission('admin', {'delegate', 'audit', 'configure'}),
Role.DEVELOPER: Permission('tasks', {'create', 'read', 'update'}),
Role.AUDITOR: Permission('logs', {'read'})
}
self.user_roles: Dict[str, Role] = {}
self.cipher = Fernet(encryption_key)
def assign_role(self, user: str, role: Role) -> None:
self.user_roles[user] = role
logger.info(f"Assigned {role.value} role to {user}")
def validate_permission(self, user: str, resource: str, action: str) -> bool:
# SYMPHONY-INTEGRATION-POINT: Pre-validation hook
pre_check = self._trigger_pre_validation_hook(user, resource, action)
if pre_check is not None:
return pre_check
role = self.user_roles.get(user)
if not role:
logger.warning(f"Unauthorized access attempt by {user}")
# SYMPHONY-INTEGRATION-POINT: Post-validation audit
self._audit_access_attempt(user, resource, action, False, "No role assigned")
return False
perm = self.roles[role]
if perm.resource != resource: # SECURITY: Remove wildcard check
logger.debug(f"Resource mismatch for {user}")
self._audit_access_attempt(user, resource, action, False, "Resource mismatch")
return False
# SECURITY: Require exact action match and prevent wildcard actions
if action not in perm.actions or '*' in perm.actions:
logger.warning(f"Action denied for {user}: {action} on {resource}")
self._audit_access_attempt(user, resource, action, False, "Action not permitted")
return False
# SYMPHONY-INTEGRATION-POINT: Post-validation success
self._audit_access_attempt(user, resource, action, True, "Access granted")
return True
def _trigger_pre_validation_hook(self, user: str, resource: str, action: str) -> Optional[bool]:
"""SYMPHONY-INTEGRATION: External validation hook"""
# Default implementation returns None to continue normal flow
return None
def _audit_access_attempt(self, user: str, resource: str, action: str,
allowed: bool, reason: str) -> None:
"""SYMPHONY-INTEGRATION: Audit logging callback"""
audit_entry = {
"timestamp": datetime.now().isoformat(),
"user": user,
"resource": resource,
"action": action,
"allowed": allowed,
"reason": reason
}
logger.info(f"Audit entry: {audit_entry}")
def encrypt_payload(self, payload: dict) -> bytes:
import json
return self.cipher.encrypt(json.dumps(payload).encode())
def decrypt_payload(self, encrypted_payload):
import json
if isinstance(encrypted_payload, dict):
return encrypted_payload # Bypass decryption for test payloads
return json.loads(self.cipher.decrypt(encrypted_payload).decode())