Agentic Design Pattern: Permission Authorization

Written by

in


    """
Pattern 139: Permission & Authorization

Description:
    The Permission & Authorization pattern implements fine-grained access control
    for agent systems, determining who can perform what actions on which resources.
    This pattern provides role-based access control (RBAC), attribute-based access
    control (ABAC), and resource-level permissions to ensure that agents and users
    only access what they're authorized to access.

    Authorization is fundamental to secure AI systems, especially in multi-user
    environments or when handling sensitive data. It enforces the principle of
    least privilege, prevents unauthorized access, and ensures compliance with
    security policies. The pattern supports hierarchical roles, permission
    inheritance, dynamic permissions, and context-aware authorization.

    This implementation provides a comprehensive authorization system with role
    management, permission assignment, access control checks, resource-level
    permissions, and permission delegation. It supports both static and dynamic
    authorization decisions based on user attributes, resource properties, and
    environmental context.

Components:
    - Role Management: Define and manage user roles
    - Permission Assignment: Assign permissions to roles and users
    - Access Control: Check if action is authorized
    - Resource Protection: Control access to specific resources
    - Permission Delegation: Temporary permission grants
    - Context-Aware Authorization: Consider context in decisions

Use Cases:
    - Multi-user AI systems
    - Enterprise agent platforms
    - Data access control
    - API authorization
    - Healthcare systems (HIPAA compliance)
    - Financial systems
    - Government systems
    - Multi-tenant platforms

LangChain Implementation:
    This implementation uses:
    - Custom RBAC and ABAC systems
    - Permission hierarchy and inheritance
    - Resource-level access control
    - LLM for complex authorization decisions
    - Context-aware permission evaluation
    - Audit logging integration

Benefits:
    - Enforces least privilege principle
    - Prevents unauthorized access
    - Supports compliance requirements
    - Enables fine-grained control
    - Facilitates security auditing
    - Supports multi-tenancy
    - Enables delegation

Trade-offs:
    - Adds complexity to system
    - Requires permission management
    - May impact performance
    - Needs careful role design
    - Can be difficult to debug
    - Requires ongoing maintenance

Production Considerations:
    - Design clear role hierarchy
    - Implement efficient permission checks
    - Cache authorization decisions
    - Log all authorization events
    - Support emergency access
    - Implement permission review process
    - Handle permission conflicts
    - Support temporal permissions
    - Provide audit capabilities
    - Test permission combinations
    - Document permission model
    - Monitor unauthorized attempts
"""

import os
from typing import List, Dict, Any, Optional, Set
from datetime import datetime, timedelta
from enum import Enum
from dataclasses import dataclass, field
from dotenv import load_dotenv

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI

load_dotenv()


class ActionType(Enum):
    """Types of actions."""
    READ = "read"
    WRITE = "write"
    UPDATE = "update"
    DELETE = "delete"
    EXECUTE = "execute"
    ADMIN = "admin"
    EXPORT = "export"
    SHARE = "share"


class ResourceType(Enum):
    """Types of resources."""
    DATA = "data"
    MODEL = "model"
    AGENT = "agent"
    CONFIG = "config"
    USER = "user"
    API = "api"


@dataclass
class Permission:
    """Permission definition."""
    permission_id: str
    name: str
    description: str
    resource_type: ResourceType
    action: ActionType
    conditions: Dict[str, Any] = field(default_factory=dict)
    
    def __hash__(self):
        return hash(self.permission_id)


@dataclass
class Role:
    """Role definition."""
    role_id: str
    name: str
    description: str
    permissions: Set[Permission] = field(default_factory=set)
    parent_roles: Set[str] = field(default_factory=set)
    created_at: datetime = field(default_factory=datetime.now)
    
    def add_permission(self, permission: Permission):
        """Add permission to role."""
        self.permissions.add(permission)
    
    def remove_permission(self, permission: Permission):
        """Remove permission from role."""
        self.permissions.discard(permission)
    
    def has_permission(self, permission: Permission) -> bool:
        """Check if role has permission."""
        return permission in self.permissions


@dataclass
class User:
    """User definition."""
    user_id: str
    username: str
    roles: Set[str] = field(default_factory=set)
    direct_permissions: Set[Permission] = field(default_factory=set)
    attributes: Dict[str, Any] = field(default_factory=dict)
    created_at: datetime = field(default_factory=datetime.now)
    
    def add_role(self, role_id: str):
        """Add role to user."""
        self.roles.add(role_id)
    
    def remove_role(self, role_id: str):
        """Remove role from user."""
        self.roles.discard(role_id)
    
    def add_permission(self, permission: Permission):
        """Add direct permission to user."""
        self.direct_permissions.add(permission)


