From 88de93114161a2b9a86f32a1b77201dac47e0756 Mon Sep 17 00:00:00 2001 From: Romain Derie Date: Fri, 1 Mar 2019 17:17:23 +0000 Subject: [PATCH] [FIX] payment_authorize: use SHA-512 instead of MD5 as not supported Authorize.Net is phasing out the MD5 based hash use for transaction response verification in favor of the SHA-512 based hash utilizing a Signature Key. Instead of hashing with md5 the transaction key, it is now required to hash the signature key (binary format) with SHA-512. Support for MD5 will be dropped the 7th March 2019 for sandbox environment and the 28th March 2019 for production environment, initially planned for the 14th. Note that as of February 11, 2019 authorize removed the ability to configure or update MD5 Hash setting in the Merchant Interface. Merchants who had this setting configured have been emailed/contacted. opw-1943030 Usefull links: https://developer.authorize.net/support/hash_upgrade/ https://support.authorize.net/s/article/What-is-a-Signature-Key https://support.authorize.net/s/article/MD5-Hash-End-of-Life-Signature-Key-Replacement https://support.authorize.net/s/article/Do-I-need-to-upgrade-my-transaction-fingerprint-from-HMAC-MD5-to-HMAC-SHA512-and-how closes odoo/odoo#31642 Signed-off-by: Romain Derie (rde) --- addons/payment_authorize/models/payment.py | 13 +++++++++++-- addons/payment_authorize/tests/test_authorize.py | 15 +++------------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/addons/payment_authorize/models/payment.py b/addons/payment_authorize/models/payment.py index 73c7c044e0a..6c31e7a499e 100644 --- a/addons/payment_authorize/models/payment.py +++ b/addons/payment_authorize/models/payment.py @@ -5,6 +5,7 @@ from datetime import datetime import hashlib import hmac import logging +import string import time import urlparse @@ -54,7 +55,15 @@ class PaymentAcquirerAuthorize(models.Model): values['x_fp_timestamp'], values['x_amount'], values['x_currency_code']]) - return hmac.new(str(values['x_trans_key']), data, hashlib.md5).hexdigest() + + # [BACKWARD COMPATIBILITY] Check that the merchant did update his transaction + # key to signature key (end of MD5 support from Authorize.net) + # The signature key is now '128-character hexadecimal format', while the + # transaction key was only 16-character. + if len(values['x_trans_key']) == 128: + return hmac.new(values['x_trans_key'].decode("hex"), data, hashlib.sha512).hexdigest().upper() + else: + return hmac.new(str(values['x_trans_key']), data, hashlib.md5).hexdigest() @api.multi def authorize_form_generate_values(self, values): @@ -172,7 +181,7 @@ class TxAuthorize(models.Model): def _authorize_form_get_tx_from_data(self, data): """ Given a data dict coming from authorize, verify it and find the related transaction record. """ - reference, trans_id, fingerprint = data.get('x_invoice_num'), data.get('x_trans_id'), data.get('x_MD5_Hash') + reference, trans_id, fingerprint = data.get('x_invoice_num'), data.get('x_trans_id'), data.get('x_SHA2_Hash') or data.get('x_MD5_Hash') if not reference or not trans_id or not fingerprint: error_msg = _('Authorize: received data with missing reference (%s) or trans_id (%s) or fingerprint (%s)') % (reference, trans_id, fingerprint) _logger.info(error_msg) diff --git a/addons/payment_authorize/tests/test_authorize.py b/addons/payment_authorize/tests/test_authorize.py index 35be8a99b17..2d1d7665ce3 100644 --- a/addons/payment_authorize/tests/test_authorize.py +++ b/addons/payment_authorize/tests/test_authorize.py @@ -1,7 +1,5 @@ # -*- coding: utf-8 -*- -import hashlib -import hmac import time import urlparse import unittest @@ -32,15 +30,6 @@ class AuthorizeCommon(PaymentAcquirerCommon): @odoo.tests.common.post_install(True) class AuthorizeForm(AuthorizeCommon): - def _authorize_generate_hashing(self, values): - data = '^'.join([ - values['x_login'], - values['x_fp_sequence'], - values['x_fp_timestamp'], - values['x_amount'], - ]) + '^' - return hmac.new(str(values['x_trans_key']), data, hashlib.md5).hexdigest() - def test_10_Authorize_form_render(self): self.assertEqual(self.authorize.environment, 'test', 'test without test environment') @@ -84,7 +73,7 @@ class AuthorizeForm(AuthorizeCommon): 'x_ship_to_state': None, } - form_values['x_fp_hash'] = self._authorize_generate_hashing(form_values) + form_values['x_fp_hash'] = self.env['payment.acquirer']._authorize_generate_hashing(form_values) # render the button res = self.authorize.render('SO004', 320.0, self.currency_usd.id, values=self.buyer_values) # check form result @@ -108,7 +97,9 @@ class AuthorizeForm(AuthorizeCommon): # typical data posted by authorize after client has successfully paid authorize_post_data = { 'return_url': u'/shop/payment/validate', + # x_MD5_Hash will be empty starting the 28th March 2019 'x_MD5_Hash': u'7934485E1C105940BE854208D10FAB4F', + 'x_SHA2_Hash': u'7D3AC844BE8CA3F649AB885A90D22CFE35B850338EC91D1A5ADD819A85FF948A3D777334A18CDE36821DC8F2B42A6E1950C1FF96B52B60F23201483A656195FB', 'x_account_number': u'XXXX0027', 'x_address': u'Huge Street 2/543', 'x_amount': u'320.00',