Skip to content

Allow throwing an access denied exception on denormalization of secured properties #7221

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/Serializer/AbstractItemNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use ApiPlatform\Metadata\Exception\InvalidArgumentException;
use ApiPlatform\Metadata\Exception\ItemNotFoundException;
use ApiPlatform\Metadata\IriConverterInterface;
use ApiPlatform\Metadata\Metadata;
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
use ApiPlatform\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
Expand All @@ -26,6 +27,7 @@
use ApiPlatform\Metadata\UrlGeneratorInterface;
use ApiPlatform\Metadata\Util\ClassInfoTrait;
use ApiPlatform\Metadata\Util\CloneTrait;
use ApiPlatform\Symfony\Security\Exception\AccessDeniedException;
use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
Expand Down Expand Up @@ -266,14 +268,28 @@
$options = $this->getFactoryOptions($context);
$propertyNames = iterator_to_array($this->propertyNameCollectionFactory->create($resourceClass, $options));

$operation = $context['operation'] ?? null;
$extraProperties = $operation instanceof Metadata ?
$operation->getExtraProperties() :
($context['extra_properties'] ?? []);

Check warning on line 274 in src/Serializer/AbstractItemNormalizer.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/AbstractItemNormalizer.php#L274

Added line #L274 was not covered by tests

$throwOnAccessDenied = $extraProperties['throw_on_access_denied'] ?? false;
$securityMessage = $operation?->getSecurityMessage() ?? null;

// Revert attributes that aren't allowed to be changed after a post-denormalize check
foreach (array_keys($data) as $attribute) {
$attribute = $this->nameConverter ? $this->nameConverter->denormalize((string) $attribute) : $attribute;
$attributeMeta = $this->propertyMetadataFactory->create($resourceClass, $attribute, $options);
$attributeExtraProperties = $attributeMeta->getExtraProperties() ?? [];
$throwOnAccessDenied = (bool) ($attributeExtraProperties['throw_on_access_denied'] ?? $throwOnAccessDenied);
if (!\in_array($attribute, $propertyNames, true)) {
continue;
}

if (!$this->canAccessAttributePostDenormalize($object, $previousObject, $attribute, $context)) {
if ($throwOnAccessDenied) {
throw new AccessDeniedException($securityMessage ?? 'Access denied');

Check warning on line 291 in src/Serializer/AbstractItemNormalizer.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/AbstractItemNormalizer.php#L290-L291

Added lines #L290 - L291 were not covered by tests
}
if (null !== $previousObject) {
$this->setValue($object, $attribute, $this->propertyAccessor->getValue($previousObject, $attribute));
} else {
Expand Down
169 changes: 169 additions & 0 deletions src/Serializer/Tests/AbstractItemNormalizerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\IriConverterInterface;
use ApiPlatform\Metadata\Operations;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
use ApiPlatform\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
use ApiPlatform\Metadata\Property\PropertyNameCollection;
Expand All @@ -40,6 +41,7 @@
use ApiPlatform\Serializer\Tests\Fixtures\ApiResource\PropertyCollectionIriOnlyRelation;
use ApiPlatform\Serializer\Tests\Fixtures\ApiResource\RelatedDummy;
use ApiPlatform\Serializer\Tests\Fixtures\ApiResource\SecuredDummy;
use ApiPlatform\Symfony\Security\Exception\AccessDeniedException;
use Doctrine\Common\Collections\ArrayCollection;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
Expand Down Expand Up @@ -306,6 +308,173 @@
]));
}

public function testDenormalizeWithSecuredPropertyAndThrowOnAccessDeniedExtraPropertyInAttributeMetaThrowsAccessDeniedExceptionWithSecurityMessage(): void

Check warning on line 311 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L311

Added line #L311 was not covered by tests
{
$data = [
'title' => 'foo',
'adminOnlyProperty' => 'secret',
];
$propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
$propertyNameCollectionFactoryProphecy->create(SecuredDummy::class, [])->willReturn(new PropertyNameCollection(['title', 'adminOnlyProperty']));

Check warning on line 318 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L313-L318

Added lines #L313 - L318 were not covered by tests

$propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);

Check warning on line 320 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L320

Added line #L320 was not covered by tests

