Skip to content

Commit 978bd5b

Browse files
committed
fix: Allow admin component to define acl_resource for added security
1 parent f58d401 commit 978bd5b

5 files changed

Lines changed: 39 additions & 33 deletions

File tree

Controller/Adminhtml/Index/Html.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,20 +48,12 @@ public function __construct(
4848
private readonly ComponentRegistry $componentRegistry,
4949
private readonly MessageManager $messageManager,
5050
private readonly Validator $formKeyValidator,
51-
private readonly RequestInterface $request,
5251
private readonly AuthorizationInterface $authorization,
5352
) {
5453
}
5554

5655
public function execute(): ResultInterface|ResponseInterface
5756
{
58-
$aclResource = $this->request->getParam('acl_resource');
59-
if (!empty($aclResource) && !$this->authorization->isAllowed($aclResource)) {
60-
throw new AuthorizationException(
61-
__('Access denied.')
62-
);
63-
}
64-
6557
$data = $this->requestDataLoader->load();
6658
$this->requestDataLoader->mergeRequestParams();
6759
$layout = $this->layoutLoader->load($data['handles']);
@@ -70,6 +62,14 @@ public function execute(): ResultInterface|ResponseInterface
7062
$updates = $this->sortUpdates($updates);
7163

7264
foreach ($updates as $update) {
65+
if (isset($update['aclResource'])) {
66+
if (!empty($aclResource) && !$this->authorization->isAllowed($update['aclResource'])) {
67+
throw new AuthorizationException(
68+
__('Access denied.')
69+
);
70+
}
71+
}
72+
7373
try {
7474
$this->repositoryDispatcher->dispatch(
7575
$update['component'],

Util/ComponentUtil.php

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Magento\Framework\App\Request\Http;
66
use Magento\Framework\App\RequestInterface;
7+
use Magento\Framework\App\State;
78
use Magento\Framework\Data\Form\FormKey as FormKeyModel;
89
use Magento\Framework\UrlFactory;
910
use Magento\Framework\View\Element\AbstractBlock;
@@ -17,7 +18,8 @@ public function __construct(
1718
private readonly RequestInterface $request,
1819
private readonly FormKeyModel $formKey,
1920
private readonly IdConvertor $idConvertor,
20-
private readonly AjaxSignature $ajaxSignature
21+
private readonly AjaxSignature $ajaxSignature,
22+
private readonly State $appState
2123
) {
2224
}
2325

@@ -67,12 +69,19 @@ public function getRequestData(): array
6769
];
6870
}
6971

72+
public function getComponentUpdateData(AbstractBlock $block): array
73+
{
74+
return [
75+
'handles' => $this->getHandles($block),
76+
'pageHandles' => $this->getPageHandles($block),
77+
'request' => $this->getRequestData(),
78+
];
79+
}
80+
7081
public function getSignature(AbstractBlock $block): string
7182
{
7283
return $this->ajaxSignature->sign(
73-
$this->getHandles($block),
74-
$this->getPageHandles($block),
75-
$this->getRequestData()
84+
$this->getComponentUpdateData($block)
7685
);
7786
}
7887

Util/Controller/RequestDataLoader.php

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,13 @@ public function load(): array
3535

3636
private function validateSignature(array $data): void
3737
{
38-
$isValid = $this->ajaxSignature->verify(
39-
(array)($data['handles'] ?? []),
40-
(array)($data['pageHandles'] ?? []),
41-
(array)($data['request'] ?? []),
42-
(string)($data['signature'] ?? '')
43-
);
38+
$input = array_intersect_key($data, array_flip([
39+
'handles',
40+
'pageHandles',
41+
'request'
42+
]));
43+
44+
$isValid = $this->ajaxSignature->verify($input, (string)($data['signature'] ?? ''));
4445

4546
if (false === $isValid) {
4647
throw new RuntimeException('Payload was tampered with');

Util/Security/AjaxSignature.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,24 @@ public function __construct(
1111
) {
1212
}
1313

14-
public function sign(array $handles, array $pageHandles, array $request): string
14+
public function sign(array $data): string
1515
{
1616
return hash_hmac(
1717
'sha256',
18-
$this->buildPayload($handles, $pageHandles, $request),
18+
$this->buildPayload($data),
1919
$this->getCryptKey()
2020
);
2121
}
2222

23-
public function verify(array $handles, array $pageHandles, array $request, string $signature): bool
23+
public function verify(array $data, string $signature): bool
2424
{
25-
$expectedSignature = $this->sign($handles, $pageHandles, $request);
25+
$expectedSignature = $this->sign($data);
2626
return hash_equals($expectedSignature, $signature);
2727
}
2828

29-
private function buildPayload(array $handles, array $pageHandles, array $request): string
29+
private function buildPayload(array $data): string
3030
{
31-
return (string)json_encode([$handles, $pageHandles, $request], JSON_UNESCAPED_SLASHES);
31+
return (string)json_encode($data, JSON_UNESCAPED_SLASHES);
3232
}
3333

3434
private function getCryptKey(): string

view/base/templates/script/ajax-queue.phtml

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -169,18 +169,14 @@ if ($interval < 10) {
169169
};
170170
},
171171
buildBody(requests) {
172+
const componentData = JSON.parse('<?= /* @noEscape */ json_encode(
173+
$componentUtil->getComponentUpdateData($block)
174+
) ?>');
175+
172176
return {
177+
...componentData,
173178
updates: this.getUpdates(requests),
174179
targets: this.getTargets(requests),
175-
handles: <?= /* @noEscape */ json_encode(
176-
$componentUtil->getHandles($block)
177-
) ?>,
178-
pageHandles: <?= /* @noEscape */ json_encode(
179-
$componentUtil->getPageHandles($block)
180-
) ?>,
181-
request: <?= /* @noEscape */ json_encode(
182-
$componentUtil->getRequestData()
183-
) ?>,
184180
signature: <?= /* @noEscape */ json_encode(
185181
$componentUtil->getSignature($block)
186182
) ?>

0 commit comments

Comments
 (0)