Completed
Push — master ( 5f1c93...626f54 )
by Julito
31:28
created

ResourceNodeVoter::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
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\Resource\ResourceRights;
10
use Chamilo\CoreBundle\Entity\Session;
11
use Chamilo\CoreBundle\Entity\ToolResourceRights;
12
use Doctrine\Common\Collections\ArrayCollection;
13
use Sonata\AdminBundle\Security\Acl\Permission\AdminPermissionMap;
14
use Symfony\Component\DependencyInjection\ContainerInterface;
15
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
16
//use Symfony\Component\Security\Core\Authorization\Voter\AbstractVoter;
17
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
18
use Symfony\Component\Security\Core\User\UserInterface;
19
use Zend\Permissions\Acl\Acl;
20
use Zend\Permissions\Acl\Role\GenericRole as Role;
21
//use Zend\Permissions\Acl\Resource\GenericResource as Resource;
22
use Symfony\Component\Security\Acl\Permission\MaskBuilder;
23
24
use Symfony\Component\Security\Core\Authorization\Voter\Voter as AbstractVoter;
25
//use Sonata\AdminBundle\Security\Acl\Permission\MaskBuilder;
26
27
/**
28
 * Class ResourceNodeVoter
29
 * @package Chamilo\CoreBundle\Security\Authorization\Voter
30
 */
