fix(permisos): los endpoints de datos ya no se abren sin el módulo asignado

Primera tanda del hueco reportado en el commit anterior: el permiso tapaba
la página HTML pero no los datos. Cualquier usuario con sesión podía pedir
GET /app/loadusers o DELETE /app/doc/paginas/:id escribiendo la URL, sin
tener el submódulo asignado.

No alcanzaba con poner MenuMiddleware en esas rutas: compara la ruta pedida
contra los submódulos del rol, y el endpoint de datos vive en otra ruta que
la pantalla (/app/loadusers alimenta /app/users). Compararla consigo misma
nunca coincidiría y dejaría afuera hasta a quien sí tiene el permiso.

RequiereModulo("/app/users") declara en la ruta a qué pantalla pertenece el
endpoint, y valida ese submódulo. El administrador sigue entrando a todo,
igual que en MenuMiddleware.

Esta tanda cubre lo que más duele: identidad y permisos (usuarios, roles,
módulos, submódulos), donde una fuga es escalada de privilegios, y
Documentación, que es el módulo que disparó la auditoría.

Quedan las otras tandas (contabilidad, facturas, clientes, servidores...).
Se hace por partes a propósito: cerrar 400 rutas de una puede dejar gente
afuera de pantallas que hoy usa.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-08-15 20:25:31 -05:00
co-authored by Claude Sonnet 5
parent 6942c04d27
commit 55f28f5c06
3 changed files with 103 additions and 32 deletions
+23
View File
@@ -47,3 +47,26 @@ func TestPuedeVerRutaSinPermisos(t *testing.T) {
t.Error("una URL vacía no debería habilitar nada")
}
}
// RequiereModulo compara contra el submódulo DECLARADO en la ruta, no contra
// la ruta pedida. Es lo que permite proteger /app/loadusers con el permiso de
// la pantalla /app/users: compararlo consigo mismo nunca coincidiría y
// bloquearía incluso a quien sí tiene el permiso.
func TestRequiereModuloUsaElSubmoduloDeclarado(t *testing.T) {
permisos := []string{"/app/users"}
// El endpoint de datos vive en otra ruta que la pantalla.
if !PuedeVerRuta("/app/users", permisos) {
t.Error("con el permiso de la pantalla se debe poder pedir sus datos")
}
// Y comparar la ruta del endpoint contra el permiso NO coincide: por eso
// hace falta declarar el submódulo en vez de mirar c.Path().
if PuedeVerRuta("/app/loadusers", permisos) {
t.Error("la ruta del endpoint no coincide con la del submódulo — " +
"si coincidiera, no haría falta RequiereModulo")
}
// Sin el permiso, no se accede.
if PuedeVerRuta("/app/users", []string{"/app/clientes"}) {
t.Error("con otro permiso no se debe acceder a los datos de usuarios")
}
}