[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/plugins/multifactorauth/fixed/src/Extension/ -> Fixed.php (source)

   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  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer