[FIX] *: add sudo when accessing views
The method fields_view_get should be the only way to retrieve the view content. This method is executed in a super-user context. To avoid retrieving views for a model a user does not have access to (as it may reveal some informations like name of fields), add a verification of 'read' rights before retrieving the view content. Execute _postprocess_access_rights with sudo(False) as this method is used to evaluate which buttons should be displayed. Remove the su flag to avoid misleading the user and displaying a button they won't be able to use. Retrieving the database id from an view key is not considered as a sensitive information and get_view_id and viewref can be left as a public methods. Add missing sudo when needed Change _handle_visibility in website to avoid increasing the query count: Checking the visibility (to fail most of the time) to retry in sudo was making unecessary queries.
This commit is contained in:
@@ -64,7 +64,7 @@ class QWeb(models.AbstractModel):
|
||||
key = el.attrib.pop('t-snippet')
|
||||
el.set('t-call', key)
|
||||
el.set('t-call-options', "{'snippet-key': '" + key + "'}")
|
||||
View = self.env['ir.ui.view']
|
||||
View = self.env['ir.ui.view'].sudo()
|
||||
view_id = View.get_view_id(key)
|
||||
name = View.browse(view_id).name
|
||||
thumbnail = el.attrib.pop('t-thumbnail', "oe-thumbnail")
|
||||
|
||||
@@ -340,7 +340,10 @@ class Website(Home):
|
||||
|
||||
@http.route('/website/toggle_switchable_view', type='json', auth='user', website=True)
|
||||
def toggle_switchable_view(self, view_key):
|
||||
request.website.viewref(view_key).toggle_active()
|
||||
if request.website.user_has_groups('website.group_website_designer'):
|
||||
request.website.viewref(view_key).toggle_active()
|
||||
else:
|
||||
return werkzeug.exceptions.Forbidden()
|
||||
|
||||
@http.route('/website/reset_template', type='http', auth='user', methods=['POST'], website=True, csrf=False)
|
||||
def reset_template(self, view_id, mode='soft', redirect='/', **kwargs):
|
||||
|
||||
@@ -359,10 +359,7 @@ class View(models.Model):
|
||||
"""
|
||||
error = False
|
||||
|
||||
try:
|
||||
self.visibility # avoid useless sudo() in case page is public
|
||||
except AccessError:
|
||||
self = self.sudo()
|
||||
self = self.sudo()
|
||||
|
||||
if self.visibility and not request.env.user.has_group('website.group_website_designer'):
|
||||
if (self.visibility == 'connected' and request.website.is_public_user()):
|
||||
|
||||
@@ -670,7 +670,7 @@ class Website(models.Model):
|
||||
:param raise_if_not_found: should the method raise an error if no view found
|
||||
:return: The view record or empty recordset
|
||||
'''
|
||||
View = self.env['ir.ui.view']
|
||||
View = self.env['ir.ui.view'].sudo()
|
||||
view = View
|
||||
if isinstance(view_id, str):
|
||||
if 'website_id' in self._context:
|
||||
@@ -700,7 +700,7 @@ class Website(models.Model):
|
||||
|
||||
@tools.ormcache_context(keys=('website_id',))
|
||||
def _cache_customize_show_views(self):
|
||||
views = self.env['ir.ui.view'].with_context(active_test=False).search([('customize_show', '=', True)])
|
||||
views = self.env['ir.ui.view'].with_context(active_test=False).sudo().search([('customize_show', '=', True)])
|
||||
views = views.filter_duplicate()
|
||||
return {v.key: v.active for v in views}
|
||||
|
||||
@@ -862,7 +862,7 @@ class Website(models.Model):
|
||||
|
||||
def get_website_pages(self, domain=[], order='name', limit=None):
|
||||
domain += self.get_current_website().website_domain()
|
||||
pages = self.env['website.page'].search(domain, order=order, limit=limit)
|
||||
pages = self.env['website.page'].sudo().search(domain, order=order, limit=limit)
|
||||
return pages
|
||||
|
||||
def search_pages(self, needle=None, limit=None):
|
||||
|
||||
@@ -552,7 +552,7 @@ class IrActionsReport(models.Model):
|
||||
website = request.website
|
||||
context = dict(context, translatable=context.get('lang') != request.env['ir.http']._get_default_lang().code)
|
||||
|
||||
view_obj = self.env['ir.ui.view'].with_context(context)
|
||||
view_obj = self.env['ir.ui.view'].sudo().with_context(context)
|
||||
values.update(
|
||||
time=time,
|
||||
context_timestamp=lambda t: fields.Datetime.context_timestamp(self.with_context(tz=user.tz), t),
|
||||
|
||||
@@ -118,7 +118,7 @@ class IrQWeb(models.AbstractModel, QWeb):
|
||||
if lang != env.context.get('lang'):
|
||||
env = env(context=dict(env.context, lang=lang))
|
||||
|
||||
template = env['ir.ui.view'].read_template(name)
|
||||
template = env['ir.ui.view'].sudo().read_template(name)
|
||||
|
||||
# QWeb's `read_template` will check if one of the first children of
|
||||
# what we send to it has a "t-name" attribute having `name` as value
|
||||
@@ -126,7 +126,7 @@ class IrQWeb(models.AbstractModel, QWeb):
|
||||
# with view ids or children view or children primary views, force it here.
|
||||
def is_child_view(view_name):
|
||||
view_id = self.env['ir.ui.view'].get_view_id(view_name)
|
||||
view = self.env['ir.ui.view'].browse(view_id)
|
||||
view = self.env['ir.ui.view'].sudo().browse(view_id)
|
||||
return view.inherit_id is not None
|
||||
|
||||
if isinstance(name, int) or is_child_view(name):
|
||||
|
||||
@@ -864,7 +864,8 @@ actual arch.
|
||||
""" Compute and set on node access rights based on view type. Specific
|
||||
views can add additional specific rights like creating columns for
|
||||
many2one-based grouping views. """
|
||||
Model = self.env[model]
|
||||
# testing ACL as real user
|
||||
Model = self.env[model].sudo(False)
|
||||
is_base_model = self.env.context.get('base_model_name', model) == model
|
||||
|
||||
if node.tag in ('kanban', 'tree', 'form', 'activity'):
|
||||
@@ -971,7 +972,7 @@ actual arch.
|
||||
}
|
||||
attrs['views'] = views
|
||||
if field.comodel_name in self.env:
|
||||
Comodel = self.env[field.comodel_name]
|
||||
Comodel = self.env[field.comodel_name].sudo(False)
|
||||
node_info['attr_model'] = Comodel
|
||||
if field.type in ('many2one', 'many2many'):
|
||||
can_create = Comodel.check_access_rights('create', raise_exception=False)
|
||||
@@ -1505,7 +1506,7 @@ actual arch.
|
||||
return template
|
||||
if '.' not in template:
|
||||
raise ValueError('Invalid template id: %r' % template)
|
||||
view = self.search([('key', '=', template)], limit=1)
|
||||
view = self.sudo().search([('key', '=', template)], limit=1)
|
||||
return view and view.id or self.env['ir.model.data'].xmlid_to_res_id(template, raise_if_not_found=True)
|
||||
|
||||
def clear_cache(self):
|
||||
@@ -1627,7 +1628,7 @@ actual arch.
|
||||
time=time,
|
||||
datetime=datetime,
|
||||
relativedelta=relativedelta,
|
||||
xmlid=self.key,
|
||||
xmlid=self.sudo().key,
|
||||
viewid=self.id,
|
||||
to_text=pycompat.to_text,
|
||||
image_data_uri=image_data_uri,
|
||||
|
||||
+3
-2
@@ -1463,7 +1463,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
|
||||
|
||||
@api.model
|
||||
def _fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False):
|
||||
View = self.env['ir.ui.view']
|
||||
View = self.env['ir.ui.view'].sudo()
|
||||
result = {
|
||||
'model': self._name,
|
||||
'field_parent': False,
|
||||
@@ -1528,7 +1528,8 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
|
||||
* if some tag other than 'position' is found in parent view
|
||||
:raise Invalid ArchitectureError: if there is view type other than form, tree, calendar, search etc defined on the structure
|
||||
"""
|
||||
view = self.env['ir.ui.view'].browse(view_id)
|
||||
self.check_access_rights('read')
|
||||
view = self.env['ir.ui.view'].sudo().browse(view_id)
|
||||
|
||||
# Get the view arch and all other attributes describing the composition of the view
|
||||
result = self._fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu)
|
||||
|
||||
Reference in New Issue
Block a user