Skip to content

Commit 2f74114

Browse files
authored
Merge pull request #37 from magento-gl/Arrows_IMS_17Mar23
Adobe IMS Phase 2 Security Fixes
2 parents 75e4cc4 + 3d9406f commit 2f74114

File tree

23 files changed

+1061
-81
lines changed

23 files changed

+1061
-81
lines changed

AdminAdobeIms/Controller/Adminhtml/OAuth/ImsCallback.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
use Magento\Backend\Controller\Adminhtml\Auth;
1717
use Magento\Backend\Model\View\Result\Redirect;
1818
use Magento\Framework\App\Action\HttpGetActionInterface;
19+
use Magento\Framework\App\ActionInterface;
20+
use Magento\Framework\App\RequestInterface;
21+
use Magento\Framework\App\ResponseInterface;
1922

2023
/**
2124
* Callback for handling redirect from Adobe IMS
@@ -57,6 +60,28 @@ public function __construct(
5760
$this->userContext = $userContext;
5861
}
5962

63+
/**
64+
* Validate IMS state is valid
65+
*
66+
* @param RequestInterface $request
67+
* @return ResponseInterface
68+
*/
69+
public function dispatch(RequestInterface $request)
70+
{
71+
$request->setParam('form_key', $request->getParam('state', null));
72+
if (!$this->_formKeyValidator->validate($request)) {
73+
$this->logger->critical(__('Invalid state returned in callback from IMS.'));
74+
$this->imsErrorMessage(
75+
'Error signing in',
76+
'Something went wrong and we could not sign you in. ' .
77+
'Please try again or contact your administrator.'
78+
);
79+
$this->_actionFlag->set('', ActionInterface::FLAG_NO_DISPATCH, true);
80+
return $this->_redirect($this->_helper->getHomePageUrl());
81+
}
82+
return parent::dispatch($request);
83+
}
84+
6085
/**
6186
* Execute AdobeIMS callback
6287
*

AdminAdobeIms/Controller/Adminhtml/OAuth/ImsReauthCallback.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414
use Magento\Backend\App\Action\Context;
1515
use Magento\Backend\Controller\Adminhtml\Auth;
1616
use Magento\Framework\App\Action\HttpGetActionInterface;
17+
use Magento\Framework\App\RequestInterface;
1718
use Magento\Framework\Controller\Result\Raw;
1819
use Magento\Framework\Controller\ResultFactory;
1920
use Magento\Framework\Controller\ResultInterface;
21+
use Magento\Framework\Exception\NotFoundException;
2022

2123
class ImsReauthCallback extends Auth implements HttpGetActionInterface
2224
{
@@ -91,6 +93,7 @@ public function execute(): ResultInterface
9193
}
9294

9395
try {
96+
$this->validateStateKey($this->getRequest());
9497
$this->adminTokenUserService->processLoginRequest(true);
9598

9699
$response = sprintf(
@@ -112,4 +115,19 @@ public function execute(): ResultInterface
112115

113116
return $resultRaw;
114117
}
118+
119+
/**
120+
* Validate IMS state is valid
121+
*
122+
* @param RequestInterface $request
123+
* @return void
124+
* @throws NotFoundException
125+
*/
126+
private function validateStateKey(RequestInterface $request): void
127+
{
128+
$request->setParam('form_key', $request->getParam('state', null));
129+
if (!$this->_formKeyValidator->validate($request)) {
130+
throw new NotFoundException(__('Invalid state returned from IMS'));
131+
}
132+
}
115133
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
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\AdminAdobeIms\Plugin;
9+
10+
use Magento\AdminAdobeIms\Service\ImsConfig;
11+
use Magento\Backend\Block\Widget\Form as WidgetForm;
12+
use Magento\Framework\Data\Form as DataForm;
13+
14+
/**
15+
* Plugin Class used to change the user form field to readonly for IMS users
16+
*/
17+
class UpdateUserFormFieldsPlugin
18+
{
19+
/**
20+
* @var ImsConfig
21+
*/
22+
private ImsConfig $adminImsConfig;
23+
24+
/**
25+
* @var array
26+
*/
27+
private array $fieldsToReadonly = [
28+
'email',
29+
'username',
30+
'firstname',
31+
'lastname'
32+
];
33+
34+
/**
35+
* @param ImsConfig $adminImsConfig
36+
*/
37+
public function __construct(ImsConfig $adminImsConfig)
38+
{
39+
$this->adminImsConfig = $adminImsConfig;
40+
}
41+
42+
/**
43+
* Update fields to readonly if adobe ims is enabled
44+
*
45+
* @param WidgetForm $subject
46+
* @param DataForm $result
47+
* @return DataForm
48+
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
49+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
50+
* @SuppressWarnings(PHPMD.NPathComplexity)
51+
*/
52+
public function afterGetForm(WidgetForm $subject, DataForm $result): DataForm
53+
{
54+
if ($this->adminImsConfig->enabled() === false) {
55+
return $result;
56+
}
57+
58+
if ($result->getElement('base_fieldset')) {
59+
$disableLocaleField = false;
60+
foreach ($result->getElement('base_fieldset')->getElements() as $element) {
61+
if (in_array($element->getId(), $this->fieldsToReadonly, true) && $element->getValue()) {
62+
$disableLocaleField = true;
63+
$element->setData('readonly', true);
64+
}
65+
if ($element->getId() === 'interface_locale' && $disableLocaleField) {
66+
$element->setData('readonly', true);
67+
}
68+
}
69+
}
70+
return $result;
71+
}
72+
}

