metis-desk/docs/auditorias/resources-global-scope/04-aislamiento-autorizacion.md
2026-10-25 01:19:17 +02:00

19 KiB
Raw Blame History

04 — Aislamiento y autorización

Lo que garantiza hoy cada control

CONFIRMADO: requireAuthenticated valida sesión mediante userId/authVersion y usuario activo. No recibe companyId ni aplica ACL por compañía. ResourceUseCases valida UUID de path; SequelizeResourceRepository.load comprueba existencia de compañía y carga exclusivamente sus recursos. Esto protege referencias entre entidades del contexto, pero no establece una ACL por operador sobre esa compañía. El modelo de soporte compartido está documentado expresamente en docs/arquitectura/proveedor-de-relaciones-tipadas.md; no es por sí mismo una vulnerabilidad del modelo actual. auth: require-authenticated.ts:6 load: sequelize-resource.repository.ts:58 routes: resource.routes.ts:54.

CONFIRMADO: existe isInitialAdmin, usado en IdentityUseCases.administrator para gestionar usuarios. No existe un catálogo de roles en estas rutas ni un guard de administración global de recursos. El catálogo de definiciones acepta scope global con el mismo authenticate. No denominar a ese control «administrador de compañía», que no está implementado. admin: identity.use-cases.ts:75 catalogRoutes: resource-catalog.routes.ts:65.

RIESGO ALTO (A01): un operador autenticado puede invocar rutas de catálogo global sin permiso específico, según composición/rutas inspeccionadas. Es un déficit respecto al objetivo de edición global restringida; no se realizó explotación HTTP ni se afirma escalada respecto al producto actual, que describe un espacio común de soporte. RIESGO CRÍTICO condicionado (A02): si se usa esa autenticación como aislamiento de operadores por compañía, cambiar companyId a otra compañía existente no encuentra una ACL que lo impida. Aceptar/rechazar este modelo de soporte compartido es decisión de producto previa a R2.2. runtime: identity-runtime.ts:17 auth: require-authenticated.ts:6.

Las relaciones tipadas usan contextos emitidos por SessionRelationshipReadAccess, WeakMap y reautorización de sesión/existencia de compañía antes de leer. CONFIRMADO: tampoco implementan una ACL operador–compañía. No extender su companyId obligatorio a NULL para representar un producto global: es el contexto operativo del consumidor. relationshipAuth: relationship-read-access.ts:7.

CONFIRMADO: registerIdentityRoutes monta su router en /api antes de registrar los módulos; su middleware de escrituras comprueba Origin y x-csrf-token de sesión. Esto protege contra CSRF, no concede privilegio global. csrf: identity.routes.ts:105.

Inventario de filtros y consultas

Clasificación de intención futura: 1 solo compañía; 2 globales permitidos + compañía; 3 solo globales; 4 referencia concreta autorizada; 5 administración global. Esta tabla cubre las familias encontradas en lecturas y escrituras; sus consumidores se expanden en 05.

Punto / símbolos Filtro actual Intención futura / actuación
readInventory, load, ResourceUseCases.save/setActive/remove companyId → IDs del contexto 1 para gestión local; nuevo lector 2/4 para productos; no ampliar escritura local
ResourceCatalog.visible, availability global/local de definiciones 2 de plantillas, 5 al editar global; no es catálogo de productos
ResourceInventoryService.list inventory por compañía Mantener 1 en contrato genérico; método explícito 2/4 para aplicaciones
Software repository load/save/remove instalaciones/revisiones/activos de compañía; recursos vía servicio 1 para operación y licencia; 2/4 solo para resourceId software
Application repository load/save/remove configuraciones/perfiles/personas de compañía 1 para operación; 2/4 para aplicación
Certificate repository compañía; servicio de recursos y usage certificate 1/4; rechazar globales
Remote repository / remoteReferences compañía; cualquier resource local como target 1/4; no heredar globales por compartir servicio
Support repository resources.companyId=:companyId, support stockKey/usage 1/4; conservar restricción compuesta
DirectoryDomainReader / NetworkShareReader ID + companyId, join proyección 1/4; nunca productos globales
Options/SummaryResolvers directorio y SMB contexto autorizado + companyId + IDs/search/cursor 1/4; búsqueda especializada permanece local
readResourceProjections mailboxes/access con compañía 1; mailbox/access son operativos
readResourceProjectionHistory solo itemId tras selección de raíz 4; no exponer como API por ID sin comprobar raíz
removeResource ID bloqueado; DELETE final id AND companyId 1/4 local; ruta 5 global separada con protección de usados
prepareResourceTemplateUpdates DISTINCT companyId por plantilla y carga por compañía Administración transversal 5; procesar globales aparte y mantener orden de locks
ResourceDashboardReader stats/entries/activity filtro compañía opcional; joins companies Administración/transversal existente; no aplicar 2 automáticamente, revisar recuentos NULL
migrateLegacyResources / migrateSupportResources proyecciones por compañía / IDs legacy Migración interna; conservar propiedad, no activar lectura global
Web inventario, software, aplicaciones, certificados, remote, entornos y puestos inventoryKeys.company(id) y filtros en memoria 1 para inventario operativo; 2/4 explícito para nombres/aplicaciones en todos los consumidores

