api-platform / api-platform/core
[Security] Document is persisted before voters result on securityPostDenormalize
- 主要言語
- PHP
- スター
- 2.6k
- フォーク
- 980
- 平均マージ
- 2日 4時間
- マージ済み PR(30日)
- 49
説明
**API Platform version(s) affected**: 4.3.5
**Description**
When a resource is behind a voter on Patch operation and custom logic is called with a Voter using `securityPostDenormalize`, the incoming document is still persisted and therefore is written in the database if a flush comes after.
AgentRole.php
```php
#[ApiResource(operations: [
new Patch(
securityPostDenormalize: "is_granted('ROLE_UPDATE', object)",
extraProperties: ['throw_on_access_denied' => true],
),
])]
```
AgentRoleVoter.php
```php
protected function supports(string $attribute, mixed $subject): bool
{
$supportAttributes = $attribute == 'ROLE_UPDATE';
$supportSubject = $subject instanceof AgentRole;
return $supportAttributes && $supportSubject;
}
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
{
// some false logic
}
```
AgentRoleTest.php
```php
use ResetDatabase;
public function testChangeAgentRoleToDev()
{
$client = static::createClientWithCredentials();
$dm = $this->getContainer()->get(DocumentManager::class);
$agentRoles = AgentRoleFactory::createSequence([
['agentId' => '1', 'roles' => ['ROLE_USER']],
['agentId' => '2', 'roles' => ['ROLE_USER']]
]);
$client->request('PATCH', '/agent_roles/1', [
'headers' => ['Content-Type' => 'application/merge-patch+json'],
'json' => [
'roles' => ['ROLE_USER', 'ROLE_DEV']
]
]);
$this->assertResponseStatusCodeSame(403); // OK
// I would need to use $dm->clear() to flush previous operation without persisting
// $dm->clear();
$currentUserRole = $dm->getRepository(AgentRole::class)->findOneBy([
'agentId' => 'user' // current logged user
]);
$currentUserRole->setRoles(['ROLE_ADMIN']);
$dm->persist($currentUserRole);
$dm->flush(); // <-------- this persist also the request operation which wasn't persisted on request execution
}
```
Before flush:
After:
コントリビューションガイド
調査の方向性
Start with the securityPostDenormalize processing and the AgentRoleTest.php reproduction, then trace how the DocumentManager handles the denied PATCH object. Run the shown test scenario and verify that a later flush does not persist changes from the failed request while still persisting the explicitly changed current-user role.
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- php
- 領域
- authorization, databases
- issue の種類
- バグ
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 活発さ
- 静か
- 明瞭さ
- おおむね明確
- 初心者へのやさしさ
- 52/100