if (!method_exists(PropertyInfoExtractor::class, 'getType')) {
$propertyMetadataFactoryProphecy->create(SecuredDummy::class, 'title', [])->willReturn((new ApiProperty())->withBuiltinTypes([new LegacyType(LegacyType::BUILTIN_TYPE_STRING)])->withDescription('')->withReadable(false)->withWritable(true));
$propertyMetadataFactoryProphecy->create(SecuredDummy::class, 'adminOnlyProperty', [])->willReturn((new ApiProperty())->withBuiltinTypes([new LegacyType(LegacyType::BUILTIN_TYPE_STRING)])->withDescription('')->withReadable(true)->withSecurityPostDenormalize('is_granted(\'ROLE_ADMIN\')')->withExtraProperties(['throw_on_access_denied' => true]));

Check warning on line 324 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L322-L324

Added lines #L322 - L324 were not covered by tests
} else {
$propertyMetadataFactoryProphecy->create(SecuredDummy::class, 'title', [])->willReturn((new ApiProperty())->withNativeType(Type::string())->withDescription('')->withReadable(false)->withWritable(true));
$propertyMetadataFactoryProphecy->create(SecuredDummy::class, 'adminOnlyProperty', [])->willReturn((new ApiProperty())->withNativeType(Type::string())->withDescription('')->withReadable(true)->withSecurityPostDenormalize('is_granted(\'ROLE_ADMIN\')')->withExtraProperties(['throw_on_access_denied' => true]));

Check warning on line 327 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L326-L327

Added lines #L326 - L327 were not covered by tests
}

$iriConverterProphecy = $this->prophesize(IriConverterInterface::class);

Check warning on line 330 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L330

Added line #L330 was not covered by tests

$propertyAccessorProphecy = $this->prophesize(PropertyAccessorInterface::class);

Check warning on line 332 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L332

Added line #L332 was not covered by tests

$resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
$resourceClassResolverProphecy->getResourceClass(null, SecuredDummy::class)->willReturn(SecuredDummy::class);
$resourceClassResolverProphecy->isResourceClass(SecuredDummy::class)->willReturn(true);

Check warning on line 336 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L334-L336

Added lines #L334 - L336 were not covered by tests

$serializerProphecy = $this->prophesize(SerializerInterface::class);
$serializerProphecy->willImplement(NormalizerInterface::class);

Check warning on line 339 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L338-L339

Added lines #L338 - L339 were not covered by tests

$resourceAccessChecker = $this->prophesize(ResourceAccessCheckerInterface::class);
$resourceAccessChecker->isGranted(
SecuredDummy::class,
'is_granted(\'ROLE_ADMIN\')',
Argument::that(function (array $context) {
return \array_key_exists('property', $context)
&& \array_key_exists('object', $context)
&& \array_key_exists('previous_object', $context)
&& 'adminOnlyProperty' === $context['property']
&& null === $context['previous_object']
&& $context['object'] instanceof SecuredDummy;
})
)->willReturn(false);

Check warning on line 353 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L341-L353

Added lines #L341 - L353 were not covered by tests

$normalizer = new class($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $iriConverterProphecy->reveal(), $resourceClassResolverProphecy->reveal(), $propertyAccessorProphecy->reveal(), null, null, [], null, $resourceAccessChecker->reveal()) extends AbstractItemNormalizer {};
$normalizer->setSerializer($serializerProphecy->reveal());

Check warning on line 356 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L355-L356

Added lines #L355 - L356 were not covered by tests

$this->expectException(AccessDeniedException::class);
$this->expectExceptionMessage('Access denied');

Check warning on line 359 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L358-L359

Added lines #L358 - L359 were not covered by tests

$normalizer->denormalize($data, SecuredDummy::class);

Check warning on line 361 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L361

Added line #L361 was not covered by tests
}

public function testDenormalizeWithSecuredPropertyAndThrowOnAccessDeniedExtraPropertyInOperationAndSecurityMessageInOperationThrowsAccessDeniedExceptionWithSecurityMessage(): void

Check warning on line 364 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L364

Added line #L364 was not covered by tests
{
$data = [
'title' => 'foo',
'adminOnlyProperty' => 'secret',
];
$propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
$propertyNameCollectionFactoryProphecy->create(SecuredDummy::class, [])->willReturn(new PropertyNameCollection(['title', 'adminOnlyProperty']));

Check warning on line 371 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L366-L371

Added lines #L366 - L371 were not covered by tests

$propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);

Check warning on line 373 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L373

Added line #L373 was not covered by tests