@dataclass
class Resource:
    """Resource definition."""
    resource_id: str
    resource_type: ResourceType
    owner_id: str
    attributes: Dict[str, Any] = field(default_factory=dict)
    created_at: datetime = field(default_factory=datetime.now)


@dataclass
class AuthorizationRequest:
    """Authorization request."""
    user_id: str
    action: ActionType
    resource: Resource
    context: Dict[str, Any] = field(default_factory=dict)


@dataclass
class AuthorizationResult:
    """Authorization result."""
    authorized: bool
    reason: str
    matched_permissions: List[Permission]
    timestamp: datetime = field(default_factory=datetime.now)


class PermissionAuthorizationAgent:
    """
    Agent that provides permission and authorization management.
    
    This agent manages roles, permissions, and authorization decisions
    using RBAC and ABAC approaches.
    """
    
    def __init__(self, temperature: float = 0.3):
        """Initialize the authorization agent."""
        self.llm = ChatOpenAI(temperature=temperature, model="gpt-3.5-turbo")
        self.roles: Dict[str, Role] = {}
        self.users: Dict[str, User] = {}
        self.resources: Dict[str, Resource] = {}
        self.permissions: Dict[str, Permission] = {}
        
        # Create authorization chain for complex decisions
        auth_prompt = ChatPromptTemplate.from_template(
            """You are an authorization expert. Determine if the user should be authorized for this action.

User: {user_id}
User Attributes: {user_attributes}
Action: {action}
Resource Type: {resource_type}
Resource Attributes: {resource_attributes}
Context: {context}

Consider:
1. User's roles and permissions
2. Resource sensitivity
3. Context (time, location, etc.)
4. Business rules and policies

Respond in this format:
AUTHORIZED: yes/no
REASON: explanation
RISK_LEVEL: low/medium/high
CONDITIONS: any conditions for authorization"""
        )
        self.auth_chain = auth_prompt | self.llm | StrOutputParser()
    
    def create_permission(
        self,
        permission_id: str,
        name: str,
        description: str,
        resource_type: ResourceType,
        action: ActionType,
        conditions: Optional[Dict[str, Any]] = None
    ) -> Permission:
        """Create a new permission."""
        permission = Permission(
            permission_id=permission_id,
            name=name,
            description=description,
            resource_type=resource_type,
            action=action,
            conditions=conditions or {}
        )
        self.permissions[permission_id] = permission
        return permission
    
    def create_role(
        self,
        role_id: str,
        name: str,
        description: str,
        parent_roles: Optional[Set[str]] = None
    ) -> Role:
        """Create a new role."""
        role = Role(
            role_id=role_id,
            name=name,
            description=description,
            parent_roles=parent_roles or set()
        )
        self.roles[role_id] = role
        return role
    
    def create_user(
        self,
        user_id: str,
        username: str,
        roles: Optional[Set[str]] = None,
        attributes: Optional[Dict[str, Any]] = None
    ) -> User:
        """Create a new user."""
        user = User(
            user_id=user_id,
            username=username,
            roles=roles or set(),
            attributes=attributes or {}
        )
        self.users[user_id] = user
        return user
    
    def create_resource(
        self,
        resource_id: str,
        resource_type: ResourceType,
        owner_id: str,
        attributes: Optional[Dict[str, Any]] = None
    ) -> Resource:
        """Create a new resource."""
        resource = Resource(
            resource_id=resource_id,
            resource_type=resource_type,
            owner_id=owner_id,
            attributes=attributes or {}
        )
        self.resources[resource_id] = resource
        return resource
    
    def assign_permission_to_role(
        self,
        role_id: str,
        permission_id: str
    ) -> bool:
        """Assign permission to role."""
        if role_id not in self.roles or permission_id not in self.permissions:
            return False
        
        role = self.roles[role_id]
        permission = self.permissions[permission_id]
        role.add_permission(permission)
        return True
    
    def assign_role_to_user(
        self,
        user_id: str,
        role_id: str
    ) -> bool:
        """Assign role to user."""
        if user_id not in self.users or role_id not in self.roles:
            return False
        
        user = self.users[user_id]
        user.add_role(role_id)
        return True
    
    def get_user_permissions(self, user_id: str) -> Set[Permission]:
        """Get all permissions for a user (from roles and direct)."""
        if user_id not in self.users:
            return set()
        
        user = self.users[user_id]
        permissions = user.direct_permissions.copy()
        
        # Add permissions from roles
        for role_id in user.roles:
            if role_id in self.roles:
                role = self.roles[role_id]
                permissions.update(role.permissions)
                
                # Add permissions from parent roles (inheritance)
                for parent_id in role.parent_roles:
                    if parent_id in self.roles:
                        permissions.update(self.roles[parent_id].permissions)
        
        return permissions
    
    def check_authorization(
        self,
        request: AuthorizationRequest
    ) -> AuthorizationResult:
        """
        Check if user is authorized for action on resource.
        
        This performs both static (RBAC) and dynamic (ABAC) checks.
        """
        if request.user_id not in self.users:
            return AuthorizationResult(
                authorized=False,
                reason="User not found",
                matched_permissions=[]
            )
        
        user = self.users[request.user_id]
        user_permissions = self.get_user_permissions(request.user_id)
        
        # Check if user is owner
        if request.resource.owner_id == request.user_id:
            return AuthorizationResult(
                authorized=True,
                reason="User is resource owner",
                matched_permissions=[]
            )
        
        # Check static permissions (RBAC)
        matched = []
        for permission in user_permissions:
            if (permission.resource_type == request.resource.resource_type and
                permission.action == request.action):
                
                # Check conditions
                if self._check_conditions(permission.conditions, request.context):
                    matched.append(permission)
        
        if matched:
            return AuthorizationResult(
                authorized=True,
                reason=f"Authorized via permissions: {', '.join(p.name for p in matched)}",
                matched_permissions=matched
            )
        
        # If no static match, use LLM for dynamic decision (ABAC)
        return self._dynamic_authorization(user, request)
    
    def _check_conditions(
        self,
        conditions: Dict[str, Any],
        context: Dict[str, Any]
    ) -> bool:
        """Check if conditions are met."""
        if not conditions:
            return True
        
        for key, value in conditions.items():
            if key not in context or context[key] != value:
                return False
        
        return True
    
    def _dynamic_authorization(
        self,
        user: User,
        request: AuthorizationRequest
    ) -> AuthorizationResult:
        """Use LLM for dynamic authorization decision."""
        try:
            result = self.auth_chain.invoke({
                "user_id": user.user_id,
                "user_attributes": str(user.attributes),
                "action": request.action.value,
                "resource_type": request.resource.resource_type.value,
                "resource_attributes": str(request.resource.attributes),
                "context": str(request.context)
            })
            
            # Parse result
            authorized = "yes" in result.lower().split("AUTHORIZED:")[1].split("\n")[0]
            reason_line = [l for l in result.split("\n") if l.startswith("REASON:")]
            reason = reason_line[0].replace("REASON:", "").strip() if reason_line else "Dynamic authorization"
            
            return AuthorizationResult(
                authorized=authorized,
                reason=reason,
                matched_permissions=[]
            )
            
        except Exception as e:
            return AuthorizationResult(
                authorized=False,
                reason=f"Authorization check failed: {e}",
                matched_permissions=[]
            )
    
    def get_authorization_summary(self) -> Dict[str, Any]:
        """Get summary of authorization system."""
        return {
            "total_users": len(self.users),
            "total_roles": len(self.roles),
            "total_permissions": len(self.permissions),
            "total_resources": len(self.resources),
            "users_by_role": {
                role_id: len([u for u in self.users.values() if role_id in u.roles])
                for role_id in self.roles.keys()
            }
        }