Evidencia: read: resource-inventory-relational.ts:195 catalog: resource-catalog.aggregate.ts:14 service: resource-inventory.service.ts:7 softwareRead: sequelize-software-installation.repository.ts:27 applicationRead: sequelize-application-configuration.repository.ts:34 certificateFK: configuration-snapshots.ts:80 remoteRead: sequelize-remote-connection.repository.ts:92 supportRead: sequelize-support.repository.ts:21 directoryRead: directory-domain-reader.ts:19 shareRead: network-share-reader.ts:22 directoryOptions: directory-domain-options-reader.ts:15 shareOptions: network-share-options.ts:11 directorySummaries: directory-domain-summary-resolver.ts:27 shareSummaries: network-share-summary-resolver.ts:27 remove: remove-resource.ts:37 propagation: prepare-resource-template-updates.ts:15 dashboard: resource-dashboard-reader.ts:15 legacy: migrate-legacy-resources.ts:216 supportMigration: migrate-support-resources.ts:44 projectionRead: resource-projection-reader.ts:33 processRead: sequelize-process.repository.ts:109 inventoryAPI: inventory-api.ts:11.

Contrato propuesto de visibilidad y acceso

PROPUESTO: autorizar primero el contexto operativo C desde sesión. Para un propósito application, aceptar (scope=global AND plantilla elegible global AND sin integración operativa) OR (scope=company AND owner=C AND usage application). Para software se añade OS local; para licencia se exige company=C y usage license. El contexto de compañía sigue siendo obligatorio aunque el producto no tenga propietario.

Operación Operador autenticado en contexto C autorizado Administrador global explícitamente autorizado Sin sesión
Buscar aplicación Globales elegibles activos + locales C Igual, o catálogo administrativo 401
Resolver referencia usada Global elegible incluso inactivo + local C Según finalidad de consulta 401
Leer recurso local de B desde C Denegar/404 uniforme Solo tras autorizar contexto B, sin bypass implícito 401
Crear/editar recurso local Política de escritura C Misma política contextual 401
Crear/editar/desactivar global Denegar Permiso específico 401
Eliminar global Denegar Solo sin referencias actuales/históricas y operación explícita 401
Ver instalaciones/usuarios/licencias de otras compañías desde producto global Denegar Solo vista agregada autorizada expresamente 401
Cambiar ámbito, plantilla o fusionar Denegar Fuera del CRUD ordinario; contrato de migración aprobado 401

Esta matriz no describe permisos ya implementados. Propuesta inicial: guard público de Identity para la capacidad de gestión global, provisionalmente mapeado al administrador inicial si se aprueba. No crear un RBAC genérico solo para este cambio; tampoco concederla a cualquier usuario por poder editar una compañía. El control debe cubrir también cambios de plantilla/campos globales que propagan al catálogo.

Referencias y riesgo IDOR

Hoy la referencia enviada por navegador se verifica en backend (softwareReferences/applicationReferences) contra recursos cargados de C; IDs ajenos fallan aunque se manipule el formulario. Edición de instalación/configuración fija destino; remove consulta id y companyId. Las FKs simples solo prueban existencia de Resource, no propiedad. softwarePolicy: software-installation-policy.ts:5 softwareMapper: software-installation-input.mapper.ts:15 applicationPolicy: application-configuration-policy.ts:5 applicationMapper: application-configuration-input.mapper.ts:11.

