Seguridad y cifrado
Usuarios — /users

CRUD de usuarios, con perfil de acceso, interfaces permitidas y suscripción a alertas. El login puede ser local (contraseña en el CMS) o vía LDAP/Active Directory, según la configuración global.
El teléfono solo aparece en el formulario cuando la suscripción a alertas está activada — es el único lugar donde se usa el número, en el payload que el canal WhatsApp entrega a la automatización (ver Alertas). Con la suscripción activada pasa a ser obligatorio; desactivarla limpia el campo.
Recibe resumen diario es una suscripción aparte, y a propósito: enciende el correo de la Radiografía del Día, que sale recortado por las Aplicaciones e Interfaces que ese usuario ve. Atarlo a la suscripción de alertas obligaría a quien solo quiere el resumen por correo a registrar un celular, ya que la suscripción de alertas gobierna también el WhatsApp.
Interfaces permitidas
Es el segundo eje de permiso, independiente del Perfil: el Perfil dice qué pantallas abre el usuario; las Interfaces permitidas dicen qué datos ve dentro de ellas. Un operador con la Herramienta Mensajes liberada, pero con solo dos Interfaces marcadas, ve los mensajes de esas dos.
La lista viene agrupada por Aplicación, y el encabezado de cada grupo trae una casilla Todas que libera (o quita) el grupo entero de una vez — en una planta donde el usuario recibe la Aplicación completa, marcar 18 interfaces una a una era el camino normal, no la excepción. Con solo parte del grupo marcada, la casilla queda en estado intermedio: se ve que la Aplicación está parcialmente liberada sin abrir el grupo y revisar interfaz por interfaz.
Ninguna interfaz marcada significa acceso irrestricto, no acceso nulo — misma convención del administrador. Es el valor por defecto para quien cuida la instalación entera; restringir es el acto explícito.
El recorte vale por ruta, no solo por el listado: pedir un registro por id devuelve 404 cuando pertenece a una Interfaz fuera de su alcance, y el cuerpo de un POST no consigue apuntar a una Interfaz que usted no tiene. Vale también para la escritura, y no solo para la lectura — crear, editar o borrar un registro de una Aplicación que usted no ve es rechazado, incluso cuando la edición intenta mover el registro hacia allá.
Once pantallas fueron alineadas a esa regla a lo largo de septiembre de 2026 — Alertas, Errores de Negocio, el Cockpit, Credenciales, API Keys, Variables de Aplicación, Claves de Cifrado, Reglas de Cifrado, Transformadores, los logs de Recolección y de Envío y Conexiones Externas —, así que un usuario restringido puede notar que pasó a ver menos de lo que veía antes. Es la corrección, no una regresión.
Las tres últimas entraron por caminos distintos, y vale saber cuál es el de cada una:
| Pantalla | Qué pasó a recortar |
|---|---|
| Transformadores | Sin Alcance el Transformador es global y todos lo ven; con Alcance, solo quien tiene una de las Interfaces alcanzadas. Vale también en las rutas por id — sin eso, el script de otra área estaba a un GET de distancia |
| Log de Recolección y Log de Envío | Los mensajes ya se recortaban; se filtraba el eje, que agrupa por la Aplicación que envió — y quien envía a su Interfaz suele ser la Aplicación de otra área. Los orígenes fuera de su alcance se vuelven una barra agregada, sin nombre. Se va el nombre, no el número: el total sigue coincidiendo con la pantalla de Mensajes |
| Conexiones Externas | La conexión gana dueño por el uso — el Keep Alive de una Aplicación y las Recolecciones que buscan por ella. Una conexión que nadie usa todavía sigue visible para todos, si no desaparecería de la pantalla en el instante siguiente al Guardar |
Lo que cada usuario ve sobre sí mismo
En el popover del propio usuario, en el encabezado, cualquiera consulta sus Interfaces liberadas — agrupadas por Aplicación, con el tipo (Recolección o Entrega) y el estado de bloqueo de cada una. No depende de tener la Herramienta Usuarios ni Aplicaciones en el perfil: ver los propios permisos es distinto de administrar los de los demás.
El mismo popover permite cambiar o quitar la foto del avatar. La imagen se reduce a 256×256 JPEG en el navegador antes de subir — la foto original de la cámara nunca llega a la base de datos — y el servidor solo acepta un data URL de imagen.
Perfiles — /roles

