Completed
Pull Request — master (#91)
by Piotr
03:42
created

SecuredManager::hasElement()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

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