Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR128 additions #129

Merged
merged 9 commits into from
Apr 27, 2019
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ php:
- 7.0
- 7.1
- 7.2
- 7.3

# This triggers builds to run on the new TravisCI infrastructure.
# See: http://docs.travis-ci.com/user/workers/container-based-infrastructure/
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,16 @@ $data = $response->getData();

$data['paymentProfile']['customerProfileId'];
$data['paymentProfile']['customerPaymentProfileId'];
//Now you can use these 2 fields to reference this customer and this payment profile for later use with
//the rest of the CIM driver features as usual.

// Now you can use these 2 fields to reference this customer and this payment profile for later use with
// the rest of the CIM driver features as usual.
```

## DPM and SIM Signatures

DPM and SIM used to sign their requests with the `transactionKey` using the mdh HMAC algorithm.
From early 2019, this algorithm is being removed completely.
Instead, the SHA-512 HMAC algorithm is used to sign the DPM and SIM requsts,
Instead, the SHA-512 HMAC algorithm is used to sign the DPM and SIM requests,
and to validate the received notifications.

To start using the SHA-512 signing, set your `signatureKey` in the gateway:
Expand Down
1 change: 1 addition & 0 deletions src/Message/DPMAuthorizeRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* Authorize.Net DPM Authorize Request.
* Takes the data that will be used to create the direct-post form.
*/

class DPMAuthorizeRequest extends SIMAuthorizeRequest
{
protected $action = 'AUTH_ONLY';
Expand Down
2 changes: 1 addition & 1 deletion src/Message/DPMCompleteRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
/**
* Authorize.Net DPM Complete Authorize Request
*/
class DPMCompleteRequest extends SIMCompleteAuthorizeRequest
class DPMCompleteRequest extends SIMCompleteRequest
{
public function sendData($data)
{
Expand Down
2 changes: 1 addition & 1 deletion src/Message/DPMCompleteResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
/**
* SIM and DPM both have identical needs when handling the notify request.
*/
class DPMCompleteResponse extends SIMCompleteAuthorizeResponse
class DPMCompleteResponse extends SIMCompleteResponse
{
}
5 changes: 3 additions & 2 deletions src/Message/SIMAbstractRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

namespace Omnipay\AuthorizeNet\Message;

use Omnipay\Common\Message\AbstractRequest;

/**
* Authorize.Net SIM Abstract Request
*/

use Omnipay\Common\Message\AbstractRequest;

abstract class SIMAbstractRequest extends AbstractRequest
{
/**
Expand Down
8 changes: 5 additions & 3 deletions src/Message/SIMAuthorizeRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ public function getData()
}

$data = array_merge($data, $this->getBillingData());
$data['x_fp_hash'] = $this->getHash($data);

$data['x_fp_hash'] = $this->createHash($data);

return $data;
}
Expand All @@ -64,10 +65,11 @@ public function getData()
* modified en-route.
* It uses the TransactionKey, which is a shared secret between the merchant
* and Authorize.Net The sequence and timestamp provide additional salt.
*
* @param $data
* @return string
*/
public function getHash($data)
public function createHash($data)
{
$fingerprint = implode(
'^',
Expand All @@ -77,7 +79,7 @@ public function getHash($data)
$data['x_fp_timestamp'],
$data['x_amount']
)
).'^';
) . '^';

// If x_currency_code is specified, then it must follow the final trailing carat.

Expand Down
7 changes: 7 additions & 0 deletions src/Message/SIMAuthorizeResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,11 @@ public function getRedirectData()
{
return $this->getData();
}

public function getTransactionId()
{
return isset($this->data[SIMAbstractRequest::TRANSACTION_ID_PARAM])
? $this->data[SIMAbstractRequest::TRANSACTION_ID_PARAM]
: null;
}
}
86 changes: 0 additions & 86 deletions src/Message/SIMCompleteAuthorizeRequest.php

This file was deleted.

158 changes: 158 additions & 0 deletions src/Message/SIMCompleteRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
<?php

namespace Omnipay\AuthorizeNet\Message;

use Omnipay\Common\Exception\InvalidRequestException;

/**
* Authorize.Net SIM Complete Authorize Request
*/
class SIMCompleteRequest extends SIMAbstractRequest
{
/**
* Get the transaction ID passed in through the custom field.
* This is used to look up the transaction in storage.
*/
public function getTransactionId()
{
return $this->httpRequest->request->get(static::TRANSACTION_ID_PARAM);
}

public function getData()
{
// The hash sent in the callback from the Authorize.Net gateway.
$hashPosted = $this->getPostedHash();

// Calculate the hash locally, using the shared "hash secret" and login ID.
$hashCalculated = $this->getHash();

if ($hashPosted !== $hashCalculated) {
// If the hash is incorrect, then we can't trust the source nor anything sent.
// Throwing exceptions here is probably a bad idea. We are trying to get the data,
// and if it is invalid, then we need to be able to log that data for analysis.
// Except we can't, baceuse the exception means we can't get to the data.
// For now, this is consistent with other OmniPay gateway drivers.

throw new InvalidRequestException('Incorrect hash');
}

// The hashes have passed, but the amount should also be validated against the
// amount in the stored and retrieved transaction. If the application has the
// ability to retrieve the transaction (using the transaction_id sent as a custom
// form field, or perhaps in an otherwise unused field such as x_invoice_id.

$amount = $this->getAmount();
$postedAmount = $this->httpRequest->request->get('x_amount');

if (isset($amount) && $amount != $postedAmount) {
// The amounts don't match. Someone may have been playing with the
// transaction references.

throw new InvalidRequestException('Incorrect amount');
}

return $this->httpRequest->request->all();
}

/**
* @return string
*/
public function getHash()
{
if ($this->getSignatureKey()) {
return $this->getSha512Hash();
} else {
return $this->getMd5Hash();
}
}

/**
* Generate md5 hash.
*
* @param $transaction_reference
* @param $amount
* @return string
*/
public function getMd5Hash()
{
$transactionReference = $this->httpRequest->request->get('x_trans_id');
$amount = $this->httpRequest->request->get('x_amount');

$key = array(
$this->getHashSecret(),
$this->getApiLoginId(),
$transactionReference,
$amount,
);

return md5(implode('', $key));
}

/**
* Generate sha512 hash.
* Required fields are provided in Table 18 in
* https://www.authorize.net/content/dam/authorize/documents/SIM_guide.pdf#page=73
*
* @return string hash generated from server request transformed to upper case
*/
public function getSha512Hash()
{
$signatureKey = $this->getSignatureKey();
$request = $this->httpRequest->request;

$hashData = '^' . implode('^', [
$request->get('x_trans_id'),
$request->get('x_test_request'),
$request->get('x_response_code'),
$request->get('x_auth_code'),
$request->get('x_cvv2_resp_code'),
$request->get('x_cavv_response'),
$request->get('x_avs_code'),
$request->get('x_method'),
$request->get('x_account_number'),
$request->get('x_amount'),
$request->get('x_company'),
$request->get('x_first_name'),
$request->get('x_last_name'),
$request->get('x_address'),
$request->get('x_city'),
$request->get('x_state'),
$request->get('x_zip'),
$request->get('x_country'),
$request->get('x_phone'),
$request->get('x_fax'),
$request->get('x_email'),
$request->get('x_ship_to_company'),
$request->get('x_ship_to_first_name'),
$request->get('x_ship_to_last_name'),
$request->get('x_ship_to_address'),
$request->get('x_ship_to_city'),
$request->get('x_ship_to_state'),
$request->get('x_ship_to_zip'),
$request->get('x_ship_to_country'),
$request->get('x_invoice_num'),
]) . '^';
$hash = hash_hmac('sha512', $hashData, hex2bin($signatureKey));

return strtoupper($hash);
}

/**
* Get posted hash from the callback from the Authorize.Net gateway.
*
* @return string|null
*/
public function getPostedHash()
{
if ($signatureKey = $this->getSignatureKey()) {
return strtoupper($this->httpRequest->request->get('x_SHA2_Hash'));
}

return strtolower($this->httpRequest->request->get('x_MD5_Hash'));
}

public function sendData($data)
{
return $this->response = new SIMCompleteResponse($this, $data);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

namespace Omnipay\AuthorizeNet\Message;

/**
* Authorize.Net SIM Complete Authorize Response
*/

use Omnipay\Common\Message\AbstractResponse;
use Omnipay\Common\Message\RedirectResponseInterface;
use Symfony\Component\HttpFoundation\Response as HttpResponse;

/**
* Authorize.Net SIM Complete Authorize Response
*/
class SIMCompleteAuthorizeResponse extends AbstractResponse implements RedirectResponseInterface
class SIMCompleteResponse extends AbstractResponse implements RedirectResponseInterface
{
// Response codes returned by Authorize.Net

Expand Down
2 changes: 1 addition & 1 deletion src/SIMGateway.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public function authorize(array $parameters = array())

public function completeAuthorize(array $parameters = array())
{
return $this->createRequest('\Omnipay\AuthorizeNet\Message\SIMCompleteAuthorizeRequest', $parameters);
return $this->createRequest('\Omnipay\AuthorizeNet\Message\SIMCompleteRequest', $parameters);
}

public function capture(array $parameters = array())
Expand Down
2 changes: 1 addition & 1 deletion tests/Message/DPMAuthorizeRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public function testGetHash()

$expected = hash_hmac('md5', 'user^a^b^c^', 'key');

$this->assertSame($expected, $this->request->getHash($data));
$this->assertSame($expected, $this->request->createHash($data));
}

public function testSend()
Expand Down
Loading