# Seguridad y Control de Acceso - Website Sale Aplicoop ## Descripción General El addon implementa un sistema completo de control de acceso basado en: 1. **ACL (Access Control List)** - Permisos de lectura, escritura, creación y eliminación 2. **Record Rules** - Filtros automáticos de registros por compañía 3. **Grupos de Usuarios** - Roles con permisos específicos ## Arquitectura de Seguridad ``` Usuario ↓ Grupo (group_group_order_user / group_group_order_manager) ↓ ACL (ir.model.access.csv) → Permisos globales (CRUD) ↓ Record Rules (record_rules.csv) → Filtros por compañía ↓ Datos Accesibles ``` ## 1. ACL (Access Control List) Ubicación: [security/ir.model.access.csv](../security/ir.model.access.csv) ### Estructura ```csv id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_group_order_user,group.order user,model_group_order,website_sale_aplicoop.group_group_order_user,1,0,0,0 access_group_order_manager,group.order manager,model_group_order,website_sale_aplicoop.group_group_order_manager,1,1,1,1 ``` ### Campos | Campo | Descripción | |-------|-------------| | `id` | Identificador único interno | | `name` | Descripción legible | | `model_id:id` | Referencia al modelo (model_group_order) | | `group_id:id` | Grupo de usuarios que recibe permisos | | `perm_read` | 1 = Puede leer, 0 = No puede leer | | `perm_write` | 1 = Puede editar, 0 = No puede editar | | `perm_create` | 1 = Puede crear, 0 = No puede crear | | `perm_unlink` | 1 = Puede eliminar, 0 = No puede eliminar | ### Roles y Permisos #### Grupo: `group_group_order_user` (Usuarios Finales) ```csv access_group_order_user,group.order user,model_group_order, website_sale_aplicoop.group_group_order_user,1,0,0,0 ``` **Permisos:** - ✅ Leer órdenes (`perm_read=1`) - ❌ Editar órdenes (`perm_write=0`) - ❌ Crear órdenes (`perm_create=0`) - ❌ Eliminar órdenes (`perm_unlink=0`) **Casos de uso:** - Navegar órdenes disponibles - Ver detalles de pedido - Agregar productos al carrito #### Grupo: `group_group_order_manager` (Administradores) ```csv access_group_order_manager,group.order manager,model_group_order, website_sale_aplicoop.group_group_order_manager,1,1,1,1 ``` **Permisos:** - ✅ Leer órdenes (`perm_read=1`) - ✅ Editar órdenes (`perm_write=1`) - ✅ Crear órdenes (`perm_create=1`) - ✅ Eliminar órdenes (`perm_unlink=1`) **Casos de uso:** - Crear y gestionar órdenes - Modificar configuración de órdenes - Cerrar o cancelar órdenes - Eliminar órdenes (si es necesario) ## 2. Record Rules (Reglas de Registro) Ubicación: [security/record_rules.csv](../security/record_rules.csv) ### Propósito Las record rules filtran automáticamente qué registros puede ver/editar un usuario según el valor del campo `company_id`. ``` Usuario de Company A ↓ Record Rule: domain = [('company_id', 'in', company_ids)] ↓ Company_ids (del usuario) = [1] (Company A) ↓ Solo puede acceder a registros donde company_id = 1 ``` ### Estructura ```csv id,name,model_id:id,groups:eval,domain_force,perm_read,perm_write,perm_create,perm_unlink rule_group_order_company_read,group.order: company access read,model_group_order, website_sale_aplicoop.group_group_order_user,"[('company_id', 'in', company_ids)]",1,0,0,0 rule_group_order_company_write,group.order: company access write,model_group_order, website_sale_aplicoop.group_group_order_manager,"[('company_id', 'in', company_ids)]",1,1,1,1 rule_group_order_manager_global,group.order: manager global access,model_group_order, "['admin']","[]",1,1,1,1 ``` ### Campos | Campo | Descripción | |-------|-------------| | `id` | Identificador único | | `name` | Descripción | | `model_id:id` | Modelo que aplica la regla | | `groups:eval` | Grupo de usuarios (evaluado como Python) | | `domain_force` | Filtro dominio (sintaxis de búsqueda Odoo) | | `perm_read/write/create/unlink` | Permisos bajo esta regla | ### Reglas Implementadas #### Rule 1: Usuarios Finales - Lectura por Compañía ```csv rule_group_order_company_read,group.order: company access read,model_group_order, website_sale_aplicoop.group_group_order_user,"[('company_id', 'in', company_ids)]",1,0,0,0 ``` **Dominio:** `[('company_id', 'in', company_ids)]` - `company_ids` = lista de compañías del usuario - Filtra automáticamente por compañía **Ejemplo:** ``` Usuario "Juan" pertenece a [Company A] Intenta ver órdenes Dominio aplicado: company_id IN (1) Resultado: Solo órdenes de Company A ``` #### Rule 2: Administradores - Lectura/Escritura por Compañía ```csv rule_group_order_company_write,group.order: company access write,model_group_order, website_sale_aplicoop.group_group_order_manager,"[('company_id', 'in', company_ids)]",1,1,1,1 ``` **Dominio:** `[('company_id', 'in', company_ids)]` - Igual que usuarios finales - Pero con permisos de escritura/creación **Ejemplo:** ``` Admin "Pedro" pertenece a [Company A, Company B] Crea nueva orden Dominio aplicado: company_id IN (1, 2) - Si crea en Company A: ✅ Permitido - Si crea en Company B: ✅ Permitido - Si intenta acceder a Company C: ❌ Denegado ``` #### Rule 3: Superusuarios - Acceso Global ```csv rule_group_order_manager_global,group.order: manager global access,model_group_order, "['admin']","[]",1,1,1,1 ``` **Grupo:** `['admin']` (Superusuario de Odoo) **Dominio:** `[]` (vacío = sin restricción) **Comportamiento:** - Acceso completo a todos los registros - Puede ver/editar órdenes de cualquier compañía - Sin filtrado por company_id ## Flujo de Control de Acceso ### Escenario 1: Usuario Final Lee Órdenes ``` 1. Usuario "Maria" (group_group_order_user, Company A) 2. Abre menú "Órdenes de Grupo" 3. Odoo verifica: a) ACL: ¿Tiene perm_read=1? → Sí (grupo_group_order_user) b) Record Rule: ¿Cumple domain [('company_id', 'in', [1])]? - Solo órdenes donde company_id = 1 4. Resultado: Maria ve solo sus órdenes de Company A ``` ### Escenario 2: Usuario Intenta Editar Orden ``` 1. Usuario "Carlos" (group_group_order_user, Company A) 2. Intenta editar orden de Company A 3. Odoo verifica: a) ACL: ¿Tiene perm_write=1? → No (grupo_group_order_user tiene 0) b) Resultado: ❌ Acceso denegado - no puede editar ``` ### Escenario 3: Admin Edita Orden de Otra Compañía ``` 1. Admin "Rosa" (group_group_order_manager, Company A, B) 2. Intenta editar orden de Company B 3. Odoo verifica: a) ACL: ¿Tiene perm_write=1? → Sí (grupo_group_order_manager) b) Record Rule: ¿Cumple domain [('company_id', 'in', [1, 2])]? - company_id de orden = 2 - 2 IN (1, 2) = Sí c) Resultado: ✅ Rosa puede editar la orden ``` ### Escenario 4: Superuser Accede a Todo ``` 1. Admin "System" (superuser) 2. Intenta editar cualquier orden de cualquier compañía 3. Odoo verifica: a) Es admin? → Sí b) Rule: rule_group_order_manager_global aplica (domain = []) c) Resultado: ✅ Acceso completo, sin restricciones ``` ## Tests Archivo: [tests/test_record_rules.py](../tests/test_record_rules.py) ### Casos de Prueba 1. **test_user_company1_can_read_own_orders** - Verifica que usuario de Company A ve sus órdenes 2. **test_user_company1_cannot_read_company2_orders** - Verifica que usuario NO ve órdenes de Company B 3. **test_admin_can_read_all_orders** - Verifica que admin con acceso a ambas compañías ve todo 4. **test_user_cannot_write_other_company_order** - Verifica que usuario no puede editar órdenes de otra compañía (AccessError) 5. **test_record_rule_filters_search** - Verifica que búsqueda automáticamente filtra por compañía 6. **test_cross_company_access_denied** - Verifica que acceso entre compañías es denegado 7. **test_admin_can_bypass_company_restriction** - Verifica que admin puede acceder a cualquier compañía ### Ejecución ```bash # Ejecutar solo tests de record rules odoo -d odoo -i website_sale_aplicoop -t website_sale_aplicoop.tests.test_record_rules --test-enable --stop-after-init # Con pytest pytest tests/test_record_rules.py -v ``` ## Mejores Prácticas ### ✅ Hacer 1. **Confiar en ACL y Record Rules** ```python # Odoo filtra automáticamente orders = env['group.order'].search([]) # Solo devuelve órdenes de compañía del usuario ``` 2. **Usar grupos de seguridad correctamente** ```xml