Skip to content

Commit ae8b347

Browse files
committed
MAGETWO-95365: Update Magento\Ui\Controller\Adminhtml\Index\Render\Handle controller
1 parent 991d785 commit ae8b347

File tree

4 files changed

+192
-12
lines changed

4 files changed

+192
-12
lines changed

app/code/Magento/Ui/Controller/Adminhtml/Index/Render/Handle.php

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,33 +9,87 @@
99
use Magento\Ui\Component\Control\ActionPool;
1010
use Magento\Ui\Component\Wrapper\UiComponent;
1111
use Magento\Ui\Controller\Adminhtml\AbstractAction;
12+
use Magento\Backend\App\Action\Context;
13+
use Magento\Framework\View\Element\UiComponentFactory;
14+
use Magento\Framework\View\Element\UiComponent\ContextFactory;
15+
use Magento\Framework\App\ObjectManager;
1216

1317
/**
1418
* Class Handle
1519
*/
1620
class Handle extends AbstractAction
1721
{
22+
/**
23+
* @var ContextFactory
24+
*/
25+
private $contextFactory;
26+
27+
/**
28+
* @param Context $context
29+
* @param UiComponentFactory $factory
30+
* @param ContextFactory|null $contextFactory
31+
*/
32+
public function __construct(
33+
Context $context,
34+
UiComponentFactory $factory,
35+
ContextFactory $contextFactory = null
36+
) {
37+
parent::__construct($context, $factory);
38+
$this->contextFactory = $contextFactory
39+
?: ObjectManager::getInstance()->get(ContextFactory::class);
40+
}
41+
1842
/**
1943
* Render UI component by namespace in handle context
2044
*
2145
* @return void
2246
*/
2347
public function execute()
2448
{
49+
$response = '';
2550
$handle = $this->_request->getParam('handle');
2651
$namespace = $this->_request->getParam('namespace');
2752
$buttons = $this->_request->getParam('buttons', false);
28-
2953
$this->_view->loadLayout(['default', $handle], true, true, false);
54+
$layout = $this->_view->getLayout();
55+
$context = $this->contextFactory->create(
56+
[
57+
'namespace' => $namespace,
58+
'pageLayout' => $layout
59+
]
60+
);
3061

31-
$uiComponent = $this->_view->getLayout()->getBlock($namespace);
32-
$response = $uiComponent instanceof UiComponent ? $uiComponent->toHtml() : '';
62+
$component = $this->factory->create($namespace, null, ['context' => $context]);
63+
if ($this->validateAclResource($component->getContext()->getDataProvider()->getConfigData())) {
64+
$uiComponent = $layout->getBlock($namespace);
65+
$response = $uiComponent instanceof UiComponent ? $uiComponent->toHtml() : '';
66+
}
3367

3468
if ($buttons) {
35-
$actionsToolbar = $this->_view->getLayout()->getBlock(ActionPool::ACTIONS_PAGE_TOOLBAR);
69+
$actionsToolbar = $layout->getBlock(ActionPool::ACTIONS_PAGE_TOOLBAR);
3670
$response .= $actionsToolbar instanceof Template ? $actionsToolbar->toHtml() : '';
3771
}
3872

3973
$this->_response->appendBody($response);
4074
}
75+
76+
/**
77+
* Optionally validate ACL resource of components with a DataSource/DataProvider
78+
*
79+
* @param mixed $dataProviderConfigData
80+
* @return bool
81+
*/
82+
private function validateAclResource($dataProviderConfigData)
83+
{
84+
if (isset($dataProviderConfigData['aclResource'])
85+
&& !$this->_authorization->isAllowed($dataProviderConfigData['aclResource'])
86+
) {
87+
if (!$this->_request->isAjax()) {
88+
$this->_redirect('admin/denied');
89+
}
90+
return false;
91+
}
92+
93+
return true;
94+
}
4195
}

app/code/Magento/Ui/Test/Unit/Controller/Adminhtml/Index/Render/HandleTest.php

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
namespace Magento\Ui\Test\Unit\Controller\Adminhtml\Index\Render;
77

88
use Magento\Ui\Controller\Adminhtml\Index\Render\Handle;
9+
use Magento\Framework\View\Element\UiComponent\ContextInterface;
910