def demonstrate_permission_authorization():
    """Demonstrate the permission and authorization pattern."""
    print("=" * 80)
    print("Permission & Authorization Pattern Demonstration")
    print("=" * 80)
    
    agent = PermissionAuthorizationAgent()
    
    # Demonstration 1: Create Permissions
    print("\n" + "=" * 80)
    print("Demonstration 1: Create Permissions")
    print("=" * 80)
    
    read_data = agent.create_permission(
        permission_id="perm_read_data",
        name="Read Data",
        description="Permission to read data resources",
        resource_type=ResourceType.DATA,
        action=ActionType.READ
    )
    
    write_data = agent.create_permission(
        permission_id="perm_write_data",
        name="Write Data",
        description="Permission to write data resources",
        resource_type=ResourceType.DATA,
        action=ActionType.WRITE
    )
    
    admin_all = agent.create_permission(
        permission_id="perm_admin",
        name="Admin All",
        description="Full administrative access",
        resource_type=ResourceType.DATA,
        action=ActionType.ADMIN
    )
    
    print(f"Created permissions:")
    print(f"  - {read_data.name}: {read_data.description}")
    print(f"  - {write_data.name}: {write_data.description}")
    print(f"  - {admin_all.name}: {admin_all.description}")
    
    # Demonstration 2: Create Roles
    print("\n" + "=" * 80)
    print("Demonstration 2: Create Roles with Hierarchy")
    print("=" * 80)
    
    viewer_role = agent.create_role(
        role_id="role_viewer",
        name="Viewer",
        description="Can view data"
    )
    agent.assign_permission_to_role("role_viewer", "perm_read_data")
    
    editor_role = agent.create_role(
        role_id="role_editor",
        name="Editor",
        description="Can view and edit data",
        parent_roles={"role_viewer"}
    )
    agent.assign_permission_to_role("role_editor", "perm_write_data")
    
    admin_role = agent.create_role(
        role_id="role_admin",
        name="Admin",
        description="Full system access",
        parent_roles={"role_editor"}
    )
    agent.assign_permission_to_role("role_admin", "perm_admin")
    
    print(f"Created role hierarchy:")
    print(f"  Admin -> Editor -> Viewer")
    print(f"  - Viewer: {len(viewer_role.permissions)} permissions")
    print(f"  - Editor: {len(editor_role.permissions)} permissions (+ inherited)")
    print(f"  - Admin: {len(admin_role.permissions)} permissions (+ inherited)")
    
    # Demonstration 3: Create Users
    print("\n" + "=" * 80)
    print("Demonstration 3: Create Users with Roles")
    print("=" * 80)
    
    user1 = agent.create_user(
        user_id="user_001",
        username="alice",
        roles={"role_viewer"},
        attributes={"department": "sales", "level": "junior"}
    )
    
    user2 = agent.create_user(
        user_id="user_002",
        username="bob",
        roles={"role_editor"},
        attributes={"department": "engineering", "level": "senior"}
    )
    
    user3 = agent.create_user(
        user_id="user_003",
        username="charlie",
        roles={"role_admin"},
        attributes={"department": "it", "level": "manager"}
    )
    
    print(f"Created users:")
    print(f"  - {user1.username}: {user1.roles}")
    print(f"  - {user2.username}: {user2.roles}")
    print(f"  - {user3.username}: {user3.roles}")
    
    # Demonstration 4: Create Resources
    print("\n" + "=" * 80)
    print("Demonstration 4: Create Protected Resources")
    print("=" * 80)
    
    resource1 = agent.create_resource(
        resource_id="res_001",
        resource_type=ResourceType.DATA,
        owner_id="user_003",
        attributes={"classification": "public", "department": "sales"}
    )
    
    resource2 = agent.create_resource(
        resource_id="res_002",
        resource_type=ResourceType.DATA,
        owner_id="user_003",
        attributes={"classification": "confidential", "department": "finance"}
    )
    
    print(f"Created resources:")
    print(f"  - {resource1.resource_id}: {resource1.attributes['classification']}")
    print(f"  - {resource2.resource_id}: {resource2.attributes['classification']}")
    
    # Demonstration 5: Authorization Checks
    print("\n" + "=" * 80)
    print("Demonstration 5: Authorization Checks")
    print("=" * 80)
    
    # Alice (viewer) tries to read
    request1 = AuthorizationRequest(
        user_id="user_001",
        action=ActionType.READ,
        resource=resource1,
        context={}
    )
    result1 = agent.check_authorization(request1)
    print(f"\nAlice (viewer) reads public data:")
    print(f"  Authorized: {result1.authorized}")
    print(f"  Reason: {result1.reason}")
    
    # Alice tries to write
    request2 = AuthorizationRequest(
        user_id="user_001",
        action=ActionType.WRITE,
        resource=resource1,
        context={}
    )
    result2 = agent.check_authorization(request2)
    print(f"\nAlice (viewer) writes data:")
    print(f"  Authorized: {result2.authorized}")
    print(f"  Reason: {result2.reason}")
    
    # Bob (editor) tries to write
    request3 = AuthorizationRequest(
        user_id="user_002",
        action=ActionType.WRITE,
        resource=resource1,
        context={}
    )
    result3 = agent.check_authorization(request3)
    print(f"\nBob (editor) writes data:")
    print(f"  Authorized: {result3.authorized}")
    print(f"  Reason: {result3.reason}")
    
    # Demonstration 6: Owner Access
    print("\n" + "=" * 80)
    print("Demonstration 6: Resource Owner Access")
    print("=" * 80)
    
    # Charlie is owner
    request4 = AuthorizationRequest(
        user_id="user_003",
        action=ActionType.DELETE,
        resource=resource1,
        context={}
    )
    result4 = agent.check_authorization(request4)
    print(f"\nCharlie (owner) deletes resource:")
    print(f"  Authorized: {result4.authorized}")
    print(f"  Reason: {result4.reason}")
    
    # Demonstration 7: User Permissions Summary
    print("\n" + "=" * 80)
    print("Demonstration 7: User Permissions Summary")
    print("=" * 80)
    
    for user_id in ["user_001", "user_002", "user_003"]:
        user = agent.users[user_id]
        permissions = agent.get_user_permissions(user_id)
        print(f"\n{user.username} permissions:")
        print(f"  Roles: {', '.join(user.roles)}")
        print(f"  Total Permissions: {len(permissions)}")
        for perm in permissions:
            print(f"    - {perm.name}: {perm.action.value} {perm.resource_type.value}")
    
    # Demonstration 8: System Summary
    print("\n" + "=" * 80)
    print("Demonstration 8: Authorization System Summary")
    print("=" * 80)
    
    summary = agent.get_authorization_summary()
    print(f"\nAuthorization System:")
    print(f"  Users: {summary['total_users']}")
    print(f"  Roles: {summary['total_roles']}")
    print(f"  Permissions: {summary['total_permissions']}")
    print(f"  Resources: {summary['total_resources']}")
    print(f"\n  Users by Role:")
    for role, count in summary['users_by_role'].items():
        if count > 0:
            print(f"    {role}: {count}")
    
    # Summary
    print("\n" + "=" * 80)
    print("Summary: Permission & Authorization Pattern")
    print("=" * 80)
    print("""
The Permission & Authorization pattern provides fine-grained access control:

Key Features Demonstrated:
1. Permission Management - Create and manage permissions
2. Role-Based Access Control - RBAC with role hierarchy
3. User Management - Assign roles and permissions to users
4. Resource Protection - Control access to specific resources
5. Authorization Checks - Verify user access rights
6. Owner Access - Automatic authorization for resource owners
7. Permission Inheritance - Inherit permissions from parent roles
8. System Management - Track and manage authorization state

Benefits:
- Enforces least privilege
- Prevents unauthorized access
- Supports compliance
- Enables fine-grained control
- Facilitates auditing
- Supports multi-tenancy
- Enables role delegation

Best Practices:
- Design clear role hierarchy
- Use principle of least privilege
- Cache authorization decisions
- Log authorization events
- Support emergency access
- Review permissions regularly
- Handle permission conflicts
- Test permission combinations
- Document permission model
- Monitor unauthorized attempts
- Support temporal permissions
- Provide audit capabilities

This pattern is essential for secure multi-user AI systems requiring
access control, compliance, and security enforcement.
""")