if (!method_exists(PropertyInfoExtractor::class, 'getType')) {
$propertyMetadataFactoryProphecy->create(SecuredDummy::class, 'title', [])->willReturn((new ApiProperty())->withBuiltinTypes([new LegacyType(LegacyType::BUILTIN_TYPE_STRING)])->withDescription('')->withReadable(false)->withWritable(true));
$propertyMetadataFactoryProphecy->create(SecuredDummy::class, 'adminOnlyProperty', [])->willReturn((new ApiProperty())->withBuiltinTypes([new LegacyType(LegacyType::BUILTIN_TYPE_STRING)])->withDescription('')->withReadable(true)->withSecurityPostDenormalize('is_granted(\'ROLE_ADMIN\')'));

Check warning on line 377 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L375-L377

Added lines #L375 - L377 were not covered by tests
} else {
$propertyMetadataFactoryProphecy->create(SecuredDummy::class, 'title', [])->willReturn((new ApiProperty())->withNativeType(Type::string())->withDescription('')->withReadable(false)->withWritable(true));
$propertyMetadataFactoryProphecy->create(SecuredDummy::class, 'adminOnlyProperty', [])->willReturn((new ApiProperty())->withNativeType(Type::string())->withDescription('')->withReadable(true)->withSecurityPostDenormalize('is_granted(\'ROLE_ADMIN\')'));

Check warning on line 380 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L379-L380

Added lines #L379 - L380 were not covered by tests
}

$iriConverterProphecy = $this->prophesize(IriConverterInterface::class);

Check warning on line 383 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L383

Added line #L383 was not covered by tests

$propertyAccessorProphecy = $this->prophesize(PropertyAccessorInterface::class);

Check warning on line 385 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L385

Added line #L385 was not covered by tests

$resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
$resourceClassResolverProphecy->getResourceClass(null, SecuredDummy::class)->willReturn(SecuredDummy::class);
$resourceClassResolverProphecy->isResourceClass(SecuredDummy::class)->willReturn(true);

Check warning on line 389 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L387-L389

Added lines #L387 - L389 were not covered by tests

$serializerProphecy = $this->prophesize(SerializerInterface::class);
$serializerProphecy->willImplement(NormalizerInterface::class);

Check warning on line 392 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L391-L392

Added lines #L391 - L392 were not covered by tests

$resourceAccessChecker = $this->prophesize(ResourceAccessCheckerInterface::class);
$resourceAccessChecker->isGranted(
SecuredDummy::class,
'is_granted(\'ROLE_ADMIN\')',
Argument::that(function (array $context) {
return \array_key_exists('property', $context)
&& \array_key_exists('object', $context)
&& \array_key_exists('previous_object', $context)
&& 'adminOnlyProperty' === $context['property']
&& null === $context['previous_object']
&& $context['object'] instanceof SecuredDummy;
})
)->willReturn(false);

Check warning on line 406 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L394-L406

Added lines #L394 - L406 were not covered by tests

$normalizer = new class($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $iriConverterProphecy->reveal(), $resourceClassResolverProphecy->reveal(), $propertyAccessorProphecy->reveal(), null, null, [], null, $resourceAccessChecker->reveal()) extends AbstractItemNormalizer {};
$normalizer->setSerializer($serializerProphecy->reveal());

Check warning on line 409 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L408-L409

Added lines #L408 - L409 were not covered by tests

$this->expectException(AccessDeniedException::class);
$this->expectExceptionMessage('Custom access denied message');

Check warning on line 412 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L411-L412

Added lines #L411 - L412 were not covered by tests

$operation = new Patch(securityMessage: 'Custom access denied message', extraProperties: ['throw_on_access_denied' => true]);

Check warning on line 414 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L414

Added line #L414 was not covered by tests

$normalizer->denormalize($data, SecuredDummy::class, 'json', [
'operation' => $operation,
]);

Check warning on line 418 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L416-L418

Added lines #L416 - L418 were not covered by tests
}

public function testDenormalizeWithSecuredPropertyAndThrowOnAccessDeniedExtraPropertyInOperationThrowsAccessDeniedException(): void

Check warning on line 421 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L421

Added line #L421 was not covered by tests
{
$data = [
'title' => 'foo',
'adminOnlyProperty' => 'secret',
];
$propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
$propertyNameCollectionFactoryProphecy->create(SecuredDummy::class, [])->willReturn(new PropertyNameCollection(['title', 'adminOnlyProperty']));

Check warning on line 428 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L423-L428

Added lines #L423 - L428 were not covered by tests

$propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);

