[FIX] base: attachment check linked record 'write'

When an attachment is linked to a record (res_id and res_model are set)
we check the access rights and access rules of that record.

The access we check on linked record has changed as follow:

- 15905e78 (2013) => we check `write` access right/rule for `create`
- f5ebc509 (2014) => we check `write` access right for all mode
- 66644e85 (2015) => we check write access right for all but create mode

So currently we check on the linked record for each mode:

- create: write access right / write access rule
- read:   read access right  / read access rule
- write:  write access right / write access rule
- unlink: write access right / unlink access rule

The behavior is not expected for `unlink`, we should check if we have
write access through access rules instead of checking unlink access.

Without the change, the added test failed with a `unlink` access rule
AccessError on the linked record.

opw-2154448
closes #41814

closes odoo/odoo#42264

X-original-commit: 2b3fc2e3b80f191b4cd126abccf6f94b1302ac11
Signed-off-by: Nicolas Lempereur (nle) <nle@odoo.com>
This commit is contained in:
Nicolas Lempereur
2019-12-20 14:14:12 +00:00
parent 75f91ca8e9
commit 26fac9a834
2 changed files with 43 additions and 5 deletions
+6 -5
View File
@@ -384,8 +384,9 @@ class IrAttachment(models.Model):
records = self.env[res_model].browse(res_ids).exists()
# For related models, check if we can write to the model, as unlinking
# and creating attachments can be seen as an update to the model
records.check_access_rights('write' if mode in ('create', 'unlink') else mode)
records.check_access_rule(mode)
access_mode = 'write' if mode in ('create', 'unlink') else mode
records.check_access_rights(access_mode)
records.check_access_rule(access_mode)
def _read_group_allowed_fields(self):
@@ -478,9 +479,9 @@ class IrAttachment(models.Model):
return len(result) if count else list(result)
def read(self, fields=None, load='_classic_read'):
def _read(self, fields):
self.check('read')
return super(IrAttachment, self).read(fields, load=load)
return super(IrAttachment, self)._read(fields)
def write(self, vals):
self.check('write', values=vals)
@@ -528,7 +529,7 @@ class IrAttachment(models.Model):
record_tuple_set.add(record_tuple)
for record_tuple in record_tuple_set:
(res_model, res_id) = record_tuple
self.check('write', values={'res_model':res_model, 'res_id':res_id})
self.check('create', values={'res_model':res_model, 'res_id':res_id})
return super(IrAttachment, self).create(vals_list)
def _post_add_create(self):
@@ -4,6 +4,7 @@ import base64
import hashlib
import os
from odoo.exceptions import AccessError
from odoo.tests.common import TransactionCase
HASH_SPLIT = 2 # FIXME: testing implementations detail is not a good idea
@@ -69,3 +70,39 @@ class TestIrAttachment(TransactionCase):
a2_fn = os.path.join(self.filestore, a2_store_fname2)
self.assertTrue(os.path.isfile(a2_fn))
def test_06_linked_record_permission(self):
model_ir_attachment = self.env.ref('base.model_ir_attachment')
Attachment = self.Attachment.with_user(self.env.ref('base.user_demo').id)
a1 = self.Attachment.create({'name': 'a1'})
vals = {'name': 'attach', 'res_id': a1.id, 'res_model': 'ir.attachment'}
a2 = Attachment.create(vals)
# remove access to linked record a1
rule = self.env['ir.rule'].create({
'name': 'test_rule', 'domain_force': "[('id', '!=', %s)]" % a1.id,
'model_id': self.env.ref('base.model_ir_attachment').id,
})
a2.invalidate_cache(ids=a2.ids)
# no read permission on linked record
with self.assertRaises(AccessError):
a2.datas
# read permission on linked record
rule.perm_read = False
a2.datas
# no write permission on linked record
with self.assertRaises(AccessError):
a3 = Attachment.create(vals)
with self.assertRaises(AccessError):
a2.write({'datas': self.blob2_b64})
with self.assertRaises(AccessError):
a2.unlink()
# write permission on linked record
rule.perm_write = False
a4 = Attachment.create(vals)
a4.write({'datas': self.blob2_b64})
a4.unlink()