Files
enterprise-addons/sign/tests/test_attachment_access.py
T

251 lines
11 KiB
Python

# Part of Odoo. See LICENSE file for full copyright and licensing details.
import base64
import io
from odoo.exceptions import AccessError
from odoo.tests import TransactionCase, users
from odoo.tools.pdf import PdfFileWriter
from odoo.tools import mute_logger
class testAttachmentAccess(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.user = cls.env['res.users'].create({
'name': "foo",
'login': "foo",
'email': "foo@bar.com",
'group_ids': [(6, 0, [cls.env.ref('sign.group_sign_user').id])]
})
with io.BytesIO() as stream:
PdfFileWriter().write(stream)
stream.seek(0)
cls.pdf = base64.b64encode(stream.read())
def test_user_template_attachment_without_res_fields(self):
"""Test an employee can create a template linked to an attachment without res_model/res_id"""
env_user = self.env(user=self.user)
# As user, create an attachment without res_model/res_id
attachment = env_user['ir.attachment'].create({'name': 'foo', 'datas': self.pdf})
# As user, create a sign.template
template = env_user['sign.template'].create({})
# As user, create a sign.document linked to that attachment
document = env_user['sign.document'].create({
'attachment_id': attachment.id,
'template_id': template.id,
})
# As user, ensure the content of the attachment can be read through the document
self.assertEqual(document.datas, self.pdf)
# As user, create another attachment without res_model/res_id
attachment_2 = env_user['ir.attachment'].create({'name': 'foo', 'datas': self.pdf})
# As user, change the attachment of the template to this second attachment
document.write({'attachment_id': attachment_2.id})
# As user, ensure the content of this second attachment can be read through the document
self.assertEqual(document.datas, self.pdf)
def test_user_template_attachment_without_res_fields_created_by_admin(self):
"""Test an employee can read the content of the template's attachment created by another user, the admin,
and the attachment does not have a res_model/res_id
"""
# As admin, create an attachment without res_model/res_id
attachment = self.env['ir.attachment'].create({'name': 'foo', 'datas': self.pdf})
# As admin, create a sign.document and sign.template linked to that attachment
template = self.env['sign.template'].create({})
document = self.env['sign.document'].create({
'attachment_id': attachment.id,
'template_id': template.id,
})
# As user, ensure the attachment itself cannot be read
self.env.invalidate_all()
with self.assertRaises(AccessError):
attachment.with_user(self.user).datas
# But, as user, the content of the attachment can be read through the template
self.assertEqual(document.with_user(self.user).datas, self.pdf)
# As admin, create a second attachment without res_model/res_id
attachment = self.env['ir.attachment'].create({'name': 'bar', 'datas': self.pdf})
# As admin, link this second attachment to the previously created document (write instead of create)
document.write({'attachment_id': attachment.id})
# As user ensure the attachment itself cannot be read
self.env.invalidate_all()
with self.assertRaises(AccessError):
self.assertEqual(attachment.with_user(self.user).datas, self.pdf)
# But, as user, the content of the attachment can be read through the document
self.assertEqual(document.with_user(self.user).datas, self.pdf)
def test_user_read_unallowed_attachment(self):
"""Test a user cannot access an attachment he is not supposed to through a sign template"""
# As admin, create an attachment for which you require the settings group to access
autovacuum_job = self.env.ref('base.autovacuum_job')
attachment_forbidden = self.env['ir.attachment'].create({
'name': 'foo', 'datas': self.pdf,
'res_model': autovacuum_job._name, 'res_id': autovacuum_job.id,
})
# As user, make sure this is indeed not possible to access that attachment data directly
self.env.invalidate_all()
with self.assertRaises(AccessError):
attachment_forbidden.with_user(self.user).datas
# As user, create a template pointing to that attachment
# and make sure it raises an access error
with self.assertRaises(AccessError):
template = self.env['sign.template'].create({})
document = self.env['sign.document'].with_user(self.user).create({
'attachment_id': attachment_forbidden.id,
'template_id': template.id,
})
document.datas
# As user, update the attachment of an existing template to the unallowed attachment
# and make sure it raises an access error
attachment_tmp = self.env['ir.attachment'].with_user(self.user).create({
'name': 'bar', 'datas': self.pdf,
})
template = self.env['sign.template'].with_user(self.user).create({
'name': "test template",
})
document = self.env['sign.document'].with_user(self.user).create({
'attachment_id': attachment_tmp.id,
'template_id': template.id,
})
with self.assertRaises(AccessError):
document.write({'attachment_id': attachment_forbidden.id})
document.datas
with self.assertRaises(AccessError):
self.env["sign.document"].with_user(self.user).onchange(
{"attachment_id": attachment_forbidden.id},
["attachment_id"],
{"datas": {}},
)
with self.assertRaises(AccessError):
self.env["sign.document"].with_user(self.user).with_context(
default_attachment_id=attachment_forbidden.id,
).onchange(
{},
[],
{"attachment_id": {}, "datas": {}},
)
self.env["ir.default"].with_user(self.user).set(
"sign.document",
"attachment_id",
attachment_forbidden.id,
user_id=True,
)
with self.assertRaises(AccessError):
self.env["sign.document"].with_user(self.user).onchange(
{},
[],
{"attachment_id": {}, "datas": {}},
)
@users('foo')
@mute_logger('odoo.addons.base.models.ir_model', 'odoo.addons.base.models.ir_rule', 'odoo.models')
def test_access_sign_user_fields(self):
"""Test an employee can read and write his own signature / initials but not others"""
# This test doesn't make sense if the record read/updated are sudo,
# it needs to be tested with the employee access rights
admin = self.env.ref('base.user_admin')
self.assertTrue(
admin.env.user == self.user and not admin.env.su,
'This test makes sense only if it is tested with employee access rights'
)
my_user = self.env['res.users'].browse(self.env.user.id)
self.assertTrue(
my_user.env.user == self.user and not my_user.env.su,
'This test makes sense only if it is tested with employee access rights'
)
sign_user_fields = ['sign_signature', 'sign_initials']
# Set a signature / initials for the admin, to test if the employee can read or change it later on
for field in sign_user_fields:
admin.sudo()[field] = base64.b64encode(b'admin')
signature = base64.b64encode(b'foo')
for field in sign_user_fields:
# A user must be able to change his own signature / initials
my_user[field] = signature
# and read
self.assertEqual(my_user[field], signature, f'An employee must be able to read his own {field!r}')
# but not others
with self.assertRaises(AccessError, msg=f'An employee must not be able to write {field!r} of another user'):
admin[field] = signature
with self.assertRaises(AccessError, msg=f'An employee must not be able to read {field!r} of another user'):
admin[field]
# Let's take the assumption the employee obtains the attachment id linked to the admin attachments somehow.
# Hence herebelow the sudo just to get the id of the attachment
attachment_id = self.env['ir.attachment'].sudo().search([
('res_model', '=', 'res.users'),
('res_id', '=', admin.id),
('res_field', '=', field),
]).id
with self.assertRaises(
AccessError,
msg=f'An employee must not be able to read the attachment related to the {field!r} of another user'
):
self.env['ir.attachment'].browse(attachment_id).datas
def test_user_sign_item(self):
env_user = self.env(user=self.user)
attachment = env_user['ir.attachment'].create({'name': 'foo', 'datas': self.pdf})
attachment_2 = env_user['ir.attachment'].create({'name': 'foo', 'datas': self.pdf})
template = env_user['sign.template'].create({})
template_2 = self.env['sign.template'].create({})
document = env_user['sign.document'].create({
'attachment_id': attachment.id,
'template_id': template.id,
})
document_2 = self.env['sign.document'].create({
'attachment_id': attachment_2.id,
'template_id': template_2.id,
})
sign_item = env_user['sign.item'].create({
'document_id': document.id,
'type_id': self.env.ref('sign.sign_item_type_name').id,
'posX': 0.190,
'posY': 0.185,
'width': 0.680,
'height': 0.015,
})
with self.assertRaises(AccessError):
template_2.with_env(env_user).read(['name'])
with self.assertRaises(AccessError):
document_2.with_env(env_user).read(['name'])
with self.assertRaises(AccessError):
sign_item.template_id = template_2
with self.assertRaises(AccessError):
sign_item.document_id = document_2
with self.assertRaises(AccessError):
env_user['sign.item'].create({
'document_id': document_2.id,
'type_id': self.env.ref('sign.sign_item_type_name').id,
'posX': 0.190,
'posY': 0.185,
'width': 0.680,
'height': 0.015,
})
sign_item = env_user['sign.item'].create({
'document_id': document.id,
'template_id': template_2.id,
'type_id': self.env.ref('sign.sign_item_type_name').id,
'posX': 0.190,
'posY': 0.185,
'width': 0.680,
'height': 0.015,
})
self.assertEqual(sign_item.template_id, template)