Skip to content

Commit a9c1b53

Browse files
authored
fix: clone Parameters before mutation in security and validator providers (#8378)
1 parent fe84af2 commit a9c1b53

3 files changed

Lines changed: 8 additions & 3 deletions

File tree

src/State/Provider/SecurityParameterProvider.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ public function provide(Operation $operation, array $uriVariables = [], array $c
5252

5353
$operation = $request?->attributes->get('_api_operation') ?? $operation;
5454

55-
$parameters = $operation->getParameters() ?? new Parameters();
55+
$existingParameters = $operation->getParameters();
56+
$parameters = $existingParameters ? clone $existingParameters : new Parameters();
5657

5758
if ($operation instanceof HttpOperation) {
5859
foreach ($operation->getUriVariables() ?? [] as $key => $uriVariable) {

src/State/Tests/Provider/SecurityParameterProviderTest.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
use ApiPlatform\Metadata\GetCollection;
1717
use ApiPlatform\Metadata\Link;
18+
use ApiPlatform\Metadata\Parameters;
1819
use ApiPlatform\Metadata\ResourceAccessCheckerInterface;
1920
use ApiPlatform\State\Provider\SecurityParameterProvider;
2021
use ApiPlatform\State\ProviderInterface;
@@ -28,16 +29,18 @@ public function testIsGrantedLink(): void
2829
{
2930
$obj = new \stdClass();
3031
$barObj = new \stdClass();
32+
$sharedParams = new Parameters();
3133
$operation = new GetCollection(uriVariables: [
3234
'barId' => new Link(toProperty: 'bar', fromClass: 'Bar', security: 'is_granted("some_voter", "bar")'),
33-
], class: \stdClass::class);
35+
], class: \stdClass::class, parameters: $sharedParams);
3436
$decorated = $this->createMock(ProviderInterface::class);
3537
$decorated->method('provide')->willReturn($obj);
3638
$request = new Request(attributes: ['bar' => $barObj]);
3739
$resourceAccessChecker = $this->createMock(ResourceAccessCheckerInterface::class);
3840
$resourceAccessChecker->expects($this->once())->method('isGranted')->with('Bar', 'is_granted("some_voter", "bar")', ['object' => $obj, 'previous_object' => null, 'request' => $request, 'bar' => $barObj, 'barId' => 1, 'operation' => $operation])->willReturn(true);
3941
$accessChecker = new SecurityParameterProvider($decorated, $resourceAccessChecker);
4042
$accessChecker->provide($operation, ['barId' => 1], ['request' => $request]);
43+
$this->assertCount(0, $sharedParams, 'provide() must not mutate the Parameters object stored on the cached operation');
4144
}
4245

4346
public function testIsNotGrantedLink(): void

src/Symfony/Validator/State/ParameterValidatorProvider.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ public function provide(Operation $operation, array $uriVariables = [], array $c
5252
}
5353

5454
$constraintViolationList = new ConstraintViolationList();
55-
$parameters = $operation->getParameters() ?? new Parameters();
55+
$existingParameters = $operation->getParameters();
56+
$parameters = $existingParameters ? clone $existingParameters : new Parameters();
5657

5758
if ($operation instanceof HttpOperation) {
5859
foreach ($operation->getUriVariables() ?? [] as $key => $uriVariable) {

0 commit comments

Comments
 (0)