Check warning on line 430 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L430

Added line #L430 was not covered by tests

if (!method_exists(PropertyInfoExtractor::class, 'getType')) {
$propertyMetadataFactoryProphecy->create(SecuredDummy::class, 'title', [])->willReturn((new ApiProperty())->withBuiltinTypes([new LegacyType(LegacyType::BUILTIN_TYPE_STRING)])->withDescription('')->withReadable(false)->withWritable(true));
$propertyMetadataFactoryProphecy->create(SecuredDummy::class, 'adminOnlyProperty', [])->willReturn((new ApiProperty())->withBuiltinTypes([new LegacyType(LegacyType::BUILTIN_TYPE_STRING)])->withDescription('')->withReadable(true)->withSecurityPostDenormalize('is_granted(\'ROLE_ADMIN\')'));

Check warning on line 434 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L432-L434

Added lines #L432 - L434 were not covered by tests
} else {
$propertyMetadataFactoryProphecy->create(SecuredDummy::class, 'title', [])->willReturn((new ApiProperty())->withNativeType(Type::string())->withDescription('')->withReadable(false)->withWritable(true));
$propertyMetadataFactoryProphecy->create(SecuredDummy::class, 'adminOnlyProperty', [])->willReturn((new ApiProperty())->withNativeType(Type::string())->withDescription('')->withReadable(true)->withSecurityPostDenormalize('is_granted(\'ROLE_ADMIN\')'));

Check warning on line 437 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L436-L437

Added lines #L436 - L437 were not covered by tests
}

$iriConverterProphecy = $this->prophesize(IriConverterInterface::class);

Check warning on line 440 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L440

Added line #L440 was not covered by tests

$propertyAccessorProphecy = $this->prophesize(PropertyAccessorInterface::class);

Check warning on line 442 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L442

Added line #L442 was not covered by tests

$resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
$resourceClassResolverProphecy->getResourceClass(null, SecuredDummy::class)->willReturn(SecuredDummy::class);
$resourceClassResolverProphecy->isResourceClass(SecuredDummy::class)->willReturn(true);

Check warning on line 446 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L444-L446

Added lines #L444 - L446 were not covered by tests

$serializerProphecy = $this->prophesize(SerializerInterface::class);
$serializerProphecy->willImplement(NormalizerInterface::class);

Check warning on line 449 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L448-L449

Added lines #L448 - L449 were not covered by tests

$resourceAccessChecker = $this->prophesize(ResourceAccessCheckerInterface::class);
$resourceAccessChecker->isGranted(
SecuredDummy::class,
'is_granted(\'ROLE_ADMIN\')',
Argument::that(function (array $context) {
return \array_key_exists('property', $context)
&& \array_key_exists('object', $context)
&& \array_key_exists('previous_object', $context)
&& 'adminOnlyProperty' === $context['property']
&& null === $context['previous_object']
&& $context['object'] instanceof SecuredDummy;
})
)->willReturn(false);

Check warning on line 463 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L451-L463

Added lines #L451 - L463 were not covered by tests

$normalizer = new class($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $iriConverterProphecy->reveal(), $resourceClassResolverProphecy->reveal(), $propertyAccessorProphecy->reveal(), null, null, [], null, $resourceAccessChecker->reveal()) extends AbstractItemNormalizer {};
$normalizer->setSerializer($serializerProphecy->reveal());

Check warning on line 466 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L465-L466

Added lines #L465 - L466 were not covered by tests

$this->expectException(AccessDeniedException::class);
$this->expectExceptionMessage('Access denied');

Check warning on line 469 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L468-L469

Added lines #L468 - L469 were not covered by tests

$operation = new Patch(extraProperties: ['throw_on_access_denied' => true]);

Check warning on line 471 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L471

Added line #L471 was not covered by tests

$normalizer->denormalize($data, SecuredDummy::class, 'json', [
'operation' => $operation,
]);

Check warning on line 475 in src/Serializer/Tests/AbstractItemNormalizerTest.php

View check run for this annotation

Codecov / codecov/patch

src/Serializer/Tests/AbstractItemNormalizerTest.php#L473-L475

Added lines #L473 - L475 were not covered by tests
}

public function testDenormalizeWithSecuredProperty(): void
{
$data = [
Expand Down
Loading