Skip to content

Commit 776c14a

Browse files
Merge remote-tracking branch 'gl_adobe_ims/CABPI-515-phase2' into Arrows_IMS_17Mar23
2 parents 75e4cc4 + e8a32b7 commit 776c14a

File tree

10 files changed

+486
-31
lines changed

10 files changed

+486
-31
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
}

AdminAdobeIms/Service/ImsConfig.php

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,6 @@ class ImsConfig extends Config
1616
private const XML_PATH_LOGGING_ENABLED = 'adobe_ims/integration/logging_enabled';
1717
private const XML_PATH_NEW_ADMIN_EMAIL_TEMPLATE = 'adobe_ims/email/content_template';
1818

19-
/**
20-
* @var ScopeConfigInterface
21-
*/
22-
private ScopeConfigInterface $scopeConfig;
23-
24-
/**
25-
* @param ScopeConfigInterface $scopeConfig
26-
* @param UrlInterface $url
27-
*/
28-
public function __construct(
29-
ScopeConfigInterface $scopeConfig,
30-
UrlInterface $url
31-
) {
32-
parent::__construct($scopeConfig, $url);
33-
$this->scopeConfig = $scopeConfig;
34-
}
35-
3619
/**
3720
* Check if module is enabled
3821
*
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
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\Test\Unit\Controller\Adminhtml\OAuth;
9+
10+
use Magento\AdminAdobeIms\Controller\Adminhtml\OAuth\ImsCallback;
11+
use Magento\AdminAdobeIms\Logger\AdminAdobeImsLogger;
12+
use Magento\AdminAdobeIms\Service\ImsConfig;
13+
use Magento\Authorization\Model\UserContextInterface;
14+
use Magento\Backend\App\Action\Context;
15+
use Magento\Backend\Helper\Data;
16+
use Magento\Backend\Model\Auth\Session;
17+
use Magento\Framework\App\ActionFlag;
18+
use Magento\Framework\App\Request\Http;
19+
use Magento\Framework\App\RequestInterface;
20+
use Magento\Framework\Data\Form\FormKey\Validator;
21+
use Magento\Framework\Message\Manager;
22+
use Magento\Framework\ObjectManager\ObjectManager;
23+
use Magento\Framework\Validator\Locale;
24+
use PHPUnit\Framework\MockObject\MockObject;
25+
use PHPUnit\Framework\TestCase;
26+
27+
/**
28+
* Unit test for \Magento\AdminAdobeIms\Controller\Adminhtml\OAuth\ImsCallback controller.
29+
*
30+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
31+
*/
32+
class ImsCallbackTest extends TestCase
33+
{
34+
/**
35+
* @var Validator|mixed|MockObject
36+
*/
37+
private mixed $validatorMock;
38+
39+
/**
40+
* @var RequestInterface|mixed|MockObject
41+
*/
42+
private mixed $requestMock;
43+
44+
/**
45+
* @var AdminAdobeImsLogger|mixed|MockObject
46+
*/
47+
private mixed $loggerMock;
48+
49+
/**
50+
* @var Data|mixed|MockObject
51+
*/
52+
private mixed $helperMock;
53+
54+
/**
55+
* @var Manager|mixed|MockObject
56+
*/
57+
private mixed $messagesMock;
58+
59+
/**
60+
* @var mixed|ImsCallback
61+
*/
62+
private mixed $controller;
63+
64+
/**
65+
* @var Session|mixed|MockObject
66+
*/
67+
private mixed $authSessionMock;
68+
69+
/**
70+
* @var ActionFlag|mixed|MockObject
71+
*/
72+
private mixed $actionFlagMock;
73+
74+
/**
75+
* @var Session|mixed|MockObject
76+
*/
77+
private mixed $authMock;
78+
79+
/**
80+
* @var ObjectManager|mixed|MockObject
81+
*/
82+
private mixed $objectManagerMock;
83+
84+
/**
85+
* @var Locale|mixed|MockObject
86+
*/
87+
private mixed $localeMock;
88+
89+
/**
90+
* @var \Magento\Backend\Model\Locale\Manager|mixed|MockObject
91+
*/
92+
private mixed $managerMock;
93+
94+
/**
95+
* @inheritDoc
96+
*/
97+
protected function setUp(): void
98+
{
99+
$this->objectManagerMock = $this->getMockBuilder(ObjectManager::class)
100+
->disableOriginalConstructor()
101+
->onlyMethods(['get', 'create'])
102+
->getMock();
103+
$this->requestMock = $this->getMockBuilder(Http::class)
104+
->disableOriginalConstructor()
105+
->onlyMethods(['getParam', 'setParam'])
106+
->getMock();
107+
$responseMock = $this->getMockBuilder(\Magento\Framework\App\Response\Http::class)
108+
->disableOriginalConstructor()
109+
->addMethods([])
110+
->getMock();
111+
$this->validatorMock = $this->getMockBuilder(Validator::class)
112+
->disableOriginalConstructor()
113+
->getMock();
114+
$this->loggerMock = $this->getMockBuilder(AdminAdobeImsLogger::class)
115+
->disableOriginalConstructor()
116+
->getMock();
117+
$this->messagesMock = $this->getMockBuilder(Manager::class)
118+
->disableOriginalConstructor()
119+
->onlyMethods(['addComplexErrorMessage'])
120+
->getMockForAbstractClass();
121+
$this->authSessionMock = $this->getMockBuilder(Session::class)
122+
->disableOriginalConstructor()
123+
->addMethods(['setIsUrlNotice', 'getLocale'])
124+
->getMock();
125+
$this->authMock = $this->getMockBuilder(Session::class)
126+
->disableOriginalConstructor()
127+
->getMock();
128+
$this->actionFlagMock = $this->getMockBuilder(ActionFlag::class)
129+
->disableOriginalConstructor()
130+
->getMock();
131+
$this->localeMock = $this->getMockBuilder(Locale::class)
132+
->disableOriginalConstructor()
133+
->onlyMethods(['isValid'])
134+
->getMock();
135+
$this->managerMock = $this->getMockBuilder(\Magento\Backend\Model\Locale\Manager::class)
136+
->disableOriginalConstructor()
137+
->onlyMethods(['switchBackendInterfaceLocale'])
138+
->getMock();
139+
$this->helperMock = $this->getMockBuilder(Data::class)
140+
->disableOriginalConstructor()
141+
->onlyMethods(['getHomePageUrl', 'getUrl'])
142+
->getMock();
143+
$imsConfigMock = $this->getMockBuilder(ImsConfig::class)
144+
->disableOriginalConstructor()
145+
->getMock();
146+
$userContext = $this->getMockForAbstractClass(UserContextInterface::class);
147+
$contextMock = $this->getMockBuilder(Context::class)
148+
->addMethods(['getFrontController', 'getTranslator'])
149+
->onlyMethods([
150+
'getRequest',
151+
'getFormKeyValidator',
152+
'getMessageManager',
153+
'getHelper',
154+
'getActionFlag',
155+
'getResponse',
156+
'getSession',
157+
'getAuth',
158+
'getObjectManager'
159+
])
160+
->disableOriginalConstructor()
161+
->getMock();
162+
$contextMock->expects($this->once())->method('getObjectManager')->willReturn($this->objectManagerMock);
163+
$contextMock->expects($this->once())->method('getResponse')->willReturn($responseMock);
164+
$contextMock->expects($this->once())->method('getAuth')->willReturn($this->authMock);
165+
$contextMock->expects($this->once())->method('getRequest')->willReturn($this->requestMock);
166+
$contextMock->expects($this->once())->method('getFormKeyValidator')->willReturn($this->validatorMock);
167+
$contextMock->expects($this->once())->method('getActionFlag')->willReturn($this->actionFlagMock);
168+
$contextMock->expects($this->once())->method('getSession')->willReturn($this->authSessionMock);
169+
$contextMock->expects($this->once())->method('getHelper')->willReturn($this->helperMock);
170+
$contextMock->expects($this->once())->method('getMessageManager')->willReturn($this->messagesMock);
171+
172+
$this->controller = new ImsCallback(
173+
$contextMock,
174+
$imsConfigMock,
175+
$this->loggerMock,
176+
$userContext
177+
);
178+
}
179+
180+
/**
181+
* Validate if state exists in ims callback url.
182+
* @return void
183+
*/
184+
public function testStateExistsInImsCallback(): void
185+
{
186+
$this->addMockData();
187+
$this->validatorMock->expects($this->once())->method('validate')
188+
->with($this->requestMock)
189+
->willReturn(true);
190+
$response = $this->controller->dispatch($this->requestMock);
191+
$this->assertEquals(200, $response->getHttpResponseCode());
192+
}
193+
194+
/**
195+
* Validate if state not exists in ims callback url.
196+
* @return void
197+
*/
198+
public function testStateNotExistsInImsCallback(): void
199+
{
200+
$this->addMockData();
201+
$this->validatorMock->expects($this->once())->method('validate')
202+
->with($this->requestMock)
203+
->willReturn(false);
204+
$response = $this->controller->dispatch($this->requestMock);
205+
$this->assertEquals(302, $response->getHttpResponseCode());
206+
}
207+
208+
/**
209+
* Add mock data for tests
210+
* @return void
211+
*/
212+
private function addMockData(): void
213+
{
214+
$this->requestMock->expects($this->any())->method('setParam')
215+
->with('form_key')
216+
->willReturnSelf();
217+
$this->requestMock->expects($this->any())->method('getParam')
218+
->withConsecutive(['state'], ['locale'])
219+
->willReturnOnConsecutiveCalls('abc', 'en');
220+
$this->authSessionMock->expects($this->any())->method('setIsUrlNotice')
221+
->willReturnSelf();
222+
$this->authSessionMock->expects($this->any())->method('getLocale')
223+
->willReturn('en');
224+
$this->actionFlagMock->expects($this->any())->method('get')
225+
->with('', 'check_url_settings')
226+
->willReturn(true);
227+
$this->helperMock->expects($this->any())->method('getHomePageUrl')
228+
->willReturn('https://magento.test/admin');
229+
$this->helperMock->expects($this->any())->method('getUrl')
230+
->willReturn('https://magento.test/admin');
231+
$this->authMock->expects($this->any())->method('isLoggedIn')->willReturn(false);
232+
$this->objectManagerMock
233+
->method('get')
234+
->withConsecutive([Locale::class], [\Magento\Backend\Model\Locale\Manager::class])
235+
->willReturnOnConsecutiveCalls($this->localeMock, $this->managerMock);
236+
}
237+
}

0 commit comments

Comments
 (0)