Skip to content
Snippets Groups Projects
Commit 57665a02 authored by Martin Trigaux's avatar Martin Trigaux
Browse files

[FIX] base: keep evaluation context unchanged


Before this commit, the evaluation context was forced with sudo(False)
as the call to _render_qweb_html was made with sudo(True). The sudo
was removed to prevent rendering a report on any object.

This was problematic for reports such as sale.order portal page where
the public user does not have access to the record but uses a custom
verification mechanism using an access_token field and then calling
_render with sudo.

This commit moves the sudo call to keep the _get_evaluation_context
with the same environment and allow to call _render with sudo

Add tests with sale portal building the report as low-priviledge user

closes odoo/odoo#56806

Related: odoo/enterprise#12795
Signed-off-by: default avatarMartin Trigaux (mat) <mat@odoo.com>
parent 4fc8374e
Branches
Tags
No related merge requests found
......@@ -2,7 +2,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.sale.tests.common import TestSaleCommon
from odoo.exceptions import AccessError, UserError, ValidationError
from odoo.tests import tagged
from odoo.tests import HttpCase, tagged
@tagged('post_install', '-at_install')
......@@ -122,3 +122,59 @@ class TestAccessRights(TestSaleCommon):
# Employee can't delete the SO
with self.assertRaises(AccessError):
self.order.with_user(self.company_data['default_user_employee']).unlink()
@tagged('post_install', '-at_install')
class TestAccessRightsControllers(HttpCase):
def test_access_controller(self):
portal_so = self.env.ref("sale.portal_sale_order_2").sudo()
portal_so._portal_ensure_token()
token = portal_so.access_token
private_so = self.env.ref("sale.sale_order_1")
self.authenticate(None, None)
# Test public user can't print an order without a token
req = self.url_open(
url='/my/orders/%s?report_type=pdf' % portal_so.id,
allow_redirects=False,
)
self.assertEqual(req.status_code, 302)
# or with a random token
req = self.url_open(
url='/my/orders/%s?access_token=%s&report_type=pdf' % (
portal_so.id,
"foo",
),
allow_redirects=False,
)
self.assertEqual(req.status_code, 302)
# but works fine with the right token
req = self.url_open(
url='/my/orders/%s?access_token=%s&report_type=pdf' % (
portal_so.id,
token,
),
allow_redirects=False,
)
self.assertEqual(req.status_code, 200)
self.authenticate("portal", "portal")
# do not need the token when logged in
req = self.url_open(
url='/my/orders/%s?report_type=pdf' % portal_so.id,
allow_redirects=False,
)
self.assertEqual(req.status_code, 200)
# but still can't access another order
req = self.url_open(
url='/my/orders/%s?report_type=pdf' % private_so.id,
allow_redirects=False,
)
self.assertEqual(req.status_code, 302)
......@@ -694,13 +694,13 @@ class IrActionsReport(models.Model):
data = {}
data.setdefault('report_type', 'pdf')
# access the report details with sudo() but evaluation context as sudo(False)
# access the report details with sudo() but evaluation context as current user
self_sudo = self.sudo()
# In case of test environment without enough workers to perform calls to wkhtmltopdf,
# fallback to render_html.
if (tools.config['test_enable'] or tools.config['test_file']) and not self.env.context.get('force_report_rendering'):
return self_sudo._render_qweb_html(res_ids, data=data)
return self._render_qweb_html(res_ids, data=data)
# As the assets are generated during the same transaction as the rendering of the
# templates calling them, there is a scenario where the assets are unreachable: when
......@@ -791,7 +791,7 @@ class IrActionsReport(models.Model):
data = {}
data.setdefault('report_type', 'text')
data = self._get_rendering_context(docids, data)
return self._render_template(self.report_name, data), 'text'
return self._render_template(self.sudo().report_name, data), 'text'
@api.model
def _render_qweb_html(self, docids, data=None):
......@@ -801,7 +801,7 @@ class IrActionsReport(models.Model):
data = {}
data.setdefault('report_type', 'html')
data = self._get_rendering_context(docids, data)
return self._render_template(self.report_name, data), 'html'
return self._render_template(self.sudo().report_name, data), 'html'
@api.model
def _get_rendering_context_model(self):
......@@ -810,23 +810,23 @@ class IrActionsReport(models.Model):
@api.model
def _get_rendering_context(self, docids, data):
# access the report details with sudo() but evaluation context as current user
self_sudo = self.sudo()
# If the report is using a custom model to render its html, we must use it.
# Otherwise, fallback on the generic html rendering.
report_model = self._get_rendering_context_model()
report_model = self_sudo._get_rendering_context_model()
data = data and dict(data) or {}
if report_model is not None:
# _render_ may be executed in sudo but evaluation context as real user
report_model = report_model.sudo(False)
data.update(report_model._get_report_values(docids, data=data))
else:
# _render_ may be executed in sudo but evaluation context as real user
docs = self.env[self.model].sudo(False).browse(docids)
docs = self.env[self_sudo.model].browse(docids)
data.update({
'doc_ids': docids,
'doc_model': self.model,
'doc_model': self_sudo.model,
'docs': docs,
})
return data
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment