Skip to content

Commit 644bae1

Browse files
committed
Issue #148: Fixed error with redirect loop explosions
1 parent 96853eb commit 644bae1

File tree

4 files changed

+38
-16
lines changed

4 files changed

+38
-16
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ language: php
22

33
addons:
44
firefox: "47.0.1"
5-
postgresql: "9.4"
5+
postgresql: "9.5"
66

77
cache:
88
directories:

classes/manager.php

+35-14
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,12 @@ public static function should_require_mfa($url, $preventredirect) {
314314
// Remove all params before comparison.
315315
$url->remove_all_params();
316316

317+
// Dont redirect if already on auth.php
318+
$authurl = new \moodle_url('/admin/tool/mfa/auth.php');
319+
if ($url->compare($authurl)) {
320+
return self::NO_REDIRECT;
321+
}
322+
317323
// Soft maintenance mode.
318324
if (!empty($CFG->maintenance_enabled)) {
319325
return self::NO_REDIRECT;
@@ -362,17 +368,20 @@ public static function should_require_mfa($url, $preventredirect) {
362368
}
363369

364370
// Site policy.
365-
if (isset($USER->policyagreed) && !$USER->policyagreed
366-
&& defined('NO_SITEPOLICY_CHECK') && !NO_SITEPOLICY_CHECK) {
371+
if (isset($USER->policyagreed) && !$USER->policyagreed) {
367372
$manager = new \core_privacy\local\sitepolicy\manager();
368373
$policyurl = $manager->get_redirect_url(false);
369-
if (!empty($policyurl)) {
374+
if (!empty($policyurl) && $url->compare($policyurl)) {
370375
return self::NO_REDIRECT;
371376
}
372377
}
373378

374379
// WS/AJAX check.
375380
if (WS_SERVER || AJAX_SCRIPT) {
381+
if (isset($SESSION->mfa_pending) && !empty($SESSION->mfa_pending)) {
382+
// Allow AJAX and WS, but never from auth.php
383+
return self::NO_REDIRECT;
384+
}
376385
return self::REDIRECT_EXCEPTION;
377386
}
378387

@@ -385,9 +394,8 @@ public static function should_require_mfa($url, $preventredirect) {
385394
}
386395

387396
// Circular checks.
388-
$authurl = new \moodle_url('/admin/tool/mfa/auth.php');
389-
if (isset($SESSION->mfa_redir_referer) &&
390-
$SESSION->mfa_redir_referer != $authurl) {
397+
if (isset($SESSION->mfa_redir_referer)
398+
&& $SESSION->mfa_redir_referer != $authurl) {
391399
if ($SESSION->mfa_redir_referer == get_local_referer(true)) {
392400
// Possible redirect loop.
393401
if (!isset($SESSION->mfa_redir_count)) {
@@ -406,10 +414,6 @@ public static function should_require_mfa($url, $preventredirect) {
406414
// Set referer after checks.
407415
$SESSION->mfa_redir_referer = get_local_referer(true);
408416

409-
$safe = new \moodle_url('/admin/tool/mfa/auth.php');
410-
if ($safe->compare($url)) {
411-
return self::NO_REDIRECT;
412-
}
413417
return self::REDIRECT;
414418
}
415419

@@ -419,10 +423,10 @@ public static function should_require_mfa($url, $preventredirect) {
419423
* @return array
420424
*/
421425
public static function get_factor_no_redirect_urls() {
422-
$factors = \tool_mfa\plugininfo\factor::get_enabled_factors();
426+
$factors = \tool_mfa\plugininfo\factor::get_factors();
423427
$urls = array();
424428
foreach ($factors as $factor) {
425-
$urls += $factor->get_no_redirect_urls();
429+
$urls = array_merge($urls, $factor->get_no_redirect_urls());
426430
}
427431
return $urls;
428432
}
@@ -464,7 +468,17 @@ public static function require_auth($courseorid = null, $autologinguest = null,
464468

465469
if (empty($SESSION->tool_mfa_authenticated) || !$SESSION->tool_mfa_authenticated) {
466470
$cleanurl = new \moodle_url($ME);
471+
$authurl = new \moodle_url('/admin/tool/mfa/auth.php');
472+
467473
$redir = self::should_require_mfa($cleanurl, $preventredirect);
474+
475+
if ($redir == self::NO_REDIRECT && !$cleanurl->compare($authurl)) {
476+
// A non-MFA page that should take precedence.
477+
// This check is for any pages, such as site policy, that must occur before MFA.
478+
// This check allows AJAX and WS requests to fire on these pages without throwing an exception.
479+
$SESSION->mfa_pending = true;
480+
}
481+
468482
if ($redir == self::REDIRECT) {
469483
if (empty($SESSION->wantsurl)) {
470484
!empty($setwantsurltome)
@@ -473,9 +487,16 @@ public static function require_auth($courseorid = null, $autologinguest = null,
473487

474488
$SESSION->tool_mfa_setwantsurl = true;
475489
}
476-
redirect(new \moodle_url('/admin/tool/mfa/auth.php'));
490+
// Remove pending status.
491+
// We must now auth with MFA, now that pending statuses are resolved.
492+
unset($SESSION->mfa_pending);
493+
redirect($authurl);
477494
} else if ($redir == self::REDIRECT_EXCEPTION) {
478-
throw new \moodle_exception('redirecterrordetected', 'error');
495+
if (!empty($SESSION->mfa_redir_referer)) {
496+
throw new \moodle_exception('redirecterrordetected', 'tool_mfa', $SESSION->mfa_redir_referer);
497+
} else {
498+
throw new \moodle_exception('redirecterrordetected', 'error');
499+
}
479500
}
480501
}
481502
}

lang/en/tool_mfa.php

+1
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,4 @@
107107
$string['factorrevoked'] = 'Factor \'{$a}\' successfully revoked.';
108108
$string['connector'] = ' AND ';
109109
$string['pending'] = 'Pending';
110+
$string['redirecterrordetected'] = 'Unsupported redirect detected, script execution terminated. Redirection error occured between MFA and {$a}.';

version.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
defined('MOODLE_INTERNAL') || die();
2727

28-
$plugin->version = 2019121900; // The current plugin version (Date: YYYYMMDDXX).
28+
$plugin->version = 2020021300; // The current plugin version (Date: YYYYMMDDXX).
2929
$plugin->requires = 2018051708.05; // Requires MDL-60470 improvement.
3030
$plugin->component = 'tool_mfa';
3131
$plugin->release = 'v1.0';

0 commit comments

Comments
 (0)