111 lines
5.3 KiB
Python
111 lines
5.3 KiB
Python
# -*- coding: utf-8 -*-
|
|
from odoo import models
|
|
from odoo.http import request
|
|
import logging
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class IrHttp(models.AbstractModel):
|
|
_inherit = 'ir.http'
|
|
|
|
@classmethod
|
|
def _pre_dispatch(cls, rule, args):
|
|
"""
|
|
Sanitize allowed_company_ids in the request session, request environment,
|
|
and request parameters contexts BEFORE the environment is fully used.
|
|
This prevents AccessError from environments.py when any of these contexts
|
|
contain company IDs that are not in the user's authorized list.
|
|
"""
|
|
try:
|
|
if request.env.uid:
|
|
# Use sudo() to query the user's companies safely, bypassing company restrictions.
|
|
user_cids = set(request.env.user.sudo()._get_company_ids())
|
|
default_cid = request.env.user.sudo().company_id.id
|
|
|
|
def sanitize_context_cids(context, user_cids, default_cid):
|
|
if not isinstance(context, dict) or 'allowed_company_ids' not in context:
|
|
return False
|
|
cids = context['allowed_company_ids']
|
|
if not isinstance(cids, list):
|
|
return False
|
|
valid_cids = [c for c in cids if c in user_cids]
|
|
if not valid_cids:
|
|
valid_cids = [default_cid]
|
|
if valid_cids != cids:
|
|
_logger.warning("Sanitized allowed_company_ids in context from %s to %s for user %s", cids, valid_cids, request.env.uid)
|
|
context['allowed_company_ids'] = valid_cids
|
|
return True
|
|
return False
|
|
|
|
# Sanitize session context
|
|
if getattr(request, 'session', None) and getattr(request.session, 'context', None):
|
|
sanitize_context_cids(request.session.context, user_cids, default_cid)
|
|
|
|
# Sanitize request.env.context
|
|
env_context = dict(request.env.context)
|
|
if sanitize_context_cids(env_context, user_cids, default_cid):
|
|
request.update_context(**env_context)
|
|
|
|
# Sanitize request params root context
|
|
if isinstance(getattr(request, 'params', None), dict):
|
|
root_context = request.params.get('context')
|
|
if isinstance(root_context, dict):
|
|
sanitize_context_cids(root_context, user_cids, default_cid)
|
|
|
|
# Sanitize request params kwargs context
|
|
kwargs = request.params.get('kwargs')
|
|
if isinstance(kwargs, dict):
|
|
kwargs_context = kwargs.get('context')
|
|
if isinstance(kwargs_context, dict):
|
|
sanitize_context_cids(kwargs_context, user_cids, default_cid)
|
|
except Exception as e:
|
|
_logger.warning("IrHttp: could not sanitize company context in _pre_dispatch: %s", e, exc_info=True)
|
|
|
|
return super()._pre_dispatch(rule, args)
|
|
|
|
@classmethod
|
|
def _dispatch(cls, endpoint):
|
|
"""
|
|
Sanitize allowed_company_ids in the request parameters (request.params)
|
|
context AFTER they have been populated by the JSON-RPC dispatcher but
|
|
BEFORE the controller/model method is executed.
|
|
"""
|
|
try:
|
|
if request.env.uid:
|
|
# Use sudo() to query the user's companies safely, bypassing company restrictions.
|
|
user_cids = set(request.env.user.sudo()._get_company_ids())
|
|
default_cid = request.env.user.sudo().company_id.id
|
|
|
|
def sanitize_context_cids(context, user_cids, default_cid):
|
|
if not isinstance(context, dict) or 'allowed_company_ids' not in context:
|
|
return False
|
|
cids = context['allowed_company_ids']
|
|
if not isinstance(cids, list):
|
|
return False
|
|
valid_cids = [c for c in cids if c in user_cids]
|
|
if not valid_cids:
|
|
valid_cids = [default_cid]
|
|
if valid_cids != cids:
|
|
_logger.warning("Sanitized allowed_company_ids in _dispatch from %s to %s for user %s", cids, valid_cids, request.env.uid)
|
|
context['allowed_company_ids'] = valid_cids
|
|
return True
|
|
return False
|
|
|
|
# Sanitize request params root context
|
|
if isinstance(getattr(request, 'params', None), dict):
|
|
root_context = request.params.get('context')
|
|
if isinstance(root_context, dict):
|
|
sanitize_context_cids(root_context, user_cids, default_cid)
|
|
|
|
# Sanitize request params kwargs context
|
|
kwargs = request.params.get('kwargs')
|
|
if isinstance(kwargs, dict):
|
|
kwargs_context = kwargs.get('context')
|
|
if isinstance(kwargs_context, dict):
|
|
sanitize_context_cids(kwargs_context, user_cids, default_cid)
|
|
except Exception as e:
|
|
_logger.warning("IrHttp: could not sanitize company context in _dispatch: %s", e, exc_info=True)
|
|
|
|
return super()._dispatch(endpoint)
|