From a08e32d2b533351e31597cd1359ac9ebdb1d68a1 Mon Sep 17 00:00:00 2001 From: "Gabriel (gdpf)" Date: Wed, 3 Apr 2024 13:38:44 +0200 Subject: [PATCH] [FIX] calendar: events privacy for uninvited admins This commit reverts odoo/odoo#133504, as it was deliberating access to private event information to uninvited administrators in the calendar view. Only the event organizer and its attendees must be able to fetch private events information. In addition, two tests have been added to: 1. ensure the confidentiality of private events from uninvited administrators and 2. prohibit uninvited administrators from edit the information of any event, private or not. task-3837646 closes odoo/odoo#160308 Signed-off-by: Yannick Tivisse (yti) Signed-off-by: Gabriel de Paula Felix (gdpf) --- addons/calendar/models/calendar_event.py | 2 +- addons/calendar/tests/test_access_rights.py | 38 +++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/addons/calendar/models/calendar_event.py b/addons/calendar/models/calendar_event.py index de4c178ece9..2b8f172a5c0 100644 --- a/addons/calendar/models/calendar_event.py +++ b/addons/calendar/models/calendar_event.py @@ -288,7 +288,7 @@ class Meeting(models.Model): @api.depends_context('uid') def _compute_user_can_edit(self): for event in self: - event.user_can_edit = self.env.user in event.partner_ids.user_ids + event.user_id or self.env.user.has_group('base.group_partner_manager') + event.user_can_edit = self.env.user in event.partner_ids.user_ids + event.user_id @api.depends('attendee_ids') def _compute_invalid_email_partner_ids(self): diff --git a/addons/calendar/tests/test_access_rights.py b/addons/calendar/tests/test_access_rights.py index 0df1053020c..0a79a198038 100644 --- a/addons/calendar/tests/test_access_rights.py +++ b/addons/calendar/tests/test_access_rights.py @@ -18,6 +18,7 @@ class TestAccessRights(TransactionCase): cls.raoul = new_test_user(cls.env, login='raoul', groups='base.group_user') cls.george = new_test_user(cls.env, login='george', groups='base.group_user') cls.portal = new_test_user(cls.env, login='pot', groups='base.group_portal') + cls.admin_user = new_test_user(cls.env, login='admin_user', groups='base.group_partner_manager') def create_event(self, user, **values): return self.env['calendar.event'].with_user(user).create({ @@ -158,3 +159,40 @@ class TestAccessRights(TransactionCase): 'start': datetime.now() + timedelta(days=2), 'stop': datetime.now() + timedelta(days=2, hours=2), }) + + def test_admin_cant_fetch_uninvited_private_events(self): + """ + Administrators must not be able to fetch information from private events which + they are not attending (i.e. events which it is not an event partner). The privacy + of the event information must always be kept. Public events can be read normally. + """ + john_private_evt = self.create_event(self.john, name='priv', privacy='private', location='loc_1', description='priv') + john_public_evt = self.create_event(self.john, name='pub', privacy='public', location='loc_2', description='pub') + self.env.invalidate_all() + + # For the private event, ensure that no private field can be read, such as: 'name', 'location' and 'description'. + for (field, value) in [('name', 'Busy'), ('location', False), ('description', False)]: + hidden_information = self.read_event(self.admin_user, john_private_evt, field) + self.assertEqual(hidden_information, value, "The field '%s' information must be hidden, even for uninvited admins." % field) + + # For the public event, ensure that the same fields can be read by the admin. + for (field, value) in [('name', 'pub'), ('location', 'loc_2'), ('description', "

pub

")]: + field_information = self.read_event(self.admin_user, john_public_evt, field) + self.assertEqual(str(field_information), value, "The field '%s' information must be readable by the admin." % field) + + def test_admin_cant_edit_uninvited_events(self): + """ + Administrators must not be able to edit events that they are not attending. + The event is property of the organizer and its attendees only, private or not. + """ + john_public_evt = self.create_event(self.john, name='pub', privacy='public', location='loc_2', description='pub') + john_private_evt = self.create_event(self.john, name='priv', privacy='private', location='loc_1', description='priv') + + for event in [john_public_evt, john_private_evt]: + # Ensure that uninvited admin can not edit the event since it is not an event partner (attendee). + with self.assertRaises(AccessError): + event.with_user(self.admin_user)._compute_user_can_edit() + + # Ensure that AccessError is raised when trying to update the uninvited event. + with self.assertRaises(AccessError): + event.with_user(self.admin_user).write({'name': 'forbidden-update'})