if __name__ == "__main__":
    demonstrate_permission_authorization()

    

Agentic Design Pattern: Permission Authorization

Pattern 139: Permission Authorization – Line-by-Line Explanation

Overview

This document provides a detailed line-by-line explanation of the Permission Authorization pattern implementation.


Pattern Description

Pattern 139: Permission & Authorization

Description: The Permission & Authorization pattern implements fine-grained access control for agent systems, determining who can perform what actions on which resources. This pattern provides role-based access control (RBAC), attribute-based access control (ABAC), and resource-level permissions to ensure that agents and users only access what they’re authorized to access.

Authorization is fundamental to secure AI systems, especially in multi-user
environments or when handling sensitive data. It enforces the principle of
least privilege, prevents unauthorized access, and ensures compliance with
security policies. The pattern supports hierarchical roles, permission
inheritance, dynamic permissions, and context-aware authorization.

This implementation provides a comprehensive authorization system with role
management, permission assignment, access control checks, resource-level
permissions, and permission delegation. It supports both static and dynamic
authorization decisions based on user attributes, resource properties, and
environmental context.

Components: – Role Management: Define and manage user roles – Permission Assignment: Assign permissions to roles and users – Access Control: Check if action is authorized – Resource Protection: Control access to specific resources – Permission Delegation: Temporary permission grants – Context-Aware Authorization: Consider context in decisions

