4.7 KiB
4.7 KiB
RF-MGN-001-005: Reset de Contraseña
Módulo: MGN-001 - Fundamentos Prioridad: P0 (MVP) Story Points: 5 Estado: Definido Fecha: 2025-11-23
Descripción
El sistema debe permitir a los usuarios solicitar el reset de su contraseña cuando la olvidan. Se envía un token temporal por email que permite establecer una nueva contraseña.
Actores
- Actor Principal: Usuario (olvidó contraseña)
- Actores Secundarios: Sistema de Email
Precondiciones
- Usuario debe tener cuenta activa
- Sistema de email debe estar configurado
- Tenant debe estar activo
Flujo Principal
- Usuario accede a página de login y selecciona "Olvidé mi contraseña"
- Usuario ingresa su email
- Sistema valida que email existe en el tenant actual
- Sistema genera token único de reset (UUID) con expiración 24h
- Sistema guarda token en auth.password_reset_tokens con expires_at
- Sistema envía email con link: {app_url}/reset-password?token={token}
- Usuario recibe email y hace clic en link
- Sistema valida que token existe y no ha expirado
- Usuario ingresa nueva contraseña (2 veces para confirmar)
- Sistema valida política de contraseña
- Sistema hashea nueva contraseña con bcrypt
- Sistema actualiza auth.users.password_hash
- Sistema marca token como usado (used_at = NOW())
- Sistema invalida refresh tokens existentes (logout en otros dispositivos)
- Sistema muestra mensaje: "Contraseña actualizada. Inicie sesión"
Flujos Alternativos
FA-1: Email No Encontrado
- Si email no existe en tenant
- Sistema NO revela que email no existe (seguridad)
- Sistema muestra: "Si el email existe, recibirá instrucciones"
- Sistema NO envía email
FA-2: Token Expirado
- Si token existe pero expires_at < NOW()
- Sistema retorna error 400: "Token expirado. Solicite nuevo reset"
FA-3: Token Inválido
- Si token no existe en BD
- Sistema retorna error 400: "Token inválido"
FA-4: Token Ya Usado
- Si token.used_at IS NOT NULL
- Sistema retorna error 400: "Token ya fue utilizado. Solicite nuevo reset"
FA-5: Contraseña Débil
- Si nueva contraseña no cumple política
- Sistema retorna error 400: "Contraseña debe tener 8+ caracteres, mayúscula, número, símbolo"
FA-6: Múltiples Solicitudes de Reset
- Usuario solicita múltiples tokens en corto tiempo
- Sistema invalida tokens anteriores (solo último es válido)
- Sistema aplica rate limiting (max 3 solicitudes por hora)
Reglas de Negocio
- RN-1: Token de reset expira en 24 horas
- RN-2: Token solo puede usarse una vez
- RN-3: Nueva contraseña debe cumplir política de seguridad
- RN-4: Sistema NO revela si email existe o no (prevenir enumeración)
- RN-5: Múltiples solicitudes de reset invalidan tokens anteriores
- RN-6: Rate limiting: máximo 3 solicitudes por hora por IP
- RN-7: Reset de contraseña invalida refresh tokens existentes
Criterios de Aceptación
- Usuario puede solicitar reset de contraseña con su email
- Sistema envía email con token de reset válido por 24h
- Usuario puede establecer nueva contraseña usando token
- Token expirado no permite reset
- Token solo puede usarse una vez
- Nueva contraseña debe cumplir política de seguridad
- Sistema NO revela si email existe (prevenir enumeración)
- Reset invalida sesiones activas en otros dispositivos
- Rate limiting previene abuso (max 3 solicitudes/hora)
- Link de reset tiene formato seguro (HTTPS, token complejo)
Entidades Involucradas
- Principales:
- auth.password_reset_tokens (token, user_id, expires_at, used_at)
- auth.users (password_hash)
- Relacionadas:
- auth.sessions (tokens a invalidar)
Referencias
Notas Técnicas
- Patrón Odoo: Similar a reset password en portal
- Token: UUID v4 (aleatorio, no predecible)
- Expiración: Cronjob limpia tokens expirados diariamente
- Email Template:
Hola {{user.name}}, Recibimos una solicitud para restablecer tu contraseña. Haz clic en el siguiente enlace para establecer una nueva contraseña: {{reset_link}} Este enlace expira en 24 horas. Si no solicitaste este cambio, ignora este email. - Seguridad:
- No revelar si email existe
- Token largo (UUID = 36 caracteres)
- HTTPS obligatorio en producción
- Rate limiting por IP
Dependencias
- RF Dependientes: RF-MGN-001-001 (Autenticación)
- Bloqueante para: Ninguno (funcionalidad independiente)