Skip to content

Commit 633cd15

Browse files
ENGCOM-1155: [ForwardPort 2.3-develop] Remove regenerate session id in \Magento\Checkout\Controller\Index\Index #14429
2 parents 9a0cd39 + b68a546 commit 633cd15

File tree

2 files changed

+148
-64
lines changed

2 files changed

+148
-64
lines changed

app/code/Magento/Checkout/Controller/Index/Index.php

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,35 @@ public function execute()
3232
return $this->resultRedirectFactory->create()->setPath('checkout/cart');
3333
}
3434

35-
$this->_customerSession->regenerateId();
35+
// generate session ID only if connection is unsecure according to issues in session_regenerate_id function.
36+
// @see http://php.net/manual/en/function.session-regenerate-id.php
37+
if (!$this->isSecureRequest()) {
38+
$this->_customerSession->regenerateId();
39+
}
3640
$this->_objectManager->get(\Magento\Checkout\Model\Session::class)->setCartWasUpdated(false);
3741
$this->getOnepage()->initCheckout();
3842
$resultPage = $this->resultPageFactory->create();
3943
$resultPage->getConfig()->getTitle()->set(__('Checkout'));
4044
return $resultPage;
4145
}
46+
47+
/**
48+
* Checks if current request uses SSL and referer also is secure.
49+
*
50+
* @return bool
51+
*/
52+
private function isSecureRequest(): bool
53+
{
54+
$request = $this->getRequest();
55+
56+
$referrer = $request->getHeader('referer');
57+
$secure = false;
58+
59+
if ($referrer) {
60+
$scheme = parse_url($referrer, PHP_URL_SCHEME);
61+
$secure = $scheme === 'https';
62+
}
63+
64+
return $secure && $request->isSecure();
65+
}
4266
}

app/code/Magento/Checkout/Test/Unit/Controller/Index/IndexTest.php

Lines changed: 123 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
11
<?php
22
/**
3-
* Test for \Magento\Checkout\Controller\Index\Index
4-
*
53
* Copyright © Magento, Inc. All rights reserved.
64
* See COPYING.txt for license details.
75
*/
6+
declare(strict_types=1);
87

98
namespace Magento\Checkout\Test\Unit\Controller\Index;
109

11-
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManager;
10+
use Magento\Customer\Model\Session;
11+
use Magento\Framework\App\Request\Http;
12+
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
13+
use PHPUnit_Framework_MockObject_Builder_InvocationMocker as InvocationMocker;
14+
use PHPUnit_Framework_MockObject_Matcher_InvokedCount as InvokedCount;
15+
use PHPUnit_Framework_MockObject_MockObject as MockObject;
16+
use Magento\Checkout\Helper\Data;
17+
use Magento\Quote\Model\Quote;
18+
use Magento\Framework\View\Result\Page;
19+
use Magento\Checkout\Controller\Index\Index;
20+
use Magento\Framework\ObjectManagerInterface;
1221

1322
/**
1423
* @SuppressWarnings(PHPMD.TooManyFields)
@@ -17,108 +26,111 @@
1726
class IndexTest extends \PHPUnit\Framework\TestCase
1827
{
1928
/**
20-
* @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager
29+
* @var ObjectManager
2130
*/
2231
private $objectManager;
2332

2433
/**
25-
* @var \PHPUnit_Framework_MockObject_MockObject
34+
* @var MockObject
2635
*/
2736
private $objectManagerMock;
2837

2938
/**
30-
* @var \PHPUnit_Framework_MockObject_MockObject
39+
* @var Data|MockObject
3140
*/
32-
private $dataMock;
41+
private $data;
3342

3443
/**
35-
* @var \PHPUnit_Framework_MockObject_MockObject
44+
* @var MockObject
3645
*/
37-
private $quoteMock;
46+
private $quote;
3847

3948
/**
40-
* @var \PHPUnit_Framework_MockObject_MockObject
49+
* @var MockObject
4150
*/
4251
private $contextMock;
4352

4453
/**
45-
* @var \PHPUnit_Framework_MockObject_MockObject
54+
* @var Session|MockObject
4655
*/
47-
private $sessionMock;
56+
private $session;
4857