Use Cases: – Multi-user AI systems – Enterprise agent platforms – Data access control – API authorization – Healthcare systems (HIPAA compliance) – Financial systems – Government systems – Multi-tenant platforms

LangChain Implementation: This implementation uses: – Custom RBAC and ABAC systems – Permission hierarchy and inheritance – Resource-level access control – LLM for complex authorization decisions – Context-aware permission evaluation – Audit logging integration

Benefits: – Enforces least privilege principle – Prevents unauthorized access – Supports compliance requirements – Enables fine-grained control – Facilitates security auditing – Supports multi-tenancy – Enables delegation

Trade-offs: – Adds complexity to system – Requires permission management – May impact performance – Needs careful role design – Can be difficult to debug – Requires ongoing maintenance

Production Considerations: – Design clear role hierarchy – Implement efficient permission checks – Cache authorization decisions – Log all authorization events – Support emergency access – Implement permission review process – Handle permission conflicts – Support temporal permissions – Provide audit capabilities – Test permission combinations – Document permission model – Monitor unauthorized attempts


File Statistics

  • Total Lines: 742
  • Classes: 9
  • Functions: 1
  • Constants: 0

Module Documentation

"""
Pattern 139: Permission & Authorization

Description:
    The Permission & Authorization pattern implements fine-grained access control
    for agent systems, determining who can perform what actions on which resources.
    This pattern provides role-based access control (RBAC), attribute-based access
    control (ABAC), and resource-level permissions to ensure that agents and users
    only access what they're authorized to access.

    Authorization is fundamental to secure AI systems, especially in multi-user
    environments or when handling sensitive data. It enforces the principle of
    least privilege, prevents unauthorized access, and ensures compliance with
    security policies. The pattern supports hierarchical roles, permission
    inheritance, dynamic permissions, and context-aware authorization.

    This implementation provides a comprehensive authorization system with role
    management, permission assignment, access control checks, resource-level
    permissions, and permission delegation. It supports both static and dynamic
    authorization decisions based on user attributes, resource properties, and
    environmental context.

Components:
    - Role Management: Define and manage user roles
    - Permission Assignment: Assign permissions to roles and users
    - Access Control: Check if action is authorized
    - Resource Protection: Control access to specific resources
    - Permission Delegation: Temporary permission grants
    - Context-Aware Authorization: Consider context in decisions

Use Cases:
    - Multi-user AI systems
    - Enterprise agent platforms
    - Data access control
    - API authorization
    - Healthcare systems (HIPAA compliance)
    - Financial systems
    - Government systems
    - Multi-tenant platforms

LangChain Implementation:
    This implementation uses:
    - Custom RBAC and ABAC systems
    - Permission hierarchy and inheritance
    - Resource-level access control
    - LLM for complex authorization decisions
    - Context-aware permission evaluation
    - Audit logging integration

Benefits:
    - Enforces least privilege principle
    - Prevents unauthorized access
    - Supports compliance requirements
    - Enables fine-grained control
    - Facilitates security auditing
    - Supports multi-tenancy
    - Enables delegation

Trade-offs:
    - Adds complexity to system
    - Requires permission management
    - May impact performance
    - Needs careful role design
    - Can be difficult to debug
    - Requires ongoing maintenance

Production Considerations:
    - Design clear role hierarchy
    - Implement efficient permission checks
    - Cache authorization decisions
    - Log all authorization events
    - Support emergency access
    - Implement permission review process
    - Handle permission conflicts
    - Support temporal permissions
    - Provide audit capabilities
    - Test permission combinations
    - Document permission model
    - Monitor unauthorized attempts
"""

