account_shared_bank_cash/models/ir_http.py

139 lines
6.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,
)
# Roll back the aborted transaction so subsequent DB queries in this
# request can still execute. Without this PostgreSQL keeps the
# connection in an InFailedSqlTransaction state and rejects every
# further query in the same request.
try:
request.env.cr.rollback()
except Exception:
pass
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,
)
# Roll back the aborted transaction so subsequent DB queries in this
# request can still execute. Without this PostgreSQL keeps the
# connection in an InFailedSqlTransaction state and rejects every
# further query in the same request.
try:
request.env.cr.rollback()
except Exception:
pass
return super()._dispatch(endpoint)