Commit 50123810 authored by Tom Ashe's avatar Tom Ashe Committed by Jonathan Sacksick
Browse files

Issue #3254044 by TomTech, bradjones1, micahw156, mjmorley, jsacksick: Bump lcobucci/jwt to ^4.

parent 2027f3d4
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -7,6 +7,6 @@
    "require": {
        "drupal/commerce": "^2.25",
        "commerceguys/authnet": "^1.1.2",
        "lcobucci/jwt": "~3.1"
        "lcobucci/jwt": "^4"
    }
}
+20 −10
Original line number Diff line number Diff line
@@ -2,13 +2,15 @@

namespace Drupal\commerce_authnet\Controller;

use Drupal\commerce_payment\Entity\PaymentGateway;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Drupal\commerce_payment\Entity\PaymentGateway;
use Lcobucci\JWT\Signer\Key\InMemory;
use Lcobucci\JWT\Validation\Constraint\SignedWith;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RequestStack;

/**
 * Verifies JWT in the CCA process.
@@ -49,17 +51,25 @@ class CcaValidation implements ContainerInjectionInterface {
  public function validateJwt() {
    $response_jwt = $this->requestStack->getCurrentRequest()->request->get('responseJwt');

    /** @var \Lcobucci\JWT\Token $token */
    $token = (new Parser())->parse($response_jwt);
    $signer = new Sha256();

    $gateway_id = $this->requestStack->getCurrentRequest()->request->get('gatewayId');
    /** @var \Drupal\commerce_payment\Entity\PaymentGateway $gateway */
    $gateway = PaymentGateway::load($gateway_id);
    $api_key = $gateway->getPlugin()->getCcaApiKey();
    $claims = $token->getClaims();

    $configuration = Configuration::forSymmetricSigner(
      new Sha256(),
      InMemory::plainText($api_key)
    );
    // Set validation constraints.
    $constraints = [
      new SignedWith($configuration->signer(), $configuration->signingKey()),
    ];
    $configuration->setValidationConstraints(...$constraints);
    $token = $configuration->parser()->parse($response_jwt);

    $claims = $token->claims()->all();
    $response = [
      'verified' => $token->verify($signer, $api_key),
      'verified' => $configuration->validator()->validate($token, ...$configuration->validationConstraints()),
      'payload' => $claims,
    ];
    return new JsonResponse($response);
+65 −43
Original line number Diff line number Diff line
@@ -2,34 +2,36 @@

namespace Drupal\commerce_authnet\Plugin\Commerce\PaymentGateway;

use CommerceGuys\AuthNet\DataTypes\CreditCard as AuthnetCreditCard;
use CommerceGuys\AuthNet\UpdateCustomerPaymentProfileRequest;
use Drupal\commerce_order\Entity\OrderInterface;
use Drupal\commerce_payment\CreditCard;
use Drupal\commerce_payment\Entity\PaymentInterface;
use Drupal\commerce_payment\Entity\PaymentMethodInterface;
use Drupal\commerce_payment\Exception\DeclineException;
use Drupal\commerce_payment\Exception\HardDeclineException;
use Drupal\commerce_payment\Exception\InvalidResponseException;
use Drupal\commerce_payment\Exception\PaymentGatewayException;
use Drupal\commerce_price\Price;
use CommerceGuys\AuthNet\CreateCustomerPaymentProfileRequest;
use CommerceGuys\AuthNet\CreateCustomerProfileRequest;
use CommerceGuys\AuthNet\CreateTransactionRequest;
use CommerceGuys\AuthNet\UpdateHeldTransactionRequest;
use CommerceGuys\AuthNet\DataTypes\BillTo;
use CommerceGuys\AuthNet\DataTypes\CardholderAuthentication;
use CommerceGuys\AuthNet\DataTypes\CreditCard as AuthnetCreditCard;
use CommerceGuys\AuthNet\DataTypes\CreditCard as CreditCardDataType;
use CommerceGuys\AuthNet\DataTypes\LineItem;
use CommerceGuys\AuthNet\DataTypes\Order as OrderDataType;
use CommerceGuys\AuthNet\DataTypes\OpaqueData;
use CommerceGuys\AuthNet\DataTypes\Order as OrderDataType;
use CommerceGuys\AuthNet\DataTypes\PaymentProfile;
use CommerceGuys\AuthNet\DataTypes\Profile;
use CommerceGuys\AuthNet\DataTypes\TransactionRequest;
use CommerceGuys\AuthNet\DataTypes\ShipTo;
use CommerceGuys\AuthNet\DataTypes\TransactionRequest;
use CommerceGuys\AuthNet\UpdateCustomerPaymentProfileRequest;
use CommerceGuys\AuthNet\UpdateHeldTransactionRequest;
use Drupal\commerce_order\Entity\OrderInterface;
use Drupal\commerce_payment\CreditCard;
use Drupal\commerce_payment\Entity\PaymentInterface;
use Drupal\commerce_payment\Entity\PaymentMethodInterface;
use Drupal\commerce_payment\Exception\DeclineException;
use Drupal\commerce_payment\Exception\HardDeclineException;
use Drupal\commerce_payment\Exception\InvalidResponseException;
use Drupal\commerce_payment\Exception\PaymentGatewayException;
use Drupal\commerce_price\Price;
use Drupal\Core\Form\FormStateInterface;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Signer\Key\InMemory;
use Lcobucci\JWT\Validation\Constraint\SignedWith;