1011
class HandleTest extends \PHPUnit\Framework\TestCase
1112
{
@@ -27,22 +28,42 @@ class HandleTest extends \PHPUnit\Framework\TestCase
2728
/**
2829
* @var \PHPUnit_Framework_MockObject_MockObject
2930
*/
30-
protected $componentFactoryMock;
31+
protected $viewMock;
32+
33+
/**
34+
* @var Handle
35+
*/
36+
protected $controller;
37+
38+
/**
39+
* @var \Magento\Framework\AuthorizationInterface|\PHPUnit_Framework_MockObject_MockObject
40+
*/
41+
private $authorizationMock;
3142

3243
/**
3344
* @var \PHPUnit_Framework_MockObject_MockObject
3445
*/
35-
protected $viewMock;
46+
private $uiComponentContextMock;
3647

3748
/**
38-
* @var Handle
49+
* @var \Magento\Framework\View\Element\UiComponentInterface|\PHPUnit_Framework_MockObject_MockObject
3950
*/
40-
protected $controller;
51+
private $uiComponentMock;
52+
53+
/**
54+
* @var \PHPUnit_Framework_MockObject_MockObject
55+
*/
56+
private $uiFactoryMock;
57+
58+
/**
59+
* @var \Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface|
60+
* \PHPUnit_Framework_MockObject_MockObject
61+
*/
62+
private $dataProviderMock;
4163

4264
public function setUp()
4365
{
4466
$this->contextMock = $this->createMock(\Magento\Backend\App\Action\Context::class);
45-
$this->componentFactoryMock = $this->createMock(\Magento\Framework\View\Element\UiComponentFactory::class);
4667

4768
$this->requestMock = $this->createMock(\Magento\Framework\App\RequestInterface::class);
4869
$this->contextMock->expects($this->atLeastOnce())->method('getRequest')->willReturn($this->requestMock);
@@ -52,8 +73,34 @@ public function setUp()
5273

5374
$this->viewMock = $this->createMock(\Magento\Framework\App\ViewInterface::class);
5475
$this->contextMock->expects($this->atLeastOnce())->method('getView')->willReturn($this->viewMock);
55-
56-
$this->controller = new Handle($this->contextMock, $this->componentFactoryMock);
76+
$this->authorizationMock = $this->getMockForAbstractClass(\Magento\Framework\AuthorizationInterface::class);
77+
$this->authorizationMock->expects($this->any())
78+
->method('isAllowed')
79+
->willReturn(true);
80+
$this->uiComponentContextMock = $this->getMockForAbstractClass(ContextInterface::class);
81+
$this->uiComponentMock = $this->getMockForAbstractClass(
82+
\Magento\Framework\View\Element\UiComponentInterface::class
83+
);
84+
$this->dataProviderMock = $this->getMockForAbstractClass(
85+
\Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface::class
86+
);
87+
$this->uiComponentContextMock->expects($this->once())
88+
->method('getDataProvider')
89+
->willReturn($this->dataProviderMock);
90+
$this->uiFactoryMock = $this->getMockBuilder(\Magento\Framework\View\Element\UiComponentFactory::class)
91+
->disableOriginalConstructor()
92+
->getMock();
93+
$this->uiComponentMock->expects($this->any())
94+
->method('getContext')
95+
->willReturn($this->uiComponentContextMock);
96+
$this->uiFactoryMock->expects($this->any())
97+
->method('create')
98+
->willReturn($this->uiComponentMock);
99+
$this->dataProviderMock->expects($this->once())
100+
->method('getConfigData')
101+
->willReturn([]);
102+
$contextMock = $this->createMock(\Magento\Framework\View\Element\UiComponent\ContextFactory::class);
103+
$this->controller = new Handle($this->contextMock, $this->uiFactoryMock, $contextMock);
57104
}
58105

59106
public function testExecuteNoButtons()
@@ -83,7 +130,7 @@ public function testExecute()
83130
->with(['default', $result], true, true, false);
84131

85132
$layoutMock = $this->createMock(\Magento\Framework\View\LayoutInterface::class);
86-
$this->viewMock->expects($this->exactly(2))->method('getLayout')->willReturn($layoutMock);
133+
$this->viewMock->expects($this->once())->method('getLayout')->willReturn($layoutMock);
87134

88135
$layoutMock->expects($this->exactly(2))->method('getBlock');
89136

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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\Ui\Controller\Adminhtml\Index\Renderer;
9+
10+
use Magento\TestFramework\Helper\Bootstrap;
11+
use Magento\Framework\AuthorizationInterface;
12+
13+
/**
14+
* @magentoAppArea adminhtml
15+
*/
16+
class HandleTest extends \Magento\TestFramework\TestCase\AbstractBackendController
17+
{
18+
/**
19+
* @magentoDataFixture Magento/Customer/_files/customer.php
20+
*/
21+
public function testExecuteWhenUserDoesNotHavePermission()
22+
{
23+
Bootstrap::getObjectManager()->configure([
24+
'preferences' => [
25+
AuthorizationInterface::class => \Magento\Ui\Model\AuthorizationMock::class,
26+
]
27+
]);
28+
$this->getRequest()->setParam('handle', 'customer_index_index');
29+
$this->getRequest()->setParam('namespace', 'customer_listing');
30+
$this->getRequest()->setParam('sorting%5Bfield%5D', 'entity_id');
31+
$this->getRequest()->setParam('paging%5BpageSize%5D', 20);
32+
$this->getRequest()->setParam('isAjax', 1);
33+
$this->dispatch('backend/mui/index/render_handle');
34+
$output = $this->getResponse()->getBody();
35+
$this->assertEmpty($output, 'The acl restriction wasn\'t applied properly');
36+
}
37+
38+
/**
39+
* @magentoDataFixture Magento/Customer/_files/customer.php
40+
*/
41+
public function testExecuteWhenUserHasPermission()
42+
{
43+
$this->getRequest()->setParam('handle', 'customer_index_index');
44+
$this->getRequest()->setParam('namespace', 'customer_listing');
45+
$this->getRequest()->setParam('sorting%5Bfield%5D', 'entity_id');
46+
$this->getRequest()->setParam('paging%5BpageSize%5D', 20);
47+
$this->getRequest()->setParam('isAjax', 1);
48+
$this->dispatch('backend/mui/index/render_handle');
49+
$output = $this->getResponse()->getBody();
50+
$this->assertNotEmpty($output, 'The acl restriction wasn\'t applied properly');
51+
}
52+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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\Ui\Model;
9+
10+
/**
11+
* Check current user permission on resource and privilege.
12+
*/
13+
class AuthorizationMock extends \Magento\Framework\Authorization
14+
{
15+
/**
16+
* Check current user permission on resource and privilege
17+
*
18+
* @param string $resource
19+
* @param string $privilege
20+
* @return boolean
21+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
22+
*/
23+
public function isAllowed($resource, $privilege = null)
24+
{
25+
return $resource !== 'Magento_Customer::manage';
26+
}
27+
}

0 commit comments

Comments
 (0)