Skip to content

Commit bf1e137

Browse files
authored
Merge pull request #7749 from magento-cia/cia-2.4.6-bugfixes-06262022
Cia-2.4.6-develop-bugfixes-06262022
2 parents b2bfd05 + 5d0de1e commit bf1e137

File tree

4 files changed

+182
-16
lines changed

4 files changed

+182
-16
lines changed
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Customer\Model\Plugin;
9+
10+
use Magento\Customer\Model\Session;
11+
use Magento\Framework\App\Area;
12+
use Magento\Framework\App\State;
13+
use Magento\Framework\Session\SaveHandlerInterface;
14+
use Magento\Framework\Session\StorageInterface;
15+
use Magento\Framework\Exception\SessionException;
16+
use Psr\Log\LoggerInterface;
17+
use Magento\Framework\Exception\LocalizedException;
18+
19+
/**
20+
* Clears previous active sessions after logout
21+
*
22+
* @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
23+
*/
24+
class ClearSessionsAfterLogoutPlugin
25+
{
26+
/**
27+
* Array key for all active previous session ids.
28+
*/
29+
private const PREVIOUS_ACTIVE_SESSIONS = 'previous_active_sessions';
30+
31+
/**
32+
* @var Session
33+
*/
34+
private Session $session;
35+
36+
/**
37+
* @var SaveHandlerInterface
38+
*/
39+
private SaveHandlerInterface $saveHandler;
40+
41+
/**
42+
* @var StorageInterface
43+
*/
44+
private StorageInterface $storage;
45+
46+
/**
47+
* @var State
48+
*/
49+
private State $state;
50+
51+
/**
52+
* @var LoggerInterface
53+
*/
54+
private LoggerInterface $logger;
55+
56+
/**
57+
* Initialize Dependencies
58+
*
59+
* @param Session $customerSession
60+
* @param SaveHandlerInterface $saveHandler
61+
* @param StorageInterface $storage
62+
* @param State $state
63+
* @param LoggerInterface $logger
64+
*/
65+
public function __construct(
66+
Session $customerSession,
67+
SaveHandlerInterface $saveHandler,
68+
StorageInterface $storage,
69+
State $state,
70+
LoggerInterface $logger
71+
) {
72+
$this->session = $customerSession;
73+
$this->saveHandler = $saveHandler;
74+
$this->storage = $storage;
75+
$this->state = $state;
76+
$this->logger = $logger;
77+
}
78+
79+
/**
80+
* Plugin to clear session after logout
81+
*
82+
* @param Session $subject
83+
* @param Session $result
84+
* @return Session
85+
* @throws LocalizedException
86+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
87+
*/
88+
public function afterLogout(Session $subject, Session $result): Session
89+
{
90+
$isAreaFrontEnd = $this->state->getAreaCode() === Area::AREA_FRONTEND;
91+
$previousSessions = $this->storage->getData(self::PREVIOUS_ACTIVE_SESSIONS);
92+
93+
if ($isAreaFrontEnd && !empty($previousSessions)) {
94+
foreach ($previousSessions as $sessionId) {
95+
try {
96+
$this->session->start();
97+
$this->saveHandler->destroy($sessionId);
98+
$this->session->writeClose();
99+
} catch (SessionException $e) {
100+
$this->logger->error($e);
101+
}
102+
103+
}
104+
$this->storage->setData(self::PREVIOUS_ACTIVE_SESSIONS, []);
105+
}
106+
return $result;
107+
}
108+
}

app/code/Magento/Customer/Model/Plugin/CustomerNotification.php

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
declare(strict_types=1);
67

78
namespace Magento\Customer\Model\Plugin;
89

@@ -16,13 +17,21 @@
1617
use Magento\Framework\App\RequestInterface;
1718
use Magento\Framework\App\State;
1819
use Magento\Framework\Exception\NoSuchEntityException;
20+
use Magento\Framework\Session\StorageInterface;
1921
use Psr\Log\LoggerInterface;
2022

