# -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo.tests.common import SavepointCase from odoo.exceptions import AccessError, UserError class TestMailSecurity(SavepointCase): @classmethod def setUpClass(cls): super().setUpClass() cls.secret_group = cls.env['res.groups'].create({ 'name': 'secret group', }) cls.user_1 = cls.env['res.users'].create({ 'name': 'User 1', 'login': 'user_1', 'email': '---', 'groups_id': [(6, 0, [cls.secret_group.id, cls.env.ref('base.group_user').id])], }) cls.user_2 = cls.env['res.users'].create({ 'name': 'User 2', 'login': 'user_2', 'email': '---', 'groups_id': [(6, 0, [cls.secret_group.id, cls.env.ref('base.group_user').id])], }) cls.user_3 = cls.env['res.users'].create({ 'name': 'User 3', 'login': 'user_3', 'email': '---', }) cls.private_channel_1 = cls.env['mail.channel'].create({ 'name': 'Secret channel', 'public': 'private', 'channel_type': 'channel', }) cls.group_channel_1 = cls.env['mail.channel'].create({ 'name': 'Group channel', 'public': 'groups', 'channel_type': 'channel', 'group_public_id': cls.secret_group.id, }) cls.public_channel_1 = cls.env['mail.channel'].create({ 'name': 'Public channel of user 1', 'public': 'public', 'channel_type': 'channel', }) cls.private_channel_1.channel_last_seen_partner_ids.unlink() cls.group_channel_1.channel_last_seen_partner_ids.unlink() cls.public_channel_1.channel_last_seen_partner_ids.unlink() ########################### # PRIVATE CHANNEL & BASIC # ########################### def test_channel_acls_01(self): """Test access on private channel.""" res = self.env['mail.channel.partner'].search([('channel_id', '=', self.private_channel_1.id)]) self.assertFalse(res) # User 1 can join private channel with SUDO self.private_channel_1.with_user(self.user_1).sudo().action_follow() res = self.env['mail.channel.partner'].search([('channel_id', '=', self.private_channel_1.id)]) self.assertEqual(res.partner_id, self.user_1.partner_id) # User 2 can not join private channel with self.assertRaises(AccessError): self.private_channel_1.with_user(self.user_2).action_follow() # But user 2 can join public channel self.public_channel_1.with_user(self.user_2).action_follow() res = self.env['mail.channel.partner'].search([('channel_id', '=', self.public_channel_1.id)]) self.assertEqual(res.partner_id, self.user_2.partner_id) # User 2 can not create a `mail.channel.partner` to join the private channel with self.assertRaises(AccessError): self.env['mail.channel.partner'].with_user(self.user_2).create({ 'partner_id': self.user_2.partner_id.id, 'channel_id': self.private_channel_1.id, }) # User 2 can not write on `mail.channel.partner` to join the private channel channel_partner = self.env['mail.channel.partner'].with_user(self.user_2).search([('partner_id', '=', self.user_2.partner_id.id)])[0] with self.assertRaises(AccessError): channel_partner.channel_id = self.private_channel_1.id with self.assertRaises(AccessError): channel_partner.write({'channel_id': self.private_channel_1.id}) # But with SUDO, User 2 can channel_partner.sudo().channel_id = self.private_channel_1.id # User 2 can not write on the `partner_id` of `mail.channel.partner` # of an other partner to join a private channel channel_partner_1 = self.env['mail.channel.partner'].search([('channel_id', '=', self.private_channel_1.id), ('partner_id', '=', self.user_1.partner_id.id)]) with self.assertRaises(AccessError): channel_partner_1.with_user(self.user_2).partner_id = self.user_2.partner_id self.assertEqual(channel_partner_1.partner_id, self.user_1.partner_id) # but with SUDO he can... channel_partner_1.with_user(self.user_2).sudo().partner_id = self.user_2.partner_id self.assertEqual(channel_partner_1.partner_id, self.user_2.partner_id) def test_channel_acls_03(self): """Test invitation in private channel part 1 (invite using crud methods).""" self.private_channel_1.with_user(self.user_1).sudo().action_follow() channel_partners = self.env['mail.channel.partner'].search([('channel_id', '=', self.private_channel_1.id)]) self.assertEqual(len(channel_partners), 1) # User 2 is not in the private channel, he can not invite user 3 with self.assertRaises(AccessError): self.env['mail.channel.partner'].with_user(self.user_2).create({ 'partner_id': self.user_3.partner_id.id, 'channel_id': self.private_channel_1.id, }) # User 1 is in the private channel, he can invite other users self.env['mail.channel.partner'].with_user(self.user_1).create({ 'partner_id': self.user_3.partner_id.id, 'channel_id': self.private_channel_1.id, }) channel_partners = self.env['mail.channel.partner'].search([('channel_id', '=', self.private_channel_1.id)]) self.assertEqual(channel_partners.mapped('partner_id'), self.user_1.partner_id | self.user_3.partner_id) # But User 3 can not write on the `mail.channel.partner` of other user channel_partner_1 = self.env['mail.channel.partner'].search([('channel_id', '=', self.private_channel_1.id), ('partner_id', '=', self.user_1.partner_id.id)]) channel_partner_3 = self.env['mail.channel.partner'].search([('channel_id', '=', self.private_channel_1.id), ('partner_id', '=', self.user_3.partner_id.id)]) channel_partner_3.with_user(self.user_3).custom_channel_name = 'Test' with self.assertRaises(AccessError): channel_partner_1.with_user(self.user_2).custom_channel_name = 'Blabla' self.assertNotEqual(channel_partner_1.custom_channel_name, 'Blabla') def test_channel_acls_04(self): """Test invitation in private channel part 2 (use `invite` action).""" self.private_channel_1.with_user(self.user_1).sudo().action_follow() channel_partners = self.env['mail.channel.partner'].search([('channel_id', '=', self.private_channel_1.id)]) self.assertEqual(channel_partners.mapped('partner_id'), self.user_1.partner_id) # User 2 is not in the channel, he can not invite user 3 with self.assertRaises(AccessError): self.private_channel_1.with_user(self.user_2).channel_invite([self.user_3.partner_id.id]) channel_partners = self.env['mail.channel.partner'].search([('channel_id', '=', self.private_channel_1.id)]) self.assertEqual(channel_partners.mapped('partner_id'), self.user_1.partner_id) # User 1 is in the channel, he can not invite user 3 self.private_channel_1.with_user(self.user_1).channel_invite([self.user_3.partner_id.id]) channel_partners = self.env['mail.channel.partner'].search([('channel_id', '=', self.private_channel_1.id)]) self.assertEqual(channel_partners.mapped('partner_id'), self.user_1.partner_id | self.user_3.partner_id) def test_channel_acls_05(self): """Test kick/leave channel.""" self.private_channel_1.with_user(self.user_1).sudo().action_follow() self.private_channel_1.with_user(self.user_3).sudo().action_follow() channel_partners = self.env['mail.channel.partner'].search([('channel_id', '=', self.private_channel_1.id)]) self.assertEqual(len(channel_partners), 2) # User 2 is not in the channel, he can not kick user 1 with self.assertRaises(AccessError): channel_partners.with_user(self.user_2).unlink() # User 3 is in the channel, he can kick user 1 channel_partners.with_user(self.user_3).unlink() ################# # GROUP CHANNEL # ################# def test_channel_acls_06(self): """Test basics on group channel.""" channel_partners = self.env['mail.channel.partner'].search([('channel_id', '=', self.group_channel_1.id)]) self.assertFalse(channel_partners) # user 1 is in the group, he can join the channel self.group_channel_1.with_user(self.user_1).action_follow() channel_partners = self.env['mail.channel.partner'].search([('channel_id', '=', self.group_channel_1.id)]) self.assertEqual(channel_partners.mapped('partner_id'), self.user_1.partner_id) # user 3 is not in the group, he can not join with self.assertRaises(AccessError): self.group_channel_1.with_user(self.user_3).action_follow() channel_partners = self.env['mail.channel.partner'].search([('channel_id', '=', self.group_channel_1.id)]) with self.assertRaises(AccessError): channel_partners.with_user(self.user_3).partner_id = self.user_3.partner_id channel_partners = self.env['mail.channel.partner'].search([('channel_id', '=', self.group_channel_1.id)]) self.assertEqual(channel_partners.mapped('partner_id'), self.user_1.partner_id) # user 1 can not invite user 3 because he's not in the group with self.assertRaises(UserError): self.group_channel_1.with_user(self.user_1).channel_invite([self.user_3.partner_id.id]) channel_partners = self.env['mail.channel.partner'].search([('channel_id', '=', self.group_channel_1.id)]) self.assertEqual(channel_partners.mapped('partner_id'), self.user_1.partner_id) # but user 2 is in the group and can be invited by user 1 self.group_channel_1.with_user(self.user_1).channel_invite([self.user_2.partner_id.id]) channel_partners = self.env['mail.channel.partner'].search([('channel_id', '=', self.group_channel_1.id)]) self.assertEqual(channel_partners.mapped('partner_id'), self.user_1.partner_id | self.user_2.partner_id) ################## # PUBLIC CHANNEL # ################## def test_channel_acls_07(self): """Test basics on public channel.""" channel_partners = self.env['mail.channel.partner'].search([('channel_id', '=', self.public_channel_1.id)]) self.assertFalse(channel_partners) self.public_channel_1.with_user(self.user_1).action_follow() channel_partners = self.env['mail.channel.partner'].search([('channel_id', '=', self.public_channel_1.id)]) self.assertEqual(channel_partners.mapped('partner_id'), self.user_1.partner_id) self.public_channel_1.with_user(self.user_2).action_follow() channel_partners = self.env['mail.channel.partner'].search([('channel_id', '=', self.public_channel_1.id)]) self.assertEqual(channel_partners.mapped('partner_id'), self.user_1.partner_id | self.user_2.partner_id)