• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

api-platform / core / 7581037639

19 Jan 2024 08:03AM UTC coverage: 59.207% (-0.1%) from 59.351%
7581037639

push

github

web-flow
feat(symfony): Link security (#5290)

* [Link] Start Link Security

* feat(provider): Auto Resolve Get Operation and Parameters

* chore(CS): fix CS

* feat(tests): Add DenyAccessListener tests

* feat(tests): Add link security behat tests

* fix(test): fix mongodb document configuration

* fix(readlistner): fix error 500 on not existing entity

* feat(linksecurity): expand functionality to cover all combinations of to and from property and add optional object name

* feat(linksecurity): add more tests

* chore: fix cs

* chore: phpstan fix

* fix: Move logic to refactored, now used, classes

* fix: refactor unit tests

* fix: backport for legacy event system as well

* Revert "fix: backport for legacy event system as well"

This reverts commit 16f14c836.

* refactor: Refactor ReadProvider.php and AccessCheckerProvider.php to extract link security into their own providers

* mark providers final, disable feature by default

42 of 74 new or added lines in 5 files covered. (56.76%)

200 existing lines in 3 files now uncovered.

16427 of 27745 relevant lines covered (59.21%)

32.77 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

33.33
/src/Symfony/Security/State/LinkedReadProvider.php
1
<?php
2

3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <dunglas@gmail.com>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11

12
declare(strict_types=1);
13

14
namespace ApiPlatform\Symfony\Security\State;
15

16
use ApiPlatform\Exception\InvalidIdentifierException;
17
use ApiPlatform\Exception\InvalidUriVariableException;
18
use ApiPlatform\Metadata\HttpOperation;
19
use ApiPlatform\Metadata\Link;
20
use ApiPlatform\Metadata\Operation;
21
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
22
use ApiPlatform\State\Exception\ProviderNotFoundException;
23
use ApiPlatform\State\ProviderInterface;
24
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
25

26
/**
27
 * Checks if the linked resources have security attributes and prepares them for access checking.
28
 *
29
 * @experimental
30
 */
31
final class LinkedReadProvider implements ProviderInterface
32
{
33
    public function __construct(
34
        private readonly ProviderInterface $decorated,
35
        private readonly ProviderInterface $locator,
36
        private readonly ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory
37
    ) {
38
    }
92✔
39

40
    public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
41
    {
42
        $data = $this->decorated->provide($operation, $uriVariables, $context);
92✔
43

44
        if (!$operation instanceof HttpOperation) {
89✔
NEW
45
            return $data;
×
46
        }
47

48
        $request = ($context['request'] ?? null);
89✔
49

50
        if ($operation->getUriVariables()) {
89✔
51
            foreach ($operation->getUriVariables() as $key => $uriVariable) {
19✔
52
                if (!$uriVariable instanceof Link || !$uriVariable->getSecurity()) {
19✔
53
                    continue;
19✔
54
                }
55

NEW
56
                $relationClass = $uriVariable->getFromClass() ?? $uriVariable->getToClass();
×
57

NEW
58
                if (!$relationClass) {
×
NEW
59
                    continue;
×
60
                }
61

NEW
62
                $parentOperation = $this->resourceMetadataCollectionFactory
×
NEW
63
                    ->create($relationClass)
×
NEW
64
                    ->getOperation($operation->getExtraProperties()['parent_uri_template'] ?? null);
×
65
                try {
NEW
66
                    $relation = $this->locator->provide($parentOperation, [$uriVariable->getIdentifiers()[0] => $request?->attributes->all()[$key]], $context);
×
NEW
67
                } catch (ProviderNotFoundException) {
×
NEW
68
                    $relation = null;
×
69
                }
70

NEW
71
                if (!$relation) {
×
NEW
72
                    throw new NotFoundHttpException('Relation for link security not found.');
×
73
                }
74

75
                try {
NEW
76
                    $securityObjectName = $uriVariable->getSecurityObjectName();
×
77

NEW
78
                    if (!$securityObjectName) {
×
NEW
79
                        $securityObjectName = $uriVariable->getToProperty() ?? $uriVariable->getFromProperty();
×
80
                    }
81

NEW
82
                    $request?->attributes->set($securityObjectName, $relation);
×
NEW
83
                } catch (InvalidIdentifierException|InvalidUriVariableException $e) {
×
NEW
84
                    throw new NotFoundHttpException('Invalid identifier value or configuration.', $e);
×
85
                }
86
            }
87
        }
88

89
        return $data;
89✔
90
    }
91
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc