# US-MGN-001-002-003: Validar Permisos en Runtime (Guards/Middleware) **RF Asociado:** [RF-MGN-001-002](../../02-modelado/requerimientos-funcionales/mgn-001/RF-MGN-001-002-gestion-roles.md) **Módulo:** MGN-001 - Fundamentos **Epic:** Autenticación y Seguridad **Prioridad:** P0 (MVP) **Story Points:** 3 **Sprint:** Sprint 2 **Estado:** Ready for Development **Fecha:** 2025-11-24 --- ## User Story **Como** sistema de seguridad, **Quiero** validar automáticamente los permisos del usuario antes de ejecutar cualquier acción, **Para** garantizar que solo usuarios autorizados puedan acceder a funcionalidades específicas. --- ## Descripción Detallada Esta user story implementa el middleware/guard que valida permisos en cada request. El sistema debe: 1. Interceptar requests a endpoints protegidos 2. Extraer user_id y tenant_id del JWT token 3. Consultar permisos del usuario (roles + permisos, con caché) 4. Validar si tiene el permiso requerido (ej: 'sale.order.create') 5. Si tiene permiso: continuar con la acción 6. Si NO tiene permiso: retornar 403 Forbidden y registrar en audit_log --- ## Criterios de Aceptación ### Escenario 1: Usuario con permiso ejecuta acción **Dado que** soy usuario con rol "Contador" que tiene permiso 'account.invoice.create', **Cuando** intento crear una factura via POST /api/v1/invoices, **Entonces** el middleware valida mis permisos, confirma que tengo el permiso, y permite la ejecución. ### Escenario 2: Usuario sin permiso intenta acción **Dado que** soy usuario con rol "Auditor" que solo tiene 'account.invoice.read', **Cuando** intento eliminar una factura via DELETE /api/v1/invoices/123, **Entonces** el middleware retorna 403 "No tiene permisos para esta acción" y registra el intento en audit_log. ### Escenario 3: Administrador bypass RBAC **Dado que** soy usuario con rol "Administrator" (is_admin=true), **Cuando** intento cualquier acción, **Entonces** el middleware hace bypass de validación de permisos y permite todo. ### Escenario 4: Usuario con múltiples roles (allow overrides deny) **Dado que** tengo rol "Auditor" (solo read) y rol "Contador" (CRUD), **Cuando** intento crear factura, **Entonces** el sistema aplica política "allow overrides deny" y permite la acción (porque Contador lo permite). ### Escenario 5: Permisos cacheados actualizados **Dado que** administrador actualiza mis permisos (agrega 'sale.order.create'), **Cuando** intento crear orden de venta, **Entonces** el sistema detecta caché inválido, recarga permisos, y permite la acción. ### Escenario 6: Frontend condiciona UI según permisos **Dado que** no tengo permiso 'account.payment.delete', **Cuando** el frontend consulta mis permisos via hook usePermissions(), **Entonces** el botón "Eliminar Pago" no se renderiza en la UI. --- ## Reglas de Negocio - **RN-1:** Todos los endpoints transaccionales deben estar protegidos con guard de permisos. - **RN-2:** Rol Administrator (is_admin=true) hace bypass completo de RBAC. - **RN-3:** Usuario con múltiples roles: "allow overrides deny". - **RN-4:** Permisos se cachean en Redis con TTL 1 hora. - **RN-5:** Al cambiar permisos de rol, se invalida caché de todos los usuarios con ese rol. - **RN-6:** Intentos de acceso no autorizado se registran en audit_log para auditoría. - **RN-7:** Performance: validación de permisos < 10ms (usando caché). --- ## Tareas Técnicas (Checklist de Implementación) ### Backend - [ ] Crear guard: `PermissionsGuard` que implementa `CanActivate` - [ ] Crear decorador: `@RequirePermission('model.action')` para endpoints - [ ] Implementar método: `PermissionsService.getUserPermissions(userId)` con caché - [ ] Implementar método: `PermissionsService.hasPermission(userId, permission)` - [ ] Implementar lógica de "allow overrides deny" para múltiples roles - [ ] Implementar bypass para is_admin=true - [ ] Implementar caché de permisos en Redis (key: `permissions:user:{userId}`) - [ ] Implementar invalidación de caché al actualizar permisos de rol - [ ] Crear endpoint: `GET /api/v1/auth/me/permissions` - Listar permisos del usuario actual - [ ] Registrar intentos no autorizados en audit_log (user_id, action, timestamp, ip) - [ ] Agregar unit tests (10 test cases) - [ ] Agregar integration tests (8 test cases) - [ ] Documentar en Swagger respuestas 403 ### Frontend - [ ] Crear hook: `usePermissions(permissions: string[])` que retorna boolean[] - [ ] Crear hook: `useHasPermission(permission: string)` que retorna boolean - [ ] Crear componente: `} {hasPermission('sale.order.delete') && } ); ``` --- ## Casos de Prueba (Test Scenarios) ### Pruebas Funcionales 1. **TC-001: Permiso concedido** - **Input:** usuario con 'sale.order.create' intenta POST /orders - **Expected:** Request pasa guard, acción ejecutada 2. **TC-002: Permiso denegado** - **Input:** usuario sin 'sale.order.delete' intenta DELETE /orders/1 - **Expected:** 403 Forbidden, audit_log registrado 3. **TC-003: Administrator bypass** - **Input:** usuario Administrator intenta cualquier acción - **Expected:** Bypass validación, siempre permitido 4. **TC-004: Múltiples roles (allow overrides deny)** - **Input:** usuario con RolA (deny) y RolB (allow) - **Expected:** Acción permitida (allow wins) 5. **TC-005: Caché hit** - **Input:** 2 requests seguidas del mismo usuario - **Expected:** 1ra consulta DB, 2da usa caché Redis 6. **TC-006: Caché invalidation** - **Input:** actualizar permisos de rol, usuario intenta acción - **Expected:** Caché invalidado, consulta DB, permisos actualizados 7. **TC-007: Frontend condicional rendering** - **Input:** usePermissions(['sale.order.create']) - **Expected:** Hook retorna [true] si tiene permiso, [false] si no ### Pruebas No Funcionales 1. **Performance:** - Validación con caché: < 10ms - Validación sin caché (cache miss): < 50ms 2. **Seguridad:** - No exponer información sensible en mensajes de error - Registrar TODOS los intentos de acceso no autorizado 3. **Concurrencia:** - Manejar race conditions en invalidación de caché --- ## Dependencias - **User Stories bloqueantes:** - US-MGN-001-002-001 (Crear Roles) - US-MGN-001-002-002 (Asignar Permisos) - **Módulos requeridos:** Redis para caché - **Datos maestros necesarios:** Roles y permisos configurados --- ## Notas de Implementación **Backend - NestJS Guard:** ```typescript @Injectable() export class PermissionsGuard implements CanActivate { async canActivate(context: ExecutionContext): Promise { const request = context.switchToHttp().getRequest(); const user = request.user; // Del JWT const requiredPermission = this.reflector.get('permission', context.getHandler()); if (user.is_admin) return true; // Bypass const hasPermission = await this.permissionsService.hasPermission( user.id, requiredPermission ); if (!hasPermission) { await this.auditLog(user.id, requiredPermission, false); throw new ForbiddenException('No tiene permisos para esta acción'); } return true; } } ``` **Frontend - React Hook:** ```typescript export function usePermissions(permissions: string[]) { const { user } = useAuthStore(); return permissions.map(perm => user.permissions?.includes(perm) || user.is_admin ); } ``` --- ## Estimación Detallada | Tarea | Estimación | |-------|------------| | Backend Development | 2 horas | | Frontend Development | 2 horas | | Testing (Unit + Integration) | 1.5 horas | | Code Review | 0.5 horas | | **TOTAL** | **6 horas** | **Equivalente:** 3 Story Points --- ## Definition of Done (DoD) - [ ] PermissionsGuard implementado y funcionando - [ ] Decorador @RequirePermission funcionando - [ ] Caché de permisos en Redis implementado - [ ] Hooks usePermissions y useHasPermission funcionando - [ ] Audit log de accesos no autorizados funcionando - [ ] Unit tests escritos y pasando (cobertura > 80%) - [ ] Integration tests escritos y pasando - [ ] Code review completado - [ ] Documentación actualizada - [ ] Merge a branch `develop` completado --- ## Referencias - [RF-MGN-001-002: Gestión de Roles y Permisos](../../02-modelado/requerimientos-funcionales/mgn-001/RF-MGN-001-002-gestion-roles.md) - [ET-BACKEND-MGN-001-002](../../02-modelado/especificaciones-tecnicas/backend/mgn-001/ET-BACKEND-MGN-001-002-gestion-roles.md) - [ET-FRONTEND-MGN-001-002](../../02-modelado/especificaciones-tecnicas/frontend/mgn-001/ET-FRONTEND-MGN-001-002-gestion-roles.md) - [TRACEABILITY-MGN-001.yaml](../../02-modelado/trazabilidad/TRACEABILITY-MGN-001.yaml)