Json.php 10.6 KB
Newer Older
1
<?php
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/**
 *                       ######
 *                       ######
 * ############    ####( ######  #####. ######  ############   ############
 * #############  #####( ######  #####. ######  #############  #############
 *        ######  #####( ######  #####. ######  #####  ######  #####  ######
 * ###### ######  #####( ######  #####. ######  #####  #####   #####  ######
 * ###### ######  #####( ######  #####. ######  #####          #####  ######
 * #############  #############  #############  #############  #####  ######
 *  ############   ############  #############   ############  #####  ######
 *                                      ######
 *                               #############
 *                               ############
 *
 * Adyen Payment module (https://www.adyen.com/)
 *
 * Copyright (c) 2015 Adyen BV (https://www.adyen.com/)
 * See LICENSE.txt for license details.
 *
 * Author: Adyen <magento@adyen.com>
 */
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

namespace Adyen\Payment\Controller\Process;

use Symfony\Component\Config\Definition\Exception\Exception;

/**
 * Class Json
 * @package Adyen\Payment\Controller\Process
 */
class Json extends \Magento\Framework\App\Action\Action
{
    /**
     * @var \Magento\Framework\ObjectManagerInterface
     */
    protected $_objectManager;

    /**
     * @var \Magento\Framework\Controller\Result\RawFactory
     */
    protected $_resultFactory;

44 45 46 47
    /**
     * @var \Adyen\Payment\Helper\Data
     */
    protected $_adyenHelper;
48

49 50
    /**
     * @param \Magento\Framework\App\Action\Context $context
51
     * @param \Adyen\Payment\Helper\Data $adyenHelper
52 53
     */
    public function __construct(
54 55
        \Magento\Framework\App\Action\Context $context,
        \Adyen\Payment\Helper\Data $adyenHelper
56 57 58 59
    ) {
        parent::__construct($context);
        $this->_objectManager = $context->getObjectManager();
        $this->_resultFactory = $context->getResultFactory();
60
        $this->_adyenHelper = $adyenHelper;
61 62 63 64 65 66 67 68
    }

    /**
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function execute()
    {
        try {
69
            $notificationItems = json_decode(file_get_contents('php://input'), true);
70 71 72 73 74 75
            $notificationMode = isset($notificationItems['live']) ? $notificationItems['live'] : "";

            if($notificationMode != "" && $this->_validateNotificationMode($notificationMode))
            {
                foreach($notificationItems['notificationItems'] as $notificationItem)
                {
76
                    $status = $this->_processNotification($notificationItem['NotificationRequestItem'], $notificationMode);
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
                    if($status == "401"){
                        $this->_return401();
                        return;
                    }
                }
                $this->getResponse()
                    ->clearHeader('Content-Type')
                    ->setHeader('Content-Type', 'text/html')
                    ->setBody("[accepted]");
                return;
            } else
            {
                if($notificationMode == "") {
                    $this->_return401();
                    return;
                }
                throw new \Magento\Framework\Exception\LocalizedException(__('Mismatch between Live/Test modes of Magento store and the Adyen platform'));
            }
        } catch (Exception $e) {
            throw new \Magento\Framework\Exception\LocalizedException(__($e->getMessage()));
        }
    }

    /**
     * @param $notificationMode
     * @return bool
     */
    protected function _validateNotificationMode($notificationMode)
    {
106
        $mode = $this->_adyenHelper->getAdyenAbstractConfigData('demo_mode');
107
        if ($mode=='1' &&  $notificationMode == "false" || $mode=='0' &&  $notificationMode == 'true') {
108 109 110
            return true;
        }
        return false;
111 112 113 114 115 116 117 118
    }


    /**
     * $desc save notification into the database for cronjob to execute notificaiton
     * @param $response
     * @throws \Magento\Framework\Exception\LocalizedException
     */
119
    protected function _processNotification($response, $notificationMode)
120
    {
121 122
        // TODO: log the response

123 124 125
        // validate the notification
        if($this->authorised($response))
        {
126 127
            // check if notificaiton already exists
            if(!$this->_isDuplicate($response)) {
128

129
                try {
130

131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
                    $notification = $this->_objectManager->create('Adyen\Payment\Model\Notification');

                    if (isset($response['pspReference'])) {
                        $notification->setPspreference($response['pspReference']);
                    }
                    if (isset($response['merchantReference'])) {
                        $notification->setMerchantReference($response['merchantReference']);
                    }
                    if (isset($response['eventCode'])) {
                        $notification->setEventCode($response['eventCode']);
                    }
                    if (isset($response['success'])) {
                        $notification->setSuccess($response['success']);
                    }
                    if (isset($response['paymentMethod'])) {
                        $notification->setPaymentMethod($response['paymentMethod']);
                    }
                    if (isset($response['amount'])) {
                        $notification->setAmountValue($response['amount']['value']);
                        $notification->setAmountCurrency($response['amount']['currency']);
                    }
                    if (isset($response['reason'])) {
                        $notification->setReason($response['reason']);
                    }
155

156
                    $notification->setLive($notificationMode);
157

158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
                    if (isset($response['additionalData'])) {
                        $notification->setAddtionalData(serialize($response['additionalData']));
                    }
                    if (isset($response['done'])) {
                        $notification->setDone($response['done']);
                    }

                    // do this to set both fields in the correct timezone
                    $date = new \DateTime();
                    $notification->setCreatedAt($date);
                    $notification->setUpdatedAt($date);

                    $notification->save();

                } catch (Exception $e) {
                    throw new \Magento\Framework\Exception\LocalizedException(__($e->getMessage()));
                }
175
            }
176 177
        } else {
            return "401";
178 179 180 181 182 183 184 185 186 187 188 189 190
        }
    }


    /**
     * @desc HTTP Authentication of the notification
     * @param $response
     */
    protected function authorised($response)
    {
        // Add CGI support
        $this->_fixCgiHttpAuthentication();

191
        $internalMerchantAccount = $this->_adyenHelper->getAdyenAbstractConfigData('merchant_account');
192 193 194 195 196 197 198 199
        $username = $this->_adyenHelper->getAdyenAbstractConfigData('notification_username');
        $password = $this->_adyenHelper->getNotificationPassword();

        $submitedMerchantAccount = $response['merchantAccountCode'];

        if (empty($submitedMerchantAccount) && empty($internalMerchantAccount)) {
            if(strtolower(substr($response['pspReference'],0,17)) == "testnotification_" || strtolower(substr($response['pspReference'],0,5)) == "test_") {
                echo 'merchantAccountCode is empty in magento settings'; exit();
200
            }
201 202 203 204 205 206 207
            return false;
        }

        // validate username and password
        if ((!isset($_SERVER['PHP_AUTH_USER']) && !isset($_SERVER['PHP_AUTH_PW']))) {
            if(strtolower(substr($response['pspReference'],0,17)) == "testnotification_" || strtolower(substr($response['pspReference'],0,5)) == "test_") {
                echo 'Authentication failed: PHP_AUTH_USER and PHP_AUTH_PW are empty. See Adyen Magento manual CGI mode'; exit();
208
            }
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
            return false;
        }

        $accountCmp = !$this->_adyenHelper->getAdyenAbstractConfigDataFlag('multiple_merchants')
            ? strcmp($submitedMerchantAccount, $internalMerchantAccount)
            : 0;

        $usernameCmp = strcmp($_SERVER['PHP_AUTH_USER'], $username);
        $passwordCmp = strcmp($_SERVER['PHP_AUTH_PW'], $password);
        if ($accountCmp === 0 && $usernameCmp === 0 && $passwordCmp === 0) {
            return true;
        }

        // If notification is test check if fields are correct if not return error
        if(strtolower(substr($response['pspReference'],0,17)) == "testnotification_" || strtolower(substr($response['pspReference'],0,5)) == "test_") {
            if($accountCmp != 0) {
                echo 'MerchantAccount in notification is not the same as in Magento settings'; exit();
            } elseif($usernameCmp != 0 || $passwordCmp != 0) {
                echo 'username (PHP_AUTH_USER) and\or password (PHP_AUTH_PW) are not the same as Magento settings'; exit();
228
            }
229
        }
230

231 232
        return false;
    }
233

234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249

    /**
     * $desc if notification is already saved ignore it
     * @param $response
     * @return bool
     */
    protected function _isDuplicate($response)
    {
        $pspReference = trim($response['pspReference']);
        $eventCode = trim($response['eventCode']);
        $success = trim($response['success']);

        $notification = $this->_objectManager->create('Adyen\Payment\Model\Notification');
        return $notification->isDuplicate($pspReference, $eventCode, $success);
    }

250 251 252 253 254 255 256 257 258 259 260 261
    /**
     * Fix these global variables for the CGI
     */
    protected function _fixCgiHttpAuthentication() { // unsupported is $_SERVER['REMOTE_AUTHORIZATION']: as stated in manual :p
        if (isset($_SERVER['REDIRECT_REMOTE_AUTHORIZATION']) && $_SERVER['REDIRECT_REMOTE_AUTHORIZATION'] != '') { //pcd note: no idea who sets this
            list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', base64_decode($_SERVER['REDIRECT_REMOTE_AUTHORIZATION']));
        } elseif(!empty($_SERVER['HTTP_AUTHORIZATION'])){ //pcd note: standard in magento?
            list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
        } elseif (!empty($_SERVER['REMOTE_USER'])) { //pcd note: when cgi and .htaccess modrewrite patch is executed
            list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', base64_decode(substr($_SERVER['REMOTE_USER'], 6)));
        } elseif (!empty($_SERVER['REDIRECT_REMOTE_USER'])) { //pcd note: no idea who sets this
            list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', base64_decode(substr($_SERVER['REDIRECT_REMOTE_USER'], 6)));
262 263 264 265 266 267 268 269 270 271 272 273
        }
    }

    /**
     *
     */
    protected function _return401()
    {

        $this->getResponse()->setHttpResponseCode(401);
    }
}