# Project Task Portal Security Architecture ## Overview This document outlines the comprehensive security implementation for portal treatment professionals accessing project.task objects (events) in the bemade_sports_clinic module. ## Security Principles Applied ### 1. **Explicit Authorization Only** - **NO** blanket access based on `privacy_visibility = 'portal'` - **YES** explicit authorization through follower relationships or team membership - **Principle**: Users must be explicitly granted access, not implicitly through project settings ### 2. **Multi-Layer Security Architecture** 1. **ACL Level**: Model-level CRUD permissions 2. **Record Rule Level**: Record-level filtering based on explicit relationships 3. **Field Level**: Field-level group access controls 4. **Controller Level**: Additional business logic validation ## Implementation Details ### Access Control Lists (ACLs) **File**: `security/ir.model.access.csv` ```csv # Portal Treatment Professionals get read/write/create access to project tasks access_project_task_portal_tp,Portal TP Access for Project Tasks,project.model_project_task,bemade_sports_clinic.group_portal_treatment_professional,1,1,1,0 # Portal Treatment Professionals get read/write access to projects (for follower management) access_project_project_portal_tp,Portal TP Access for Projects,project.model_project_project,bemade_sports_clinic.group_portal_treatment_professional,1,1,0,0 # Read-only access to supporting models access_project_task_type_portal_tp,Portal TP Access for Task Types,project.model_project_task_type,bemade_sports_clinic.group_portal_treatment_professional,1,0,0,0 access_project_tags_portal_tp,Portal TP Access for Project Tags,project.model_project_tags,bemade_sports_clinic.group_portal_treatment_professional,1,0,0,0 access_project_milestone_portal_tp,Portal TP Access for Project Milestones,project.model_project_milestone,bemade_sports_clinic.group_portal_treatment_professional,1,0,0,0 ``` ### Record Rules **File**: `security/project_task_portal_rules.xml` #### Project Task Access Rule ```xml [ '|', '|', '|', # Tasks assigned to the user ('user_ids', 'in', [user.id]), # Tasks where user is a follower ('message_partner_ids', 'in', [user.partner_id.id]), # Tasks from projects where user is a follower ('project_id.message_partner_ids', 'in', [user.partner_id.id]), # Tasks from projects where user's teams are partners ('project_id.partner_id', 'in', user.partner_id.team_staff_rel_ids.mapped('team_id.id') or [0]) ] ``` #### Project Access Rule ```xml [ '|', # Projects where user is explicitly a follower ('message_partner_ids', 'in', [user.partner_id.id]), # Projects where user's teams are partners ('partner_id', 'in', user.partner_id.team_staff_rel_ids.mapped('team_id.id') or [0]) ] ``` ### Field-Level Security **Files**: `models/project_task.py` and `models/project_project.py` All critical fields are overridden with explicit group access for authorized sports clinic users only: ```python # SECURE: Only authorized sports clinic portal users, not all portal users _portal_groups = 'base.group_user,bemade_sports_clinic.group_portal_treatment_professional,bemade_sports_clinic.group_portal_team_coach' # Core fields name = fields.Char(groups=_portal_groups) description = fields.Html(groups=_portal_groups) user_ids = fields.Many2many(groups=_portal_groups) project_id = fields.Many2one(groups=_portal_groups) # ... and many more ``` ### Controller Security **File**: `controllers/events_portal.py` #### Secure Domain Construction ```python def _prepare_events_domain(self, view_type='all'): # Base domain: tasks from projects where user has explicit authorization base_domain = [ '|', '|', # Tasks from projects where user's teams are partners ('project_id.partner_id', 'in', team_ids or [0]), # Tasks from projects where user is a follower ('project_id.message_partner_ids', 'in', [partner.id]), # Tasks where user is directly assigned or following '|', ('user_ids', 'in', [user.id]), ('message_partner_ids', 'in', [partner.id]) ] ``` #### Project Filtering ```python def _get_available_projects(self): # Only show projects where user has explicit authorization domain = [ '|', # Projects where user's teams are partners ('partner_id', 'in', team_ids or [0]), # Projects where user is explicitly a follower ('message_partner_ids', 'in', [partner.id]) ] ``` ## Security Validation ### Model-Level Access Checking ```python def check_portal_task_access(self): # 1. Check user is assigned to task # 2. Check user is follower of task # 3. Check user is follower of project # 4. Check user's teams are partners of project # NO blanket portal visibility check ``` ### Project Configuration ```python def ensure_portal_access_for_treatment_professionals(self): # Only add treatment professionals who are staff on the team # NO blanket addition of all portal users ``` ## Critical Security Fixes Applied ### ❌ **BEFORE (Vulnerable)** ```python # SECURITY FLAW: Any portal user could access any portal-visible project domain = [ '|', '|', ('partner_id', 'in', team_ids), ('message_partner_ids', 'in', [partner.id]), ('privacy_visibility', '=', 'portal') # ← VULNERABILITY ] ``` ### ✅ **AFTER (Secure)** ```python # SECURE: Only explicitly authorized users can access projects domain = [ '|', ('partner_id', 'in', team_ids or [0]), # Team relationship ('message_partner_ids', 'in', [partner.id]) # Explicit follower ] ``` ## Testing and Validation ### Security Test Utility **File**: `models/project_task_security_test.py` - Admin UI for testing field access - Validates all security layers - Tests unauthorized access scenarios ### Comprehensive Test Suite **File**: `tests/test_project_task_portal_security.py` - 10 test cases covering all security aspects - Validates proper access isolation - Tests record rule enforcement ## Best Practices Established 1. **Explicit Authorization Required**: Never grant access based solely on project privacy settings 2. **Follower-Based Security**: Use message_partner_ids for explicit access control 3. **Team-Based Authorization**: Link project access to sports team relationships 4. **Layered Security**: Multiple security layers working together 5. **Principle of Least Privilege**: Grant minimum necessary permissions ## Common Security Anti-Patterns Avoided 1. **❌ Portal Visibility OR Condition**: `('privacy_visibility', '=', 'portal')` as standalone OR 2. **❌ Blanket Group Access**: Adding all portal users as followers 3. **❌ Overly Broad Domains**: Using `[(1, '=', 1)]` or similar catch-all domains 4. **❌ Missing Fallbacks**: Not using `or [0]` for empty list protection ## Deployment Checklist - [ ] Update module to install new security files - [ ] Run security tests to validate implementation - [ ] Verify portal users can only access authorized projects/tasks - [ ] Test that unauthorized users are properly denied access - [ ] Validate field-level access works correctly in portal UI ## Maintenance Guidelines 1. **Always use explicit authorization** when creating new access rules 2. **Test security boundaries** whenever adding new portal functionality 3. **Document security decisions** for future developers 4. **Regular security audits** of domain logic and record rules 5. **Follow the established patterns** for consistent security implementation