AdminAdobeIms/Plugin/UserSavePlugin.php

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99

1010
use Exception;
1111
use Magento\AdminAdobeIms\Service\ImsConfig;
12+
use Magento\User\Model\ResourceModel\User as UserResourceModel;
1213
use Magento\User\Model\User;
14+
use Magento\User\Model\UserFactory;
1315

1416
class UserSavePlugin
1517
{
@@ -18,18 +20,35 @@ class UserSavePlugin
1820
*/
1921
private ImsConfig $adminImsConfig;
2022

23+
/**
24+
* @var UserFactory
25+
*/
26+
private UserFactory $userFactory;
27+
28+
/**
29+
* @var UserResourceModel
30+
*/
31+
private UserResourceModel $userResource;
32+
2133
/**
2234
* @param ImsConfig $adminImsConfig
35+
* @param UserFactory $userFactory
36+
* @param UserResourceModel $userResource
2337
*/
2438
public function __construct(
25-
ImsConfig $adminImsConfig
39+
ImsConfig $adminImsConfig,
40+
UserFactory $userFactory,
41+
UserResourceModel $userResource
2642
) {
2743
$this->adminImsConfig = $adminImsConfig;
44+
$this->userFactory = $userFactory;
45+
$this->userResource = $userResource;
2846
}
2947

3048
/**
3149
* Generate a random password for new user when AdminAdobeIMS Module is enabled
3250
*
51+
* And revert firstname, lastname, username, email, and InterfaceLocale to original for saved user.
3352
* We create a random password for the user, because User Object needs to have a password
3453
* and this way we do not need to update the db_schema or add a lot of complex preferences
3554
*
@@ -46,10 +65,31 @@ public function beforeBeforeSave(User $subject): array
4665
if (!$subject->getId()) {
4766
$subject->setPassword($this->generateRandomPassword());
4867
}
68+
$this->revertReadonlyFieldsData($subject);
4969

5070
return [];
5171
}
5272

73+
/**
74+
* Revert fields to original state because these fields are readonly for IMS User
75+
*
76+
* @param User $subject
77+
* @return void
78+
*/
79+
private function revertReadonlyFieldsData(User $subject): void
80+
{
81+
if ($subject->hasDataChanges() && $subject->getId()) {
82+
$savedUser = $this->userFactory->create();
83+
$this->userResource->load($savedUser, $subject->getId());
84+
85+
$subject->setUserName($savedUser->getUserName());
86+
$subject->setEmail($savedUser->getEmail());
87+
$subject->setFirstName($savedUser->getFirstName());
88+
$subject->setLastName($savedUser->getLastName());
89+
$subject->setInterfaceLocale($savedUser->getInterfaceLocale());
90+
}
91+
}
92+
5393
/**
5494
* Generate random password string
5595
*
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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\AdminAdobeIms\Plugin;
9+
10+
use Magento\AdminAdobeIms\Logger\AdminAdobeImsLogger;
11+
use Magento\AdobeImsApi\Api\IsTokenValidInterface;
12+
use Magento\Backend\Model\Auth;
13+
14+
/**
15+
* Validate ims access token
16+
*/
17+
class ValidateAccessTokenPlugin
18+
{
19+
/**
20+
* @var AdminAdobeImsLogger
21+
*/
22+
private AdminAdobeImsLogger $logger;
23+
24+
/**
25+
* @var IsTokenValidInterface
26+
*/
27+
private IsTokenValidInterface $isTokenValid;
28+
29+
/**
30+
* @param IsTokenValidInterface $isTokenValid
31+
* @param AdminAdobeImsLogger $logger
32+
*/
33+
public function __construct(
34+
IsTokenValidInterface $isTokenValid,
35+
AdminAdobeImsLogger $logger
36+
) {
37+
$this->isTokenValid = $isTokenValid;
38+
$this->logger = $logger;
39+
}
40+
41+
/**
42+
* Check if IMS access token is still valid
43+
*
44+
* @param Auth $subject
45+
* @param bool $result
46+
* @return bool
47+
* @throws \Magento\Framework\Exception\AuthorizationException
48+
*/
49+
public function afterIsLoggedIn(Auth $subject, bool $result): bool
50+
{
51+
$accessToken = $subject->getAuthStorage()->getAdobeAccessToken();
52+
if ($result && $accessToken) {
53+
if (!$this->isTokenValid->validateToken($accessToken)) {
54+
$subject->logout();
55+
$this->logger->error('Admin Access Token is not valid');
56+
return false;
57+
}
58+
}
59+
return $result;
60+
}
61+
}

0 commit comments

Comments
 (0)