1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 namespace tool_mfa\local; 18 19 use tool_mfa\local\factor\object_factor_base; 20 21 defined('MOODLE_INTERNAL') || die(); 22 23 require_once($CFG->libdir.'/ddllib.php'); 24 require_once($CFG->libdir.'/xmlize.php'); 25 require_once($CFG->libdir.'/messagelib.php'); 26 27 /** 28 * Admin setting for MFA. 29 * 30 * @package tool_mfa 31 * @author Mikhail Golenkov <golenkovm@gmail.com> 32 * @copyright Catalyst IT 33 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 34 */ 35 class admin_setting_managemfa extends \admin_setting { 36 37 /** 38 * Calls parent::__construct with specific arguments 39 */ 40 public function __construct() { 41 $this->nosave = true; 42 parent::__construct('mfaui', get_string('mfasettings', 'tool_mfa'), '', ''); 43 } 44 45 /** 46 * Always returns true 47 * 48 * @return bool 49 */ 50 public function get_setting(): bool { 51 return true; 52 } 53 54 /** 55 * Always returns '' and doesn't write anything 56 * 57 * @param mixed $data 58 * @return string Always returns '' 59 */ 60 public function write_setting($data): string { 61 return ''; 62 } 63 64 /** 65 * Returns XHTML to display Manage MFA admin page. 66 * 67 * @param mixed $data Unused 68 * @param string $query 69 * 70 * @return string highlight 71 * @throws \coding_exception 72 * @throws \moodle_exception 73 */ 74 public function output_html($data, $query=''): string { 75 global $OUTPUT; 76 77 $return = $OUTPUT->box_start('generalbox'); 78 $return .= $this->define_manage_mfa_table(); 79 $return .= $OUTPUT->box_end(); 80 81 $return .= $OUTPUT->heading(get_string('settings:combinations', 'tool_mfa'), 3); 82 $return .= $OUTPUT->box_start('generalbox'); 83 $return .= $this->define_factor_combinations_table(); 84 $return .= $OUTPUT->box_end(); 85 86 return highlight($query, $return); 87 } 88 89 /** 90 * Defines main table with configurable factors. 91 * 92 * @return string HTML code 93 * @throws \coding_exception 94 * @throws \moodle_exception 95 */ 96 public function define_manage_mfa_table() { 97 global $OUTPUT; 98 $sesskey = sesskey(); 99 100 $txt = get_strings(['enable', 'disable', 'moveup', 'movedown', 'order', 'settings']); 101 $txt->factor = get_string('factor', 'tool_mfa'); 102 $txt->weight = get_string('weight', 'tool_mfa'); 103 $txt->setup = get_string('setuprequired', 'tool_mfa'); 104 $txt->input = get_string('inputrequired', 'tool_mfa'); 105 106 $table = new \html_table(); 107 $table->id = 'managemfatable'; 108 $table->attributes['class'] = 'admintable generaltable'; 109 $table->head = [ 110 $txt->factor, 111 $txt->enable, 112 $txt->order, 113 $txt->weight, 114 $txt->settings, 115 $txt->setup, 116 $txt->input, 117 ]; 118 $table->colclasses = ['leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign']; 119 $table->data = []; 120 121 $factors = \tool_mfa\plugininfo\factor::get_factors(); 122 $enabledfactors = \tool_mfa\plugininfo\factor::get_enabled_factors(); 123 $order = 1; 124 125 foreach ($factors as $factor) { 126 $settingsparams = ['section' => 'factor_'.$factor->name]; 127 $settingsurl = new \moodle_url('settings.php', $settingsparams); 128 $settingslink = \html_writer::link($settingsurl, $txt->settings); 129 130 if ($factor->is_enabled()) { 131 $hideshowparams = ['action' => 'disable', 'factor' => $factor->name, 'sesskey' => $sesskey]; 132 $hideshowurl = new \moodle_url('tool/mfa/index.php', $hideshowparams); 133 $hideshowlink = \html_writer::link($hideshowurl, $OUTPUT->pix_icon('t/hide', $txt->disable)); 134 $class = ''; 135 136 if ($order > 1) { 137 $upparams = ['action' => 'up', 'factor' => $factor->name, 'sesskey' => $sesskey]; 138 $upurl = new \moodle_url('tool/mfa/index.php', $upparams); 139 $uplink = \html_writer::link($upurl, $OUTPUT->pix_icon('t/up', $txt->moveup)); 140 } else { 141 $uplink = \html_writer::link('', $uplink = $OUTPUT->spacer(['style' => 'margin-right: .5rem'])); 142 } 143 144 if ($order < count($enabledfactors)) { 145 $downparams = ['action' => 'down', 'factor' => $factor->name, 'sesskey' => $sesskey]; 146 $downurl = new \moodle_url('tool/mfa/index.php', $downparams); 147 $downlink = \html_writer::link($downurl, $OUTPUT->pix_icon('t/down', $txt->movedown)); 148 } else { 149 $downlink = ''; 150 } 151 $updownlink = $uplink.$downlink; 152 $order++; 153 } else { 154 $hideshowparams = ['action' => 'enable', 'factor' => $factor->name, 'sesskey' => $sesskey]; 155 $hideshowurl = new \moodle_url('tool/mfa/index.php', $hideshowparams); 156 $hideshowlink = \html_writer::link($hideshowurl, $OUTPUT->pix_icon('t/show', $txt->enable)); 157 $class = 'dimmed_text'; 158 $updownlink = ''; 159 } 160 161 $hassetup = $factor->has_setup() ? get_string('yes') : get_string('no'); 162 $hasinput = $factor->has_input() ? get_string('yes') : get_string('no'); 163 164 $rowarray = [ 165 $factor->get_display_name(), 166 $hideshowlink, 167 $updownlink, 168 $factor->get_weight(), 169 $settingslink, 170 $hassetup, 171 $hasinput, 172 ]; 173 $row = new \html_table_row($rowarray); 174 $row->attributes['class'] = $class; 175 176 $table->data[] = $row; 177 } 178 179 return \html_writer::table($table); 180 } 181 182 /** 183 * Defines supplementary table that shows available combinations of factors enough for successful authentication. 184 * 185 * @return string HTML code 186 */ 187 public function define_factor_combinations_table() { 188 global $OUTPUT; 189 190 $factors = \tool_mfa\plugininfo\factor::get_enabled_factors(); 191 $combinations = $this->get_factor_combinations($factors, 0, count($factors) - 1); 192 193 if (empty($combinations)) { 194 return $OUTPUT->notification(get_string('error:notenoughfactors', 'tool_mfa'), 'notifyproblem'); 195 } 196 197 $txt = get_strings(['combination', 'totalweight'], 'tool_mfa'); 198 $table = new \html_table(); 199 $table->id = 'managemfatable'; 200 $table->attributes['class'] = 'admintable generaltable table table-bordered'; 201 $table->head = [$txt->combination, $txt->totalweight]; 202 $table->colclasses = ['leftalign', 'centeralign']; 203 $table->data = []; 204 205 $factorstringconnector = get_string('connector', 'tool_mfa'); 206 foreach ($combinations as $combination) { 207 $factorstrings = array_map(static function(object_factor_base $factor): string { 208 return $factor->get_summary_condition() . ' <sup>' . $factor->get_weight() . '</sup>'; 209 }, $combination['combination']); 210 211 $string = implode(" {$factorstringconnector} ", $factorstrings); 212 $table->data[] = new \html_table_row([$string, $combination['totalweight']]); 213 } 214 215 return \html_writer::table($table); 216 } 217 218 /** 219 * Recursive method to get all possible combinations of given factors. 220 * Output is filtered by combination total weight (should be greater than 100). 221 * 222 * @param array $allfactors initial array of factor objects 223 * @param int $start start position in initial array 224 * @param int $end end position in initial array 225 * @param int $totalweight total weight of combination 226 * @param array $combination combination candidate 227 * @param array $result array that includes combination total weight and subarray of factors combination 228 * 229 * @return array 230 */ 231 public function get_factor_combinations($allfactors, $start = 0, $end = 0, 232 $totalweight = 0, $combination = [], $result = []) { 233 234 if ($totalweight >= 100) { 235 // Ensure this is a valid combination before appending result. 236 $valid = true; 237 foreach ($combination as $factor) { 238 if (!$factor->check_combination($combination)) { 239 $valid = false; 240 } 241 } 242 if ($valid) { 243 $result[] = ['totalweight' => $totalweight, 'combination' => $combination]; 244 } 245 return $result; 246 } else if ($start > $end) { 247 return $result; 248 } 249 250 $combinationnext = $combination; 251 $combinationnext[] = $allfactors[$start]; 252 253 $result = $this->get_factor_combinations( 254 $allfactors, 255 $start + 1, 256 $end, 257 $totalweight + $allfactors[$start]->get_weight(), 258 $combinationnext, 259 $result); 260 261 $result = $this->get_factor_combinations( 262 $allfactors, 263 $start + 1, 264 $end, 265 $totalweight, 266 $combination, 267 $result); 268 269 return $result; 270 } 271 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body