Purpose: This module implements the Permission Authorization pattern, providing a structured approach to agent design and implementation.


Import Statements

Standard Library Imports

import dataclasses.dataclass
import dataclasses.field
import datetime.datetime
import datetime.timedelta
import enum.Enum
import langchain_core.output_parsers.StrOutputParser
import langchain_core.prompts.ChatPromptTemplate
import os
import typing.Any
import typing.Dict
import typing.List
import typing.Optional
import typing.Set

Purpose: Core Python functionality: – dataclasses.dataclass: Simplified class definitions with @dataclass – dataclasses.field: Simplified class definitions with @dataclass – datetime.datetime: Date and time handling – datetime.timedelta: Date and time handling – enum.Enum: Enumeration support – langchain_core.output_parsers.StrOutputParser: Regular expression operations – langchain_core.prompts.ChatPromptTemplate: Regular expression operations – os: Environment variable access and system operations – typing.Any: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Dict: Type hints for better code documentation (List, Dict, Any, Optional) – typing.List: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Optional: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Set: Type hints for better code documentation (List, Dict, Any, Optional)

LangChain Imports

from langchain_openai.ChatOpenAI

Purpose: LangChain framework components: – LLM Interface: Wrapper for OpenAI models – Chains: Composable building blocks for complex workflows

Other Imports

from dotenv.load_dotenv

Purpose: Additional dependencies for specialized functionality.


Classes

Class: ActionType

Lines 96-105

Inherits from: Enum

Purpose:

Types of actions.

Class: ResourceType

Lines 108-115

Inherits from: Enum

Purpose:

Types of resources.

Class: Permission

Lines 119-129

Purpose:

Permission definition.

Methods:

__hash__(self)

Lines 128-129

