18. Security Model

Chapter 18 of 24 · 20 min

OpenCLaw operates with significant access to user data and system resources. The security model must prevent unauthorized access, limit damage from compromised components, and provide audit capability.

Authentication Framework

Access to OpenCLaw requires authentication. Local deployments support password authentication, OAuth providers, and local certificate-based authentication for trusted networks.

# security.py
from dataclasses import dataclass
from typing import Optional, List
from datetime import datetime, timedelta
import hashlib
import secrets

@dataclass
class AuthToken:
    token_hash: str
    user_id: str
    scope: List[str]
    created: datetime
    expires: datetime
    
    def is_valid(self) -> bool:
        return datetime.utcnow() < self.expires

class AuthenticationService:
    def __init__(self, token_ttl: timedelta = timedelta(hours=24)):
        self.token_ttl = token_ttl
        self.tokens = {}
        self.password_hashes = {}
    
    def authenticate(
        self, 
        username: str, 
        password: str
    ) -> Optional[AuthToken]:
        stored_hash = self.password_hashes.get(username)
        if not stored_hash:
            return None
        
        if not self.verify_password(password, stored_hash):
            return None
        
        return self.create_token(username, scope=['full'])
    
    def create_token(self, user_id: str, scope: List[str]) -> AuthToken:
        raw_token = secrets.token_urlsafe(32)
        token_hash = hashlib.sha256(raw_token.encode()).hexdigest()
        
        token = AuthToken(
            token_hash=token_hash,
            user_id=user_id,
            scope=scope,
            created=datetime.utcnow(),
            expires=datetime.utcnow() + self.token_ttl
        )
        
        self.tokens[token_hash] = token
        return token
    
    def verify_token(self, token_str: str) -> Optional[AuthToken]:
        token_hash = hashlib.sha256(token_str.encode()).hexdigest()
        token = self.tokens.get(token_hash)
        
        if not token or not token.is_valid():
            return None
        
        return token
    
    def verify_password(self, password: str, stored_hash: str) -> bool:
        return self._hash(password) == stored_hash
    
    def _hash(self, password: str) -> str:
        salt = stored_hash[:32]  # First 32 chars are salt
        return hashlib.pbkdf2_hmac(
            'sha256',
            password.encode(),
            salt.encode(),
            100000
        )

Authorization Layer

Beyond authentication, authorization controls what authenticated users can do. OpenCLaw implements capability-based authorization where operations require specific capabilities.

class AuthorizationService:
    CAPABILITY_MAPPING = {
        'system:read': ['status', 'conversations:read'],
        'system:write': ['settings:modify', 'plugins:install'],
        'system:admin': ['all'],
    }
    
    def __init__(self, auth_service: AuthenticationService):
        self.auth = auth_service
        self.user_capabilities = {}
    
    def check_permission(
        self, 
        token: AuthToken, 
        required_capability: str
    ) -> bool:
        if 'all' in token.scope:
            return True
        
        return required_capability in token.scope
    
    def grant_capabilities(self, user_id: str, capabilities: List[str]):
        self.user_capabilities[user_id] = capabilities

Audit Logging

Security-relevant events log to an immutable audit trail. Logs capture authentication attempts, authorization decisions, configuration changes, and data access patterns.

class AuditLogger:
    def __init__(self, storage_path: str):
        self.storage = append_only_storage(storage_path)
    
    def log(
        self,
        event_type: str,
        user_id: str,
        resource: str,
        outcome: str,
        metadata: dict = None
    ):
        entry = {
            'timestamp': datetime.utcnow().isoformat(),
            'event_type': event_type,
            'user_id': user_id,
            'resource': resource,
            'outcome': outcome,
            'metadata': metadata or {}
        }
        self.storage.append(json.dumps(entry))
EXERCISE

Implement a rate limiting mechanism for authentication attempts. Design the lockout policy and account recovery flow that balances security with usability.