Skip to content

Commit c1b046b

Browse files
committed
MC-41013: Prevent errors from incorrect configurations
1 parent c71ea49 commit c1b046b

File tree

3 files changed

+66
-17
lines changed

3 files changed

+66
-17
lines changed

app/etc/di.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,9 @@
698698
<item name="0" xsi:type="string">Magento\Framework\Data\OptionSourceInterface</item>
699699
<item name="1" xsi:type="string">Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface</item>
700700
</argument>
701+
<argument name="deniedClassList" xsi:type="array">
702+
<item name="0" xsi:type="string">Magento\Framework\Model\ResourceModel\AbstractResource</item>
703+
</argument>
701704
</arguments>
702705
</type>
703706
<type name="Magento\Framework\Mview\View">

lib/internal/Magento/Framework/View/Element/UiComponent/Argument/Interpreter/ConfigurableObject.php

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ class ConfigurableObject implements InterpreterInterface
2424
*/
2525
private $classWhitelist = [];
2626

27+
/**
28+
* @var array
29+
*/
30+
private $deniedClassList = [];
31+
2732
/**
2833
* @var ObjectManagerInterface
2934
*/
@@ -52,17 +57,20 @@ class ConfigurableObject implements InterpreterInterface
5257
* @param array $classWhitelist
5358
* @param ClassReader|null $classReader
5459
* @param ConfigInterface|null $objectManagerConfig
60+
* @param array $deniedClassList
5561
*/
5662
public function __construct(
5763
ObjectManagerInterface $objectManager,
5864
InterpreterInterface $argumentInterpreter,
5965
array $classWhitelist = [],
6066
ClassReader $classReader = null,
61-
ConfigInterface $objectManagerConfig = null
67+
ConfigInterface $objectManagerConfig = null,
68+
array $deniedClassList = []
6269
) {
6370
$this->objectManager = $objectManager;
6471
$this->argumentInterpreter = $argumentInterpreter;
6572
$this->classWhitelist = $classWhitelist;
73+
$this->deniedClassList = $deniedClassList;
6674
$this->classReader = $classReader ?? $objectManager->get(ClassReader::class);
6775
$this->objectManagerConfig = $objectManagerConfig ?? $objectManager->get(ConfigInterface::class);
6876
}
@@ -85,25 +93,12 @@ public function evaluate(array $data)
8593
if (!isset($arguments['class'])) {
8694
throw new \InvalidArgumentException('Node "argument" with name "class" is required for this type.');
8795
}
88-
8996
$className = $arguments['class'];
9097
unset($arguments['class']);
91-
92-
$type = $this->objectManagerConfig->getInstanceType(
93-
$this->objectManagerConfig->getPreference($className)
94-
);
95-
96-
$classParents = $this->getParents($type);
97-
98-
$whitelistIntersection = array_intersect($classParents, $this->classWhitelist);
99-
100-
if (empty($whitelistIntersection)) {
101-
throw new \InvalidArgumentException(
102-
sprintf('Class argument is invalid: %s', $className)
103-
);
104-
}
10598
}
10699

100+
$this->isValid($className);
101+
107102
return $this->objectManager->create($className, $arguments);
108103
}
109104

@@ -115,7 +110,7 @@ public function evaluate(array $data)
115110
*/
116111
private function getParents(string $type)
117112
{
118-
$classParents = $this->classReader->getParents($type);
113+
$classParents = $this->classReader->getParents($type) ?? [];
119114
foreach ($classParents as $parent) {
120115
if (empty($parent)) {
121116
continue;
@@ -125,4 +120,30 @@ private function getParents(string $type)
125120

126121
return $classParents;
127122
}
123+
124+
/**
125+
* Check that provided class could be evaluated like an argument.
126+
*
127+
* @param string $className
128+
* @throws \InvalidArgumentException
129+
*/
130+
private function isValid(string $className): void
131+
{
132+
$type = $this->objectManagerConfig->getInstanceType(
133+
$this->objectManagerConfig->getPreference($className)
134+
);
135+
136+
$classParents = $this->getParents($type);
137+
138+
if (!empty($classParents)) {
139+
$whitelistIntersection = array_intersect($classParents, $this->classWhitelist);
140+
$deniedIntersection = array_intersect($classParents, $this->deniedClassList);
141+
142+
if (empty($whitelistIntersection) || !empty($deniedIntersection)) {
143+
throw new \InvalidArgumentException(
144+
sprintf('Class argument is invalid: %s', $className)
145+
);
146+
}
147+
}
148+
}
128149
}

lib/internal/Magento/Framework/View/Test/Unit/UiComponent/Argument/Interpreter/ConfigurableObjectTest.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ protected function setUp(): void
6565
],
6666
'classReader' => $this->classReader,
6767
'objectManagerConfig' => $this->objectManagerConfig,
68+
'deniedClassList' => [
69+
\Foo\Bar\ClassC::class,
70+
\Foo\Bar\InterfaceC::class,
71+
],
6872
]
6973
);
7074
}
@@ -268,6 +272,27 @@ public function invalidDataProvider()
268272
\InvalidArgumentException::class,
269273
'Class argument is invalid: MyFooClass'
270274
],
275+
[
276+
[
277+
'argument' => [
278+
'class' => ['value' => 'MyFooClass'],
279+
'myarg' => ['value' => 'bar'],
280+
],
281+
],
282+
'MyFooClass',
283+
[
284+
['MyFooClass', ['Something', 'skipme']],
285+
['Something', ['dontcare', 'SomethingElse']],
286+
['SomethingElse', [\Foo\Bar\ClassC::class, 'unrelated']],
287+
['skipme', []],
288+
['dontcare', []],
289+
['unrelated', [\Foo\Bar\InterfaceC::class]],
290+
[\Foo\Bar\ClassC::class, []],
291+
[\Foo\Bar\InterfaceC::class, []],
292+
],
293+
\InvalidArgumentException::class,
294+
'Class argument is invalid: MyFooClass',
295+
],
271296
];
272297
}
273298
}

0 commit comments

Comments
 (0)