Skip to content

Commit d980afd

Browse files
committed
[Link] Start Link Security
1 parent 902b135 commit d980afd

File tree

3 files changed

+72
-1
lines changed

3 files changed

+72
-1
lines changed

src/Metadata/Link.php

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::TARGET_PARAMETER)]
1717
final class Link
1818
{
19-
public function __construct(private ?string $parameterName = null, private ?string $fromProperty = null, private ?string $toProperty = null, private ?string $fromClass = null, private ?string $toClass = null, private ?array $identifiers = null, private ?bool $compositeIdentifier = null, private ?string $expandedValue = null)
19+
public function __construct(private ?string $parameterName = null, private ?string $fromProperty = null, private ?string $toProperty = null, private ?string $fromClass = null, private ?string $toClass = null, private ?array $identifiers = null, private ?bool $compositeIdentifier = null, private ?string $expandedValue = null, private ?string $security = null, private ?string $securityMessage = null)
2020
{
2121
// For the inverse property shortcut
2222
if ($this->parameterName && class_exists($this->parameterName)) {
@@ -128,6 +128,35 @@ public function withExpandedValue(string $expandedValue): self
128128
return $self;
129129
}
130130

131+
public function getSecurity(): ?string
132+
{
133+
return $this->security;
134+
}
135+
136+
public function getSecurityMessage(): ?string
137+
{
138+
return $this->securityMessage;
139+
}
140+
141+
142+
143+
public function withSecurity(?string $security): self
144+
{
145+
$self = clone $this;
146+
$self->security = $security;
147+
148+
return $self;
149+
}
150+
151+
public function withSecurityMessage(?string $securityMessage): self
152+
{
153+
$self = clone $this;
154+
$self->securityMessage = $securityMessage;
155+
156+
return $self;
157+
}
158+
159+
131160
public function withLink(self $link): self
132161
{
133162
$self = clone $this;
@@ -164,6 +193,14 @@ public function withLink(self $link): self
164193
$self->expandedValue = $expandedValue;
165194
}
166195

196+
if (!$self->getSecurity() && ($security = $link->getSecurity())) {
197+
$self->security = $security;
198+
}
199+
200+
if (!$self->getSecurityMessage() && ($securityMessage = $link->getSecurityMessage())) {
201+
$self->securityMessage = $securityMessage;
202+
}
203+
167204
return $self;
168205
}
169206
}

src/Symfony/EventListener/DenyAccessListener.php

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

1414
namespace ApiPlatform\Symfony\EventListener;
1515

16+
use ApiPlatform\Metadata\Link;
1617
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
1718
use ApiPlatform\Symfony\Security\ResourceAccessCheckerInterface;
1819
use ApiPlatform\Util\OperationRequestInitiatorTrait;
@@ -97,5 +98,17 @@ private function checkSecurity(Request $request, string $attribute, array $extra
9798
if (!$this->resourceAccessChecker->isGranted($attributes['resource_class'], $isGranted, $extraVariables)) {
9899
throw new AccessDeniedException($message ?? 'Access Denied.');
99100
}
101+
102+
if ($operation->getUriVariables()) {
103+
foreach ($operation->getUriVariables() as $key => $uriVariable) {
104+
if (!$uriVariable instanceof Link || !$uriVariable->getSecurity()) {
105+
continue;
106+
}
107+
108+
if (!$this->resourceAccessChecker->isGranted($uriVariable->getToProperty(), $uriVariable->getSecurity(), $extraVariables)) {
109+
throw new AccessDeniedException($uriVariable->getSecurityMessage() ?? 'Access Denied.');
110+
}
111+
}
112+
}
100113
}
101114
}

src/Symfony/EventListener/ReadListener.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@
1414
namespace ApiPlatform\Symfony\EventListener;
1515

1616
use ApiPlatform\Api\UriVariablesConverterInterface;
17+
use ApiPlatform\Doctrine\Orm\State\ItemProvider;
1718
use ApiPlatform\Exception\InvalidIdentifierException;
1819
use ApiPlatform\Exception\InvalidUriVariableException;
1920
use ApiPlatform\Metadata\HttpOperation;
2021
use ApiPlatform\Metadata\Put;
22+
use ApiPlatform\Metadata\Get;
23+
use ApiPlatform\Metadata\Link;
2124
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
2225
use ApiPlatform\Serializer\SerializerContextBuilderInterface;
2326
use ApiPlatform\State\ProviderInterface;
@@ -104,6 +107,24 @@ public function onKernelRequest(RequestEvent $event): void
104107
throw new NotFoundHttpException('Not Found');
105108
}
106109

110+
if ($operation->getUriVariables()) {
111+
foreach ($operation->getUriVariables() as $key => $uriVariable) {
112+
if (!$uriVariable instanceof Link || !$uriVariable->getSecurity()) {
113+
continue;
114+
}
115+
$operationUriVariables = $uriVariable->getIdentifiers();
116+
$relationClass = $uriVariable->getFromClass();
117+
try {
118+
//$uriVariables = $this->getOperationUriVariables($operation, $parameters, $resourceClass);
119+
$tmp = $this->provider->provide(new Get(uriVariables: $operationUriVariables, class: $relationClass, provider: ItemProvider::class), ['id' => $parameters[$key]], $context);
120+
$request->attributes->set($uriVariable->getToProperty(), $tmp);
121+
} catch (InvalidIdentifierException|InvalidUriVariableException $e) {
122+
throw new NotFoundHttpException('Invalid identifier value or configuration.', $e);
123+
}
124+
}
125+
}
126+
127+
107128
$request->attributes->set('data', $data);
108129
$request->attributes->set('previous_data', $this->clone($data));
109130
}

0 commit comments

Comments
 (0)