Skip to content

Commit 0162222

Browse files
committed
AC-9803: Force sign-in session invalidated
1 parent 45cc4db commit 0162222

File tree

5 files changed

+239
-22
lines changed

5 files changed

+239
-22
lines changed

app/code/Magento/User/Block/User/Edit.php

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,20 @@
11
<?php
2-
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
2+
/************************************************************************
3+
*
4+
* Copyright 2025 Adobe
5+
* All Rights Reserved.
6+
*
7+
* NOTICE: All information contained herein is, and remains
8+
* the property of Adobe and its suppliers, if any. The intellectual
9+
* and technical concepts contained herein are proprietary to Adobe
10+
* and its suppliers and are protected by all applicable intellectual
11+
* property laws, including trade secret and copyright laws.
12+
* Dissemination of this information or reproduction of this material
13+
* is strictly forbidden unless prior written permission is obtained
14+
* from Adobe.
15+
* ************************************************************************
516
*/
17+
declare(strict_types=1);
618

719
namespace Magento\User\Block\User;
820

@@ -70,7 +82,7 @@ protected function _construct()
7082
'label' => __('Force Sign-In'),
7183
'class' => 'invalidate-token',
7284
'onclick' => "deleteConfirm('" . $this->escapeJs($this->escapeHtml($deleteConfirmMsg)) .
73-
"', '" . $this->getInvalidateUrl() . "')",
85+
"', '" . $this->getInvalidateUrl() . "', {data:{{$this->_objectId}:{$objId}}})",
7486
]
7587
);
7688
}
@@ -149,6 +161,6 @@ public function getValidationUrl()
149161
*/
150162
public function getInvalidateUrl()
151163
{
152-
return $this->getUrl('adminhtml/*/invalidatetoken', ['_current' => true]);
164+
return $this->getUrl('adminhtml/*/invalidatetoken');
153165
}
154166
}

app/code/Magento/User/Controller/Adminhtml/Auth/ResetPasswordPost.php

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,61 @@
11
<?php
2-
/**
2+
/************************************************************************
33
*
4-
* Copyright © Magento, Inc. All rights reserved.
5-
* See COPYING.txt for license details.
4+
* Copyright 2025 Adobe
5+
* All Rights Reserved.
6+
*
7+
* NOTICE: All information contained herein is, and remains
8+
* the property of Adobe and its suppliers, if any. The intellectual
9+
* and technical concepts contained herein are proprietary to Adobe
10+
* and its suppliers and are protected by all applicable intellectual
11+
* property laws, including trade secret and copyright laws.
12+
* Dissemination of this information or reproduction of this material
13+
* is strictly forbidden unless prior written permission is obtained
14+
* from Adobe.
15+
* ************************************************************************
616
*/
17+
declare(strict_types=1);
18+
719
namespace Magento\User\Controller\Adminhtml\Auth;
820

21+
use Magento\Framework\App\Action\HttpGetActionInterface;
22+
use Magento\Framework\App\Action\HttpPostActionInterface;
923
use Magento\User\Controller\Adminhtml\Auth;
1024
use Magento\Backend\App\Action\Context;
1125
use Magento\Framework\App\ObjectManager;
1226
use Magento\Backend\Helper\Data;
1327
use Magento\User\Model\UserFactory;
28+
use Magento\User\Helper\ForceSignIn;
1429

