CreaRack-SL

Terminal Auth Local del Agent · Fase 2 (frontend, token opcional)

Descripción

Segundo paso de la arquitectura de seguridad del Agent local. Complementa a Fase 1 (backend).

La web ahora manda el token de auth local automáticamente a cada llamada fetch dirigida al Agent (localhost:5050 / 127.0.0.1:5050), sin necesidad de modificar los ~35 call-sites del código cliente uno a uno.

Característica clave: Token OPCIONAL

El token es completamente opcional en esta fase. Si no existe aún (porque el Agent aún no lo deposita hasta Fase 3, o no hay sesión de usuario), la llamada se emite sin header Authorization y se comporta idénticamente al estado actual. Por eso este cambio es totalmente inocuo para los .exe antiguos y para las webs sin sesión.

No da seguridad por sí sola — es fontanería. El candado real (Agent .exe exigiendo y validando el token, cerrando CORS) llega en Fase 3.

Cómo funciona

Intercepción de window.fetch

Se carga temprano en base.html el módulo static/js/modules/agent_auth.js. Este módulo:

  1. Obtención del token (una sola vez por carga de página, memoizado):

    • Pregunta al Agent local su identidad: GET http://localhost:5050/info → extrae agent_id
    • Consulta el SaaS: GET /api/agent/local-token?agent_id=...
    • Solo responde si hay sesión + fleet:view + el agent pertenece al tenant del usuario
    • Si falla en cualquier paso, devuelve null (no rompe nada)
  2. Reescritura de window.fetch: Intercepta ALL llamadas fetch. Si el URL es de Agent y hay token, añade Authorization: Bearer <token>. Si no hay token, la llamada pasa como antes.

Casos especiales (no son fetch simples)

Consola SSH (iframe)

El iframe (ssh_client.js) recibe el token por postMessage con tipo SET_AUTH_TOKEN antes de recibir la configuración SSH. El targetOrigin está acotado al Agent local.

  • Un Agent viejo que no entiende el mensaje lo ignora (inocuo).
  • El nuevo lo usa para autenticar el WebSocket SSH.

Descargas de logs

Migradas de window.open() (no lleva headers) a fetch+blob (window.downloadFromAgent()):

  • En TerminalToolbar.js: descarga al parar grabación
  • En ssh_integration.js: descarga al cerrar sesión SSH

La función downloadFromAgent() pasa por window.fetch interceptado, así que el token se añade automáticamente.

Cambios en el código

ArchivoCambio
static/js/modules/agent_auth.jsNuevo. 96 LOC. Interceptor + token fetch + descarga
static/js/modules/ssh_client.jsAñade postMessage SET_AUTH_TOKEN antes de config SSH
static/js/editor/ssh_integration.jsSustituye window.open() por downloadFromAgent()
static/js/terminal/TerminalToolbar.jsSustituye window.open() por downloadFromAgent()
templates/base.htmlCarga agent_auth.js temprano (defer, antes de módulos)
CHANGELOG.mdEntrada Fase 2, con ADR ref
RELEASE_NOTES.mds125: Agente local más seguro, paso 2

Dependencias y relaciones

  • ADR: decision--20260610--terminal-auth-local-cross-origin — arquitectura + token spec
  • Fase anterior: feature--terminal--auth-local-fase-1 (backend /api/agent/local-token)
  • Entidad técnica: entity--static--module--agent-auth (el módulo interceptor)
  • Cliente: entity--static--module--ssh-client, entity--static--class--TerminalToolbar
  • Concepto: [[concept—security—cross-origin-local-auth]]

Testing

⚠️ No cubierto por CI — requiere smoke manual en navegador con el Agent .exe corriendo localmente.

Pruebas recomendadas:

  1. Con Agent viejo (sin token en /info): todas las llamadas siguen funcionando sin token.
  2. Con Agent Fase 2 (retorna token): verifica que el header Authorization: Bearer <token> se añade.
  3. Descarga de logs: confirma que blob se crea y descarga correctamente.
  4. Consola SSH (iframe): verifica que el token llega a tiempo antes del WS.

Véase también

  • [[decision—20260610—terminal-auth-local-cross-origin]]
  • [[entity—static—module—agent-auth]]
  • [[entity—static—module—ssh-client]]
  • [[feature—terminal—auth-local-fase-1]]
  • [[concept—security—cross-origin-local-auth]]