summaryrefslogtreecommitdiff
path: root/odoo
diff options
context:
space:
mode:
authorVictor Feyens <vfe@odoo.com>2019-10-11 16:14:19 +0000
committerVictor Feyens <vfe@odoo.com>2019-10-24 17:12:16 +0000
commitf76c5a8bbd9a4f639c59b7f602b165c8d38ff360 (patch)
tree4dfe9c504dd3d4233c303fb53424c74e875edac0 /odoo
parentebac65bebf709481561a18a02ed77eba80e73ede (diff)
[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: Raphael Collet <rco@odoo.com>
Diffstat (limited to 'odoo')
-rw-r--r--odoo/addons/base/i18n/base.pot6
-rw-r--r--odoo/api.py87
2 files changed, 69 insertions, 24 deletions
diff --git a/odoo/addons/base/i18n/base.pot b/odoo/addons/base/i18n/base.pot
index 0454f19cb0a..769dc898f55 100644
--- a/odoo/addons/base/i18n/base.pot
+++ b/odoo/addons/base/i18n/base.pot
@@ -21502,6 +21502,12 @@ msgid ""
msgstr ""
#. module: base
+#: code:addons/api.py:0
+#, python-format
+msgid "Access to unauthorized or invalid companies."
+msgstr ""
+
+#. module: base
#: code:addons/base/models/ir_rule.py:0
#, python-format
msgid ""
diff --git a/odoo/api.py b/odoo/api.py
index d3766ea3f3e..931dc5ab149 100644
--- a/odoo/api.py
+++ b/odoo/api.py
@@ -51,6 +51,7 @@ from decorator import decorate, decorator
from werkzeug.local import Local, release_local
import odoo
+from .tools.translate import _
from odoo.tools import frozendict, classproperty, lazy_property, StackMap
from odoo.exceptions import CacheMiss
@@ -541,35 +542,73 @@ class Environment(Mapping):
@lazy_property
def company(self):
- """ return the company in which the user is logged in (as an instance) """
- company_ids = self.context.get('allowed_company_ids', False)
+ """Return the current company (as an instance).
+
+ 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:
- company_id = int(company_ids[0])
- if company_id in self.user.company_ids.ids:
- return self['res.company'].browse(company_id)
+ 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[0])
return self.user.company_id
@lazy_property
def companies(self):
- """ 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')
- # Prevent the user to enable companies for which he doesn't have any access
- 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]
- except Exception:
- # 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
- allowed_company_ids = self.user.company_ids.ids
- return self['res.company'].browse(allowed_company_ids)
+ """Return a recordset of the enabled companies by the user.
+
+ If not specified in the context('allowed_company_ids'),
+ fallback on current user companies.
+
+ :raise AccessError: invalid or unauthorized 'allowed_company_ids' context key content.
+ :return: current companies (default=`self.user.company_ids`)
+ :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 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
def lang(self):