You just can install Cweagans Composer Patches using this command below:
composer require cweagans/composer-patches
then add this snippet in your composer.json
file inside the extra node:
"extra": {
...
"patches": {
"magento/module-authorizenet": {
"Authorizenet-MD5": "m2-hotfixes/Auth.net.md5.composer-2019-02-27-11-51-12.patch"
}
}
}
And create this patch file in a folder m2-hotfixes, it will be like this:
m2-hotfixes/Auth.net.md5.composer-2019-02-27-11-51-12.patch
The content of this file will be:
Index: vendor/magento/module-authorizenet/Model/Directpost.php
<+>UTF-8
===================================================================
--- a/vendor/magento/module-authorizenet/Model/Directpost.php (revision 01fbfeba9bd743266199e30260376a9c1b95fbf5)
+++ b/vendor/magento/module-authorizenet/Model/Directpost.php (revision a0dade4d8bc15b651d8b1ea0e7e4e3580fb1d3ae)
@@ -531,15 +531,16 @@
public function validateResponse()
{
$response = $this->getResponse();
- //md5 check
- if (!$this->getConfigData('trans_md5')
- || !$this->getConfigData('login')
- || !$response->isValidHash($this->getConfigData('trans_md5'), $this->getConfigData('login'))
+ $hashConfigKey = !empty($response->getData('x_SHA2_Hash')) ? 'signature_key' : 'trans_md5';
+
+ //hash check
+ if (!$response->isValidHash($this->getConfigData($hashConfigKey), $this->getConfigData('login'))
) {
throw new \Magento\Framework\Exception\LocalizedException(
__('The transaction was declined because the response hash validation failed.')
);
}
+
return true;
}
Index: vendor/magento/module-authorizenet/Model/Directpost/Request.php
<+>UTF-8
===================================================================
--- a/vendor/magento/module-authorizenet/Model/Directpost/Request.php (revision 01fbfeba9bd743266199e30260376a9c1b95fbf5)
+++ b/vendor/magento/module-authorizenet/Model/Directpost/Request.php (revision a0dade4d8bc15b651d8b1ea0e7e4e3580fb1d3ae)
@@ -7,6 +7,7 @@
namespace Magento\Authorizenet\Model\Directpost;
use Magento\Authorizenet\Model\Request as AuthorizenetRequest;
+use Magento\Framework\Intl\DateTimeFactory;
/**
* Authorize.net request model for DirectPost model
@@ -18,9 +19,33 @@
*/
protected $_transKey = null;
+ /**
+ * Hexadecimal signature key.
+ *
+ * @var string
+ */
+ private $signatureKey = '';
+
+ /**
+ * @var DateTimeFactory
+ */
+ private $dateTimeFactory;
+
+ /**
+ * @param DateTimeFactory $dateTimeFactory
+ * @param array $data
+ */
+ public function __construct(
+ DateTimeFactory $dateTimeFactory,
+ array $data = []
+ ) {
+ $this->dateTimeFactory = $dateTimeFactory;
+ parent::__construct($data);
+ }
+
/**
* Return merchant transaction key.
- * Needed to generate sign.
+ * Needed to generate MD5 sign.
*
* @return string
*/
@@ -31,7 +56,7 @@
/**
* Set merchant transaction key.
- * Needed to generate sign.
+ * Needed to generate MD5 sign.
*
* @param string $transKey
* @return $this
@@ -43,7 +68,7 @@
}
/**
- * Generates the fingerprint for request.
+ * Generates the MD5 fingerprint for request.
*
* @param string $merchantApiLoginId
* @param string $merchantTransactionKey
@@ -63,7 +88,7 @@
) {
return hash_hmac(
"md5",
- $merchantApiLoginId . "^" . $fpSequence . "^" . $fpTimestamp . "^" . $amount . "^" . $currencyCode,
+ $merchantApiLoginId . '^' . $fpSequence . '^' . $fpTimestamp . '^' . $amount . '^' . $currencyCode,
$merchantTransactionKey
);
}
@@ -85,6 +110,7 @@
->setXRelayUrl($paymentMethod->getRelayUrl());
$this->_setTransactionKey($paymentMethod->getConfigData('trans_key'));
+ $this->setSignatureKey($paymentMethod->getConfigData('signature_key'));
return $this;
}
@@ -168,17 +194,81 @@
*/
public function signRequestData()
{
- $fpTimestamp = time();
- $hash = $this->generateRequestSign(
- $this->getXLogin(),
- $this->_getTransactionKey(),
- $this->getXAmount(),
- $this->getXCurrencyCode(),
- $this->getXFpSequence(),
- $fpTimestamp
- );
+ $fpDate = $this->dateTimeFactory->create('now', new \DateTimeZone('UTC'));
+ $fpTimestamp = $fpDate->getTimestamp();
+
+ if (!empty($this->getSignatureKey())) {
+ $hash = $this->generateSha2RequestSign(
+ $this->getXLogin(),
+ $this->getSignatureKey(),
+ $this->getXAmount(),
+ $this->getXCurrencyCode(),
+ $this->getXFpSequence(),
+ $fpTimestamp
+ );
+ } else {
+ $hash = $this->generateRequestSign(
+ $this->getXLogin(),
+ $this->_getTransactionKey(),
+ $this->getXAmount(),
+ $this->getXCurrencyCode(),
+ $this->getXFpSequence(),
+ $fpTimestamp
+ );
+ }
+
$this->setXFpTimestamp($fpTimestamp);
$this->setXFpHash($hash);
+
return $this;
}
+
+ /**
+ * Generates the SHA2 fingerprint for request.
+ *
+ * @param string $merchantApiLoginId
+ * @param string $merchantSignatureKey
+ * @param string $amount
+ * @param string $currencyCode
+ * @param string $fpSequence An invoice number or random number.
+ * @param string $fpTimestamp
+ * @return string The fingerprint.
+ */
+ private function generateSha2RequestSign(
+ $merchantApiLoginId,
+ $merchantSignatureKey,
+ $amount,
+ $currencyCode,
+ $fpSequence,
+ $fpTimestamp
+ ): string {
+ $message = $merchantApiLoginId . '^' . $fpSequence . '^' . $fpTimestamp . '^' . $amount . '^' . $currencyCode;
+
+ return strtoupper(hash_hmac('sha512', $message, pack('H*', $merchantSignatureKey)));
+ }
+
+ /**
+ * Return merchant hexadecimal signature key.
+ *
+ * Needed to generate SHA2 sign.
+ *
+ * @return string
+ */
+ private function getSignatureKey(): string
+ {
+ return $this->signatureKey;
+ }
+
+ /**
+ * Set merchant hexadecimal signature key.
+ *
+ * Needed to generate SHA2 sign.
+ *
+ * @param string $signatureKey
+ * @return void
+ */
+ private function setSignatureKey(string $signatureKey)
+ {
+ $this->signatureKey = $signatureKey;
+ }
}
Index: vendor/magento/module-authorizenet/Model/Directpost/Response.php
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- a/vendor/magento/module-authorizenet/Model/Directpost/Response.php (revision 01fbfeba9bd743266199e30260376a9c1b95fbf5)
+++ b/vendor/magento/module-authorizenet/Model/Directpost/Response.php (revision a0dade4d8bc15b651d8b1ea0e7e4e3580fb1d3ae)
@@ -24,27 +24,33 @@
*/
public function generateHash($merchantMd5, $merchantApiLogin, $amount, $transactionId)
{
- if (!$amount) {
- $amount = '0.00';
- }
-
return strtoupper(md5($merchantMd5 . $merchantApiLogin . $transactionId . $amount));
}
/**
* Return if is valid order id.
*
- * @param string $merchantMd5
+ * @param string $storedHash
* @param string $merchantApiLogin
* @return bool
*/
- public function isValidHash($merchantMd5, $merchantApiLogin)
+ public function isValidHash($storedHash, $merchantApiLogin)
{
- $hash = $this->generateHash($merchantMd5, $merchantApiLogin, $this->getXAmount(), $this->getXTransId());
+ if (empty($this->getData('x_amount'))) {
+ $this->setData('x_amount', '0.00');
+ }
- return Security::compareStrings($hash, $this->getData('x_MD5_Hash'));
- }
+ if (!empty($this->getData('x_SHA2_Hash'))) {
+ $hash = $this->generateSha2Hash($storedHash);
+ return Security::compareStrings($hash, $this->getData('x_SHA2_Hash'));
+ } elseif (!empty($this->getData('x_MD5_Hash'))) {
+ $hash = $this->generateHash($storedHash, $merchantApiLogin, $this->getXAmount(), $this->getXTransId());
+ return Security::compareStrings($hash, $this->getData('x_MD5_Hash'));
+ }
+ return false;
+ }
+
/**
* Return if this is approved response from Authorize.net auth request.
*
@@ -54,4 +60,54 @@
{
return $this->getXResponseCode() == \Magento\Authorizenet\Model\Directpost::RESPONSE_CODE_APPROVED;
}
+
+ /**
+ * Generates an SHA2 hash to compare against AuthNet's.
+ *
+ * @param string $signatureKey
+ * @return string
+ * @see https://support.authorize.net/s/article/MD5-Hash-End-of-Life-Signature-Key-Replacement
+ */
+ private function generateSha2Hash(string $signatureKey): string
+ {
+ $hashFields = [
+ 'x_trans_id',
+ 'x_test_request',
+ 'x_response_code',
+ 'x_auth_code',
+ 'x_cvv2_resp_code',
+ 'x_cavv_response',
+ 'x_avs_code',
+ 'x_method',
+ 'x_account_number',
+ 'x_amount',
+ 'x_company',
+ 'x_first_name',
+ 'x_last_name',
+ 'x_address',
+ 'x_city',
+ 'x_state',
+ 'x_zip',
+ 'x_country',
+ 'x_phone',
+ 'x_fax',
+ 'x_email',
+ 'x_ship_to_company',
+ 'x_ship_to_first_name',
+ 'x_ship_to_last_name',
+ 'x_ship_to_address',
+ 'x_ship_to_city',
+ 'x_ship_to_state',
+ 'x_ship_to_zip',
+ 'x_ship_to_country',
+ 'x_invoice_num',
+ ];
+
+ $message = '^';
+ foreach ($hashFields as $field) {
+ $message .= ($this->getData($field) ?? '') . '^';
+ }
+
+ return strtoupper(hash_hmac('sha512', $message, pack('H*', $signatureKey)));
+ }
}
Index: vendor/magento/module-authorizenet/etc/adminhtml/system.xml
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- a/vendor/magento/module-authorizenet/etc/adminhtml/system.xml (revision 01fbfeba9bd743266199e30260376a9c1b95fbf5)
+++ b/vendor/magento/module-authorizenet/etc/adminhtml/system.xml (revision a0dade4d8bc15b651d8b1ea0e7e4e3580fb1d3ae)
@@ -29,6 +29,10 @@
<label>Transaction Key</label>
<backend_model>Magento\Config\Model\Config\Backend\Encrypted</backend_model>
</field>
+ <field id="signature_key" translate="label" type="obscure" sortOrder="55" showInDefault="1" showInWebsite="1" showInStore="0">
+ <label>Signature Key</label>
+ <backend_model>Magento\Config\Model\Config\Backend\Encrypted</backend_model>
+ </field>
<field id="trans_md5" translate="label" type="obscure" sortOrder="60" showInDefault="1" showInWebsite="1" showInStore="0">
<label>Merchant MD5</label>
<backend_model>Magento\Config\Model\Config\Backend\Encrypted</backend_model>
Index: vendor/magento/module-authorizenet/etc/config.xml
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- a/vendor/magento/module-authorizenet/etc/config.xml (revision 01fbfeba9bd743266199e30260376a9c1b95fbf5)
+++ b/vendor/magento/module-authorizenet/etc/config.xml (revision a0dade4d8bc15b651d8b1ea0e7e4e3580fb1d3ae)
@@ -22,6 +22,7 @@
<title>Credit Card Direct Post (Authorize.net)</title>
<trans_key backend_model="Magento\Config\Model\Config\Backend\Encrypted" />
<trans_md5 backend_model="Magento\Config\Model\Config\Backend\Encrypted" />
+ <signature_key backend_model="Magento\Config\Model\Config\Backend\Encrypted" />
<allowspecific>0</allowspecific>
<currency>USD</currency>
<create_order_before>1</create_order_before>