From 4d79a1ff58ff6ff3b4fdebc609ce77896c125e3d Mon Sep 17 00:00:00 2001 From: Christophe Matthieu Date: Thu, 22 Jun 2017 15:57:54 +0200 Subject: [PATCH] [FIX] payment: prevent access error for manual payments Rev. cf1df16aea5d23006184f51a20c18f5bf3dd6d8c introduced new callback fields with restricted access. The lazy hash generation in create() was however causing access errors for manual transactions created by users who are not administrators (e.g. Accountants). Those manual transactions do not typically need a callback, but checking the presence of the callback requires a limited sudo() context. Similarly, the execute_callback() method may be called for a manual, non-admin transaction, and should not do anything if there is no callback, instead of crashing with an AccessError. The generation of the hash and execution of the callback should be done with a normal environment, though, as these must only be used for transactions run by the system. opw-747536 --- addons/payment/models/payment_acquirer.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/addons/payment/models/payment_acquirer.py b/addons/payment/models/payment_acquirer.py index b0f1c2312e9..d0dd3ec4691 100644 --- a/addons/payment/models/payment_acquirer.py +++ b/addons/payment/models/payment_acquirer.py @@ -507,7 +507,9 @@ class PaymentTransaction(models.Model): tx.write({'reference': str(tx.id)}) # Generate callback hash if it is configured on the tx; avoid generating unnecessary stuff - if tx.callback_model_id and tx.callback_res_id and tx.sudo().callback_method: + # (limited sudo env for checking callback presence, must work for manual transactions too) + tx_sudo = tx.sudo() + if tx_sudo.callback_model_id and tx_sudo.callback_res_id and tx_sudo.callback_method: tx.write({'callback_hash': tx._generate_callback_hash()}) return tx @@ -637,7 +639,13 @@ class PaymentTransaction(models.Model): @api.multi def execute_callback(self): res = None - for transaction in self.filtered(lambda tx: tx.callback_model_id and tx.callback_res_id and tx.sudo().callback_method): + for transaction in self: + # limited sudo env, only for checking callback presence, not for running it! + # manual transactions have no callback, and can pass without being run by admin user + tx_sudo = transaction.sudo() + if not (tx_sudo.callback_model_id and tx_sudo.callback_res_id and tx_sudo.callback_method): + continue + valid_token = transaction._generate_callback_hash() if not consteq(ustr(valid_token), transaction.callback_hash): _logger.warning("Invalid callback signature for transaction %d" % (transaction.id)) @@ -645,7 +653,7 @@ class PaymentTransaction(models.Model): record = self.env[transaction.callback_model_id.model].browse(transaction.callback_res_id).exists() if record: - res = getattr(record, transaction.sudo().callback_method)(transaction) + res = getattr(record, transaction.callback_method)(transaction) else: _logger.warning("Did not found record %s.%s for callback of transaction %d" % (transaction.callback_model_id.model, transaction.callback_res_id, transaction.id)) return res