From 3d2080c4c1b2d90813696699755e2481c65b8084 Mon Sep 17 00:00:00 2001 From: Julio Montoya Date: Tue, 3 Dec 2013 18:57:23 +0100 Subject: [PATCH] Authentication redirection changes. - api_not_allowed() now throws an $app->abort() with a 401 error. - code from api_protect_course_script() is now a "before" middleware attached in the legacy controller. - If a user enters a course but he don't have the correct permissions then the login page appears (instead of the classic red message about the cookies and stuff). --- main/inc/global.inc.php | 8 +- main/inc/lib/api.lib.php | 212 ++---------------- main/inc/routes.php | 97 ++++++-- .../Controller/CourseHomeController.php | 3 - 4 files changed, 103 insertions(+), 217 deletions(-) diff --git a/main/inc/global.inc.php b/main/inc/global.inc.php index b72a04ea11..9e509dc807 100644 --- a/main/inc/global.inc.php +++ b/main/inc/global.inc.php @@ -256,11 +256,7 @@ $app->error( Session::setSession($app['session']); - //$code = ($e instanceof HttpException) ? $e->getStatusCode() : 500; - // It seems that error() is executed first than the before() middleware - // @ŧodo check this one $templateStyle = api_get_setting('template'); - $templateStyle = isset($templateStyle) && !empty($templateStyle) ? $templateStyle : 'default'; if (!is_dir($app['sys_root'].'main/template/'.$templateStyle)) { @@ -273,6 +269,10 @@ $app->error( $app['default_layout'] = $app['template_style'].'/layout/layout_1_col.tpl'; /** @var Template $template */ $template = $app['template']; + + $template->setHeader($app['template.show_header']); + $template->setFooter($app['template.show_footer']); + $template->assign('error', array('code' => $code, 'message' => $message)); $response = $template->render_layout('error.tpl'); diff --git a/main/inc/lib/api.lib.php b/main/inc/lib/api.lib.php index 3c4cf19589..48930f275d 100644 --- a/main/inc/lib/api.lib.php +++ b/main/inc/lib/api.lib.php @@ -9,6 +9,9 @@ */ use \ChamiloSession as Session; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\HttpKernelInterface; + /** * Constants declaration @@ -968,68 +971,8 @@ function api_valid_email($address) { * @todo replace global variable * @author Roan Embrechts */ -function api_protect_course_script($print_headers = false, $allow_session_admins = false, $allow_drh = false) { - $is_allowed_in_course = Session::read('is_allowed_in_course'); - $is_visible = false; - - $course_info = api_get_course_info(); - - //If course is not set then is not allowed to enter in a course page - - if (empty($course_info)) { - api_not_allowed($print_headers); - } - - if (api_is_drh()) { - return true; - } - - if (api_is_platform_admin($allow_session_admins)) { - return true; - } - - if (isset($course_info) && isset($course_info['visibility'])) { - switch ($course_info['visibility']) { - default: - case COURSE_VISIBILITY_CLOSED: //Completely closed: the course is only accessible to the teachers. - 0 - if (api_get_user_id() && !api_is_anonymous() && (api_is_allowed_to_edit())) { - $is_visible = true; - } - break; - case COURSE_VISIBILITY_REGISTERED: //Private - access authorized to course members only - 1 - if (api_get_user_id() && !api_is_anonymous() && $is_allowed_in_course) { - $is_visible = true; - } - break; - case COURSE_VISIBILITY_OPEN_PLATFORM: // Open - access allowed for users registered on the platform - 2 - if (api_get_user_id() && !api_is_anonymous()) { - $is_visible = true; - } - break; - case COURSE_VISIBILITY_OPEN_WORLD: //Open - access allowed for the whole world - 3 - $is_visible = true; - break; - } - //If password is set and user is not registered to the course then the course is not visible - if ($is_allowed_in_course == false & isset($course_info['registration_code']) && !empty($course_info['registration_code'])) { - $is_visible = false; - } - } - - //Check session visibility - $session_id = api_get_session_id(); - - if (!empty($session_id)) { - //$is_allowed_in_course was set in local.inc.php - if (!$is_allowed_in_course) { - $is_visible = false; - } - } - - if (!$is_visible) { - api_not_allowed($print_headers); - return false; - } +function api_protect_course_script($print_headers = false, $allow_session_admins = false, $allow_drh = false) +{ return true; } @@ -3011,146 +2954,21 @@ function api_is_anonymous($user_id = null, $db_check = false) { return isset($_user['is_anonymous']) && $_user['is_anonymous'] === true; } -/* - * Returns a not found page - * @todo use templates to customize the not found page - */ -function api_not_found($print_headers = false) { - global $app; - $origin = isset($_GET['origin']) ? $_GET['origin'] : ''; - $show_headers = 0; - if ((!headers_sent() || $print_headers) && $origin != 'learnpath') { - $show_headers = 1; - } - $app['template.show_header'] = $show_headers; - $app['template.show_footer'] = $show_headers; - - $tpl = $app['template']; - $msg = get_lang('NotFound'); - $tpl->assign('content', $msg); - $tpl->display_one_col_template(); -} - /** - * Displays message "You are not allowed here..." and exits the entire script. - * @param bool Whether or not to print headers (default = false -> does not print them) - * - * @author Roan Embrechts - * @author Yannick Warnier - * @author Patrick Cool , Ghent University - * - * @version 1.0, February 2004 - * @version dokeos 1.8, August 2006 + * @param bool $printHeaders + * @param string $message */ -function api_not_allowed($print_headers = false, $message = null) { +function api_not_allowed($printHeaders = false, $message = null) +{ global $app; - - if (api_get_setting('sso_authentication') === 'true') { - global $osso; - if ($osso) { - $osso->logout(); - } - } - - $home_url = api_get_path(WEB_PATH); - $user_id = api_get_user_id(); - $course = api_get_course_id(); - - global $this_section; - - if (!isset($user_id)) { - //Why the CustomPages::enabled() need to be to set the request_uri - $_SESSION['request_uri'] = $_SERVER['REQUEST_URI']; - } - - if (CustomPages::enabled() && !isset($user_id)) { - CustomPages::display(CustomPages::INDEX_UNLOGGED); - } - - $origin = isset($_GET['origin']) ? $_GET['origin'] : ''; - - $msg = null; - if (isset($message)) { - $msg = $message; - } else { - $msg = Display::return_message(get_lang('NotAllowedClickBack'), 'error', false); - } - - $msg = Display::div($msg, array('align'=>'center')); - - $show_headers = 0; - - if ($print_headers && $origin != 'learnpath') { - $show_headers = 1; - } - - $app['template.show_header'] = $show_headers; - $app['template.show_footer'] = $show_headers; - - $app['template']->assign('content', $msg); - $app['allowed'] = true; - - if (($user_id!=0 && !api_is_anonymous()) && (!isset($course) || $course == -1) && empty($_GET['cidReq'])) { - // if the access is not authorized and there is some login information - // but the cidReq is not found, assume we are missing course data and send the user - // to the user_portal - //$tpl->display_one_col_template(); - $app['allowed'] = false; - return false; - } - - if (!empty($_SERVER['REQUEST_URI']) && (!empty($_GET['cidReq']) || $this_section == SECTION_MYPROFILE)) { - - //only display form and return to the previous URL if there was a course ID included - if ($user_id != 0 && !api_is_anonymous()) { - //if there is a user ID, then the user is not allowed but the session is still there. Say so and exit - //$tpl->assign('content', $msg); - $app['template']->assign('content', $msg); - $app['allowed'] = false; - return false; - } - - // If the user has no user ID, then his session has expired - $action = api_get_self().'?'.Security::remove_XSS($_SERVER['QUERY_STRING']); - $action = str_replace('&', '&', $action); - $form = new FormValidator('formLogin', 'post', $action, null, array('class'=>'form-stacked')); - - //$form->addElement('text', 'login', get_lang('UserName'), array('size' => 17)); //old - - $form->addElement('text', 'login', null, array('placeholder' => get_lang('UserName'), 'class' => 'span3 autocapitalize_off')); //new - - //$form->addElement('password', 'password', get_lang('Password'), array('size' => 17)); //old - $form->addElement('password', 'password', null, array('placeholder' => get_lang('Password'), 'class' => 'span3')); //new - $form->addElement('style_submit_button', 'submitAuth', get_lang('LoginEnter'), array('class' => 'btn span3')); - - $content = Display::return_message(get_lang('NotAllowed').'
'.get_lang('PleaseLoginAgainFromFormBelow').'
', 'error', false); - - $content .= ''; - - $app['template']->assign('content', $content); - $app['allowed'] = false; - - return false; - //$app->abort(403); + if (empty($message)) { + $message = 'Unauthorized'; } - - if ($user_id != 0 && !api_is_anonymous()) { - $app['allowed'] = false; - return false; + if ($printHeaders == false) { + $app['template.show_footer'] = false; + $app['template.show_header'] = false; } - $msg = null; - // Check if the cookies are enabled. If are enabled and if no course ID was included in the requested URL, then the user has either lost his session or is anonymous, so redirect to homepage - if( !isset($_COOKIE['TestCookie']) && empty($_COOKIE['TestCookie']) ) { - $msg = Display::return_message(get_lang('NoCookies').'

