Skip to content

Commit 817f45e

Browse files
author
Thibaut Cholley
committed
wip
1 parent 4271cf8 commit 817f45e

1 file changed

Lines changed: 38 additions & 2 deletions

File tree

src/Serializer/AbstractItemNormalizer.php

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -764,8 +764,12 @@ private function getResourceFromIri(string $data, array $context, string $resour
764764
try {
765765
$item = $this->iriConverter->getResourceFromIri($data, $context + ['fetch_data' => true]);
766766

767-
// Type-confusion guard: declared relation class must match the IRI's resource.
768-
if (!is_a($item, $resourceClass)) {
767+
// Type-confusion guard (CWE-843 / GHSA-9rjg-x2p2-h68h): the resolved
768+
// resource must be an instance of the declared class. For union-typed
769+
// properties (e.g. Foo[]|Bar[]) every resource class in the union is
770+
// accepted; a genuinely foreign type is still rejected.
771+
$allowedClasses = $context['_api_union_resource_classes'] ?? [$resourceClass];
772+
if (!\array_reduce($allowedClasses, static fn (bool $ok, string $cls): bool => $ok || \is_a($item, $cls), false)) {
769773
throw new NotNormalizableValueException(\sprintf('The iri "%s" does not reference the correct resource.', $data));
770774
}
771775

@@ -1191,6 +1195,38 @@ private function createAndValidateAttributeValue(string $attribute, mixed $value
11911195
$isMultipleTypes = \count($types) > 1;
11921196
$denormalizationException = null;
11931197

1198+
// Build the full set of resource classes across all union types so that
1199+
// getResourceFromIri()'s is_a guard can accept any valid union member.
1200+
// Without this, a Foo[]|Bar[] property rejects mixed collections because
1201+
// the guard only sees the single class being tried in each iteration.
1202+
unset($context['_api_union_resource_classes']);
1203+
if ($isMultipleTypes) {
1204+
$unionResourceClasses = [];
1205+
foreach ($types as $ut) {
1206+
if ($ut instanceof CollectionType) {
1207+
$cvt = $ut->getCollectionValueType();
1208+
if ($cvt instanceof ObjectType && $this->resourceClassResolver->isResourceClass($cvt->getClassName())) {
1209+
$unionResourceClasses[] = $cvt->getClassName();
1210+
}
1211+
} elseif ($ut instanceof ObjectType && $this->resourceClassResolver->isResourceClass($ut->getClassName())) {
1212+
$unionResourceClasses[] = $ut->getClassName();
1213+
} elseif ($ut instanceof LegacyType) {
1214+
if ($ut->isCollection()) {
1215+
foreach ($ut->getCollectionValueTypes() as $cvt) {
1216+
if (null !== ($cn = $cvt->getClassName()) && $this->resourceClassResolver->isResourceClass($cn)) {
1217+
$unionResourceClasses[] = $cn;
1218+
}
1219+
}
1220+
} elseif (null !== ($cn = $ut->getClassName()) && $this->resourceClassResolver->isResourceClass($cn)) {
1221+
$unionResourceClasses[] = $cn;
1222+
}
1223+
}
1224+
}
1225+
if ($unionResourceClasses) {
1226+
$context['_api_union_resource_classes'] = array_unique($unionResourceClasses);
1227+
}
1228+
}
1229+
11941230
foreach ($types as $t) {
11951231
if ($type instanceof Type) {
11961232
$isNullable = $type->isNullable();

0 commit comments

Comments
 (0)