PROPUESTO: Resources posee la decisión de visibilidad/elegibilidad de Resource; los casos de uso de Companies poseen la validación de activo/perfil/licencia y la asociación. Exponer un puerto público de resolución por compañía, IDs y propósito con datos mínimos y procedencia; resolver IDs desde servidor en alta, edición, importación futura y carga de referencias. No aceptar un scope del navegador como acreditación. Para un global, comprobar además que plantilla y campos no tienen propietario local.

NO CONFIRMADO: endpoint público de importación masiva de Resource. Se localizaron migraciones internas de proyecciones y herramientas de asistencia; cualquier futuro importador debe usar los mismos contratos de Application. No crear un canal privilegiado alternativo que escriba IDs sin validar.

RIESGO ALTO: invocar un futuro getById/findByPk global sin contexto ni purpose abre IDOR de recursos locales y exposición de notas/integraciones. Las lecturas actuales por IDs de hijos están precedidas por raíces filtradas; conservar esa precondición explícita. Respuesta no debe confirmar nombres, fabricante o historial de B en errores para C.

Concurrencia

RIESGO ALTO: la instalación/configuración abre transacción propia y resources.list(company) abre otra; no se transmite Transaction. Una desactivación entre validación y commit puede dejar una asociación nueva a un recurso ya inactivo. Una FK evita referencia inexistente, no garantiza active/eligibility al commit. softwareRead: sequelize-software-installation.repository.ts:27 applicationRead: sequelize-application-configuration.repository.ts:34 service: resource-inventory.service.ts:7.

Propuesta: definir punto de serialización y orden global de locks entre catálogo/recurso/compañía antes de implementar; resolver/validar en la misma unidad de consistencia mediante servicio público ligado a transacción o mecanismo equivalente. No exportar repositorios de Resources. Probar carrera de desactivación, creación, borrado y propagación; definir si una asociación concurrente se rechaza o se conserva con revisión. Ver 10.

Índice de SQL directo sobre resources

Extraído de las fuentes activas; complementa las familias de consultas anteriores. Incluye DML de migraciones sin ejecutarlas. readInventory y writeInventory usan helpers de tabla y se citan en la tabla principal, pues no contienen SQL literal sobre resources.

Sentencia / localización Clasificación de intención futura
modules/assets/src/api/infrastructure/persistence/sequelize-support.repository.ts:21 1/4: datos operativos de compañía; conservar filtro
modules/resources/src/api/infrastructure/persistence/directory-domain-options-reader.ts:32 1/4: datos operativos de compañía; conservar filtro
modules/resources/src/api/infrastructure/persistence/directory-domain-reader.ts:28 1/4: datos operativos de compañía; conservar filtro
modules/resources/src/api/infrastructure/persistence/directory-domain-summary-resolver.ts:67 1/4: datos operativos de compañía; conservar filtro
modules/resources/src/api/infrastructure/persistence/migrate-support-resources.ts:205 4: migración interna, raíz/revisión previamente seleccionada
modules/resources/src/api/infrastructure/persistence/network-share-options.ts:24 1/4: datos operativos de compañía; conservar filtro
modules/resources/src/api/infrastructure/persistence/network-share-reader.ts:32 1/4: datos operativos de compañía; conservar filtro
modules/resources/src/api/infrastructure/persistence/network-share-summary-resolver.ts:67 1/4: datos operativos de compañía; conservar filtro
modules/resources/src/api/infrastructure/persistence/prepare-resource-template-updates.ts:55 5: consulta transversal interna; decidir globals explícitamente
modules/resources/src/api/infrastructure/persistence/remove-resource.ts:101 1/4: borrado local de raíz autorizada
modules/resources/src/api/infrastructure/persistence/resource-dashboard-reader.ts:20 5: consulta transversal interna; decidir globals explícitamente
modules/resources/src/api/infrastructure/persistence/resource-dashboard-reader.ts:45 5: consulta transversal interna; decidir globals explícitamente
modules/resources/src/api/infrastructure/persistence/resource-dashboard-reader.ts:49 5: consulta transversal interna; decidir globals explícitamente
modules/resources/src/api/infrastructure/persistence/resource-dashboard-reader.ts:58 5: consulta transversal interna; decidir globals explícitamente
modules/resources/src/api/infrastructure/persistence/resource-revision-specifications.ts:126 4: migración interna, raíz/revisión previamente seleccionada