4958
/**
50-
* @var \PHPUnit_Framework_MockObject_MockObject
59+
* @var MockObject
5160
*/
5261
private $onepageMock;
5362

5463
/**
55-
* @var \PHPUnit_Framework_MockObject_MockObject
64+
* @var MockObject
5665
*/
5766
private $layoutMock;
5867

5968
/**
60-
* @var \PHPUnit_Framework_MockObject_MockObject
69+
* @var Http|MockObject
6170
*/
62-
private $requestMock;
71+
private $request;
6372

6473
/**
65-
* @var \PHPUnit_Framework_MockObject_MockObject
74+
* @var MockObject
6675
*/
6776
private $responseMock;
6877

6978
/**
70-
* @var \PHPUnit_Framework_MockObject_MockObject
79+
* @var MockObject
7180
*/
7281
private $redirectMock;
7382

7483
/**
75-
* @var \Magento\Checkout\Controller\Index\Index
84+
* @var Index
7685
*/
7786
private $model;
7887

7988
/**
80-
* @var \Magento\Framework\View\Result\Page|\PHPUnit_Framework_MockObject_MockObject
89+
* @var Page|MockObject
8190
*/
82-
protected $resultPageMock;
91+
private $resultPage;
8392

8493
/**
8594
* @var \Magento\Framework\View\Page\Config
8695
*/
87-
protected $pageConfigMock;
96+
private $pageConfigMock;
8897

8998
/**
9099
* @var \Magento\Framework\View\Page\Title
91100
*/
92-
protected $titleMock;
101+
private $titleMock;
93102

94103
/**
95104
* @var \Magento\Framework\UrlInterface
96105
*/
97-
protected $url;
106+
private $url;
98107

99108
/**
100-
* @var \Magento\Framework\Controller\Result\Redirect|\PHPUnit_Framework_MockObject_MockObject
109+
* @var \Magento\Framework\Controller\Result\Redirect|MockObject
101110
*/
102-
protected $resultRedirectMock;
111+
private $resultRedirectMock;
103112