/**
 * Provides the Accept.js payment gateway.
@@ -166,7 +168,7 @@ class AcceptJs extends OnsiteBase implements AcceptJsInterface {
    if ($this->configuration['cca_status']) {
      // Test API Id.
      // @see https://developer.cardinalcommerce.com/try-it-now.shtml
      if ($this->configuration['mode'] == 'test') {
      if ($this->configuration['mode'] === 'test') {
        return '582e0a2033fadd1260f990f6';
      }
      else {
@@ -185,7 +187,7 @@ class AcceptJs extends OnsiteBase implements AcceptJsInterface {
    if ($this->configuration['cca_status']) {
      // Test Org Unit ID.
      // @see https://developer.cardinalcommerce.com/try-it-now.shtml
      if ($this->configuration['mode'] == 'test') {
      if ($this->configuration['mode'] === 'test') {
        return '582be9deda52932a946c45c4';
      }
      else {
@@ -204,7 +206,7 @@ class AcceptJs extends OnsiteBase implements AcceptJsInterface {
    if ($this->configuration['cca_status']) {
      // Test API Key.
      // @see https://developer.cardinalcommerce.com/try-it-now.shtml
      if ($this->configuration['mode'] == 'test') {
      if ($this->configuration['mode'] === 'test') {
        return '754be3dc-10b7-471f-af31-f20ce12b9ec1';
      }
      else {
@@ -322,7 +324,7 @@ class AcceptJs extends OnsiteBase implements AcceptJsInterface {
    $request->setTransactionRequest($transaction_request);
    $response = $request->execute();

    if ($response->getResultCode() != 'Ok') {
    if ($response->getResultCode() !== 'Ok') {
      $this->logResponse($response);
      $message = $response->getMessages()[0];
      switch ($message->getCode()) {
@@ -374,7 +376,10 @@ class AcceptJs extends OnsiteBase implements AcceptJsInterface {
   */
  public function approvePayment(PaymentInterface $payment) {
    /** @var \Drupal\commerce_payment\Entity\PaymentMethod $payment_method */
    $this->assertPaymentState($payment, ['unauthorized_review', 'authorization_review']);
    $this->assertPaymentState($payment, [
      'unauthorized_review',
      'authorization_review',
    ]);
    if ($payment->isExpired()) {
      throw new HardDeclineException('This payment has expired.');
    }
@@ -384,13 +389,14 @@ class AcceptJs extends OnsiteBase implements AcceptJsInterface {
    $request->setRefTransId($payment->getRemoteId());
    $response = $request->execute();

    if ($response->getResultCode() != 'Ok') {
    if ($response->getResultCode() !== 'Ok') {
      $this->logResponse($response);
      $message = $response->getMessages()[0];
      throw new PaymentGatewayException($message->getText());
    }

    $new_state = $payment->getState()->getId() == 'unauthorized_review' ? 'authorization' : 'completed';
    $new_state = $payment->getState()
      ->getId() === 'unauthorized_review' ? 'authorization' : 'completed';
    $payment->setState($new_state);
    $payment->save();
  }
@@ -400,7 +406,10 @@ class AcceptJs extends OnsiteBase implements AcceptJsInterface {
   */
  public function declinePayment(PaymentInterface $payment) {
    /** @var \Drupal\commerce_payment\Entity\PaymentMethod $payment_method */
    $this->assertPaymentState($payment, ['unauthorized_review', 'authorization_review']);
    $this->assertPaymentState($payment, [
      'unauthorized_review',
      'authorization_review',
    ]);
    if ($payment->isExpired()) {
      throw new HardDeclineException('This payment has expired.');
    }
@@ -410,13 +419,14 @@ class AcceptJs extends OnsiteBase implements AcceptJsInterface {
    $request->setRefTransId($payment->getRemoteId());
    $response = $request->execute();

    if ($response->getResultCode() != 'Ok') {
    if ($response->getResultCode() !== 'Ok') {
      $this->logResponse($response);
      $message = $response->getMessages()[0];
      throw new PaymentGatewayException($message->getText());
    }

    $new_state = $payment->getState()->getId() == 'unauthorized_review' ? 'unauthorized_declined' : 'authorization_declined';
    $new_state = $payment->getState()
      ->getId() === 'unauthorized_review' ? 'unauthorized_declined' : 'authorization_declined';
    $payment->setState($new_state);
    $payment->save();
  }
@@ -470,7 +480,7 @@ class AcceptJs extends OnsiteBase implements AcceptJsInterface {
    $request->setTransactionRequest($transaction_request);
    $response = $request->execute();

    if ($response->getResultCode() != 'Ok') {
    if ($response->getResultCode() !== 'Ok') {
      $this->logResponse($response);
      $message = $response->getMessages()[0];
      throw new PaymentGatewayException($message->getText());
@@ -501,16 +511,24 @@ class AcceptJs extends OnsiteBase implements AcceptJsInterface {
        throw new PaymentGatewayException('Cannot continue when CCA is enabled but not used.');
      }

      /** @var \Lcobucci\JWT\Token $token */
      $token = (new Parser())->parse($payment_details['cca_jwt_response_token']);
      $signer = new Sha256();
      $configuration = Configuration::forSymmetricSigner(
        new Sha256(),
        InMemory::plainText($this->getCcaApiKey())
      );
      // Set validation constraints.
      $constraints = [
        new SignedWith($configuration->signer(), $configuration->signingKey()),
      ];
      $configuration->setValidationConstraints(...$constraints);

      $token = $configuration->parser()
        ->parse($payment_details['cca_jwt_response_token']);

      if (!$token->verify($signer, $this->getCcaApiKey())) {
      if (!$configuration->validator()
        ->validate($token, ...$configuration->validationConstraints())) {
        throw new PaymentGatewayException('Response CCA JWT is not valid.');
      }
      $claims = $token->getClaims();
      /** @var \Lcobucci\JWT\Claim $payload */
      $payload = $claims['Payload'];
      $payload = $token->claims()->get('Payload');
      if (isset($payload->getValue()->Payment->ExtendedData->SignatureVerification) && $payload->getValue()->Payment->ExtendedData->SignatureVerification === 'N') {
        throw new PaymentGatewayException('Unsuccessful signature verification.');
      }
@@ -582,7 +600,7 @@ class AcceptJs extends OnsiteBase implements AcceptJsInterface {
      'expirationDate' => sprintf('%s-%s', $payment_method->get('card_exp_month')->value, $payment_method->get('card_exp_year')->value),
    ]));
    $response = $request->execute();
    if ($response->getResultCode() != 'Ok') {
    if ($response->getResultCode() !== 'Ok') {
      $this->logResponse($response);
      $error = $response->getMessages()[0];
      throw new DeclineException('Unable to update the payment method.');
@@ -617,13 +635,11 @@ class AcceptJs extends OnsiteBase implements AcceptJsInterface {
  protected function doCreatePaymentMethod(PaymentMethodInterface $payment_method, array $payment_details) {
    $owner = $payment_method->getOwner();
    $customer_profile_id = NULL;
    $customer_data = [];
    if ($owner && !$owner->isAnonymous()) {
      $customer_profile_id = $this->getRemoteCustomerId($owner);
      if (empty($customer_profile_id)) {
        $customer_profile_id = $this->getPaymentMethodCustomerId($payment_method);
      }
      $customer_data['email'] = $owner->getEmail();
    }

    if ($customer_profile_id) {
@@ -633,7 +649,7 @@ class AcceptJs extends OnsiteBase implements AcceptJsInterface {
      $request->setPaymentProfile($payment_profile);
      $response = $request->execute();

      if ($response->getResultCode() != 'Ok') {
      if ($response->getResultCode() !== 'Ok') {
        $this->logResponse($response);
        $error = $response->getMessages()[0];
        switch ($error->getCode()) {
@@ -685,12 +701,12 @@ class AcceptJs extends OnsiteBase implements AcceptJsInterface {
      $request->setValidationMode(NULL);
      $response = $request->execute();

      if ($response->getResultCode() == 'Ok') {
      if ($response->getResultCode() === 'Ok') {
        $customer_profile_id = $response->customerProfileId;
      }
      else {
        // Handle duplicate.
        if ($response->getMessages()[0]->getCode() == 'E00039') {
        if ($response->getMessages()[0]->getCode() === 'E00039') {
          $result = array_filter(explode(' ', $response->getMessages()[0]->getText()), 'is_numeric');
          $customer_profile_id = reset($result);
        }
@@ -706,9 +722,9 @@ class AcceptJs extends OnsiteBase implements AcceptJsInterface {
      $request->setPaymentProfile($payment_profile);
      $response = $request->execute();

      if ($response->getResultCode() != 'Ok') {
      if ($response->getResultCode() !== 'Ok') {
        // If the error is not due to duplicates, log and error.
        if ($response->getMessages()[0]->getCode() != 'E00039') {
        if ($response->getMessages()[0]->getCode() !== 'E00039') {
          $this->logResponse($response);
          throw new InvalidResponseException("Unable to create payment profile for existing customer");
        }
@@ -853,13 +869,19 @@ class AcceptJs extends OnsiteBase implements AcceptJsInterface {
      'title' => $this->t('Approve'),
      'page_title' => $this->t('Approve payment'),
      'plugin_form' => 'approve-payment',
      'access' => in_array($payment_state, ['unauthorized_review', 'authorization_review']),
      'access' => in_array($payment_state, [
        'unauthorized_review',
        'authorization_review',
      ]),
    ];
    $operations['decline'] = [
      'title' => $this->t('Decline'),
      'page_title' => $this->t('Decline payment'),
      'plugin_form' => 'decline-payment',
      'access' => in_array($payment_state, ['unauthorized_review', 'authorization_review']),
      'access' => in_array($payment_state, [
        'unauthorized_review',
        'authorization_review',
      ]),
    ];

    return $operations;
+2 −0
Original line number Diff line number Diff line
@@ -313,6 +313,7 @@ abstract class OnsiteBase extends OnsitePaymentGatewayBase implements OnsitePaym
   *
   * @param \Drupal\commerce_payment\Entity\PaymentMethodInterface $payment_method
   *   The payment method.
   *
   * @return mixed
   *   The remote customer id or FALSE if it cannot be resolved.
   */
@@ -330,6 +331,7 @@ abstract class OnsiteBase extends OnsitePaymentGatewayBase implements OnsitePaym
   *
   * @param \Drupal\commerce_payment\Entity\PaymentMethodInterface $payment_method
   *   The payment method.
   *
   * @return string
   *   The remote id.
   */
+24 −15
Original line number Diff line number Diff line
@@ -4,15 +4,15 @@ namespace Drupal\commerce_authnet\PluginForm\AcceptJs;

use Drupal\commerce\InlineFormManager;
use Drupal\commerce_payment\PluginForm\PaymentMethodAddForm as BasePaymentMethodAddForm;
use Drupal\commerce_price\Calculator;
use Drupal\commerce_price\Price;
use Drupal\commerce_store\CurrentStoreInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Drupal\commerce_price\Price;
use Drupal\commerce_price\Calculator;
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Signer\Key\InMemory;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

@@ -66,7 +66,7 @@ class PaymentMethodAddForm extends BasePaymentMethodAddForm {
    /** @var \Drupal\commerce_authnet\Plugin\Commerce\PaymentGateway\AcceptJs $plugin */
    $plugin = $this->plugin;

    if ($plugin->getMode() == 'test') {
    if ($plugin->getMode() === 'test') {
      $element['#attached']['library'][] = 'commerce_authnet/accept-js-sandbox';
    }
    else {
@@ -242,7 +242,7 @@ class PaymentMethodAddForm extends BasePaymentMethodAddForm {
          '#attributes' => [
            'class' => ['accept-js-data-cca-jwt-token'],
          ],
          '#value' => (string) $this->generateJwt(),
          '#value' => $this->generateJwt()->toString(),
        ];
        $element['cca_jwt_response_token'] = [
          '#type' => 'hidden',
@@ -277,7 +277,11 @@ class PaymentMethodAddForm extends BasePaymentMethodAddForm {
      // Then we are dealing with anonymous user. Adding a customer email.
      $payment_details = $values['payment_information']['add_payment_method']['payment_details'];
      $payment_details['customer_email'] = $values['contact_information']['email'];
      $form_state->setValue(['payment_information', 'add_payment_method', 'payment_details'], $payment_details);
      $form_state->setValue([
        'payment_information',
        'add_payment_method',
        'payment_details',
      ], $payment_details);
    }
  }

@@ -302,14 +306,19 @@ class PaymentMethodAddForm extends BasePaymentMethodAddForm {
    /** @var \Drupal\commerce_authnet\Plugin\Commerce\PaymentGateway\AcceptJs $plugin */
    $plugin = $this->plugin;

    $token = (new Builder())->issuedBy($plugin->getCcaApiId())
      ->identifiedBy(uniqid(), TRUE)
      ->issuedAt($current_time)
      ->expiresAt($current_time + $expire_time)
    $configuration = Configuration::forSymmetricSigner(
      new Sha256(),
      InMemory::plainText($plugin->getCcaApiKey())
    );

    $token = $configuration->builder()->issuedBy($plugin->getCcaApiId())
      ->identifiedBy(uniqid('', TRUE))
      ->issuedAt(new \DateTimeImmutable('@' . $current_time))
      ->expiresAt(new \DateTimeImmutable('@' . ($current_time + $expire_time)))
      ->withClaim('OrgUnitId', $plugin->getCcaOrgUnitId())
      ->withClaim('Payload', $order_details)
      ->withClaim('Payload', $order_details ?? NULL)
      ->withClaim('ObjectifyPayload', TRUE)
      ->getToken(new Sha256(), new Key($plugin->getCcaApiKey()));
      ->getToken($configuration->signer(), $configuration->signingKey());

    return $token;
  }
@@ -337,10 +346,10 @@ class PaymentMethodAddForm extends BasePaymentMethodAddForm {
    $fraction_digits = $currency->getFractionDigits();
    $number = $amount->getNumber();
    if ($fraction_digits > 0) {
      $number = Calculator::multiply($number, pow(10, $fraction_digits));
      $number = Calculator::multiply($number, 10 ** $fraction_digits);
    }

    return round($number, 0);
    return (int) round($number);
  }

}
Loading