diff --git a/factor/token/classes/factor.php b/factor/token/classes/factor.php index 39c2576b..360af55b 100644 --- a/factor/token/classes/factor.php +++ b/factor/token/classes/factor.php @@ -146,7 +146,8 @@ public function global_definition_after_data($mform) { $nostate = $this->get_state() !== \tool_mfa\plugininfo\factor::STATE_PASS; if ($noproperty && $nostate) { - $expiry = get_config('factor_token', 'expiry'); + $expiryconfig = is_siteadmin() ? 'adminexpiry' : 'expiry'; + $expiry = get_config('factor_token', $expiryconfig); $expirystring = format_time($expiry); $mform->addElement('advcheckbox', 'factor_token_trust', '', get_string('form:trust', 'factor_token', $expirystring)); $mform->setType('factor_token_trust', PARAM_BOOL); @@ -218,7 +219,8 @@ public function calculate_expiry_time($basetime = null): array { // Calculate the expiry time. This is provided by config, // But optionally might need to be rounded to expire a few hours after 0000 server time. - $expiry = get_config('factor_token', 'expiry'); + $expiryconfig = is_siteadmin() ? 'adminexpiry' : 'expiry'; + $expiry = get_config('factor_token', $expiryconfig); $expirytime = $basetime + $expiry; // If expiring overnight, it should expire at 2am the following morning, if required. diff --git a/factor/token/lang/en/factor_token.php b/factor/token/lang/en/factor_token.php index 463863ca..cecb2adf 100644 --- a/factor/token/lang/en/factor_token.php +++ b/factor/token/lang/en/factor_token.php @@ -31,4 +31,6 @@ $string['settings:expireovernight_help'] = 'This forces tokens to expire overnight, preventing mid-day interruptions for users. Instead they will be asked to MFA authenticate at the start of a day after expiry.'; $string['settings:expiry'] = 'Trust duration'; $string['settings:expiry_help'] = 'The duration a device is trusted before requiring a new MFA authentication.'; +$string['settings:expiry'] = 'Administrator trust duration'; +$string['settings:expiry_help'] = 'The duration an administrator device is trusted before requiring a new MFA authentication. This allows tighter restrictions on site administrators, or no trust.'; $string['summarycondition'] = 'the user has previously trusted this device'; diff --git a/factor/token/settings.php b/factor/token/settings.php index 01296fb5..a8249d56 100644 --- a/factor/token/settings.php +++ b/factor/token/settings.php @@ -42,6 +42,10 @@ new lang_string('settings:expiry', 'factor_token'), new lang_string('settings:expiry_help', 'factor_token'), DAYSECS)); +$settings->add(new admin_setting_configduration('factor_token/adminexpiry', + new lang_string('settings:adminexpiry', 'factor_token'), + new lang_string('settings:adminexpiry_help', 'factor_token'), DAYSECS)); + $settings->add(new admin_setting_configcheckbox('factor_token/expireovernight', new lang_string('settings:expireovernight', 'factor_token'), new lang_string('settings:expireovernight_help', 'factor_token'), 1)); diff --git a/factor/token/tests/factor_test.php b/factor/token/tests/factor_test.php index c14e8d4e..5b4b6c69 100644 --- a/factor/token/tests/factor_test.php +++ b/factor/token/tests/factor_test.php @@ -27,6 +27,8 @@ */ class factor_test extends \advanced_testcase { + private $factor; + public function setUp(): void { $this->resetAfterTest(); $this->factor = new \factor_token\factor('token'); @@ -36,6 +38,7 @@ public function test_calculate_expiry_time_in_general() { $timestamp = 1642213800; // 1230 UTC. set_config('expireovernight', 0, 'factor_token'); + set_config('adminexpiry', 8 * HOURSECS, 'factor_token'); $method = new \ReflectionMethod($this->factor, 'calculate_expiry_time'); $method->setAccessible(true); @@ -69,6 +72,24 @@ public function test_calculate_expiry_time_in_general() { $this->assertLessThan($resetdelta + DAYSECS + 30, $expiry[1]); } + public function test_calculate_admin_expiry_time() { + $timestamp = 1642213800; // 1230 UTC. + + set_config('expireovernight', 0, 'factor_token'); + set_config('expiry', 24 * HOURSECS, 'factor_token'); + set_config('adminexpiry', 8 * HOURSECS, 'factor_token'); + $this->setAdminUser(); + + // Confirm that the expiry is based on the admin duration. + // Duration for regular users is covered by the general calc test. + $method = new \ReflectionMethod($this->factor, 'calculate_expiry_time'); + $method->setAccessible(true); + + $expiry = $method->invoke($this->factor, $timestamp); + $this->assertGreaterThan(7 * HOURSECS, $expiry[1]); + $this->assertLessThan(9 * HOURSECS, $expiry[1]); + } + /** * Everything should end at 2am unless adding the hours lands it between * 0 <= x < 2am, which in that case it should just expire using the raw diff --git a/factor/token/version.php b/factor/token/version.php index 61e2a350..07d557a4 100644 --- a/factor/token/version.php +++ b/factor/token/version.php @@ -26,7 +26,7 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2022011700; // The current plugin version (Date: YYYYMMDDXX). +$plugin->version = 2023101600; // The current plugin version (Date: YYYYMMDDXX). $plugin->requires = 2022041908; // Support Moodle 4.0 and higher. $plugin->component = 'factor_token'; $plugin->release = 2022011700;