Purpose: Hash operation.

Parameters:


Class: Role

Lines 133-152

Purpose:

Role definition.

Methods:

add_permission(self, permission)

Lines 142-144

Purpose:

Add permission to role.

Parameters: – permission: Permission

remove_permission(self, permission)

Lines 146-148

Purpose:

Remove permission from role.

Parameters: – permission: Permission

has_permission(self, permission)

Lines 150-152

Purpose:

Check if role has permission.

Parameters: – permission: Permission

Returns: bool


Class: User

Lines 156-175

Purpose:

User definition.

Methods:

add_role(self, role_id)

Lines 165-167

Purpose:

Add role to user.

Parameters: – role_id: Role id

remove_role(self, role_id)

Lines 169-171

Purpose:

Remove role from user.

Parameters: – role_id: Role id

add_permission(self, permission)

Lines 173-175

Purpose:

Add direct permission to user.

Parameters: – permission: Permission


Class: Resource

Lines 179-185

Purpose:

Resource definition.

Class: AuthorizationRequest

Lines 189-194

Purpose:

Authorization request.

Class: AuthorizationResult

Lines 198-203

Purpose:

Authorization result.

Class: PermissionAuthorizationAgent

Lines 206-474

Purpose:

Agent that provides permission and authorization management.

This agent manages roles, permissions, and authorization decisions
using RBAC and ABAC approaches.

Methods:

__init__(self, temperature)

Lines 214-245

Purpose:

Initialize the authorization agent.

Parameters: – temperature: Sampling temperature (0-1)

create_permission(self, permission_id, name, description, resource_type, action, conditions)

Lines 247-266

Purpose:

Create a new permission.

Parameters: – permission_id: Permission id – name: Name – description: Description – resource_type: Resource type – action: Action – conditions: Conditions

Returns: Permission

create_role(self, role_id, name, description, parent_roles)

Lines 268-283

Purpose:

Create a new role.

Parameters: – role_id: Role id – name: Name – description: Description – parent_roles: Parent roles

Returns: Role

create_user(self, user_id, username, roles, attributes)

Lines 285-300

Purpose:

Create a new user.

Parameters: – user_id: User id – username: Username – roles: Roles – attributes: Attributes

Returns: User

create_resource(self, resource_id, resource_type, owner_id, attributes)

Lines 302-317

Purpose:

Create a new resource.

Parameters: – resource_id: Resource id – resource_type: Resource type – owner_id: Owner id – attributes: Attributes

Returns: Resource

assign_permission_to_role(self, role_id, permission_id)

Lines 319-331

Purpose:

Assign permission to role.

Parameters: – role_id: Role id – permission_id: Permission id

Returns: bool

assign_role_to_user(self, user_id, role_id)

Lines 333-344

Purpose:

Assign role to user.

Parameters: – user_id: User id – role_id: Role id

Returns: bool

get_user_permissions(self, user_id)

Lines 346-365

Purpose:

Get all permissions for a user (from roles and direct).

Parameters: – user_id: User id

Returns: <ast.Subscript object at 0x000001A06D70EE50>

check_authorization(self, request)

Lines 367-412

Purpose:

Check if user is authorized for action on resource.

This performs both static (RBAC) and dynamic (ABAC) checks.

Parameters: – request: Request

Returns: AuthorizationResult

_check_conditions(self, conditions, context)

Lines 414-427

Purpose:

Check if conditions are met.

Parameters: – conditions: Conditions – context: Context

Returns: bool

_dynamic_authorization(self, user, request)

Lines 429-461

Purpose:

Use LLM for dynamic authorization decision.

Parameters: – user: User – request: Request

Returns: AuthorizationResult

get_authorization_summary(self)

Lines 463-474

Purpose:

Get summary of authorization system.

Parameters:

Returns: <ast.Subscript object at 0x000001A06D7EDE90>


Functions

demonstrate_permission_authorization()

Lines 477-737

Purpose:

Demonstrate the permission and authorization pattern.

Key Concepts Summary

Pattern Overview

The Permission Authorization pattern provides a structured approach to building AI agents with specific capabilities and behaviors. This implementation leverages LangChain’s composable components to create a robust and maintainable solution.

Core Components

  1. Agent Class: Main implementation of the pattern logic
  2. Prompt Engineering: Carefully crafted prompts to guide LLM behavior
  3. Tool Integration: Optional tools for extended functionality
  4. Memory Management: State handling across interactions
  5. Output Parsing: Structured response processing

When to Use

✅ Good for: – Scenarios requiring this specific pattern’s strengths – Applications needing structured agent behavior – Systems where explainability is important – Production environments requiring reliability