Un Perfil es un conjunto de Herramientas liberadas. Cada Herramienta corresponde a una pantalla del sistema — es lo que decide qué aparece en el menú y qué autoriza la API.
Las pantallas agrupadas por Aplicación y por Interfaz dependen de las Herramientas Aplicaciones e Interfaces para cargar sus listas. Un perfil sin ellas ve la pantalla vacía, y no un mensaje de permiso denegado.
Nivel de acceso por Herramienta

En cada Herramienta el perfil recibe un nivel, no un conjunto de métodos HTTP:
| Nivel | Qué permite |
|---|---|
| Sin acceso | La pantalla no aparece en el menú, y la API rechaza |
| Consultar | Abre la pantalla y ve los datos, sin modificar nada |
| Consultar y editar | Consulta, crea y modifica — pero no elimina. En Mensajes, es el nivel que habilita reprocesar y cancelar |
| Acceso total | Todo lo que la Herramienta permite, incluso eliminar |
| Permitir | Ejecuta la acción, en las Herramientas que no tienen pantalla propia — descifrar contenido, enviar por correo, instalar licencia |
Cada Herramienta ofrece solo los niveles que tienen sentido en ella: el Log de Auditoría solo se puede consultar, e Instalar Licencia solo se puede permitir o no. Quien lo decide es la lista de métodos que esas rutas aceptan de verdad, guardada en el propio registro de la Herramienta.
La pantalla mostraba las cuatro casillas GET / POST / PUT / DELETE, y el problema no era
estético: reprocesar un mensaje es POST en /messages, no una Herramienta aparte — así que
marcar solo GET habilitaba la pantalla y la dejaba sin funcionar, sin nada que explicara por
qué. El Modo avanzado sigue mostrando las cuatro casillas, para las combinaciones que no caben
en ningún nivel.
Los perfiles que ya vienen en el sistema
| Perfil | Para quién |
|---|---|
| CMS_Administrator | Acceso irrestricto. Nace con isAdmin y no depende de ninguna Herramienta |
| CMS_Monitor | Sigue mensajes y paneles, sin entrar en configuración |
| CMS_Monitor_Cripto | Lo mismo, más las Reglas de Cifrado y el derecho de descifrar contenido |
| CMS_Developer | Construye y mantiene integraciones, sin administrar usuarios, perfiles ni seguridad |
El CMS_Developer alcanza todo el Laboratorio de Integración — Banco de Pruebas, Planes de Prueba y Simuladores —, además de descifrar contenido, las Sesiones de IA y el MCP en lectura. No tiene Recolección, Definición de Mensaje ni el SAP SDK: son las puertas por donde se cambia lo que corre en producción.
Se crean en el arranque en el que faltan, y a partir de ahí el CMS no vuelve a tocar sus permisos: lo que usted quite en la pantalla sigue quitado en el reinicio siguiente. Para llevar un ajuste de estos perfiles a una instalación que ya existe hay un script dedicado, que muestra el plan antes de grabar.
En una instalación nueva, tres Herramientas nacen apagadas en Configuraciones › Herramientas — Definiciones de Recolección, Definiciones de Entrega y Workers —, como en la instalación de referencia. Encenderlas es un acto consciente de quien administra. Eso vale solo en la creación: el CMS nunca vuelve a encender en el reinicio lo que un administrador apagó, porque apagar una Herramienta revoca el acceso de todos los perfiles no administradores de una vez.
Acciones restringidas a administradores
Tener la Herramienta Perfiles, Usuarios o Herramientas autoriza administrar registros, no escalar privilegios. Nueve operaciones exigen que quien llama ya sea administrador, sin importar las Herramientas del perfil:
| Operación | Pantalla |
|---|---|
Marcar un Perfil como administrador (isAdmin) | Perfiles |
| Grabar la matriz de permisos de un Perfil | Perfiles |
| Cambiar el Perfil de un usuario | Usuarios |
| Cambiar el login de otra persona (el propio sigue libre) | Usuarios |
| Cambiar el origen de autenticación (local o LDAP) de cualquier cuenta | Usuarios |
| Desactivar o reactivar un usuario | Usuarios |
| Eliminar un usuario | Usuarios |
| Restablecer la contraseña de otra persona — exige además confirmar la propia contraseña (y el código 2FA, si está activo) | Usuarios |
| Crear, activar/desactivar o eliminar una Herramienta | Herramientas |
Fuera del control de acceso, dos acciones con efecto en toda la instalación también exigen administrador desde septiembre de 2026: Importar / Exportar configuración y enviar o quitar la SDK SAP (ver Herramientas que no son pantallas).
El criterio no es el campo, es la pregunta: ¿esta operación altera el control de acceso? Editar nombre, descripción, teléfono o correo sigue siendo trabajo de quien tiene la Herramienta. Y la matriz de permisos solo exige privilegio cuando cambia — la pantalla envía el formulario entero en cada edición, y reenviar lo que ya está grabado no es una concesión.
Sin esto, un perfil de soporte con escritura en Perfiles se marcaba a sí mismo como administrador;
o, sin tocar isAdmin, concedía a su propio perfil todas las Herramientas del sistema — el efecto
práctico es el mismo, porque la autorización mira la matriz e isAdmin es solo un atajo. Y, con
escritura en Usuarios, desactivaba uno a uno a los administradores hasta que no quedara nadie capaz
de revertirlo: un usuario inactivo pierde acceso a todo, incluido este control. Cada intento,
aceptado o denegado, queda en el Registro de Auditoría — igual que la concesión efectuada.
El campo endpoint de una Herramienta es inmutable después de creada: es la clave con la que la API relaciona ruta y permiso, y reapuntarlo cambiaría el significado de la Herramienta para todos los perfiles a la vez. El flag activo tiene el mismo peso — desactivar una Herramienta la revoca de todos los perfiles no administradores a la vez, y reactivarla deshace una revocación hecha a propósito.
Política de contraseña y aviso de intentos
En Configuración › Parámetros:
- Longitud mínima de la contraseña — se aplica a nuevos registros y cambios. El sistema nunca acepta menos de 8 caracteres, aunque se configure un valor menor.
- Intentos fallidos antes de alertar — errores de contraseña seguidos que envían correo a los administradores y al dueño de la cuenta. Cero desactiva el aviso.
La cuenta nunca se bloquea por intentos fallidos: bloquear al tercer error le daría a cualquiera
que conozca un login la posibilidad de derribar el acceso administrativo a propósito. Lo que encarece
el intento masivo es el límite por origen en las rutas de inicio de sesión. Cada error de contraseña
queda en el Registro de Auditoría con la acción LOGIN_FALHO y la IP de origen.
Primer acceso
La cuenta administrativa creada en la primera ejecución nace con contraseña aleatoria (impresa una sola vez en el log de la API) y contraseña expirada: el primer inicio de sesión no abre el sistema, exige definir una contraseña nueva. Lo mismo vale para toda contraseña restablecida por un administrador para otra persona.
Herramientas que no son pantallas
No toda Herramienta corresponde a un ítem del menú. Algunas gobiernan una acción dentro de una pantalla que el usuario ya tiene, y existen para poder concederse por separado:
| Herramienta | Qué libera |
|---|---|
| Descifrar Mensaje | El botón de descifrar en el detalle del mensaje |
| Enviar PDF del Mensaje | El envío del mensaje por e-mail |
| Instalar Pack y Asistente de Integración | Los asistentes que abren desde dentro de Aplicaciones |
| Agente de Integración | Las pestañas Investigar y Configurar del Asistente de IA. La pestaña Preguntar es libre y no depende de ninguna Herramienta |
| Importar / Exportar | La sección de import/export dentro de la Danger Zone — solo para administrador: la Herramienta sola ya no la libera |
| SDK SAP | La pestaña de instalación de la SDK, en Parámetros — también solo para administrador |
| Herramientas | La pestaña que activa y desactiva Herramientas del sistema |
MCP Integration Tools (/mcp/integration-tools) | Permite que el token MCP de un usuario de servicio llame a las tools del Servidor MCP de integraciones. La API Key y la Credencial de Entrada no la necesitan |
En Perfiles aparecen agrupadas bajo la pantalla a la que pertenecen — Descifrar Mensaje junto a Mensajes, Instalar Pack junto a Aplicaciones — y no en una lista suelta al final.
La separación existe para que ver no implique poder. Dar acceso a Mensajes es rutinario; dejar que alguien descifre un payload o mande el PDF hacia afuera es otra decisión, y por eso es otra casilla.
Autenticación en dos pasos (2FA)
Cuando el 2FA está activado globalmente (Configuraciones), el login pasa a ser:
POST /auth/login→ si el usuario tiene 2FA activo, devuelve untempTokende 5 minutos en vez del token de acceso;- el usuario informa el código TOTP de la app autenticadora;
POST /auth/2fa/validate(contempToken+ código) → devuelve el JWT definitivo.
Cada usuario activa el 2FA en su propia cuenta: POST /auth/2fa/generate devuelve el código QR y
POST /auth/2fa/confirmar con el primer código concluye la activación.
Con el 2FA activado globalmente y todavía no activado en su cuenta, un punto ámbar aparece en el avatar de la cabecera; el estado completo queda en la línea 2FA del menú del usuario. Cuando está todo bien no hay marca alguna — no existe acción que tomar, y un segundo sello verde compitiendo con la campana y con el contador de la Guardia solo enseñaría a ignorar el ámbar en esa barra.
Cifrado de payload
Los mensajes pueden cifrarse con AES-256-GCM antes de ser persistidos, sin afectar el payload realmente entregado o recolectado — el destino sigue recibiendo el contenido original.
Claves de Cifrado — /encryption-keys

