From bfda337488dd1b6f1d78f952669bfb244fd1dc2f Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Fri, 30 Jan 2015 15:55:37 +0100 Subject: [PATCH] Adds roles to handle CRUD permissions. ROLE_CURRENT_COURSE_STUDENT and ROLE_CURRENT_COURSE_TEACHER --- app/AppKernel.php | 2 +- app/config/config.yml | 6 +- app/config/security.yml | 10 +- main/inc/lib/api.lib.php | 4 +- src/Chamilo/CoreBundle/Entity/Course.php | 73 ++++- .../Entity/Manager/CourseManager.php | 20 -- src/Chamilo/CoreBundle/Entity/Session.php | 31 +- .../CoreBundle/Entity/ToolResourceRights.php | 45 +-- .../CoreBundle/Resources/config/services.yml | 15 +- .../Authorization/Voter/CourseVoter.php | 75 ++--- .../Authorization/Voter/ResourceLinkVoter.php | 133 --------- .../Authorization/Voter/ResourceNodeVoter.php | 268 ++++++++++++++++++ .../Authorization/Voter/SessionVoter.php | 125 ++++++++ .../EventListener/CourseAccessListener.php | 15 +- .../EventListener/CourseListener.php | 32 ++- .../Controller/NotebookController.php | 160 +++++------ .../Resources/views/Notebook/index.html.twig | 2 + 17 files changed, 654 insertions(+), 362 deletions(-) delete mode 100644 src/Chamilo/CoreBundle/Security/Authorization/Voter/ResourceLinkVoter.php create mode 100644 src/Chamilo/CoreBundle/Security/Authorization/Voter/ResourceNodeVoter.php create mode 100644 src/Chamilo/CoreBundle/Security/Authorization/Voter/SessionVoter.php diff --git a/app/AppKernel.php b/app/AppKernel.php index e6050bca0c..0313469849 100644 --- a/app/AppKernel.php +++ b/app/AppKernel.php @@ -34,7 +34,7 @@ class AppKernel extends Kernel new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(), new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(), new JMS\AopBundle\JMSAopBundle(), - new JMS\SecurityExtraBundle\JMSSecurityExtraBundle(), + //new JMS\SecurityExtraBundle\JMSSecurityExtraBundle(), new Symfony\Bundle\AsseticBundle\AsseticBundle(), // Doctrine diff --git a/app/config/config.yml b/app/config/config.yml index 91c370b1fc..4dcc2fcd91 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -177,8 +177,8 @@ swiftmailer: username: %mailer_user% password: %mailer_password% -jms_security_extra: - secure_all_services: false +#jms_security_extra: +# secure_all_services: false jms_serializer: metadata: @@ -297,4 +297,4 @@ liip_theme: # inject_on_load: false # delete_on_update: true # delete_on_remove: true -# directory_namer: chamilo_core.directory_namer.user_image +# directory_namer: chamilo_core.naming.user_image diff --git a/app/config/security.yml b/app/config/security.yml index 8c335da07a..d00bf5fe17 100644 --- a/app/config/security.yml +++ b/app/config/security.yml @@ -12,6 +12,7 @@ security: - ROLE_TEACHER - ROLE_DIRECTOR - ROLE_JURY_PRESIDENT + - ROLE_CURRENT_COURSE_TEACHER ROLE_SUPER_ADMIN: [ROLE_SONATA_ADMIN, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH] ROLE_GLOBAL_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH] ROLE_RRHH: [ROLE_TEACHER] @@ -19,9 +20,14 @@ security: ROLE_QUESTION_MANAGER: [ROLE_STUDENT, ROLE_QUESTION_MANAGER] ROLE_SESSION_MANAGER: [ROLE_STUDENT, ROLE_SESSION_MANAGER, ROLE_ALLOWED_TO_SWITCH] ROLE_STUDENT: [ROLE_STUDENT] + ROLE_CURRENT_TEACHER: [] + ROLE_CURRENT_COURSE_STUDENT: [ROLE_CURRENT_COURSE_STUDENT] + ROLE_CURRENT_COURSE_TEACHER: [ROLE_CURRENT_COURSE_TEACHER, ROLE_CURRENT_COURSE_STUDENT] + ROLE_ANONYMOUS: [ROLE_ANONYMOUS] access_decision_manager: + # strategy can be: affirmative, unanimous or consensus strategy: unanimous providers: @@ -87,5 +93,5 @@ security: - { path: ^/profile/, role: IS_AUTHENTICATED_FULLY } - { path: ^/.*, role: IS_AUTHENTICATED_ANONYMOUSLY } - acl: - connection: default +# acl: +# connection: default diff --git a/main/inc/lib/api.lib.php b/main/inc/lib/api.lib.php index 77002d8468..d7a2c83bf7 100644 --- a/main/inc/lib/api.lib.php +++ b/main/inc/lib/api.lib.php @@ -2484,7 +2484,7 @@ function api_display_tool_title($title_element) { * @todo rewrite code so it is easier to understand */ function api_display_tool_view_option() { - if (api_get_setting('student_view_enabled') != 'true') { + if (api_get_setting('course.student_view_enabled') != 'true') { return ''; } @@ -2626,7 +2626,7 @@ function api_is_allowed_to_edit($tutor = false, $coach = false, $session_coach = } // Check if the student_view is enabled, and if so, if it is activated. - if (api_get_setting('student_view_enabled') == 'true') { + if (api_get_setting('course.student_view_enabled') == 'true') { $studentViewSession = Session::read('studentview'); if (!empty($my_session_id)) { // Check if session visibility is read only for coachs diff --git a/src/Chamilo/CoreBundle/Entity/Course.php b/src/Chamilo/CoreBundle/Entity/Course.php index a6f24136fc..f7ea24ea9f 100644 --- a/src/Chamilo/CoreBundle/Entity/Course.php +++ b/src/Chamilo/CoreBundle/Entity/Course.php @@ -374,6 +374,28 @@ class Course return $this->users; } + /** + * @return ArrayCollection + */ + public function getTeachers() + { + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('status', User::COURSE_MANAGER)); + + return $this->users->matching($criteria); + } + + /** + * @return ArrayCollection + */ + public function getStudents() + { + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->eq('status', User::STUDENT)); + + return $this->users->matching($criteria); + } + /** * @param ArrayCollection $users */ @@ -387,14 +409,14 @@ class Course } /** - * @param CourseRelUser $user + * @param CourseRelUser $courseRelUser */ - public function addUsers(CourseRelUser $user) + public function addUsers(CourseRelUser $courseRelUser) { - $user->setCourse($this); + $courseRelUser->setCourse($this); - if (!$this->hasUser($user)) { - $this->users[] = $user; + if (!$this->hasSubscription($courseRelUser)) { + $this->users[] = $courseRelUser; } } @@ -402,7 +424,7 @@ class Course * @param CourseRelUser $subscription * @return bool */ - public function hasUser(CourseRelUser $subscription) + private function hasSubscription(CourseRelUser $subscription) { if ($this->getUsers()->count()) { $criteria = Criteria::create()->where( @@ -421,6 +443,45 @@ class Course return false; } + /** + * @param User $user + * @return bool + */ + public function hasUser(User $user) + { + $criteria = Criteria::create()->where( + Criteria::expr()->eq("user", $user) + ); + + return $this->getUsers()->matching($criteria)->count() > 0; + } + + /** + * @param User $user + * @return bool + */ + public function hasStudent(User $user) + { + $criteria = Criteria::create()->where( + Criteria::expr()->eq("user", $user) + ); + + return $this->getStudents()->matching($criteria)->count() > 0; + } + + /** + * @param User $user + * @return bool + */ + public function hasTeacher(User $user) + { + $criteria = Criteria::create()->where( + Criteria::expr()->eq("user", $user) + ); + + return $this->getTeachers()->matching($criteria)->count() > 0; + } + /** * Remove $user * diff --git a/src/Chamilo/CoreBundle/Entity/Manager/CourseManager.php b/src/Chamilo/CoreBundle/Entity/Manager/CourseManager.php index 7d93253bb9..cafd6ab236 100644 --- a/src/Chamilo/CoreBundle/Entity/Manager/CourseManager.php +++ b/src/Chamilo/CoreBundle/Entity/Manager/CourseManager.php @@ -42,24 +42,4 @@ class CourseManager extends BaseEntityManager { return $this->getRepository()->findOneByTitle($name); } - - /** - * @param User $user - * @param Course $course - * @return bool - */ - public function isUserSubscribedInCourse(User $user, Course $course) - { - $userCollection = $course->getUsers(); - $criteria = Criteria::create() - ->where(Criteria::expr()->eq("user", $user)); - - $userCollection = $userCollection->matching($criteria); - - if ($userCollection->count()) { - return true; - } - - return false; - } } diff --git a/src/Chamilo/CoreBundle/Entity/Session.php b/src/Chamilo/CoreBundle/Entity/Session.php index ee63062db4..dedf176fb2 100644 --- a/src/Chamilo/CoreBundle/Entity/Session.php +++ b/src/Chamilo/CoreBundle/Entity/Session.php @@ -169,6 +169,11 @@ class Session **/ protected $userCourseSubscriptions; + /** + * @var Course + **/ + protected $currentCourse; + /** * Constructor */ @@ -354,7 +359,8 @@ class Session /** * @param User $user * @param Course $course - * @param int $status + * @param int $status if not set it will check if the user is registered + * with any status * * @return bool */ @@ -371,7 +377,7 @@ class Session * * @return bool */ - public function hasStudentInCourseWithStatus(User $user, Course $course) + public function hasStudentInCourse(User $user, Course $course) { return $this->hasUserInCourse($user, $course, self::STUDENT); } @@ -853,4 +859,25 @@ class Session return false; } + + /** + * @return Course + */ + public function getCurrentCourse() + { + return $this->currentCourse; + } + + /** + * @param Course $course + * @return $this + */ + public function setCurrentCourse(Course $course) + { + // If the session is registered in the course session list. + if ($this->getCourses()->contains($course->getId())) { + $this->currentCourse = $course; + } + return $this; + } } diff --git a/src/Chamilo/CoreBundle/Entity/ToolResourceRights.php b/src/Chamilo/CoreBundle/Entity/ToolResourceRights.php index 1f846f1d69..a5c2cd8b2d 100644 --- a/src/Chamilo/CoreBundle/Entity/ToolResourceRights.php +++ b/src/Chamilo/CoreBundle/Entity/ToolResourceRights.php @@ -3,10 +3,8 @@ namespace Chamilo\CoreBundle\Entity; +use Chamilo\CoreBundle\Security\Authorization\Voter\ResourceNodeVoter; use Doctrine\ORM\Mapping as ORM; -use Sonata\AdminBundle\Security\Acl\Permission\AdminPermissionMap; -use Symfony\Component\Security\Acl\Permission\BasicPermissionMap; -use Symfony\Component\Security\Acl\Permission\MaskBuilder; /** * Tool @@ -139,49 +137,12 @@ class ToolResourceRights */ public static function getMaskList() { - $builder = new MaskBuilder(); - $builder - ->add('VIEW') - ; - - $readerMask = $builder->get(); - - $builder = new MaskBuilder(); - $builder - ->add('EDIT') - ; - - $editorMask = $builder->get(); + $readerMask = ResourceNodeVoter::getReaderMask(); + $editorMask = ResourceNodeVoter::getEditorMask(); return array( $readerMask => 'Can read', $editorMask => 'Can edit' ); } - - /** - * @return int - */ - public static function getReaderMask() - { - $builder = new MaskBuilder(); - $builder - ->add('VIEW') - ; - - return $builder->get(); - } - - /** - * @return int - */ - public static function getEditorMask() - { - $builder = new MaskBuilder(); - $builder - ->add('EDIT') - ; - - return $builder->get(); - } } diff --git a/src/Chamilo/CoreBundle/Resources/config/services.yml b/src/Chamilo/CoreBundle/Resources/config/services.yml index 3afb122f7e..a036401c6b 100644 --- a/src/Chamilo/CoreBundle/Resources/config/services.yml +++ b/src/Chamilo/CoreBundle/Resources/config/services.yml @@ -26,21 +26,28 @@ services: tags: - { name: twig.extension } - chamilo_core.security.authorization.voter.course: + chamilo_core.security.authorization.voter.course_voter: class: Chamilo\CoreBundle\Security\Authorization\Voter\CourseVoter - arguments: [ @doctrine.orm.entity_manager, @chamilo_core.manager.course ] + arguments: [ @doctrine.orm.entity_manager, @chamilo_core.manager.course, @service_container] public: false tags: - { name: security.voter } - chamilo_core.security.authorization.voter.resource_link: + chamilo_core.security.authorization.voter.session_voter: + class: Chamilo\CoreBundle\Security\Authorization\Voter\SessionVoter + arguments: [ @doctrine.orm.entity_manager, @chamilo_core.manager.course, @service_container] + public: false + tags: + - { name: security.voter } + + chamilo_core.security.authorization.voter.resource_node_voter: class: Chamilo\CoreBundle\Security\Authorization\Voter\ResourceNodeVoter public: false arguments: [ @service_container ] tags: - { name: security.voter } - chamilo_core.directory_namer.user_image: + chamilo_core.naming.user_image: class: Chamilo\CoreBundle\Naming\UserImage chamilo_core.form.type.yes_no: diff --git a/src/Chamilo/CoreBundle/Security/Authorization/Voter/CourseVoter.php b/src/Chamilo/CoreBundle/Security/Authorization/Voter/CourseVoter.php index 0e35a8653d..1542c0283c 100644 --- a/src/Chamilo/CoreBundle/Security/Authorization/Voter/CourseVoter.php +++ b/src/Chamilo/CoreBundle/Security/Authorization/Voter/CourseVoter.php @@ -7,6 +7,7 @@ use Chamilo\CoreBundle\Entity\Course; use Chamilo\CoreBundle\Entity\Manager\CourseManager; use Chamilo\UserBundle\Entity\User; use Doctrine\ORM\EntityManager; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\Security\Core\Authorization\Voter\AbstractVoter; use Symfony\Component\Security\Core\User\UserInterface; @@ -16,8 +17,9 @@ use Symfony\Component\Security\Core\User\UserInterface; */ class CourseVoter extends AbstractVoter { - const VIEW = 'view'; - const EDIT = 'edit'; + const VIEW = 'VIEW'; + const EDIT = 'EDIT'; + const DELETE = 'DELETE'; private $entityManager; private $courseManager; @@ -25,14 +27,17 @@ class CourseVoter extends AbstractVoter /** * @param EntityManager $entityManager * @param CourseManager $courseManager + * @param ContainerInterface $container */ public function __construct( EntityManager $entityManager, - CourseManager $courseManager + CourseManager $courseManager, + ContainerInterface $container ) { $this->entityManager = $entityManager; $this->courseManager = $courseManager; + $this->container = $container; } /** @@ -56,7 +61,7 @@ class CourseVoter extends AbstractVoter */ protected function getSupportedAttributes() { - return array(self::VIEW, self::EDIT); + return array(self::VIEW, self::EDIT, self::DELETE); } /** @@ -80,49 +85,45 @@ class CourseVoter extends AbstractVoter return false; } - $courseManager = $this->getCourseManager(); + $authChecker = $this->container->get('security.authorization_checker'); - switch ($attribute) { - case self::VIEW: - $session = $course->getCurrentSession(); - if (empty($session)) { - - // "Open to the world" - if ($course->isPublic()) { - //return true; - } + // Admins have access to everything + if ($authChecker->isGranted('ROLE_ADMIN')) { + dump('Im admin'); + // return true; + } - // User is subscribed in the user list. - $userIsSubscribed = $courseManager->isUserSubscribedInCourse( - $user, - $course - ); + // Is an active course + if (!$course->isActive()) { + dump('Course is not active'); + return false; + } - if ($userIsSubscribed) { - dump('user_is_subscribed'); - return true; - } + switch ($attribute) { + case self::VIEW: + // "Open to the world" no need to check if user is registered + if ($course->isPublic()) { + dump('Course is public'); + return true; + } - // Is an active course - if ($course->isActive()) { - //return true; - } - } else { - // Course in a session. - if ($session->isActive() && $course->isActive()) { - return true; - } + // User is subscribed in the course no matter if is teacher/student + if ($course->hasUser($user)) { + dump('User is subscribed in course'); + $user->addRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_STUDENT); + return true; } break; case self::EDIT: - // Teacher - // @todo - if ($user->getId() === $course->getOwner()->getId()) { + case self::DELETE: + // Only teacher can edit stuff + if ($course->hasTeacher($user)) { + $user->addRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER); return true; } break; } - dump('Course voter false!'); - return true; + dump("You dont have access to this course!!"); + return false; } } diff --git a/src/Chamilo/CoreBundle/Security/Authorization/Voter/ResourceLinkVoter.php b/src/Chamilo/CoreBundle/Security/Authorization/Voter/ResourceLinkVoter.php deleted file mode 100644 index d5e00ddeaf..0000000000 --- a/src/Chamilo/CoreBundle/Security/Authorization/Voter/ResourceLinkVoter.php +++ /dev/null @@ -1,133 +0,0 @@ -container = $container; - } - - /** - * {@inheritdoc} - */ - protected function getSupportedAttributes() - { - return array( - self::VIEW, - self::EDIT, - self::DELETE - ); - } - - /** - * {@inheritdoc} - */ - protected function getSupportedClasses() - { - return array('Chamilo\CoreBundle\Entity\Resource\ResourceLink'); - } - - /** - * @param string $attribute - * @param ResourceLink $resourceLink - * @param null $user - * - * @return bool - */ - protected function isGranted($attribute, $resourceLink, $user = null) - { - // make sure there is a user object (i.e. that the user is logged in) - if (!$user instanceof UserInterface) { - return false; - } - - // Checking admin roles - $authChecker = $this->container->get('security.authorization_checker'); - $adminRoles = array( - 'ROLE_SUPER_ADMIN', - 'ROLE_ADMIN' - ); - - foreach ($adminRoles as $adminRole) { - if ($authChecker->isGranted($adminRole)) { - //return true; - } - } - - $userSent = $resourceLink->getUser(); - - // Owner. - if ($userSent instanceof UserInterface && - $user->getUsername() == $userSent->getUsername()) { - - return true; - } - - // Getting user rights - $rightFromResourceLink = $resourceLink->getRights(); - - if ($rightFromResourceLink->count()) { - // Taken rights of the link - $rights = $rightFromResourceLink; - } else { - // Taken the rights from the default tool - $rights = $resourceLink->getResourceNode()->getTool()->getToolResourceRights(); - } - - $roles = array(); - foreach ($rights as $right) { - $roles[$right->getRole()] = $right->getMask(); - } - - $mask = new MaskBuilder(); - $mask->add($attribute); - $code = $mask->get(); - - switch ($attribute) { - case self::VIEW: - foreach ($user->getRoles() as $role) { - if (isset($roles[$role]) && $roles[$role] == $code) { - dump('return true'); - return true; - } - } - dump('return false'); - return false; - case self::EDIT: - break; - } - - // Course is visible? - if ($attribute == self::VIEW) { - return true; - } - - return false; - } -} diff --git a/src/Chamilo/CoreBundle/Security/Authorization/Voter/ResourceNodeVoter.php b/src/Chamilo/CoreBundle/Security/Authorization/Voter/ResourceNodeVoter.php new file mode 100644 index 0000000000..b45fdd588d --- /dev/null +++ b/src/Chamilo/CoreBundle/Security/Authorization/Voter/ResourceNodeVoter.php @@ -0,0 +1,268 @@ +container = $container; + } + + /** + * {@inheritdoc} + */ + protected function getSupportedAttributes() + { + return array( + self::VIEW, + self::CREATE, + self::EDIT, + self::DELETE, + self::EXPORT + ); + } + + /** + * {@inheritdoc} + */ + protected function getSupportedClasses() + { + return array('Chamilo\CoreBundle\Entity\Resource\ResourceNode'); + } + + /** + * @param string $attribute + * @param ResourceNode $resourceNode + * @param null $user + * + * @return bool + */ + protected function isGranted($attribute, $resourceNode, $user = null) + { + // Make sure there is a user object (i.e. that the user is logged in) + if (!$user instanceof UserInterface) { + return false; + } + + // Checking admin roles + $authChecker = $this->container->get('security.authorization_checker'); + + // Admins have access to everything + if ($authChecker->isGranted('ROLE_ADMIN')) { + // return true; + } + + // Check if I'm the owner + $creator = $resourceNode->getCreator(); + + if ($creator instanceof UserInterface && + $user->getUsername() == $creator->getUsername()) { + + //return true; + } + + // Checking possible links connected to this resource + $request = $this->container->get('request_stack')->getCurrentRequest(); + + $courseCode = $request->get('course'); + $sessionId = $request->get('session'); + + $links = $resourceNode->getLinks(); + $linkFound = false; + + /** @var ResourceLink $link */ + foreach ($links as $link) { + $linkUser = $link->getUser(); + $linkCourse = $link->getCourse(); + $linkSession = $link->getSession(); + $linkUserGroup = $link->getUserGroup(); + + // Check if resource was sent to the current user + if ($linkUser instanceof UserInterface && + $linkUser->getUsername() == $creator->getUsername() + ) { + $linkFound = true; + break; + } + + // @todo Check if resource was sent to a usergroup + // @todo Check if resource was sent to a group inside a course + + // Check if resource was sent to a course inside a session + if ($linkSession instanceof Session && !empty($sessionId) && + $linkCourse instanceof Course && !empty($courseCode) + ) { + $session = $this->container->get('chamilo_core.manager.session')->find($sessionId); + $course = $this->container->get('chamilo_core.manager.course')->findOneByCode($courseCode); + if ($session instanceof Session && + $course instanceof Course && + $linkCourse->getCode() == $course->getCode() && + $linkSession->getId() == $session->getId() + ) { + $linkFound = true; + break; + } + } + + // Check if resource was sent to a course + if ($linkCourse instanceof Course && !empty($courseCode)) { + $course = $this->container->get('chamilo_core.manager.course')->findOneByCode($courseCode); + if ($course instanceof Course && + $linkCourse->getCode() == $course->getCode() + ) { + $linkFound = true; + break; + } + } + } + + // No link was found! + if ($linkFound === false) { + return false; + } + + // Getting rights from the link + $rightFromResourceLink = $link->getRights(); + + if ($rightFromResourceLink->count()) { + // Taken rights from the link + $rights = $rightFromResourceLink; + } else { + // Taken the rights from the default tool + $rights = $link->getResourceNode()->getTool()->getToolResourceRights(); + } + + // Asked mask + $mask = new MaskBuilder(); + $mask->add($attribute); + $askedMask = $mask->get(); + + // Check all the right this link has. + $roles = array(); + foreach ($rights as $right) { + $roles[$right->getMask()] = $right->getRole(); + } + + // Setting zend simple ACL + $acl = new Acl(); + + // Creating roles + // @todo move this in a service + $userRole = new Role('ROLE_USER'); + $teacher = new Role(self::ROLE_CURRENT_COURSE_TEACHER); + $student = new Role(self::ROLE_CURRENT_COURSE_STUDENT); + $superAdmin = new Role('ROLE_SUPER_ADMIN'); + $admin = new Role('ROLE_ADMIN'); + + // Adding roles to the ACL + // User role + $acl->addRole($userRole); + // Adds role student + $acl->addRole($student); + // Adds teacher role, inherit student role + $acl->addRole($teacher, $student); + $acl->addRole($superAdmin); + $acl->addRole($admin); + + // Adds a resource + $resource = new Resource($link); + $acl->addResource($resource); + + // Role and permissions settings + // Students can view + + // Student can just view (read) + $acl->allow($student, null, self::getReaderMask()); + + // Teacher can view/edit + $acl->allow( + $teacher, + null, + array( + self::getReaderMask(), + self::getEditorMask() + ) + ); + + // Admin can do everything + $acl->allow($admin); + $acl->allow($superAdmin); + + foreach ($user->getRoles() as $role) { + if ($acl->isAllowed($role, $resource, $askedMask)) { + dump('passed'); + return true; + } + } + + dump('not allowed to '.$attribute); + + return false; + } + + /** + * @return int + */ + public static function getReaderMask() + { + $builder = new MaskBuilder(); + $builder + ->add(self::VIEW) + ; + + return $builder->get(); + } + + /** + * @return int + */ + public static function getEditorMask() + { + $builder = new MaskBuilder(); + $builder + ->add(self::EDIT) + ; + + return $builder->get(); + } + +} diff --git a/src/Chamilo/CoreBundle/Security/Authorization/Voter/SessionVoter.php b/src/Chamilo/CoreBundle/Security/Authorization/Voter/SessionVoter.php new file mode 100644 index 0000000000..7318fb6bc4 --- /dev/null +++ b/src/Chamilo/CoreBundle/Security/Authorization/Voter/SessionVoter.php @@ -0,0 +1,125 @@ +entityManager = $entityManager; + $this->courseManager = $courseManager; + $this->container = $container; + } + + /** + * @return EntityManager + */ + public function getEntityManager() + { + return $this->entityManager; + } + + /** + * @return CourseManager + */ + public function getCourseManager() + { + return $this->courseManager; + } + + /** + * {@inheritdoc} + */ + protected function getSupportedAttributes() + { + return array(self::VIEW, self::EDIT, self::DELETE); + } + + /** + * {@inheritdoc} + */ + protected function getSupportedClasses() + { + return array('Chamilo\CoreBundle\Entity\Session'); + } + + /** + * @param string $attribute + * @param Session $session + * @param User $user + * @return bool + */ + protected function isGranted($attribute, $session, $user = null) + { + // make sure there is a user object (i.e. that the user is logged in) + if (!$user instanceof UserInterface) { + return false; + } + // Checks if the current user was set up + $course = $session->getCurrentCourse(); + + if ($course == false) { + return false; + } + + $authChecker = $this->container->get('security.authorization_checker'); + + // Admins have access to everything + if ($authChecker->isGranted('ROLE_ADMIN')) { + // return true; + } + + if (!$session->isActive()) { + return false; + } + + switch ($attribute) { + case self::VIEW: + if (!$session->hasUserInCourse($user, $course)) { + $user->addRole('ROLE_CURRENT_SESSION_COURSE_STUDENT'); + return true; + } + + break; + case self::EDIT: + case self::DELETE: + if (!$session->hasCoachInCourseWithStatus($user, $course)) { + $user->addRole('ROLE_CURRENT_SESSION_COURSE_TEACHER'); + return true; + } + break; + } + dump("You dont have access to this session!!"); + return false; + } +} diff --git a/src/Chamilo/CourseBundle/EventListener/CourseAccessListener.php b/src/Chamilo/CourseBundle/EventListener/CourseAccessListener.php index ab66e0df69..b2c583ceba 100644 --- a/src/Chamilo/CourseBundle/EventListener/CourseAccessListener.php +++ b/src/Chamilo/CourseBundle/EventListener/CourseAccessListener.php @@ -30,13 +30,14 @@ class CourseAccessListener { $user = $event->getUser(); $course = $event->getCourse(); + if ($user && $course) { + $trackAccess = new TrackEAccess(); + $trackAccess->setCId($course->getId()); + $trackAccess->setAccessUserId($user->getId()); + $trackAccess->setAccessSessionId(0); - $trackAccess = new TrackEAccess(); - $trackAccess->setCId($course->getId()); - $trackAccess->setAccessUserId($user->getId()); - $trackAccess->setAccessSessionId(0); - - $this->em->persist($trackAccess); - $this->em->flush(); + $this->em->persist($trackAccess); + $this->em->flush(); + } } } diff --git a/src/Chamilo/CourseBundle/EventListener/CourseListener.php b/src/Chamilo/CourseBundle/EventListener/CourseListener.php index 0cb32bfc50..9383c14ae4 100644 --- a/src/Chamilo/CourseBundle/EventListener/CourseListener.php +++ b/src/Chamilo/CourseBundle/EventListener/CourseListener.php @@ -3,7 +3,10 @@ namespace Chamilo\CourseBundle\EventListener; +use Chamilo\CoreBundle\Security\Authorization\Voter\CourseVoter; +use Chamilo\CoreBundle\Security\Authorization\Voter\SessionVoter; use Doctrine\ORM\EntityManager; +use Chamilo\UserBundle\Entity\User; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\Event\FilterResponseEvent; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -11,6 +14,7 @@ use Symfony\Component\HttpKernel\Event\FilterControllerEvent; use Chamilo\CourseBundle\Controller\ToolInterface; use Chamilo\CoreBundle\Entity\Course; use Chamilo\CoreBundle\Entity\Session; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\Security\Core\Exception\AccessDeniedException; /** @@ -80,6 +84,8 @@ class CourseListener $em = $container->get('doctrine')->getManager(); $securityChecker = $container->get('security.authorization_checker'); + /** @var User $user */ + $user = $container->get('security.token_storage')->getToken()->getUser(); if (!empty($courseCode)) { /** @var Course $course */ @@ -88,20 +94,28 @@ class CourseListener // Session $sessionId = $request->get('id_session'); - if (!empty($sessionId)) { + if (empty($sessionId)) { + // Check if user is allowed to this course + // See CourseVoter.php + if (false === $securityChecker->isGranted(CourseVoter::VIEW, $course)) { + throw new AccessDeniedException('Unauthorised access to course!'); + } + } else { $session = $em->getRepository('ChamiloCoreBundle:Session')->find($sessionId); if ($session) { - $course->setCurrentSession($session); + //$course->setCurrentSession($session); $controller[0]->setSession($session); + $session->setCurrentCourse($course); + // Check if user is allowed to this course-session + // See SessionVoter.php + if (false === $securityChecker->isGranted(SessionVoter::VIEW, $session)) { + throw new AccessDeniedException('Unauthorised access to session!'); + } + } else { + throw new NotFoundHttpException('Session not found'); } } - // Check if user is allowed to this course / course-session - // See CourseVoter.php - if (false === $securityChecker->isGranted('view', $course)) { - throw new AccessDeniedException('Unauthorised access!'); - } - // Legacy code $courseInfo = api_get_course_info($course->getCode()); @@ -114,6 +128,8 @@ class CourseListener Sets the controller course in order to use $this->getCourse() */ $controller[0]->setCourse($course); + } else { + throw new NotFoundHttpException('Course not found'); } } } diff --git a/src/Chamilo/NotebookBundle/Controller/NotebookController.php b/src/Chamilo/NotebookBundle/Controller/NotebookController.php index 1c934882b4..6b84c2a092 100644 --- a/src/Chamilo/NotebookBundle/Controller/NotebookController.php +++ b/src/Chamilo/NotebookBundle/Controller/NotebookController.php @@ -14,7 +14,7 @@ use Chamilo\NotebookBundle\Tool\Notebook; use Doctrine\ORM\QueryBuilder; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; -use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpFoundation\Response; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; use APY\DataGridBundle\Grid\Source\Entity; @@ -45,7 +45,7 @@ class NotebookController extends ToolBaseCrudController public function indexAction(Request $request) { /*if (false === $this->get('security.authorization_checker')->isGranted('view', $course)) { - throw new AccessDeniedException('Unauthorised access!'); + throw new AccessDeniedHttpException('Unauthorised access!'); }*/ $source = new Entity('ChamiloNotebookBundle:CNotebook'); @@ -85,17 +85,18 @@ class NotebookController extends ToolBaseCrudController } );*/ - //$deleteMassAction = new MassAction('Delete', 'ChamiloNotebookBundle:CNotebook:deleteMass'); - $deleteMassAction = new MassAction( - 'Delete', - 'chamilo.controller.notebook:deleteMassAction', - true, - array('course' => $request->get('course')) - ); - $grid->addMassAction($deleteMassAction); + if ($this->isGranted(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER)) { + $deleteMassAction = new MassAction( + 'Delete', + 'chamilo.controller.notebook:deleteMassAction', + true, + array('course' => $request->get('course')) + ); + $grid->addMassAction($deleteMassAction); + } $myRowAction = new RowAction( - 'View', + $this->trans('View'), 'chamilo_notebook_show', false, '_self', @@ -104,35 +105,38 @@ class NotebookController extends ToolBaseCrudController $myRowAction->setRouteParameters(array('course' => $course, 'id')); $grid->addRowAction($myRowAction); - $myRowAction = new RowAction( - 'Edit', - 'chamilo_notebook_edit', - false, - '_self', - array('class' => 'btn btn-info') - ); - $myRowAction->setRouteParameters(array('course' => $course, 'id')); - $grid->addRowAction($myRowAction); + if ($this->isGranted(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER)) { - $myRowAction = new RowAction( - 'Delete', - 'chamilo_notebook_delete', - false, - '_self', - array('class' => 'btn btn-danger', 'form_delete' => true) - ); - $myRowAction->setRouteParameters(array('course' => $course, 'id')); - $grid->addRowAction($myRowAction); + $myRowAction = new RowAction( + $this->trans('Edit'), + 'chamilo_notebook_edit', + false, + '_self', + array('class' => 'btn btn-info') + ); + $myRowAction->setRouteParameters(array('course' => $course, 'id')); + $grid->addRowAction($myRowAction); + + $myRowAction = new RowAction( + $this->trans('Delete'), + 'chamilo_notebook_delete', + false, + '_self', + array('class' => 'btn btn-danger', 'form_delete' => true) + ); + $myRowAction->setRouteParameters(array('course' => $course, 'id')); + $grid->addRowAction($myRowAction); + } $grid->addExport( new CSVExport( - 'CSV Export', 'export', array('course' => $course) + $this->trans('CSV Export'), 'export', array('course' => $course) ) ); $grid->addExport( new ExcelExport( - 'Excel Export', + $this->trans('Excel Export'), 'export', array('course' => $course) ) @@ -155,9 +159,11 @@ class NotebookController extends ToolBaseCrudController $resource = $this->findOr404($request); $resourceNode = $resource->getResourceNode(); - if (false === $this->isGranted(ResourceNodeVoter::VIEW, $resourceNode)) { - throw new AccessDeniedException('Unauthorised access!'); - } + $this->denyAccessUnlessGranted( + ResourceNodeVoter::VIEW, + $resourceNode, + 'Unauthorised access to resource' + ); $view = $this ->view() @@ -169,62 +175,6 @@ class NotebookController extends ToolBaseCrudController return $this->handleView($view); } - /** - * @param ResourceNode $resourceNode - * @return ResourceLink|null - */ - public function detectLink(ResourceNode $resourceNode) - { - $user = $this->getUser(); - $session = $this->getSession(); - $course = $this->getCourse(); - - /*if ($user->getId() == $resourceNode->getCreator()->getId()) { - - }*/ - - $links = $resourceNode->getLinks(); - - $linkFound = null; - - if (!empty($links)) { - /** @var ResourceLink $link */ - foreach ($links as $link) { - $linkCourse = $link->getCourse(); - $linkSession = $link->getSession(); - $linkUser = $link->getUser(); - - if (isset($course) && isset($session)) { - if ($linkCourse->getId() == $course->getId() && - $linkSession->getId() == $session->getId() - ) { - $linkFound = $link; - break; - } - } - - if (isset($course) && isset($linkCourse)) { - if ($linkCourse->getId() == $course->getId()) { - $linkFound = $link; - break; - } - } - - if (isset($linkUser)) { - if ($linkUser->getId() == $user->getId()) { - $linkFound = $link; - break; - } - } - } - } - - if (empty($linkFound)) { - throw new NotFoundResourceException('Link not found'); - } - return $linkFound; - } - /** * @param Request $request * @@ -236,6 +186,10 @@ class NotebookController extends ToolBaseCrudController $resource = $this->createNew(); $form = $this->getForm($resource); + $this->denyAccessUnlessGranted( + ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER + ); + if ($form->handleRequest($request)->isValid()) { $sharedType = $form->get('shared')->getData(); $shareList = array(); @@ -247,14 +201,14 @@ class NotebookController extends ToolBaseCrudController $shareList = array( array( 'sharing' => 'course', - 'mask' => ToolResourceRights::getReaderMask(), - 'role' => 'ROLE_STUDENT', + 'mask' => ResourceNodeVoter::getReaderMask(), + 'role' => ResourceNodeVoter::ROLE_CURRENT_COURSE_STUDENT, 'search' => $this->getCourse()->getId() ), array( 'sharing' => 'course', - 'mask' => ToolResourceRights::getEditorMask(), - 'role' => 'ROLE_TEACHER', + 'mask' => ResourceNodeVoter::getEditorMask(), + 'role' => ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER, 'search' => $this->getCourse()->getId() ) ); @@ -370,6 +324,15 @@ class NotebookController extends ToolBaseCrudController */ public function updateAction(Request $request) { + $resource = $this->findOr404($request); + $resourceNode = $resource->getResourceNode(); + + $this->denyAccessUnlessGranted( + ResourceNodeVoter::EDIT, + $resourceNode, + 'Unauthorised access to resource' + ); + return parent::updateAction($request); } @@ -398,6 +361,14 @@ class NotebookController extends ToolBaseCrudController { /** @var AbstractResource $resource */ $resource = $this->getRepository()->find($id); + $resourceNode = $resource->getResourceNode(); + + $this->denyAccessUnlessGranted( + ResourceNodeVoter::DELETE, + $resourceNode, + 'Unauthorised access to resource' + ); + $this->domainManager->delete($resource); } @@ -408,5 +379,4 @@ class NotebookController extends ToolBaseCrudController { return $this->get('chamilo_notebook.entity.notebook_manager'); } - } diff --git a/src/Chamilo/NotebookBundle/Resources/views/Notebook/index.html.twig b/src/Chamilo/NotebookBundle/Resources/views/Notebook/index.html.twig index fea3cde10c..dfa9205178 100644 --- a/src/Chamilo/NotebookBundle/Resources/views/Notebook/index.html.twig +++ b/src/Chamilo/NotebookBundle/Resources/views/Notebook/index.html.twig @@ -1,8 +1,10 @@ +{% if is_granted('ROLE_CURRENT_COURSE_TEACHER') %}
{{ 'Add' | trans }}
+{% endif %}
{{ grid_search(grid) }}