[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * @package Joomla.Plugin 5 * @subpackage Multifactorauth.fixed 6 * 7 * @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org> 8 * @license GNU General Public License version 2 or later; see LICENSE.txt 9 */ 10 11 namespace Joomla\Plugin\Multifactorauth\Fixed\Extension; 12 13 use Joomla\CMS\Event\MultiFactor\Captive; 14 use Joomla\CMS\Event\MultiFactor\GetMethod; 15 use Joomla\CMS\Event\MultiFactor\GetSetup; 16 use Joomla\CMS\Event\MultiFactor\SaveSetup; 17 use Joomla\CMS\Event\MultiFactor\Validate; 18 use Joomla\CMS\Language\Text; 19 use Joomla\CMS\Plugin\CMSPlugin; 20 use Joomla\CMS\User\User; 21 use Joomla\Component\Users\Administrator\DataShape\CaptiveRenderOptions; 22 use Joomla\Component\Users\Administrator\DataShape\MethodDescriptor; 23 use Joomla\Component\Users\Administrator\DataShape\SetupRenderOptions; 24 use Joomla\Component\Users\Administrator\Table\MfaTable; 25 use Joomla\Event\SubscriberInterface; 26 use Joomla\Input\Input; 27 use RuntimeException; 28 29 // phpcs:disable PSR1.Files.SideEffects 30 \defined('_JEXEC') or die; 31 // phpcs:enable PSR1.Files.SideEffects 32 33 /** 34 * Joomla! Multi-factor Authentication using a fixed code. 35 * 36 * Requires a static string (password), different for each user. It effectively works as a second 37 * password. The fixed code is stored hashed, like a regular password. 38 * 39 * This is NOT to be used on production sites. It serves as a demonstration plugin and as a template 40 * for developers to create their own custom Multi-factor Authentication plugins. 41 * 42 * @since 4.2.0 43 */ 44 class Fixed extends CMSPlugin implements SubscriberInterface 45 { 46 /** 47 * Affects constructor behavior. If true, language files will be loaded automatically. 48 * 49 * @var boolean 50 * @since 4.2.0 51 */ 52 protected $autoloadLanguage = true; 53 54 /** 55 * The MFA Method name handled by this plugin 56 * 57 * @var string 58 * @since 4.2.0 59 */ 60 private $mfaMethodName = 'fixed'; 61 62 /** 63 * Should I try to detect and register legacy event listeners? 64 * 65 * @var boolean 66 * @since 4.2.0 67 * 68 * @deprecated 69 */ 70 protected $allowLegacyListeners = false; 71 72 /** 73 * Returns an array of events this subscriber will listen to. 74 * 75 * @return array 76 * 77 * @since 4.2.0 78 */ 79 public static function getSubscribedEvents(): array 80 { 81 return [ 82 'onUserMultifactorGetMethod' => 'onUserMultifactorGetMethod', 83 'onUserMultifactorCaptive' => 'onUserMultifactorCaptive', 84 'onUserMultifactorGetSetup' => 'onUserMultifactorGetSetup', 85 'onUserMultifactorSaveSetup' => 'onUserMultifactorSaveSetup', 86 'onUserMultifactorValidate' => 'onUserMultifactorValidate', 87 ]; 88 } 89 90 /** 91 * Gets the identity of this MFA Method 92 * 93 * @param GetMethod $event The event we are handling 94 * 95 * @return void 96 * @since 4.2.0 97 */ 98 public function onUserMultifactorGetMethod(GetMethod $event): void 99 { 100 $event->addResult( 101 new MethodDescriptor( 102 [ 103 'name' => $this->mfaMethodName, 104 'display' => Text::_('PLG_MULTIFACTORAUTH_FIXED_LBL_DISPLAYEDAS'), 105 'shortinfo' => Text::_('PLG_MULTIFACTORAUTH_FIXED_LBL_SHORTINFO'), 106 'image' => 'media/plg_multifactorauth_fixed/images/fixed.svg', 107 ] 108 ) 109 ); 110 } 111 112 /** 113 * Returns the information which allows Joomla to render the Captive MFA page. This is the page 114 * which appears right after you log in and asks you to validate your login with MFA. 115 * 116 * @param Captive $event The event we are handling 117 * 118 * @return void 119 * @since 4.2.0 120 */ 121 public function onUserMultifactorCaptive(Captive $event): void 122 { 123 /** 124 * @var MfaTable $record The record currently selected by the user. 125 */ 126 $record = $event['record']; 127 128 // Make sure we are actually meant to handle this Method 129 if ($record->method != $this->mfaMethodName) { 130 return; 131 } 132 133 $event->addResult( 134 new CaptiveRenderOptions( 135 [ 136 // Custom HTML to display above the MFA form 137 'pre_message' => Text::_('PLG_MULTIFACTORAUTH_FIXED_LBL_PREMESSAGE'), 138 // How to render the MFA code field. "input" (HTML input element) or "custom" (custom HTML) 139 'field_type' => 'input', 140 // The type attribute for the HTML input box. Typically "text" or "password". Use any HTML5 input type. 141 'input_type' => 'password', 142 // Placeholder text for the HTML input box. Leave empty if you don't need it. 143 'placeholder' => Text::_('PLG_MULTIFACTORAUTH_FIXED_LBL_PLACEHOLDER'), 144 // Label to show above the HTML input box. Leave empty if you don't need it. 145 'label' => Text::_('PLG_MULTIFACTORAUTH_FIXED_LBL_LABEL'), 146 // Custom HTML. Only used when field_type = custom. 147 'html' => '', 148 // Custom HTML to display below the MFA form 149 'post_message' => Text::_('PLG_MULTIFACTORAUTH_FIXED_LBL_POSTMESSAGE'), 150 ] 151 ) 152 ); 153 } 154 155 /** 156 * Returns the information which allows Joomla to render the MFA setup page. This is the page 157 * which allows the user to add or modify a MFA Method for their user account. If the record 158 * does not correspond to your plugin return an empty array. 159 * 160 * @param GetSetup $event The event we are handling 161 * 162 * @return void 163 * @since 4.2.0 164 */ 165 public function onUserMultifactorGetSetup(GetSetup $event): void 166 { 167 /** @var MfaTable $record The record currently selected by the user. */ 168 $record = $event['record']; 169 170 // Make sure we are actually meant to handle this Method 171 if ($record->method != $this->mfaMethodName) { 172 return; 173 } 174 175 // Load the options from the record (if any) 176 $options = $this->decodeRecordOptions($record); 177 178 /** 179 * Return the parameters used to render the GUI. 180 * 181 * Some MFA Methods need to display a different interface before and after the setup. For example, when setting 182 * up Google Authenticator or a hardware OTP dongle you need the user to enter a MFA code to verify they are in 183 * possession of a correctly configured device. After the setup is complete you don't want them to see that 184 * field again. In the first state you could use the tabular_data to display the setup values, pre_message to 185 * display the QR code and field_type=input to let the user enter the MFA code. In the second state do the same 186 * BUT set field_type=custom, set html='' and show_submit=false to effectively hide the setup form from the 187 * user. 188 */ 189 $event->addResult( 190 new SetupRenderOptions( 191 [ 192 'default_title' => Text::_('PLG_MULTIFACTORAUTH_FIXED_LBL_DEFAULTTITLE'), 193 'pre_message' => Text::_('PLG_MULTIFACTORAUTH_FIXED_LBL_SETUP_PREMESSAGE'), 194 'field_type' => 'input', 195 'input_type' => 'password', 196 'input_value' => $options->fixed_code, 197 'placeholder' => Text::_('PLG_MULTIFACTORAUTH_FIXED_LBL_PLACEHOLDER'), 198 'label' => Text::_('PLG_MULTIFACTORAUTH_FIXED_LBL_LABEL'), 199 'post_message' => Text::_('PLG_MULTIFACTORAUTH_FIXED_LBL_SETUP_POSTMESSAGE'), 200 ] 201 ) 202 ); 203 } 204 205 /** 206 * Parse the input from the MFA setup page and return the configuration information to be saved to the database. If 207 * the information is invalid throw a RuntimeException to signal the need to display the editor page again. The 208 * message of the exception will be displayed to the user. If the record does not correspond to your plugin return 209 * an empty array. 210 * 211 * @param SaveSetup $event The event we are handling 212 * 213 * @return void The configuration data to save to the database 214 * @since 4.2.0 215 */ 216 public function onUserMultifactorSaveSetup(SaveSetup $event): void 217 { 218 /** 219 * @var MfaTable $record The record currently selected by the user. 220 * @var Input $input The user input you are going to take into account. 221 */ 222 $record = $event['record']; 223 $input = $event['input']; 224 225 // Make sure we are actually meant to handle this Method 226 if ($record->method != $this->mfaMethodName) { 227 return; 228 } 229 230 // Load the options from the record (if any) 231 $options = $this->decodeRecordOptions($record); 232 233 // Merge with the submitted form data 234 $code = $input->get('code', $options->fixed_code, 'raw'); 235 236 // Make sure the code is not empty 237 if (empty($code)) { 238 throw new RuntimeException(Text::_('PLG_MULTIFACTORAUTH_FIXED_ERR_EMPTYCODE')); 239 } 240 241 // Return the configuration to be serialized 242 $event->addResult(['fixed_code' => $code]); 243 } 244 245 /** 246 * Validates the Multi-factor Authentication code submitted by the user in the Multi-Factor 247 * Authentication. If the record does not correspond to your plugin return FALSE. 248 * 249 * @param Validate $event The event we are handling 250 * 251 * @return void 252 * @since 4.2.0 253 */ 254 public function onUserMultifactorValidate(Validate $event): void 255 { 256 /** 257 * @var MfaTable $record The MFA Method's record you're validating against 258 * @var User $user The user record 259 * @var string|null $code The submitted code 260 */ 261 $record = $event['record']; 262 $user = $event['user']; 263 $code = $event['code']; 264 265 // Make sure we are actually meant to handle this Method 266 if ($record->method != $this->mfaMethodName) { 267 $event->addResult(false); 268 269 return; 270 } 271 272 // Load the options from the record (if any) 273 $options = $this->decodeRecordOptions($record); 274 275 // Double check the MFA Method is for the correct user 276 if ($user->id != $record->user_id) { 277 $event->addResult(false); 278 279 return; 280 } 281 282 // Check the MFA code for validity 283 $event->addResult(hash_equals($options->fixed_code, $code ?? '')); 284 } 285 286 /** 287 * Decodes the options from a record into an options object. 288 * 289 * @param MfaTable $record The record to decode options for 290 * 291 * @return object 292 * @since 4.2.0 293 */ 294 private function decodeRecordOptions(MfaTable $record): object 295 { 296 $options = [ 297 'fixed_code' => '', 298 ]; 299 300 if (!empty($record->options)) { 301 $recordOptions = $record->options; 302 303 $options = array_merge($options, $recordOptions); 304 } 305 306 return (object) $options; 307 } 308 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |