Completed
Push — master ( d7020d...a4700d )
by Daniel
06:50
created

DenyAccessListener   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 87
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 24
eloc 37
c 1
b 0
f 0
dl 0
loc 87
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A checkSecurity() 0 12 6
A isComponentLocationRestricted() 0 4 2
B isResourceRestricted() 0 20 7
A isRouteRestricted() 0 4 2
A onSecurity() 0 6 2
A __construct() 0 3 1
A isDynamicContentRestricted() 0 4 2
A isComponentRestricted() 0 5 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Silverback\ApiComponentBundle\Security\EventListener;
6
7
use Silverback\ApiComponentBundle\Entity\Component\AbstractComponent;
8
use Silverback\ApiComponentBundle\Entity\Component\ComponentLocation;
9
use Silverback\ApiComponentBundle\Entity\Content\Page\AbstractPage;
10
use Silverback\ApiComponentBundle\Entity\Content\Page\Dynamic\DynamicContent;
11
use Silverback\ApiComponentBundle\Entity\RestrictedResourceInterface;
12
use Silverback\ApiComponentBundle\Entity\Route\Route;
13
use Symfony\Component\HttpKernel\Event\ViewEvent;
14
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
15
16
/**
17
 * Denies access to content location or component resources if the content requires a security role not obtained by the user
18
 * or the component or location is not included in any contents which is accessible with the current user roles (or anonymous)
19
 *
20
 * @author Daniel West <[email protected]>
21
 */
22
final class DenyAccessListener
23
{
24
    private $authorizedChecker;
25
26
    public function __construct(AuthorizedChecker $authorizedChecker)
27
    {
28
        $this->authorizedChecker = $authorizedChecker;
29
    }
30
31
    /**
32
     * @throws AccessDeniedException
33
     */
34
    public function onSecurity(ViewEvent $event): void
35
    {
36
        if ($this->authorizedChecker->isAuthorized()) {
37
            return;
38
        }
39
        $this->checkSecurity($event->getControllerResult());
40
    }
41
42
    /**
43
     * @throws AccessDeniedException
44
     */
45
    private function checkSecurity($resource): void
46
    {
47
        if ($resource instanceof RestrictedResourceInterface) {
48
            $this->isResourceRestricted($resource);
49
        }elseif ($resource instanceof DynamicContent) {
50
            $this->isDynamicContentRestricted($resource);
51
        }elseif ($resource instanceof Route) {
52
            $this->isRouteRestricted($resource);
53
        }elseif ($resource instanceof  ComponentLocation) {
54
            $this->isComponentLocationRestricted($resource);
55
        }elseif ($resource instanceof AbstractComponent) {
56
            $this->isComponentRestricted($resource);
57
        }
58
    }
59
60
    private function isComponentRestricted(AbstractComponent $component): void
61
    {
62
        $locations = $component->getLocations();
63
        foreach ($locations as $componentLocation) {
64
            $this->isComponentLocationRestricted($componentLocation);
65
        }
66
    }
67
68
    private function isComponentLocationRestricted(ComponentLocation $componentLocation): void
69
    {
70
        if (($content = $componentLocation->getContent()) instanceof RestrictedResourceInterface) {
0 ignored issues
show
introduced by
$content = $componentLocation->getContent() is always a sub-type of Silverback\ApiComponentB...rictedResourceInterface.
Loading history...
71
            $this->isResourceRestricted($content);
72
        }
73
    }
74
75
    private function isRouteRestricted(Route $route): void
76
    {
77
        if ($page = $route->getStaticPage()) {
78
            $this->isResourceRestricted($page);
79
        }
80
    }
81
82
    private function isDynamicContentRestricted(DynamicContent $dynamicContent): void
83
    {
84
        if ($page = $dynamicContent->getDynamicPage()) {
85
            $this->isResourceRestricted($page);
86
        }
87
    }
88
89
    private function isResourceRestricted(RestrictedResourceInterface $resource): void
90
    {
91
        if ($resource instanceof AbstractPage) {
92
            if ($parent = $resource->getParent()) {
93
                $this->isResourceRestricted($parent);
94
            }
95
            if ($parentRoute = $resource->getParentRoute()) {
96
                $this->isRouteRestricted($parentRoute);
97
            }
98
        }
99
        if (!($roles = $resource->getSecurityRoles())) {
100
            return;
101
        }
102
        $checker = $this->authorizedChecker->getAuthorizationChecker();
103
        foreach ($roles as $role) {
104
            if ($checker->isGranted($role)) {
105
                return;
106
            }
107
        }
108
        throw new AccessDeniedException('ACB: Access Denied.');
109
    }
110
}
111