Skip to content

Commit cbdf43d

Browse files
authored
ENGCOM-3918: aclResource for UIComponent buttons #20408
2 parents 0b19831 + 0dc85b0 commit cbdf43d

File tree

4 files changed

+98
-3
lines changed

4 files changed

+98
-3
lines changed

app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_grid.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
<url path="sales/order_create/start"/>
1818
<class>primary</class>
1919
<label translate="true">Create New Order</label>
20+
<aclResource>Magento_Sales::create</aclResource>
2021
</button>
2122
</buttons>
2223
<spinner>sales_order_columns</spinner>

app/code/Magento/Ui/view/base/ui_component/etc/definition/ui_settings.xsd

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,13 @@
476476
</xs:documentation>
477477
</xs:annotation>
478478
</xs:element>
479+
<xs:element name="aclResource" type="xs:string" minOccurs="0" maxOccurs="1">
480+
<xs:annotation>
481+
<xs:documentation>
482+
ACL Resource used to validate access to UI Component data
483+
</xs:documentation>
484+
</xs:annotation>
485+
</xs:element>
479486
<xs:element ref="param"/>
480487
</xs:choice>
481488
<xs:attribute name="name" type="xs:string" use="required">

lib/internal/Magento/Framework/View/Element/UiComponent/Context.php

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
*/
66
namespace Magento\Framework\View\Element\UiComponent;
77

8+
use Magento\Framework\App\ObjectManager;
89
use Magento\Framework\App\RequestInterface;
10+
use Magento\Framework\AuthorizationInterface;
911
use Magento\Framework\UrlInterface;
1012
use Magento\Framework\View\Element\UiComponent\ContentType\ContentTypeFactory;
1113
use Magento\Framework\View\Element\UiComponent\Control\ActionPoolFactory;
@@ -94,6 +96,11 @@ class Context implements ContextInterface
9496
*/
9597
protected $uiComponentFactory;
9698