31
class ResourceNodeVoter extends AbstractVoter
32
{
33
    private $container;
34
35
    const VIEW = 'VIEW';
36
    const CREATE = 'CREATE';
37
    const EDIT = 'EDIT';
38
    const DELETE = 'DELETE';
39
    const EXPORT = 'EXPORT';
40
41
    const ROLE_CURRENT_COURSE_TEACHER = 'ROLE_CURRENT_COURSE_TEACHER';
42
    const ROLE_CURRENT_COURSE_STUDENT = 'ROLE_CURRENT_COURSE_STUDENT';
43
44
    /**
45
     * Constructor
46
     * @param ContainerInterface $container
47
     */
48
    public function __construct(ContainerInterface $container)
49
    {
50
        $this->container = $container;
51
    }
52
53
    /**
54
     * @inheritdoc
55
     */
56
    protected function supports($attribute, $subject)
57
    {
58
        $options = [
59
            self::VIEW,
60
            self::CREATE,
61
            self::EDIT,
62
            self::DELETE,
63
            self::EXPORT
64
        ];
65
66
        // if the attribute isn't one we support, return false
67
        if (!in_array($attribute, $options)) {
68
            return false;
69
        }
70
71
        // only vote on Post objects inside this voter
72
        if (!$subject instanceof ResourceNode) {
73
            return false;
74
        }
75
76
        return true;
77
    }
78
79
    /**
80
     * @inheritdoc
81
     */
82
    protected function voteOnAttribute($attribute, $resourceNode, TokenInterface $token)
83
    {
84
        $user = $token->getUser();
85
86
        // Make sure there is a user object (i.e. that the user is logged in)
87
        if (!$user instanceof UserInterface) {
88
            return false;
89
        }
90
91
        // Checking admin roles
92
        $authChecker = $this->container->get('security.authorization_checker');
93
94
        // Admins have access to everything
95
        if ($authChecker->isGranted('ROLE_ADMIN')) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
96
             // return true;
97
        }
98
99
        // Check if I'm the owner
100
        /*$creator = $resourceNode->getCreator();
101
        if ($creator instanceof UserInterface &&
102
            $user->getUsername() == $creator->getUsername()) {
103
104
            //return true;
105
        }*/
106
107
        // Checking possible links connected to this resource
108
        $request = $this->container->get('request_stack')->getCurrentRequest();
109
110
        $courseCode = $request->get('course');
111
        $sessionId = $request->get('session');
112
113
        $links = $resourceNode->getLinks();
114
        $linkFound = false;
115
116
        /** @var ResourceLink $link */
117
        foreach ($links as $link) {
118
            $linkUser = $link->getUser();
119
            $linkCourse = $link->getCourse();
120
            $linkSession = $link->getSession();
121
            $linkUserGroup = $link->getUserGroup();
122
123
            // Check if resource was sent to the current user
124
            if ($linkUser instanceof UserInterface &&
125
                $linkUser->getUsername() == $creator->getUsername()
0 ignored issues
show
Bug introduced by
The variable $creator does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
126
            ) {
127
                $linkFound = true;
128
                break;
129
            }
130
131
            // @todo Check if resource was sent to a usergroup
132
            // @todo Check if resource was sent to a group inside a course
133
134
            // Check if resource was sent to a course inside a session
135
            if ($linkSession instanceof Session && !empty($sessionId) &&
136
                $linkCourse instanceof Course && !empty($courseCode)
137
            ) {
138
                $session = $this->container->get('chamilo_core.entity.manager.session_manager')->find($sessionId);
139
                $course = $this->container->get('chamilo_core.entity.manager.course_manager')->findOneByCode($courseCode);
140
                if ($session instanceof Session &&
141
                    $course instanceof Course &&
142
                    $linkCourse->getCode() == $course->getCode() &&
143
                    $linkSession->getId() == $session->getId()
144
                ) {
145
                    $linkFound = true;
146
                    break;
147
                }
148
            }
149
150
            // Check if resource was sent to a course
151
            if ($linkCourse instanceof Course && !empty($courseCode)) {
152
                $course = $this->container->get('chamilo_core.manager.course')->findOneByCode($courseCode);
153
                if ($course instanceof Course &&
154
                    $linkCourse->getCode() == $course->getCode()
155
                ) {
156
                    $linkFound = true;
157
                    break;
158
                }
159
            }
160
        }
161
162
        // No link was found!
163
        if ($linkFound === false) {
164
            return false;
165
        }
166
167
        // Getting rights from the link
168
        $rightFromResourceLink = $link->getRights();
0 ignored issues
show
Bug introduced by
The variable $link seems to be defined by a foreach iteration on line 117. Are you sure the iterator is never empty, otherwise this variable is not defined?

It seems like you are relying on a variable being defined by an iteration:

foreach ($a as $b) {
}

// $b is defined here only if $a has elements, for example if $a is array()
// then $b would not be defined here. To avoid that, we recommend to set a
// default value for $b.


// Better
$b = 0; // or whatever default makes sense in your context
foreach ($a as $b) {
}

// $b is now guaranteed to be defined here.
Loading history...
169
170
        if ($rightFromResourceLink->count()) {
171
            // Taken rights from the link
172
            $rights = $rightFromResourceLink;
173
        } else {
174
            // Taken the rights from the default tool
175
            $rights = $link->getResourceNode()->getTool()->getToolResourceRights();
176
        }
177
178
        // Asked mask
179
        $mask = new MaskBuilder();
180
        $mask->add($attribute);
181
        $askedMask = $mask->get();
182
183
        // Check all the right this link has.
184
        $roles = array();
185
        foreach ($rights as $right) {
186
            $roles[$right->getMask()] = $right->getRole();
187
        }
188
189
        // Setting zend simple ACL
190
        $acl = new Acl();
191
192
        // Creating roles
193
        // @todo move this in a service
194
        $userRole = new Role('ROLE_USER');
195
        $teacher = new Role(self::ROLE_CURRENT_COURSE_TEACHER);
196
        $student = new Role(self::ROLE_CURRENT_COURSE_STUDENT);
197
        $superAdmin = new Role('ROLE_SUPER_ADMIN');
198
        $admin = new Role('ROLE_ADMIN');
199
200
        // Adding roles to the ACL
201
        // User role
202
        $acl->addRole($userRole);
203
        // Adds role student
204
        $acl->addRole($student);
205
        // Adds teacher role, inherit student role
206
        $acl->addRole($teacher, $student);
207
        $acl->addRole($superAdmin);
208
        $acl->addRole($admin);
209
210
        // Adds a resource
211
        $resource = new Resource($link);
212
        $acl->addResource($resource);
213
214
        // Role and permissions settings
215
        // Students can view
216
217
        // Student can just view (read)
218
        $acl->allow($student, null, self::getReaderMask());
219
220
        // Teacher can view/edit
221
        $acl->allow(
222
            $teacher,
223
            null,
224
            array(
225
                self::getReaderMask(),
226
                self::getEditorMask()
227
            )
228
        );
229
230
        // Admin can do everything
231
        $acl->allow($admin);
232
        $acl->allow($superAdmin);
233
234
        foreach ($user->getRoles() as $role) {
235
            if ($acl->isAllowed($role, $resource, $askedMask)) {
0 ignored issues
show
Bug introduced by
It seems like $role defined by $role on line 234 can also be of type object<Symfony\Component\Security\Core\Role\Role>; however, Zend\Permissions\Acl\Acl::isAllowed() does only seem to accept object<Zend\Permissions\...eInterface>|string|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
236
                //dump('passed');
237
                return true;
238
            }
239
        }
240
241
        //dump('not allowed to '.$attribute);
242
243
        return false;
244
    }
245
246
    /**
247
     * @return int
248
     */
249
    public static function getReaderMask()
250
    {
251
        $builder = new MaskBuilder();
252
        $builder
253
            ->add(self::VIEW)
254
        ;
255
256
        return $builder->get();
257
    }
258
259
    /**
260
     * @return int
261
     */
262
    public static function getEditorMask()
263
    {
264
        $builder = new MaskBuilder();
265
        $builder
266
            ->add(self::EDIT)
267
        ;
268
269
        return $builder->get();
270
    }
271
272
}
273