Material simétrico generado (o informado) por el usuario, guardado cifrado en reposo por envelope
encryption (CREDENCIAL_ENCRYPTION_KEY). Cada clave registra quién la creó y puede tener una
lista de usuarios autorizados a descifrar.
Una lista vacía es fail-closed: solo los usuarios con perfil administrador consiguen descifrar.
Reglas de Cifrado — /encryption-rules

Asocian una Clave a una Definición de Entrega o de Recolección, condicionadas a un texto comodín y a un sentido (Envío, Retorno o Ambos). También es posible vincular una clave incondicional directamente en la Definición.
En una Entrega con Transformador por Aplicación productora, el mensaje guarda también lo que la productora envió, en un formato que no es el de la Entrega — y la regla coincide por texto. Si el texto comodín aparece en ese contenido, la regla vale como en cualquier payload. Si no aparece, pero la regla coincidió con lo convertido, el contenido de la productora se cifra entero con la clave de esa regla: sin eso, lo convertido quedaría cifrado y el original, con el mismo dato, en claro al lado. La regla Parcial no se transfiere, porque el tramo que cifraría no existe en el otro formato.
El listado también dice quién creó y quién modificó por última vez cada regla, con fecha. Es la misma autoría de Conexiones y Transformadores: el autor es siempre quien estaba autenticado en el momento, guardado como correo electrónico, y no un campo enviado en el formulario. Una regla creada antes de que el campo existiera aparece con un guion.
Descifrado bajo demanda
El payload cifrado solo se revierte cuando alguien hace clic en Descifrar en el detalle del mensaje — nunca automáticamente en un listado o exportación. En el clic, el CMS exige:
Autorización
Estar en la lista de autorizados de la clave usada (o ser administrador).
Reautenticación
Informar la propia contraseña — y el código 2FA, si está activo.
Justificación
Un texto no vacío explicando por qué el contenido necesita ser visto.
Log de Auditoría — /reports/audit-log

Todo intento de descifrado — autorizado o no, con contraseña correcta o incorrecta — genera un evento con usuario, acción, resultado (éxito/denegado), motivo técnico de la denegación, la justificación escrita, la entidad afectada y la IP de origen.