99+
/**
100+
* @var AuthorizationInterface
101+
*/
102+
private $authorization;
103+
97104
/**
98105
* @param PageLayoutInterface $pageLayout
99106
* @param RequestInterface $request
@@ -104,7 +111,8 @@ class Context implements ContextInterface
104111
* @param Processor $processor
105112
* @param UiComponentFactory $uiComponentFactory
106113
* @param DataProviderInterface|null $dataProvider
107-
* @param string|null $namespace
114+
* @param string $namespace
115+
* @param AuthorizationInterface|null $authorization
108116
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
109117
*/
110118
public function __construct(
@@ -117,7 +125,8 @@ public function __construct(
117125
Processor $processor,
118126
UiComponentFactory $uiComponentFactory,
119127
DataProviderInterface $dataProvider = null,
120-
$namespace = null
128+
$namespace = null,
129+
AuthorizationInterface $authorization = null
121130
) {
122131
$this->namespace = $namespace;
123132
$this->request = $request;
@@ -129,6 +138,9 @@ public function __construct(
129138
$this->urlBuilder = $urlBuilder;
130139
$this->processor = $processor;
131140
$this->uiComponentFactory = $uiComponentFactory;
141+
$this->authorization = $authorization ?: ObjectManager::getInstance()->get(
142+
AuthorizationInterface::class
143+
);
132144
$this->setAcceptType();
133145
}
134146

@@ -280,6 +292,9 @@ public function addButtons(array $buttons, UiComponentInterface $component)
280292
uasort($buttons, [$this, 'sortButtons']);
281293

282294
foreach ($buttons as $buttonId => $buttonData) {
295+
if (isset($buttonData['aclResource']) && !$this->authorization->isAllowed($buttonData['aclResource'])) {
296+
continue;
297+
}
283298
if (isset($buttonData['url'])) {
284299
$buttonData['url'] = $this->getUrl($buttonData['url']);
285300
}

lib/internal/Magento/Framework/View/Test/Unit/Element/UiComponent/ContextTest.php

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,28 @@
1111

1212
use Magento\Framework\View\Element\UiComponent\Context;
1313
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
14+
use Magento\Framework\View\Element\UiComponent\Control\ActionPoolInterface;
1415

16+
/**
17+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
18+
*/
1519
class ContextTest extends \PHPUnit\Framework\TestCase
1620
{
1721
/**
1822
* @var Context
1923
*/
2024
protected $context;
2125

26+
/**
27+
* @var ActionPoolInterface
28+
*/
29+
private $actionPool;
30+
31+
/**
32+
* @var \Magento\Framework\AuthorizationInterface
33+
*/
34+
private $authorization;
35+
2236
protected function setUp()
2337
{
2438
$pageLayout = $this->getMockBuilder(\Magento\Framework\View\LayoutInterface::class)->getMock();
@@ -33,6 +47,10 @@ protected function setUp()
3347
$this->getMockBuilder(\Magento\Framework\View\Element\UiComponent\Control\ActionPoolFactory::class)
3448
->disableOriginalConstructor()
3549
->getMock();
50+
$this->actionPool = $this->getMockBuilder(ActionPoolInterface::class)
51+
->disableOriginalConstructor()
52+
->getMock();
53+
$actionPoolFactory->method('create')->willReturn($this->actionPool);
3654
$contentTypeFactory =
3755
$this->getMockBuilder(\Magento\Framework\View\Element\UiComponent\ContentType\ContentTypeFactory::class)
3856
->disableOriginalConstructor()
@@ -43,6 +61,9 @@ protected function setUp()
4361
$this->getMockBuilder(\Magento\Framework\View\Element\UiComponentFactory::class)
4462
->disableOriginalConstructor()
4563
->getMock();
64+
$this->authorization = $this->getMockBuilder(\Magento\Framework\AuthorizationInterface::class)
65+
->disableOriginalConstructor()
66+
->getMock();
4667

4768
$objectManagerHelper = new ObjectManagerHelper($this);
4869
$this->context = $objectManagerHelper->getObject(
@@ -55,11 +76,62 @@ protected function setUp()
5576
'contentTypeFactory' => $contentTypeFactory,
5677
'urlBuilder' => $urlBuilder,
5778
'processor' => $processor,
58-
'uiComponentFactory' => $uiComponentFactory
79+
'uiComponentFactory' => $uiComponentFactory,
80+
'authorization' => $this->authorization,
5981
]
6082
);
6183
}
6284

85+
public function testAddButtonWithoutAclResource()
86+
{
87+
$component = $this->getMockBuilder(\Magento\Framework\View\Element\UiComponentInterface::class)
88+
->disableOriginalConstructor()
89+
->getMock();
90+
91+
$this->actionPool->expects($this->once())->method('add');
92+
$this->authorization->expects($this->never())->method('isAllowed');
93+
94+
$this->context->addButtons([
95+
'button_1' => [
96+
'name' => 'button_1',
97+
],
98+
], $component);
99+
}
100+
101+
public function testAddButtonWithAclResourceAllowed()
102+
{
103+
$component = $this->getMockBuilder(\Magento\Framework\View\Element\UiComponentInterface::class)
104+
->disableOriginalConstructor()
105+
->getMock();
106+
107+
$this->actionPool->expects($this->once())->method('add');
108+
$this->authorization->expects($this->once())->method('isAllowed')->willReturn(true);
109+
110+
$this->context->addButtons([
111+
'button_1' => [
112+
'name' => 'button_1',
113+
'aclResource' => 'Magento_Framwork::acl',
114+
],
115+
], $component);
116+
}
117+
118+
public function testAddButtonWithAclResourceDenied()
119+
{
120+
$component = $this->getMockBuilder(\Magento\Framework\View\Element\UiComponentInterface::class)
121+
->disableOriginalConstructor()
122+
->getMock();
123+
124+
$this->actionPool->expects($this->never())->method('add');
125+
$this->authorization->expects($this->once())->method('isAllowed')->willReturn(false);
126+
127+
$this->context->addButtons([
128+
'button_1' => [
129+
'name' => 'button_1',
130+
'aclResource' => 'Magento_Framwork::acl',
131+
],
132+
], $component);
133+
}
134+
63135
/**
64136
* @dataProvider addComponentDefinitionDataProvider
65137
* @param array $components

0 commit comments

Comments
 (0)