SecuredManager::getElement()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 6
nc 2
nop 1
dl 0
loc 12
rs 10
c 1
b 0
f 0
1
<?php
2
3
/**
4
 * (c) FSi sp. z o.o. <[email protected]>
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
declare(strict_types=1);
11
12
namespace FSi\Bundle\AdminSecurityBundle\Admin;
13
14
use FSi\Bundle\AdminBundle\Admin\Element;
15
use FSi\Bundle\AdminBundle\Admin\Manager\Visitor;
16
use FSi\Bundle\AdminBundle\Admin\ManagerInterface;
17
use FSi\Bundle\AdminSecurityBundle\Security\User\EnforceablePasswordChangeInterface;
18
use RuntimeException;
19
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
20
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
21
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
22
23
class SecuredManager implements ManagerInterface
24
{
25
    /**
26
     * @var ManagerInterface
27
     */
28
    private $manager;
29
30
    /**
31
     * @var TokenStorageInterface
32
     */
33
    private $tokenStorage;
34
35
    /**
36
     * @var AuthorizationCheckerInterface
37
     */
38
    private $authorizationChecker;
39
40
    public function __construct(
41
        ManagerInterface $manager,
42
        TokenStorageInterface $tokenStorage,
43
        AuthorizationCheckerInterface $authorizationChecker
44
    ) {
45
        $this->manager = $manager;
46
        $this->tokenStorage = $tokenStorage;
47
        $this->authorizationChecker = $authorizationChecker;
48
    }
49
50
    public function addElement(Element $element): void
51
    {
52
        $this->manager->addElement($element);
53
    }
54
55
    public function hasElement(string $id): bool
56
    {
57
        if (!$this->manager->hasElement($id)) {
58
            return false;
59
        }
60
61
        $element = $this->manager->getElement($id);
62
        if ($this->isAccessToElementRestricted($element)) {
63
            return false;
64
        }
65
66
        return true;
67
    }
68
69
    /**
70
     * @param string $id
71
     * @return Element
72
     * @throws AccessDeniedException
73
     */
74
    public function getElement(string $id): Element
75
    {
76
        $element = $this->manager->getElement($id);
77
78
        if ($this->isAccessToElementRestricted($element)) {
79
            throw new AccessDeniedException(sprintf(
80
                'Access denied to element "%s"',
81
                get_class($element)
82
            ));
83
        }
84
85
        return $element;
86
    }
87
88
    /**
89
     * {@inheritdoc}
90
     */
91
    public function removeElement(string $id): void
92
    {
93
        $this->manager->removeElement($id);
94
    }
95
96
    /**
97
     * {@inheritdoc}
98
     */
99
    public function getElements(): array
100
    {
101
        return array_filter((array) $this->manager->getElements(), function (Element $element) {
102
            return !$this->isAccessToElementRestricted($element);
103
        });
104
    }
105
106
    /**
107
     * {@inheritdoc}
108
     */
109
    public function accept(Visitor $visitor): void
110
    {
111
        $visitor->visitManager($this);
112
    }
113
114
    private function isAccessToElementRestricted(Element $element): bool
115
    {
116
        if (!$this->tokenStorage->getToken()) {
117
            // The request is not behind a firewall, so all elements are restricted
118
            return true;
119
        }
120
121
        if ($this->isUserForcedToChangePassword()) {
122
            return true;
123
        }
124
125
        return $element instanceof SecuredElementInterface && !$element->isAllowed($this->authorizationChecker);
126
    }
127
128
    private function isUserForcedToChangePassword(): bool
129
    {
130
        if (!$this->authorizationChecker->isGranted('IS_AUTHENTICATED_FULLY')) {
131
            return false;
132
        }
133
134
        $user = $this->tokenStorage->getToken()->getUser();
135
        if (!($user instanceof EnforceablePasswordChangeInterface)) {
136
            return false;
137
        }
138
139
        return $user->isForcedToChangePassword();
140
    }
141
}
142