MDL-80332 tool_mobile: Fallback por app launches

This commit is contained in:
Juan Leyva
2024-03-25 16:05:07 +01:00
parent 7cec5c9b71
commit d7a0cb8d00
5 changed files with 152 additions and 8 deletions
@@ -0,0 +1,45 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace tool_mobile\local\hooks\user;
/**
* Handles mobile app launches when a third-party auth plugin did not properly set $SESSION->wantsurl.
*
* @package tool_mobile
* @copyright 2024 Juan Leyva
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class after_complete_login {
/**
* Callback to recover $SESSION->wantsurl.
*
* @param \core\hook\user\after_complete_login $hook
*/
public static function callback(\core\hook\user\after_complete_login $hook): void {
global $SESSION, $CFG;
// Check if the user is doing a mobile app launch, if that's the case, ensure $SESSION->wantsurl is correctly set.
if (!NO_MOODLE_COOKIES && !empty($_COOKIE['tool_mobile_launch'])) {
if (empty($SESSION->wantsurl) || strpos($SESSION->wantsurl, '/tool/mobile/launch.php') === false) {
$params = json_decode($_COOKIE['tool_mobile_launch'], true);
$SESSION->wantsurl = (new \moodle_url("/$CFG->admin/tool/mobile/launch.php", $params))->out(false);
}
}
}
}
@@ -0,0 +1,51 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace tool_mobile\local\hooks\user;
/**
* Handles mobile app launches when third-party auth plugins are put in front of MFA.
*
* @package tool_mobile
* @copyright 2024 Juan Leyva
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class after_user_passed_mfa {
/**
* Callback to recover $SESSION->wantsurl.
*
* @param \tool_mfa\hook\after_user_passed_mfa $hook
*/
public static function callback(\tool_mfa\hook\after_user_passed_mfa $hook): void {
global $SESSION, $CFG;
// Check if the user is doing a mobile app launch, if that's the case, ensure $SESSION->wantsurl is correctly set.
if (!NO_MOODLE_COOKIES && !empty($_COOKIE['tool_mobile_launch'])) {
if (empty($SESSION->wantsurl) || strpos($SESSION->wantsurl, '/tool/mobile/launch.php') === false) {
$params = json_decode($_COOKIE['tool_mobile_launch'], true);
$SESSION->wantsurl = (new \moodle_url("/$CFG->admin/tool/mobile/launch.php", $params))->out(false);
$SESSION->tool_mfa_has_been_redirected = true; // Indicate MFA that they need to follow $SESSION->wantsurl.
}
// Invalidate cookie as we won't be needing it anymore.
unset($_COOKIE['tool_mobile_launch']);
if (!headers_sent()) { // Just be very cautios as this is a critical code.
setcookie('tool_mobile_launch', '', -1, $CFG->sessioncookiepath);
}
}
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Hook callbacks for Moodle app tools
*
* @package tool_mobile
* @copyright 2024 Juan Leyva
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$callbacks = [
[
'hook' => core\hook\user\after_complete_login::class,
'callback' => 'tool_mobile\local\hooks\user\after_complete_login::callback',
'priority' => 500,
],
[
'hook' => tool_mfa\hook\after_user_passed_mfa::class,
'callback' => 'tool_mobile\local\hooks\user\after_user_passed_mfa::callback',
'priority' => 500,
],
];
+17 -7
View File
@@ -44,6 +44,18 @@ if (!$CFG->enablewebservices) {
throw new moodle_exception('enablewsdescription', 'webservice');
}
// Check if the service exists and is enabled.
$service = $DB->get_record('external_services', ['shortname' => $serviceshortname, 'enabled' => 1]);
if (empty($service)) {
throw new moodle_exception('servicenotavailable', 'webservice');
}
// Set a cookie indicating that there was a launch to authenticate via the site from the app.
$ldata = json_encode(['service' => $serviceshortname, 'passport' => $passport,
'urlscheme' => $urlscheme, 'confirmed' => (int) $confirmed, 'oauthsso' => $oauthsso]);
$expires = time() + (15 * MINSECS); // 15 minutes for authentication should be enough.
setcookie('tool_mobile_launch', $ldata, $expires, $CFG->sessioncookiepath, $CFG->sessioncookiedomain);
// We have been requested to start a SSO process via OpenID.
if (!empty($oauthsso) && is_enabled_auth('oauth2')) {
$wantsurl = new moodle_url('/admin/tool/mobile/launch.php',
@@ -63,17 +75,15 @@ if (empty($SESSION->justloggedin) &&
throw new moodle_exception('pluginnotenabledorconfigured', 'tool_mobile');
}
// Check if the service exists and is enabled.
$service = $DB->get_record('external_services', array('shortname' => $serviceshortname, 'enabled' => 1));
if (empty($service)) {
throw new moodle_exception('servicenotavailable', 'webservice');
}
require_login(0, false);
// Require an active user: not guest, not suspended.
core_user::require_active_user($USER);
// Remove cookie.
unset($_COOKIE['tool_mobile_launch']);
setcookie('tool_mobile_launch', '', -1, $CFG->sessioncookiepath);
// Get an existing token or create a new one.
$timenow = time();
$token = \core_external\util::generate_token_for_current_user($service);
@@ -126,7 +136,7 @@ if ($confirmed or $isios) {
}
$notice = get_string('clickheretolaunchtheapp', 'tool_mobile');
echo html_writer::link($location, $notice, array('id' => 'launchapp'));
echo $OUTPUT->box(html_writer::link($location, $notice, ['id' => 'launchapp']), 'generalbox warning centerpara');
echo html_writer::script(
"window.onload = function() {
document.getElementById('launchapp').click();
+1 -1
View File
@@ -506,7 +506,7 @@ class component_test extends advanced_testcase {
$this->assertCount(5, core_component::get_component_classes_in_namespace('core_user', 'output\\myprofile'));
// Without namespace it returns classes/ classes.
$this->assertCount(5, core_component::get_component_classes_in_namespace('tool_mobile', ''));
$this->assertCount(7, core_component::get_component_classes_in_namespace('tool_mobile', ''));
$this->assertCount(2, core_component::get_component_classes_in_namespace('tool_filetypes'));
// When no component is specified, classes are returned for the namespace in all components.