Skip to content

Commit

Permalink
Merge pull request #129 from thephpleague/pr128
Browse files Browse the repository at this point in the history
PR128 additions
  • Loading branch information
judgej authored Apr 27, 2019
2 parents 1c2c341 + bf5412b commit 8ccce31
Show file tree
Hide file tree
Showing 19 changed files with 382 additions and 177 deletions.
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

0 comments on commit 8ccce31

Please sign in to comment.