import { AdminUser } from '../entities/AdminUser'; import { AuthorizationError } from '../errors/AdminDomainError'; /** * Domain service for authorization checks * Stateless service that enforces access control rules */ export class AuthorizationService { /** * Check if an actor can perform an action on a target user */ static canPerformAction( actor: AdminUser, action: 'view' | 'manage' | 'modify_roles' | 'change_status' | 'delete', target?: AdminUser ): boolean { // Actors must be system admins and active if (!actor.isSystemAdmin() || !actor.isActive()) { return false; } switch (action) { case 'view': return this.canView(actor, target); case 'manage': return this.canManage(actor, target); case 'modify_roles': return this.canModifyRoles(actor, target); case 'change_status': return this.canChangeStatus(actor, target); case 'delete': return this.canDelete(actor, target); default: return false; } } /** * Check if actor can view target user */ private static canView(actor: AdminUser, target?: AdminUser): boolean { if (!target) { // Viewing list - only admins can view return actor.isSystemAdmin(); } // Can always view self if (actor.id.equals(target.id)) { return true; } // Owner can view everyone if (actor.hasRole('owner')) { return true; } // Admin can view non-admin users if (actor.hasRole('admin')) { return !target.isSystemAdmin(); } return false; } /** * Check if actor can manage target user */ private static canManage(actor: AdminUser, target?: AdminUser): boolean { if (!target) { return false; } // Can always manage self if (actor.id.equals(target.id)) { return true; } // Owner can manage everyone if (actor.hasRole('owner')) { return true; } // Admin can manage non-admin users if (actor.hasRole('admin')) { return !target.isSystemAdmin(); } return false; } /** * Check if actor can modify roles of target user */ private static canModifyRoles(actor: AdminUser, target?: AdminUser): boolean { if (!target) { return false; } // Only owner can modify roles if (!actor.hasRole('owner')) { return false; } // Cannot modify own roles (prevents accidental lockout) if (actor.id.equals(target.id)) { return false; } return true; } /** * Check if actor can change status of target user */ private static canChangeStatus(actor: AdminUser, target?: AdminUser): boolean { if (!target) { return false; } // Cannot change own status if (actor.id.equals(target.id)) { return false; } // Owner can change anyone's status if (actor.hasRole('owner')) { return true; } // Admin can change user status but not other admins/owners if (actor.hasRole('admin')) { return !target.isSystemAdmin(); } return false; } /** * Check if actor can delete target user */ private static canDelete(actor: AdminUser, target?: AdminUser): boolean { if (!target) { return false; } // Cannot delete self if (actor.id.equals(target.id)) { return false; } // Owner can delete anyone if (actor.hasRole('owner')) { return true; } // Admin can delete users but not admins/owners if (actor.hasRole('admin')) { return !target.isSystemAdmin(); } return false; } /** * Enforce authorization - throws if not authorized */ static enforce( actor: AdminUser, action: 'view' | 'manage' | 'modify_roles' | 'change_status' | 'delete', target?: AdminUser ): void { if (!this.canPerformAction(actor, action, target)) { const actionLabel = action.replace('_', ' '); const targetLabel = target ? `user ${target.email.value}` : 'user list'; throw new AuthorizationError( `User ${actor.email.value} is not authorized to ${actionLabel} ${targetLabel}` ); } } /** * Check if actor can list users */ static canListUsers(actor: AdminUser): boolean { return actor.isSystemAdmin() && actor.isActive(); } /** * Check if actor can create users */ static canCreateUsers(actor: AdminUser): boolean { // Only owner can create users with admin roles // Admin can create regular users return actor.isSystemAdmin() && actor.isActive(); } /** * Check if actor can assign a specific role */ static canAssignRole(actor: AdminUser, roleToAssign: string, target?: AdminUser): boolean { // Only owner can assign owner or admin roles if (roleToAssign === 'owner' || roleToAssign === 'admin') { return actor.hasRole('owner'); } // Admin can assign user role if (roleToAssign === 'user') { // Admin can assign user role to non-admin users // Owner can assign user role to anyone if (actor.hasRole('owner')) { return true; } if (actor.hasRole('admin')) { if (!target) { return true; } return !target.isSystemAdmin(); } } return false; } /** * Get permissions for actor */ static getPermissions(actor: AdminUser): string[] { const permissions: string[] = []; if (!actor.isSystemAdmin() || !actor.isActive()) { return permissions; } // Base permissions for all admins permissions.push( 'users.view', 'users.list' ); // Admin permissions if (actor.hasRole('admin')) { permissions.push( 'users.manage', 'users.status.change', 'users.create', 'users.delete' ); } // Owner permissions if (actor.hasRole('owner')) { permissions.push( 'users.manage', 'users.roles.modify', 'users.status.change', 'users.create', 'users.delete', 'users.export' ); } return permissions; } /** * Check if actor has specific permission */ static hasPermission(actor: AdminUser, permission: string): boolean { const permissions = this.getPermissions(actor); return permissions.includes(permission); } /** * Enforce permission - throws if not authorized */ static enforcePermission(actor: AdminUser, permission: string): void { if (!this.hasPermission(actor, permission)) { throw new AuthorizationError( `User ${actor.email.value} does not have permission: ${permission}` ); } } }