Skip to content

Commit b3a1a45

Browse files
committed
Merge remote-tracking branch 'trigger/MAGETWO-95363' into 2.3.0-qwerty-bugs
2 parents 104a9f0 + f2960de commit b3a1a45

File tree

4 files changed

+199
-12
lines changed

4 files changed

+199
-12
lines changed

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

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,88 @@
1010
use Magento\Ui\Component\Control\ActionPool;
1111
use Magento\Ui\Component\Wrapper\UiComponent;
1212
use Magento\Ui\Controller\Adminhtml\AbstractAction;
13+
use Magento\Backend\App\Action\Context;
14+
use Magento\Framework\View\Element\UiComponentFactory;
15+
use Magento\Framework\View\Element\UiComponent\ContextFactory;
16+
use Magento\Framework\App\ObjectManager;
1317

1418
/**
1519
* Class Handle
20+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
1621
*/
1722
class Handle extends AbstractAction implements HttpGetActionInterface
1823
{
24+
/**
25+
* @var ContextFactory
26+
*/
27+
private $contextFactory;
28+
29+
/**
30+
* @param Context $context
31+
* @param UiComponentFactory $factory
32+
* @param ContextFactory|null $contextFactory
33+
*/
34+
public function __construct(
35+
Context $context,
36+
UiComponentFactory $factory,
37+
ContextFactory $contextFactory = null
38+
) {
39+
parent::__construct($context, $factory);
40+
$this->contextFactory = $contextFactory
41+
?: ObjectManager::getInstance()->get(ContextFactory::class);
42+
}
43+
1944
/**
2045
* Render UI component by namespace in handle context
2146
*
2247
* @return void
2348
*/
2449
public function execute()
2550
{
51+
$response = '';
2652
$handle = $this->_request->getParam('handle');
2753
$namespace = $this->_request->getParam('namespace');
2854
$buttons = $this->_request->getParam('buttons', false);
29-
3055
$this->_view->loadLayout(['default', $handle], true, true, false);
56+
$layout = $this->_view->getLayout();
57+
$context = $this->contextFactory->create(
58+
[
59+
'namespace' => $namespace,
60+
'pageLayout' => $layout
61+
]
62+
);
3163

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

3570
if ($buttons) {
36-
$actionsToolbar = $this->_view->getLayout()->getBlock(ActionPool::ACTIONS_PAGE_TOOLBAR);
71+
$actionsToolbar = $layout->getBlock(ActionPool::ACTIONS_PAGE_TOOLBAR);
3772
$response .= $actionsToolbar instanceof Template ? $actionsToolbar->toHtml() : '';
3873
}
3974

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

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

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@
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

11+
/**
12+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
13+
*/
1014
class HandleTest extends \PHPUnit\Framework\TestCase
1115
{
1216
/**
@@ -27,22 +31,42 @@ class HandleTest extends \PHPUnit\Framework\TestCase
2731
/**
2832
* @var \PHPUnit_Framework_MockObject_MockObject
2933
*/
30-
protected $componentFactoryMock;
34+
protected $viewMock;
35+
36+
/**
37+
* @var Handle
38+
*/
39+
protected $controller;
40+
41+
/**
42+
* @var \Magento\Framework\AuthorizationInterface|\PHPUnit_Framework_MockObject_MockObject
43+
*/
44+
private $authorizationMock;
3145

3246
/**
3347
* @var \PHPUnit_Framework_MockObject_MockObject
3448
*/
35-
protected $viewMock;
49+
private $uiComponentContextMock;
3650

3751
/**
38-
* @var Handle
52+
* @var \Magento\Framework\View\Element\UiComponentInterface|\PHPUnit_Framework_MockObject_MockObject
3953
*/
40-
protected $controller;
54+
private $uiComponentMock;
55+
56+
/**
57+
* @var \PHPUnit_Framework_MockObject_MockObject
58+
*/
59+
private $uiFactoryMock;
60+
61+
/**
62+
* @var \Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface|
63+
* \PHPUnit_Framework_MockObject_MockObject
64+
*/
65+
private $dataProviderMock;
4166

4267
public function setUp()
4368
{
4469
$this->contextMock = $this->createMock(\Magento\Backend\App\Action\Context::class);
45-
$this->componentFactoryMock = $this->createMock(\Magento\Framework\View\Element\UiComponentFactory::class);
4670

4771
$this->requestMock = $this->createMock(\Magento\Framework\App\RequestInterface::class);
4872
$this->contextMock->expects($this->atLeastOnce())->method('getRequest')->willReturn($this->requestMock);
@@ -52,8 +76,37 @@ public function setUp()
5276

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

59112
public function testExecuteNoButtons()
@@ -83,7 +136,7 @@ public function testExecute()
83136
->with(['default', $result], true, true, false);
84137

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

88141
$layoutMock->expects($this->exactly(2))->method('getBlock');
89142

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+
* Class AuthorizationMock
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)