❌ Not ideal for: – Simple single-prompt tasks – Scenarios requiring different pattern characteristics – Resource-constrained environments (if computationally intensive)


Best Practices Demonstrated

1. Environment Configuration

  • ✅ Use .env files for API keys
  • ✅ Never hardcode credentials
  • ✅ Validate environment variables on startup

2. Error Handling

  • ✅ Graceful degradation on failures
  • ✅ Informative error messages
  • ✅ Logging for debugging

3. Prompt Engineering

  • ✅ Clear, specific instructions
  • ✅ Structured output formats
  • ✅ Few-shot examples when beneficial

4. Code Organization

  • ✅ Separation of concerns (class-based design)
  • ✅ Type hints for clarity
  • ✅ Docstrings for documentation

5. Performance Optimization

  • ✅ Appropriate temperature settings
  • ✅ Token budget management
  • ✅ Caching where applicable

LangChain Components Used

  • ChatOpenAI: OpenAI model interface
  • Chains: Sequential component composition

Why LangChain? – Composable abstractions for LLM applications – Rich ecosystem of integrations – Production-ready patterns – Active community and development


Execution Flow

1. Initialize agent with configuration
   ↓
2. Load environment and dependencies
   ↓
3. Prepare prompt with input data
   ↓
4. Invoke LLM through LangChain
   ↓
5. Parse and validate response
   ↓
6. Return formatted result

Key Decision Points: – Model selection (temperature, model type) – Prompt structure (few-shot vs zero-shot) – Error handling strategy – Output format validation


Performance Considerations

Computational Cost

  • LLM Calls: Primary cost factor (based on tokens)
  • Latency: Depends on model and input size
  • Memory: Minimal for most patterns

Optimization Strategies

  1. Prompt Optimization: Minimize tokens while maintaining clarity
  2. Caching: Cache repeated queries/responses
  3. Model Selection: Use smaller models when appropriate
  4. Batch Processing: Group similar requests
  5. Streaming: For long responses, stream tokens

Cost Estimates (Approximate)

  • GPT-3.5-turbo: ~$0.002 per request
  • GPT-4: ~$0.03 per request
  • GPT-4-turbo: ~$0.01 per request

Actual costs vary based on input/output token counts


Common Pitfalls to Avoid

1. Prompt Design Issues

❌ Vague or ambiguous instructions
✅ Clear, specific, testable prompts

2. Error Handling

❌ Ignoring API errors or rate limits
✅ Implement retry logic and graceful degradation

3. Token Management

❌ Exceeding model token limits
✅ Truncate inputs, chunk processing

4. Security

❌ Exposing API keys in code
✅ Use environment variables

5. Testing

❌ Only testing happy paths
✅ Test edge cases, failures, malformed inputs

6. Cost Management

❌ Unmonitored API usage
✅ Implement budgets, alerts, and monitoring


Further Improvements

Production Enhancements

  1. Monitoring: Add logging, metrics, tracing
  2. Validation: Input/output schema validation
  3. Rate Limiting: Implement request throttling
  4. Caching: Redis or in-memory cache for responses
  5. Async Support: Non-blocking operations for scalability

Feature Extensions

  1. Multi-Model Support: Switch between providers
  2. Fallback Models: Graceful degradation strategy
  3. Custom Tools: Domain-specific function calling
  4. Advanced Memory: Vector stores for long-term memory
  5. Evaluation: Automated testing and benchmarking

Code Quality

  1. Testing: Unit tests, integration tests
  2. Documentation: API docs, usage examples
  3. Type Safety: Stricter type hints
  4. Configuration: Externalized config files

Related Patterns

  • Pattern 138
  • Pattern 140

Pattern Families: – Reasoning Patterns (001-011) – Multi-Agent Patterns (012-019) – Tool Use Patterns (020-025) – Memory Patterns (026-031) – And many more…


Summary

The Permission Authorization pattern provides a powerful approach to building AI agents with specific capabilities. This implementation demonstrates:

✅ Key Strengths: – Clean, maintainable code structure – LangChain integration for composability – Type hints and documentation – Production-ready patterns

🎯 Best Use Cases: – Applications requiring this pattern’s characteristics – Systems needing structured agent behavior – Production environments requiring reliability

📚 Learning Resources: – LangChain Documentation: https://python.langchain.com/ – Pattern Documentation: See related patterns – OpenAI API Reference: https://platform.openai.com/docs/


File: 139_permission_authorization.py
Total Lines: 742
Pattern Category: AI Agent Design Pattern #139


Generated from actual implementation code
For educational and reference purposes

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *