Passed
Push — master ( 15dae9...698027 )
by Julito
12:28
created

ResourceNodeVoter   A

Complexity

Total Complexity 31

Size/Duplication

Total Lines 241
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 107
dl 0
loc 241
rs 9.92
c 0
b 0
f 0
wmc 31

5 Methods

Rating   Name   Duplication   Size   Complexity  
D voteOnAttribute() 0 163 25
A getReaderMask() 0 8 1
A supports() 0 21 3
A __construct() 0 3 1
A getEditorMask() 0 8 1
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
namespace Chamilo\CoreBundle\Security\Authorization\Voter;
5
6
use Chamilo\CoreBundle\Entity\Course;
7
use Chamilo\CoreBundle\Entity\Resource\ResourceLink;
8
use Chamilo\CoreBundle\Entity\Resource\ResourceNode;
9
use Chamilo\CoreBundle\Entity\Session;
10
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
11
use Symfony\Component\DependencyInjection\ContainerInterface;
12
use Symfony\Component\Security\Acl\Permission\MaskBuilder;
13
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
14
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
15
use Symfony\Component\Security\Core\User\UserInterface;
16
//use Zend\Permissions\Acl\Resource\GenericResource as Resource;
17
use Zend\Permissions\Acl\Acl;
18
use Zend\Permissions\Acl\Role\GenericRole as Role;
19
20
//use Sonata\AdminBundle\Security\Acl\Permission\MaskBuilder;
21
22
/**
23
 * Class ResourceNodeVoter.
24
 *
25
 * @package Chamilo\CoreBundle\Security\Authorization\Voter
26
 */
27
class ResourceNodeVoter extends Voter
28
{
29
    public const VIEW = 'VIEW';
30
    public const CREATE = 'CREATE';
31
    public const EDIT = 'EDIT';
32
    public const DELETE = 'DELETE';
33
    public const EXPORT = 'EXPORT';
34
35
    public const ROLE_CURRENT_COURSE_TEACHER = 'ROLE_CURRENT_COURSE_TEACHER';
36
    public const ROLE_CURRENT_COURSE_STUDENT = 'ROLE_CURRENT_COURSE_STUDENT';
37
38
    protected $container;
39
40
    /**
41
     * Constructor.
42
     *
43
     * @param ContainerInterface $container
44
     */
45
    public function __construct(ContainerInterface $container)
46
    {
47
        $this->container = $container;
48
    }
49
50
    /**
51
     * @return int
52
     */
53
    public static function getReaderMask(): int
54
    {
55
        $builder = new MaskBuilder();
56
        $builder
57
            ->add(self::VIEW)
58
        ;
59
60
        return $builder->get();
61
    }
62
63
    /**
64
     * @return int
65
     */
66
    public static function getEditorMask(): int
67
    {
68
        $builder = new MaskBuilder();
69
        $builder
70
            ->add(self::EDIT)
71
        ;
72
73
        return $builder->get();
74
    }
75
76
    /**
77
     * {@inheritdoc}
78
     */
79
    protected function supports($attribute, $subject): bool
80
    {
81
        $options = [
82
            self::VIEW,
83
            self::CREATE,
84
            self::EDIT,
85
            self::DELETE,
86
            self::EXPORT,
87
        ];
88
89
        // if the attribute isn't one we support, return false
90
        if (!in_array($attribute, $options)) {
91
            return false;
92
        }
93
94
        // only vote on Post objects inside this voter
95
        if (!$subject instanceof ResourceNode) {
96
            return false;
97
        }
98
99
        return true;
100
    }
101
102
    /**
103
     * {@inheritdoc}
104
     */
105
    protected function voteOnAttribute($attribute, $resourceNode, TokenInterface $token): bool
106
    {
107
        $user = $token->getUser();
108
        // Make sure there is a user object (i.e. that the user is logged in)
109
        if (!$user instanceof UserInterface) {
110
            return false;
111
        }
112
113
        // Checking admin roles
114
        $authChecker = $this->container->get('security.authorization_checker');
115
116
        // Admins have access to everything
117
        if ($authChecker->isGranted('ROLE_ADMIN')) {
118
            return true;
119
        }
120
121
        // Check if I'm the owner
122
        $creator = $resourceNode->getCreator();
123
124
        if ($creator instanceof UserInterface &&
125
            $user->getUsername() === $creator->getUsername()) {
126
127
            return true;
128
        }
129
130
        // Checking possible links connected to this resource
131
        $request = $this->container->get('request_stack')->getCurrentRequest();
132
133
        $courseCode = $request->get('course');
134
        $sessionId = $request->get('session');
135
136
        $links = $resourceNode->getLinks();
137
        $linkFound = false;
138
139
        /** @var ResourceLink $link */
140
        foreach ($links as $link) {
141
            $linkUser = $link->getUser();
142
            $linkCourse = $link->getCourse();
143
            $linkSession = $link->getSession();
144
            $linkUserGroup = $link->getUserGroup();
145
146
            // Check if resource was sent to the current user
147
            if ($linkUser instanceof UserInterface &&
148
                $linkUser->getUsername() === $creator->getUsername()
149
            ) {
150
                $linkFound = true;
151
                break;
152
            }
153
154
            // @todo Check if resource was sent to a usergroup
155
            // @todo Check if resource was sent to a group inside a course
156
157
            // Check if resource was sent to a course inside a session
158
            if ($linkSession instanceof Session && !empty($sessionId) &&
159
                $linkCourse instanceof Course && !empty($courseCode)
160
            ) {
161
                $session = $this->container->get('chamilo_core.entity.manager.session_manager')->find($sessionId);
162
                $course = $this->container->get('chamilo_core.entity.manager.course_manager')->findOneByCode($courseCode);
163
                if ($session instanceof Session &&
164
                    $course instanceof Course &&
165
                    $linkCourse->getCode() === $course->getCode() &&
166
                    $linkSession->getId() === $session->getId()
167
                ) {
168
                    $linkFound = true;
169
                    break;
170
                }
171
            }
172
173
            // Check if resource was sent to a course
174
            if ($linkCourse instanceof Course && !empty($courseCode)) {
175
                $course = $this->container->get('chamilo_core.manager.course')->findOneByCode($courseCode);
176
                if ($course instanceof Course &&
177
                    $linkCourse->getCode() === $course->getCode()
178
                ) {
179
                    $linkFound = true;
180
                    break;
181
                }
182
            }
183
        }
184
185
        // No link was found!
186
        if ($linkFound === false) {
187
            return false;
188
        }
189
190
        // Getting rights from the link
191
        $rightFromResourceLink = $link->getRights();
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $link seems to be defined by a foreach iteration on line 140. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
192
193
        if ($rightFromResourceLink->count()) {
194
            // Taken rights from the link
195
            $rights = $rightFromResourceLink;
196
        } else {
197
            // Taken the rights from the default tool
198
            $rights = $link->getResourceNode()->getTool()->getToolResourceRights();
199
        }
200
201
        // Asked mask
202
        $mask = new MaskBuilder();
203
        $mask->add($attribute);
204
        $askedMask = $mask->get();
205
206
        // Check all the right this link has.
207
        $roles = [];
208
        foreach ($rights as $right) {
209
            $roles[$right->getMask()] = $right->getRole();
210
        }
211
212
        // Setting zend simple ACL
213
        $acl = new Acl();
214
215
        // Creating roles
216
        // @todo move this in a service
217
        $userRole = new Role('ROLE_USER');
218
        $teacher = new Role(self::ROLE_CURRENT_COURSE_TEACHER);
219
        $student = new Role(self::ROLE_CURRENT_COURSE_STUDENT);
220
        $superAdmin = new Role('ROLE_SUPER_ADMIN');
221
        $admin = new Role('ROLE_ADMIN');
222
223
        // Adding roles to the ACL
224
        // User role
225
        $acl->addRole($userRole);
226
        // Adds role student
227
        $acl->addRole($student);
228
        // Adds teacher role, inherit student role
229
        $acl->addRole($teacher, $student);
230
        $acl->addRole($superAdmin);
231
        $acl->addRole($admin);
232
233
        // Adds a resource
234
        $resource = new Resource($link);
235
        $acl->addResource($resource);
236
237
        // Role and permissions settings
238
        // Students can view
239
240
        // Student can just view (read)
241
        $acl->allow($student, null, self::getReaderMask());
242
243
        // Teacher can view/edit
244
        $acl->allow(
245
            $teacher,
246
            null,
247
            [
248
                self::getReaderMask(),
249
                self::getEditorMask(),
250
            ]
251
        );
252
253
        // Admin can do everything
254
        $acl->allow($admin);
255
        $acl->allow($superAdmin);
256
257
        foreach ($user->getRoles() as $role) {
258
            if ($acl->isAllowed($role, $resource, $askedMask)) {
259
260
                //dump('passed');
261
                return true;
262
            }
263
        }
264
265
        //dump('not allowed to '.$attribute);
266
267
        return false;
268
    }
269
}
270