104113
protected function setUp()
105114
{
106115
// mock objects
107116
$this->objectManager = new ObjectManager($this);
108-
$this->objectManagerMock = $this->basicMock(\Magento\Framework\ObjectManagerInterface::class);
109-
$this->dataMock = $this->basicMock(\Magento\Checkout\Helper\Data::class);
110-
$this->quoteMock = $this->createPartialMock(
111-
\Magento\Quote\Model\Quote::class,
117+
$this->objectManagerMock = $this->basicMock(ObjectManagerInterface::class);
118+
$this->data = $this->basicMock(Data::class);
119+
$this->quote = $this->createPartialMock(
120+
Quote::class,
112121
['getHasError', 'hasItems', 'validateMinimumAmount', 'hasError']
113122
);
114123
$this->contextMock = $this->basicMock(\Magento\Framework\App\Action\Context::class);
115-
$this->sessionMock = $this->basicMock(\Magento\Customer\Model\Session::class);
124+
$this->session = $this->basicMock(Session::class);
116125
$this->onepageMock = $this->basicMock(\Magento\Checkout\Model\Type\Onepage::class);
117126
$this->layoutMock = $this->basicMock(\Magento\Framework\View\Layout::class);
118-
$this->requestMock = $this->basicMock(\Magento\Framework\App\RequestInterface::class);
127+
$this->request = $this->getMockBuilder(Http::class)
128+
->disableOriginalConstructor()
129+
->setMethods(['isSecure', 'getHeader'])
130+
->getMock();
119131
$this->responseMock = $this->basicMock(\Magento\Framework\App\ResponseInterface::class);
120132
$this->redirectMock = $this->basicMock(\Magento\Framework\App\Response\RedirectInterface::class);
121-
$this->resultPageMock = $this->basicMock(\Magento\Framework\View\Result\Page::class);
133+
$this->resultPage = $this->basicMock(Page::class);
122134
$this->pageConfigMock = $this->basicMock(\Magento\Framework\View\Page\Config::class);
123135
$this->titleMock = $this->basicMock(\Magento\Framework\View\Page\Title::class);
124136
$this->url = $this->createMock(\Magento\Framework\UrlInterface::class);
@@ -130,7 +142,7 @@ protected function setUp()
130142
->getMock();
131143
$resultPageFactoryMock->expects($this->any())
132144
->method('create')
133-
->willReturn($this->resultPageMock);
145+
->willReturn($this->resultPage);
134146

135147
$resultRedirectFactoryMock = $this->getMockBuilder(\Magento\Framework\Controller\Result\RedirectFactory::class)
136148
->disableOriginalConstructor()
@@ -141,21 +153,21 @@ protected function setUp()
141153
->willReturn($this->resultRedirectMock);
142154

143155
// stubs
144-
$this->basicStub($this->onepageMock, 'getQuote')->willReturn($this->quoteMock);
145-
$this->basicStub($this->resultPageMock, 'getLayout')->willReturn($this->layoutMock);
156+
$this->basicStub($this->onepageMock, 'getQuote')->willReturn($this->quote);
157+
$this->basicStub($this->resultPage, 'getLayout')->willReturn($this->layoutMock);
146158

147159
$this->basicStub($this->layoutMock, 'getBlock')
148160
->willReturn($this->basicMock(\Magento\Theme\Block\Html\Header::class));
149-
$this->basicStub($this->resultPageMock, 'getConfig')->willReturn($this->pageConfigMock);
161+
$this->basicStub($this->resultPage, 'getConfig')->willReturn($this->pageConfigMock);
150162
$this->basicStub($this->pageConfigMock, 'getTitle')->willReturn($this->titleMock);
151163
$this->basicStub($this->titleMock, 'set')->willReturn($this->titleMock);
152164

153165
// objectManagerMock
154166
$objectManagerReturns = [
155-
[\Magento\Checkout\Helper\Data::class, $this->dataMock],
167+
[Data::class, $this->data],
156168
[\Magento\Checkout\Model\Type\Onepage::class, $this->onepageMock],
157169
[\Magento\Checkout\Model\Session::class, $this->basicMock(\Magento\Checkout\Model\Session::class)],
158-
[\Magento\Customer\Model\Session::class, $this->basicMock(\Magento\Customer\Model\Session::class)],
170+
[Session::class, $this->basicMock(Session::class)],
159171

160172
];
161173
$this->objectManagerMock->expects($this->any())
@@ -165,7 +177,7 @@ protected function setUp()
165177
->willReturn($this->basicMock(\Magento\Framework\UrlInterface::class));
166178
// context stubs
167179
$this->basicStub($this->contextMock, 'getObjectManager')->willReturn($this->objectManagerMock);
168-
$this->basicStub($this->contextMock, 'getRequest')->willReturn($this->requestMock);
180+
$this->basicStub($this->contextMock, 'getRequest')->willReturn($this->request);
169181
$this->basicStub($this->contextMock, 'getResponse')->willReturn($this->responseMock);
170182
$this->basicStub($this->contextMock, 'getMessageManager')
171183
->willReturn($this->basicMock(\Magento\Framework\Message\ManagerInterface::class));
@@ -175,33 +187,82 @@ protected function setUp()
175187

176188
// SUT
177189
$this->model = $this->objectManager->getObject(
178-
\Magento\Checkout\Controller\Index\Index::class,
190+
Index::class,
179191
[
180192
'context' => $this->contextMock,
181-
'customerSession' => $this->sessionMock,
193+
'customerSession' => $this->session,
182194
'resultPageFactory' => $resultPageFactoryMock,
183195
'resultRedirectFactory' => $resultRedirectFactoryMock
184196
]
185197
);
186198
}
187199

188-
public function testRegenerateSessionIdOnExecute()
200+
/**
201+
* Checks a case when session should be or not regenerated during the request.
202+
*
203+
* @param bool $secure
204+
* @param string $referer
205+
* @param InvokedCount $expectedCall
206+
* @dataProvider sessionRegenerationDataProvider
207+
*/
208+
public function testRegenerateSessionIdOnExecute(bool $secure, string $referer, InvokedCount $expectedCall)
209+
{
210+
$this->data->method('canOnepageCheckout')
211+
->willReturn(true);
212+
$this->quote->method('hasItems')
213+
->willReturn(true);
214+
$this->quote->method('getHasError')
215+
->willReturn(false);
216+
$this->quote->method('validateMinimumAmount')
217+
->willReturn(true);
218+
$this->session->method('isLoggedIn')
219+
->willReturn(true);
220+
$this->request->method('isSecure')
221+
->willReturn($secure);
222+
$this->request->method('getHeader')
223+
->with('referer')
224+
->willReturn($referer);
225+
226+
$this->session->expects($expectedCall)
227+
->method('regenerateId');
228+
$this->assertSame($this->resultPage, $this->model->execute());
229+
}
230+
231+
/**
232+
* Gets list of variations for generating new session.
233+
*
234+
* @return array
235+
*/
236+
public function sessionRegenerationDataProvider(): array
189237
{
190-
//Stubs to control execution flow
191-
$this->basicStub($this->dataMock, 'canOnepageCheckout')->willReturn(true);
192-
$this->basicStub($this->quoteMock, 'hasItems')->willReturn(true);
193-
$this->basicStub($this->quoteMock, 'getHasError')->willReturn(false);
194-
$this->basicStub($this->quoteMock, 'validateMinimumAmount')->willReturn(true);
195-
$this->basicStub($this->sessionMock, 'isLoggedIn')->willReturn(true);
196-
197-
//Expected outcomes
198-
$this->sessionMock->expects($this->once())->method('regenerateId');
199-
$this->assertSame($this->resultPageMock, $this->model->execute());
238+
return [
239+
[
240+
'secure' => false,
241+
'referer' => 'https://test.domain.com/',
242+
'expectedCall' => self::once()
243+
],
244+
[
245+
'secure' => true,
246+
'referer' => false,
247+
'expectedCall' => self::once()
248+
],
249+
[
250+
'secure' => true,
251+
'referer' => 'http://test.domain.com/',
252+
'expectedCall' => self::once()
253+
],
254+
// This is the only case in which session regeneration can be skipped
255+
[
256+
'secure' => true,
257+
'referer' => 'https://test.domain.com/',
258+
'expectedCall' => self::never()
259+
],
260+
];
200261
}
201262

202263
public function testOnepageCheckoutNotAvailable()
203264
{
204-
$this->basicStub($this->dataMock, 'canOnepageCheckout')->willReturn(false);
265+
$this->basicStub($this->data, 'canOnepageCheckout')->willReturn(false);
205266
$expectedPath = 'checkout/cart';
206267

207268
$this->resultRedirectMock->expects($this->once())
@@ -214,7 +275,7 @@ public function testOnepageCheckoutNotAvailable()
214275

215276
public function testInvalidQuote()
216277
{
217-
$this->basicStub($this->quoteMock, 'hasError')->willReturn(true);
278+
$this->basicStub($this->quote, 'hasError')->willReturn(true);
218279

219280
$expectedPath = 'checkout/cart';
220281
$this->resultRedirectMock->expects($this->once())
@@ -226,23 +287,22 @@ public function testInvalidQuote()
226287
}
227288

228289
/**
229-
* @param \PHPUnit_Framework_MockObject_MockObject $mock
290+
* @param MockObject $mock
230291
* @param string $method
231292
*
232-
* @return \PHPUnit\Framework\MockObject_Builder_InvocationMocker
293+
* @return InvocationMocker
233294
*/
234-
private function basicStub($mock, $method)
295+
private function basicStub($mock, $method): InvocationMocker
235296
{
236-
return $mock->expects($this->any())
237-
->method($method)
238-
->withAnyParameters();
297+
return $mock->method($method)
298+
->withAnyParameters();
239299
}
240300

241301
/**
242302
* @param string $className
243-
* @return \PHPUnit_Framework_MockObject_MockObject
303+
* @return MockObject
244304
*/
245-
private function basicMock($className)
305+
private function basicMock(string $className): MockObject
246306
{
247307
return $this->getMockBuilder($className)
248308
->disableOriginalConstructor()

0 commit comments

Comments
 (0)