Skip to content
Snippets Groups Projects
Commit 7bfcb53d authored by Victor Feyens's avatar Victor Feyens
Browse files

[IMP] ORM: do not allow invalid allowed_company_ids context key.

Since https://github.com/odoo/odoo/commit/a5b6f31cf28e5381e1c85f66730bcdb55998e643

,
the current companies of the user are saved in the context as "allowed_company_ids"
context key.

In case of invalid context content, the api was computing the intersection
between the context content and the user company(ies) and falling back on user
company_id(s) when catching an error.

A sanity check was done, but no feedback was given to the user,
saying that the context change was falsy.

This commits changes this behavior to :

* raise an AccessError when trying to access self.env.company(ies) when
invalid or unauthorized companies are defined in the context.

* take sudo mode into consideration, allowing inter-company impacts,
even when current user doesn't have access to a given company,
if the code is done in a sudoed environment.

Co-Authored-By: default avatarRaphael Collet <rco@odoo.com>
parent a492047e
No related branches found
No related tags found
No related merge requests found
...@@ -21501,6 +21501,12 @@ msgid "" ...@@ -21501,6 +21501,12 @@ msgid ""
"%(fields_list)s" "%(fields_list)s"
msgstr "" msgstr ""
   
#. module: base
#: code:addons/api.py:0
#, python-format
msgid "Access to unauthorized or invalid companies."
msgstr ""
#. module: base #. module: base
#: code:addons/base/models/ir_rule.py:0 #: code:addons/base/models/ir_rule.py:0
#, python-format #, python-format
......
...@@ -51,6 +51,7 @@ from decorator import decorate, decorator ...@@ -51,6 +51,7 @@ from decorator import decorate, decorator
from werkzeug.local import Local, release_local from werkzeug.local import Local, release_local
import odoo import odoo
from .tools.translate import _
from odoo.tools import frozendict, classproperty, lazy_property, StackMap from odoo.tools import frozendict, classproperty, lazy_property, StackMap
from odoo.exceptions import CacheMiss from odoo.exceptions import CacheMiss
...@@ -541,35 +542,73 @@ class Environment(Mapping): ...@@ -541,35 +542,73 @@ class Environment(Mapping):
@lazy_property @lazy_property
def company(self): def company(self):
""" return the company in which the user is logged in (as an instance) """ """Return the current company (as an instance).
company_ids = self.context.get('allowed_company_ids', False)
If not specified in the context ('allowed_company_ids'),
fallback on current user main company.
:raise AccessError: invalid or unauthorized 'allowed_company_ids' context key content.
:return: current company (default=`self.user.company_id`)
:rtype: res.company
.. warning::
No sanity checks applied in sudo mode !
When in sudo mode, a user can access any company,
even if not in his allowed companies.
This allows to trigger inter-company modifications,
even if the current user doesn't have access to
the targeted company.
"""
company_ids = self.context.get('allowed_company_ids', [])
if company_ids: if company_ids:
company_id = int(company_ids[0]) if not self.su:
if company_id in self.user.company_ids.ids: user_company_ids = self.user.company_ids.ids
return self['res.company'].browse(company_id) if any(cid not in user_company_ids for cid in company_ids):
raise AccessError(_("Access to unauthorized or invalid companies."))
return self['res.company'].browse(company_ids[0])
return self.user.company_id return self.user.company_id
@lazy_property @lazy_property
def companies(self): def companies(self):
""" return a recordset of the enabled companies by the user """ """Return a recordset of the enabled companies by the user.
try: # In case the user tries to bidouille the url (eg: cids=1,foo,bar)
allowed_company_ids = self.context.get('allowed_company_ids') If not specified in the context('allowed_company_ids'),
# Prevent the user to enable companies for which he doesn't have any access fallback on current user companies.
users_company_ids = self.user.company_ids.ids
allowed_company_ids = [company_id for company_id in allowed_company_ids if company_id in users_company_ids] :raise AccessError: invalid or unauthorized 'allowed_company_ids' context key content.
except Exception: :return: current companies (default=`self.user.company_ids`)
# By setting the default companies to all user companies instead of the main one :rtype: res.company
# we save a lot of potential trouble in all "out of context" calls, such as
# /mail/redirect or /web/image, etc. And it is not unsafe because the user does .. warning::
# have access to these other companies. The risk of exposing foreign records
# (wrt to the context) is low because all normal RPCs will have a proper No sanity checks applied in sudo mode !
# allowed_company_ids. When in sudo mode, a user can access any company,
# Examples: even if not in his allowed companies.
# - when printing a report for several records from several companies
# - when accessing to a record from the notification email template This allows to trigger inter-company modifications,
# - when loading an binary image on a template even if the current user doesn't have access to
allowed_company_ids = self.user.company_ids.ids the targeted company.
return self['res.company'].browse(allowed_company_ids) """
company_ids = self.context.get('allowed_company_ids', [])
if company_ids:
if not self.su:
user_company_ids = self.user.company_ids.ids
if any(cid not in user_company_ids for cid in company_ids):
raise AccessError(_("Access to unauthorized or invalid companies."))
return self['res.company'].browse(company_ids)
# By setting the default companies to all user companies instead of the main one
# we save a lot of potential trouble in all "out of context" calls, such as
# /mail/redirect or /web/image, etc. And it is not unsafe because the user does
# have access to these other companies. The risk of exposing foreign records
# (wrt to the context) is low because all normal RPCs will have a proper
# allowed_company_ids.
# Examples:
# - when printing a report for several records from several companies
# - when accessing to a record from the notification email template
# - when loading an binary image on a template
return self.user.company_ids
@property @property
def lang(self): def lang(self):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment