Skip to content

Commit 8176146

Browse files
committed
ACP2E-4049: Unknown IPNs from PayPal abuses application IPN processor
1 parent 64180fc commit 8176146

File tree

3 files changed

+54
-6
lines changed

3 files changed

+54
-6
lines changed

app/code/Magento/Paypal/Model/Exception/UnknownIpnException.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
* Copyright 2025 Adobe
44
* All Rights Reserved.
55
*/
6+
declare(strict_types=1);
7+
68
namespace Magento\Paypal\Model\Exception;
79

810
use Magento\Framework\Exception\LocalizedException;

app/code/Magento/Paypal/Test/Unit/Controller/Ipn/IndexTest.php

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2011 Adobe
4+
* All Rights Reserved.
55
*/
66
declare(strict_types=1);
77

@@ -20,6 +20,7 @@
2020
use PHPUnit\Framework\MockObject\MockObject;
2121
use PHPUnit\Framework\TestCase;
2222
use Psr\Log\LoggerInterface;
23+
use Magento\Paypal\Model\Exception\UnknownIpnException;
2324

2425
/**
2526
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -86,6 +87,15 @@ public function testIndexActionException()
8687
$this->model->execute();
8788
}
8889

90+
public function testIndexActionUnknownIpnException()
91+
{
92+
$this->requestMock->expects($this->once())->method('isPost')->willReturn(true);
93+
$exception = new UnknownIpnException(__('Missing invoice field in IPN request.'));
94+
$this->requestMock->expects($this->once())->method('getPostValue')->willThrowException($exception);
95+
$this->loggerMock->expects($this->once())->method('critical')->with($this->identicalTo($exception));
96+
$this->model->execute();
97+
}
98+
8999
public function testIndexAction()
90100
{
91101
$this->requestMock->expects($this->once())->method('isPost')->willReturn(true);
@@ -94,7 +104,7 @@ public function testIndexAction()
94104
'invoice' => $incrementId,
95105
'other' => 'other data'
96106
];
97-
$this->requestMock->expects($this->exactly(2))->method('getPostValue')->willReturn($data);
107+
$this->requestMock->expects($this->once())->method('getPostValue')->willReturn($data);
98108
$ipnMock = $this->getMockForAbstractClass(IpnInterface::class);
99109
$this->ipnFactoryMock->expects($this->once())
100110
->method('create')

app/code/Magento/Paypal/Test/Unit/Model/IpnTest.php

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2015 Adobe
4+
* All Rights Reserved.
55
*/
66
declare(strict_types=1);
77

@@ -21,6 +21,11 @@
2121
use Magento\Sales\Model\OrderFactory;
2222
use PHPUnit\Framework\MockObject\MockObject;
2323
use PHPUnit\Framework\TestCase;
24+
use Magento\Paypal\Model\Exception\UnknownIpnException;
25+
use Magento\Sales\Model\Order\Email\Sender\CreditmemoSender;
26+
use Magento\Sales\Model\Order\Email\Sender\OrderSender;
27+
use Magento\Sales\Model\OrderMutexInterface;
28+
use \Psr\Log\LoggerInterface;
2429

2530
class IpnTest extends TestCase
2631
{
@@ -115,7 +120,7 @@ protected function setUp(): void
115120
'curlFactory' => $this->curlFactory,
116121
'orderFactory' => $this->_orderMock,
117122
'paypalInfo' => $this->_paypalInfo,
118-
'data' => ['payment_status' => 'Pending', 'pending_reason' => 'authorization']
123+
'data' => ['invoice' => '00000001', 'payment_status' => 'Pending', 'pending_reason' => 'authorization']
119124
]
120125
);
121126
}
@@ -157,6 +162,35 @@ public function testPaymentReviewRegisterPaymentAuthorization()
157162
$this->_ipn->processIpnRequest();
158163
}
159164

165+
public function testProcessIpnRequestThrowsException()
166+
{
167+
$creditmemoSenderMock = $this->getMockBuilder(CreditmemoSender::class)
168+
->disableOriginalConstructor()
169+
->getMock();
170+
$orderSenderMock = $this->getMockBuilder(OrderSender::class)
171+
->disableOriginalConstructor()
172+
->getMock();
173+
$orderMutexMock = $this->getMockForAbstractClass(orderMutexInterface::class);
174+
$loggerMock = $this->getMockForAbstractClass(LoggerInterface::class);
175+
$this->_ipn = new Ipn(
176+
$this->configFactory,
177+
$loggerMock,
178+
$this->curlFactory,
179+
$this->_orderMock,
180+
$this->_paypalInfo,
181+
$orderSenderMock,
182+
$creditmemoSenderMock,
183+
$orderMutexMock,
184+
[
185+
'payment_status' => 'Pending',
186+
'pending_reason' => 'fraud',
187+
'fraud_management_pending_filters_1' => 'Maximum Transaction Amount',
188+
]
189+
);
190+
$this->expectException(UnknownIpnException::class);
191+
$this->_ipn->processIpnRequest();
192+
}
193+
160194
public function testPaymentReviewRegisterPaymentFraud()
161195
{
162196
$paymentMock = $this->createPartialMock(
@@ -196,6 +230,7 @@ public function testPaymentReviewRegisterPaymentFraud()
196230
'orderFactory' => $this->_orderMock,
197231
'paypalInfo' => $this->_paypalInfo,
198232
'data' => [
233+
'invoice' => '00000001',
199234
'payment_status' => 'Pending',
200235
'pending_reason' => 'fraud',
201236
'fraud_management_pending_filters_1' => 'Maximum Transaction Amount',
@@ -241,6 +276,7 @@ public function testRegisterPaymentDenial()
241276
'orderFactory' => $this->_orderMock,
242277
'paypalInfo' => $this->_paypalInfo,
243278
'data' => [
279+
'invoice' => '00000001',
244280
'payment_status' => 'Denied',
245281
]
246282
]

0 commit comments

Comments
 (0)