15-
class ResetPasswordPost extends Auth
30+
class ResetPasswordPost extends Auth implements HttpGetActionInterface, HttpPostActionInterface
1631
{
1732
/**
1833
* @var Data
1934
*/
2035
private $backendDataHelper;
2136

37+
/**
38+
* @var ForceSignIn
39+
*/
40+
private ForceSignIn $forceSignIn;
41+
2242
/**
2343
* @param Context $context
2444
* @param UserFactory $userFactory
25-
* @param Data $backendDataHelper
45+
* @param Data|null $backendDataHelper
46+
* @param ForceSignIn|null $forceSignIn
2647
*/
2748
public function __construct(
2849
Context $context,
2950
UserFactory $userFactory,
30-
Data $backendDataHelper = null
51+
Data $backendDataHelper = null,
52+
ForceSignIn $forceSignIn = null
3153
) {
3254
parent::__construct($context, $userFactory);
3355
$this->backendDataHelper = $backendDataHelper ?: ObjectManager::getInstance()->get(Data::class);
56+
$this->forceSignIn = $forceSignIn ?: ObjectManager::getInstance()->get(ForceSignIn::class);
3457
}
58+
3559
/**
3660
* Reset forgotten password
3761
*
@@ -75,6 +99,7 @@ public function execute()
7599
}
76100
} else {
77101
$user->save();
102+
$this->forceSignIn->updateAdminSessionStatus($userId);
78103
$this->messageManager->addSuccess(__('You updated your password.'));
79104
$this->getResponse()->setRedirect(
80105
$this->backendDataHelper->getHomePageUrl()

app/code/Magento/User/Controller/Adminhtml/User/InvalidateToken.php

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,80 @@
11
<?php
2-
/**
2+
/************************************************************************
3+
*
4+
* Copyright 2025 Adobe
5+
* All Rights Reserved.
36
*
4-
* Copyright © Magento, Inc. All rights reserved.
5-
* See COPYING.txt for license details.
7+
* NOTICE: All information contained herein is, and remains
8+
* the property of Adobe and its suppliers, if any. The intellectual
9+
* and technical concepts contained herein are proprietary to Adobe
10+
* and its suppliers and are protected by all applicable intellectual
11+
* property laws, including trade secret and copyright laws.
12+
* Dissemination of this information or reproduction of this material
13+
* is strictly forbidden unless prior written permission is obtained
14+
* from Adobe.
15+
* ************************************************************************
616
*/
17+
declare(strict_types=1);
718

819
namespace Magento\User\Controller\Adminhtml\User;
920

21+
use Magento\Backend\App\Action\Context;
22+
use Magento\Framework\App\Action\HttpGetActionInterface;
23+
use Magento\Framework\App\Action\HttpPostActionInterface;
24+
use Magento\Framework\App\ObjectManager;
25+
use Magento\Framework\Registry;
1026
use Magento\Integration\Api\AdminTokenServiceInterface;
27+
use Magento\User\Controller\Adminhtml\User;
28+
use Magento\User\Model\UserFactory;
29+
use Magento\User\Helper\ForceSignIn;
1130

1231
/**
1332
* Class InvalidateToken - used to invalidate/revoke all authentication tokens for a specific user.
1433
*/
15-
class InvalidateToken extends \Magento\User\Controller\Adminhtml\User
34+
class InvalidateToken extends User implements HttpGetActionInterface, HttpPostActionInterface
1635
{
1736
/**
1837
* @var AdminTokenServiceInterface
1938
*/
2039
protected $tokenService;
2140

41+
/**
42+
* @var ForceSignIn
43+
*/
44+
private ForceSignIn $forceSignIn;
45+
2246
/**
2347
* Inject dependencies.
2448
*
25-
* @param \Magento\Backend\App\Action\Context $context
26-
* @param \Magento\Framework\Registry $coreRegistry
27-
* @param \Magento\User\Model\UserFactory $userFactory
49+
* @param Context $context
50+
* @param Registry $coreRegistry
51+
* @param UserFactory $userFactory
2852
* @param AdminTokenServiceInterface $tokenService
53+
* @param ForceSignIn|null $forceSignIn
2954
*/
3055
public function __construct(
31-
\Magento\Backend\App\Action\Context $context,
32-
\Magento\Framework\Registry $coreRegistry,
33-
\Magento\User\Model\UserFactory $userFactory,
34-
AdminTokenServiceInterface $tokenService
56+
Context $context,
57+
Registry $coreRegistry,
58+
UserFactory $userFactory,
59+
AdminTokenServiceInterface $tokenService,
60+
ForceSignIn $forceSignIn = null
3561
) {
3662
parent::__construct($context, $coreRegistry, $userFactory);
3763
$this->tokenService = $tokenService;
64+
$this->forceSignIn = $forceSignIn ?: ObjectManager::getInstance()->get(ForceSignIn::class);
3865
}
3966

4067
/**
68+
* Revoke admin token
69+
*
4170
* @return void
4271
*/
4372
public function execute()
4473
{
4574
if ($userId = $this->getRequest()->getParam('user_id')) {
4675
try {
4776
$this->tokenService->revokeAdminAccessToken($userId);
77+
$this->forceSignIn->updateAdminSessionStatus($userId);
4878
$this->messageManager->addSuccess(__('You have revoked the user\'s tokens.'));
4979
$this->_redirect('adminhtml/*/edit', ['user_id' => $userId]);
5080
return;
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
/************************************************************************
3+
*
4+
* Copyright 2025 Adobe
5+
* All Rights Reserved.
6+
*
7+
* NOTICE: All information contained herein is, and remains
8+
* the property of Adobe and its suppliers, if any. The intellectual
9+
* and technical concepts contained herein are proprietary to Adobe
10+
* and its suppliers and are protected by all applicable intellectual
11+
* property laws, including trade secret and copyright laws.
12+
* Dissemination of this information or reproduction of this material
13+
* is strictly forbidden unless prior written permission is obtained
14+
* from Adobe.
15+
* ************************************************************************
16+
*/
17+
declare(strict_types=1);
18+
19+
namespace Magento\User\Helper;
20+
21+
use Magento\Framework\App\Helper\AbstractHelper;
22+
use Magento\Framework\App\Helper\Context;
23+
use Magento\Framework\Exception\LocalizedException;
24+
use Magento\Security\Model\ResourceModel\AdminSessionInfo;
25+
use Magento\Security\Model\AdminSessionInfo as AdminSessionInfoModel;
26+
27+
/**
28+
* Update admin user session status to logged out
29+
*/
30+
class ForceSignIn extends AbstractHelper
31+
{
32+
/**
33+
* @param Context $context
34+
* @param AdminSessionInfo $adminSessionInfo
35+
*/
36+
public function __construct(
37+
Context $context,
38+
private readonly AdminSessionInfo $adminSessionInfo
39+
) {
40+
parent::__construct($context);
41+
}
42+
43+
/**
44+
* Update admin_user_session status to logged out
45+
*
46+
* @param int $userId
47+
* @throws LocalizedException
48+
*/
49+
public function updateAdminSessionStatus($userId): void
50+
{
51+
try {
52+
$this->adminSessionInfo->updateStatusByUserId(
53+
AdminSessionInfoModel::LOGGED_OUT,
54+
$userId,
55+
[AdminSessionInfoModel::LOGGED_IN]
56+
);
57+
} catch (\Exception $e) {
58+
throw new LocalizedException(__($e->getMessage()));
59+
}
60+
}
61+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
/************************************************************************
3+
*
4+
* Copyright 2025 Adobe
5+
* All Rights Reserved.
6+
*
7+
* NOTICE: All information contained herein is, and remains
8+
* the property of Adobe and its suppliers, if any. The intellectual
9+
* and technical concepts contained herein are proprietary to Adobe
10+
* and its suppliers and are protected by all applicable intellectual
11+
* property laws, including trade secret and copyright laws.
12+
* Dissemination of this information or reproduction of this material
13+
* is strictly forbidden unless prior written permission is obtained
14+
* from Adobe.
15+
* ************************************************************************
16+
*/
17+
declare(strict_types=1);
18+
19+
namespace Magento\User\Test\Unit\Helper;
20+
21+
use Magento\Framework\Exception\LocalizedException;
22+
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
23+
use Magento\Security\Model\ResourceModel\AdminSessionInfo;
24+
use PHPUnit\Framework\TestCase;
25+
use Magento\User\Helper\ForceSignIn;
26+
27+
/**
28+
* Revoke user token
29+
*/
30+
class ForceSignInTest extends TestCase
31+
{
32+
/**
33+
* @var ForceSignIn
34+
*/
35+
private $forceSignIn;
36+
37+
/**
38+
* @var AdminSessionInfo
39+
*/
40+
private $adminSessionInfo;
41+
42+
/**
43+
* @return void
44+
*/
45+
public function setUp(): void
46+
{
47+
$this->adminSessionInfo = $this->getMockBuilder(AdminSessionInfo::class)
48+
->disableOriginalConstructor()
49+
->getMock();
50+
51+
$objectManager = new ObjectManager($this);
52+
$this->forceSignIn = $objectManager->getObject(
53+
ForceSignIn::class,
54+
[
55+
'adminSessionInfo' => $this->adminSessionInfo
56+
]
57+
);
58+
}
59+
60+
/**
61+
* Update admin session status
62+
*
63+
* @return void
64+
* @throws LocalizedException
65+
*/
66+
public function testUpdateAdminSessionStatus()
67+
{
68+
$this->adminSessionInfo->expects($this->any())
69+
->method('updateStatusByUserId')
70+
->with(0, 1, [1], [], null)
71+
->willReturnSelf();
72+
$this->forceSignIn->updateAdminSessionStatus(1);
73+
}
74+
75+
/**
76+
* Throw exception for admin session
77+
*
78+
* @throws LocalizedException
79+
*/
80+
public function testExceptionUpdateAdminSessionStatus()
81+
{
82+
$this->expectException(LocalizedException::class);
83+
$this->adminSessionInfo->expects($this->any())
84+
->method('updateStatusByUserId')
85+
->with(0, 1, [1], [], null)
86+
->willReturnSelf();
87+
$this->forceSignIn->updateAdminSessionStatus(0);
88+
}
89+
}

0 commit comments

Comments
 (0)