2123
/**
2224
* Refresh the Customer session if `UpdateSession` notification registered
25+
*
26+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
2327
*/
2428
class CustomerNotification
2529
{
30+
/**
31+
* Array key for all active previous session ids.
32+
*/
33+
private const PREVIOUS_ACTIVE_SESSIONS = 'previous_active_sessions';
34+
2635
/**
2736
* @var Session
2837
*/
@@ -53,6 +62,11 @@ class CustomerNotification
5362
*/
5463
private $request;
5564

65+
/**
66+
* @var StorageInterface
67+
*/
68+
private StorageInterface $storage;
69+
5670
/**
5771
* Initialize dependencies.
5872
*
@@ -61,22 +75,25 @@ class CustomerNotification
6175
* @param State $state
6276
* @param CustomerRepositoryInterface $customerRepository
6377
* @param LoggerInterface $logger
64-
* @param RequestInterface|null $request
78+
* @param RequestInterface $request
79+
* @param StorageInterface|null $storage
6580
*/
6681
public function __construct(
6782
Session $session,
6883
NotificationStorage $notificationStorage,
6984
State $state,
7085
CustomerRepositoryInterface $customerRepository,
7186
LoggerInterface $logger,
72-
RequestInterface $request
87+
RequestInterface $request,
88+
StorageInterface $storage = null
7389
) {
7490
$this->session = $session;
7591
$this->notificationStorage = $notificationStorage;
7692
$this->state = $state;
7793
$this->customerRepository = $customerRepository;
7894
$this->logger = $logger;
7995
$this->request = $request;
96+
$this->storage = $storage ?? ObjectManager::getInstance()->get(StorageInterface::class);
8097
}
8198

8299
/**
@@ -89,18 +106,33 @@ public function __construct(
89106
*/
90107
public function beforeExecute(ActionInterface $subject)
91108
{
92-
$customerId = $this->session->getCustomerId();
93-
94-
if ($this->isFrontendRequest() && $this->isPostRequest() && $this->isSessionUpdateRegisteredFor($customerId)) {
95-
try {
96-
$this->session->regenerateId();
97-
$customer = $this->customerRepository->getById($customerId);
98-
$this->session->setCustomerData($customer);
99-
$this->session->setCustomerGroupId($customer->getGroupId());
100-
$this->notificationStorage->remove(NotificationStorage::UPDATE_CUSTOMER_SESSION, $customer->getId());
101-
} catch (NoSuchEntityException $e) {
102-
$this->logger->error($e);
109+
$customerId = (int)$this->session->getCustomerId();
110+
111+
if (!$this->isFrontendRequest()
112+
|| !$this->isPostRequest()
113+
|| !$this->isSessionUpdateRegisteredFor($customerId)) {
114+
return;
115+
}
116+
117+
try {
118+
$oldSessionId = $this->session->getSessionId();
119+
$previousSessions = $this->storage->getData(self::PREVIOUS_ACTIVE_SESSIONS);
120+
121+
if (empty($previousSessions)) {
122+
$previousSessions = [];
103123
}
124+
$previousSessions[] = $oldSessionId;
125+
$this->storage->setData(self::PREVIOUS_ACTIVE_SESSIONS, $previousSessions);
126+
$this->session->regenerateId();
127+
$customer = $this->customerRepository->getById($customerId);
128+
$this->session->setCustomerData($customer);
129+
$this->session->setCustomerGroupId($customer->getGroupId());
130+
$this->notificationStorage->remove(
131+
NotificationStorage::UPDATE_CUSTOMER_SESSION,
132+
$customer->getId()
133+
);
134+
} catch (NoSuchEntityException $e) {
135+
$this->logger->error($e);
104136
}
105137
}
106138

@@ -131,8 +163,8 @@ private function isFrontendRequest(): bool
131163
* @param int $customerId
132164
* @return bool
133165
*/
134-
private function isSessionUpdateRegisteredFor($customerId): bool
166+
private function isSessionUpdateRegisteredFor(int $customerId): bool
135167
{
136-
return $this->notificationStorage->isExists(NotificationStorage::UPDATE_CUSTOMER_SESSION, $customerId);
168+
return (bool)$this->notificationStorage->isExists(NotificationStorage::UPDATE_CUSTOMER_SESSION, $customerId);
137169
}
138170
}

app/code/Magento/Customer/Test/Unit/Model/Plugin/CustomerNotificationTest.php

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,13 @@
2020
use PHPUnit\Framework\MockObject\MockObject;
2121
use PHPUnit\Framework\TestCase;
2222
use Psr\Log\LoggerInterface;
23+
use Magento\Framework\Session\StorageInterface;
2324

25+
/**
26+
* Unit test for CustomerNotification plugin
27+
*
28+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
29+
*/
2430
class CustomerNotificationTest extends TestCase
2531
{
2632
private const STUB_CUSTOMER_ID = 1;
@@ -65,6 +71,11 @@ class CustomerNotificationTest extends TestCase
6571
*/
6672
private $plugin;
6773

74+
/**
75+
* @var StorageInterface|MockObject
76+
*/
77+
private $storage;
78+
6879
protected function setUp(): void
6980
{
7081
$this->sessionMock = $this->createMock(Session::class);
@@ -87,19 +98,27 @@ protected function setUp(): void
8798
->with(NotificationStorage::UPDATE_CUSTOMER_SESSION, self::STUB_CUSTOMER_ID)
8899
->willReturn(true);
89100

101+
$this->storage = $this
102+
->getMockBuilder(StorageInterface::class)
103+
->addMethods(['getData', 'setData'])
104+
->disableOriginalConstructor()
105+
->getMockForAbstractClass();
106+
90107
$this->plugin = new CustomerNotification(
91108
$this->sessionMock,
92109
$this->notificationStorageMock,
93110
$this->appStateMock,
94111
$this->customerRepositoryMock,
95112
$this->loggerMock,
96-
$this->requestMock
113+
$this->requestMock,
114+
$this->storage
97115
);
98116
}
99117

100118
public function testBeforeExecute()
101119
{
102120
$customerGroupId = 1;
121+
$testSessionId = [uniqid()];
103122

104123
$customerMock = $this->getMockForAbstractClass(CustomerInterface::class);
105124
$customerMock->method('getGroupId')->willReturn($customerGroupId);
@@ -116,6 +135,10 @@ public function testBeforeExecute()
116135
$this->sessionMock->expects($this->once())->method('setCustomerData')->with($customerMock);
117136
$this->sessionMock->expects($this->once())->method('setCustomerGroupId')->with($customerGroupId);
118137
$this->sessionMock->expects($this->once())->method('regenerateId');
138+
$this->storage->expects($this->once())->method('getData')->willReturn($testSessionId);
139+
$this->storage
140+
->expects($this->once())
141+
->method('setData');
119142

120143
$this->plugin->beforeExecute($this->actionMock);
121144
}

app/code/Magento/Customer/etc/frontend/di.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,4 +127,7 @@
127127
</argument>
128128
</arguments>
129129
</type>
130+
<type name="Magento\Customer\Model\Session">
131+
<plugin name="afterLogout" type="Magento\Customer\Model\Plugin\ClearSessionsAfterLogoutPlugin"/>
132+
</type>
130133
</config>

0 commit comments

Comments
 (0)