'.get_lang('BackTo').' '.get_lang('CampusHomepage').'
', 'error', false); - } else { - $msg = Display::return_message(get_lang('NotAllowed').'

'.get_lang('PleaseLoginAgainFromHomepage').'
', 'error', false); - } - $msg = Display::div($msg, array('align'=>'center')); - $app['template']->assign('content', $msg); - $app['allowed'] = false; - return false; + return $app->abort('401', $message); } diff --git a/main/inc/routes.php b/main/inc/routes.php index 878e71f5fa..993161bc08 100644 --- a/main/inc/routes.php +++ b/main/inc/routes.php @@ -2,8 +2,78 @@ /* For licensing terms, see /license.txt */ use Symfony\Component\HttpFoundation\Request; + use \ChamiloSession as Session; +// Check if users is logged in +$userIsLoggedIn = function (Request $request) use ($app) { + $login = $app['url_generator']->generate('login'); + $security = $app['security']; + if (!$security->isGranted('IS_AUTHENTICATED_FULLY')) { + return $app->redirect($login); + } +}; + +// Check if user can access a course. +$checkLogin = function (Request $request) use ($app) { + + if (api_is_platform_admin()) { + return null; + } + $isAllowedInCourse = Session::read('is_allowed_in_course'); + $courseInfo = api_get_course_info(); + $login = $app['url_generator']->generate('login'); + + if (empty($courseInfo)) { + return $app->redirect($login); + } + + $isVisible = false; + if (isset($courseInfo) && isset($courseInfo['visibility'])) { + switch ($courseInfo['visibility']) { + default: + case COURSE_VISIBILITY_CLOSED: //Completely closed: the course is only accessible to the teachers. - 0 + if (api_get_user_id() && !api_is_anonymous() && (api_is_allowed_to_edit())) { + $isVisible = true; + } + break; + case COURSE_VISIBILITY_REGISTERED: //Private - access authorized to course members only - 1 + if (api_get_user_id() && !api_is_anonymous() && $isAllowedInCourse) { + $isVisible = true; + } + break; + case COURSE_VISIBILITY_OPEN_PLATFORM: // Open - access allowed for users registered on the platform - 2 + if (api_get_user_id() && !api_is_anonymous()) { + $isVisible = true; + } + break; + case COURSE_VISIBILITY_OPEN_WORLD: //Open - access allowed for the whole world - 3 + $isVisible = true; + break; + } + //If password is set and user is not registered to the course then the course is not visible + if ($isAllowedInCourse == false & isset($courseInfo['registration_code']) && !empty($courseInfo['registration_code'])) { + $isVisible = false; + } + } + + // Check session visibility + $sessionId = api_get_session_id(); + + if (!empty($sessionId)) { + //$is_allowed_in_course was set in local.inc.php + if (!$isAllowedInCourse) { + $isVisible = false; + } + } + + if (!$isVisible) { + return $app->redirect($login); + /*$subRequest = Request::create($login, 'GET'); + return $app->handle($subRequest, HttpKernelInterface::SUB_REQUEST);*/ + } +}; + /** Setting course session and group global values */ $settingCourseConditions = function (Request $request) use ($cidReset, $app) { @@ -69,8 +139,8 @@ $settingCourseConditions = function (Request $request) use ($cidReset, $app) { if (!empty($courseCode) && $courseCode != -1) { $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE); - $time = api_get_utc_datetime(); - $sql = "UPDATE $tbl_course SET last_visit= '$time' WHERE code='$courseCode'"; + $time = api_get_utc_datetime(); + $sql = "UPDATE $tbl_course SET last_visit= '$time' WHERE code='$courseCode'"; Database::query($sql); } @@ -105,6 +175,7 @@ $settingCourseConditions = function (Request $request) use ($cidReset, $app) { } }; +/** Only course admin has access. */ $userCourseAdmin = function(Request $request) use ($app) { if (api_is_allowed_to_edit()) { return null; @@ -113,7 +184,7 @@ $userCourseAdmin = function(Request $request) use ($app) { } }; -/** Checks user permissions inside a course teacher? coach? etc */ +/** Set user permissions inside a course teacher? coach? etc */ $userPermissionsInsideACourse = function (Request $request) use ($app) { $courseId = api_get_course_int_id(); @@ -124,9 +195,6 @@ $userPermissionsInsideACourse = function (Request $request) use ($app) { $is_platformAdmin = api_is_platform_admin(); $courseReset = Session::read('courseReset'); - //$app['monolog']->addDebug($courseReset); - //$app['monolog']->addDebug($courseId); - // Course $is_courseMember = false; $is_courseAdmin = false; @@ -361,6 +429,7 @@ $afterLogin = function (Request $request) use ($app) { } }; +/** Removes the cid reset and other session values */ $removeCidReset = function (Request $request) use ($app) { // Deleting course info. Session::erase('_cid'); @@ -399,7 +468,7 @@ $removeCidResetDependingOfSection = function (Request $request) use ($app, $remo } }; -/** / and /index paths */ +/** "/" and "/index" paths */ $app->match('/', 'index.controller:indexAction', 'GET') ->assert('type', '.+') //allowing slash "/" ->before($removeCidReset) @@ -410,21 +479,24 @@ $app->match('/index', 'index.controller:indexAction', 'GET') ->after($afterLogin) ->bind('index'); -/** Userportal */ +/** User portal */ $app->get('/userportal', 'userPortal.controller:indexAction') + ->before($userIsLoggedIn) ->before($removeCidReset); $app->get('/userportal/{type}/{filter}/{page}', 'userPortal.controller:indexAction') + ->before($userIsLoggedIn) ->before($removeCidReset) ->value('type', 'courses') //default values ->value('filter', 'current') ->value('page', '1') ->bind('userportal'); -/** main files */ +/** Legacy wrapper */ $app->match('/main/{file}', 'legacy.controller:classicAction', 'GET|POST') ->before($removeCidResetDependingOfSection) ->before($settingCourseConditions) + ->before($checkLogin) ->before( function() use ($app) { // Do not load breadcrumbs @@ -437,19 +509,20 @@ $app->match('/main/{file}', 'legacy.controller:classicAction', 'GET|POST') $app->match('/login', 'index.controller:loginAction', 'GET|POST') ->bind('login'); - /** Course home instead of courses/MATHS the new URL is web/courses/MATHS */ $app->match('/courses/{cidReq}/{id_session}/', 'course_home.controller:indexAction', 'GET|POST') ->assert('id_session', '\d+') ->assert('type', '.+') ->before($settingCourseConditions) ->before($userPermissionsInsideACourse) + ->before($checkLogin) ->bind('course'); $app->match('/courses/{cidReq}', 'course_home.controller:indexAction', 'GET|POST') ->assert('type', '.+') ->before($settingCourseConditions) - ->before($userPermissionsInsideACourse); + ->before($userPermissionsInsideACourse) + ->before($checkLogin); // @todo this is the same as above but with out slash (otherwise we will have an httpexception) $app->match('/courses/{cidReq}/', 'course_home.controller:indexAction', 'GET|POST') @@ -515,13 +588,11 @@ $app->get('/data/upload/groups/{groupId}/{file}', 'index.controller:getGroupFile ->assert('type', '.+'); /** Admin */ - $app->get('/admin/dashboard', 'index.controller:dashboardAction') ->assert('type', '.+') ->bind('admin_dashboard'); /** Question manager - admin */ - $app->get('/admin/questionmanager', 'question_manager.controller:questionManagerIndexAction') ->assert('type', '.+') ->bind('admin_questionmanager'); diff --git a/src/ChamiloLMS/Controller/CourseHomeController.php b/src/ChamiloLMS/Controller/CourseHomeController.php index c306ae2c77..4ba0e7877a 100644 --- a/src/ChamiloLMS/Controller/CourseHomeController.php +++ b/src/ChamiloLMS/Controller/CourseHomeController.php @@ -102,11 +102,8 @@ class CourseHomeController */ public function getFileAction(Application $app, $courseCode, $fileName) { - api_protect_course_script(); - $courseInfo = api_get_course_info($courseCode); $sessionId = $app['request']->get('id_session'); - //$groupId = $app['request']->get('gidReq'); $docId = \DocumentManager::get_document_id($courseInfo, "/".$fileName);