You are here

abstract class TfaBasePlugin in Two-factor Authentication (TFA) 8

Base plugin class.

Hierarchy

Expanded class hierarchy of TfaBasePlugin

4 files declare their use of TfaBasePlugin
TfaRecoveryCode.php in src/Plugin/TfaValidation/TfaRecoveryCode.php
TfaTestValidationPlugin.php in tests/modules/tfa_test_plugins/src/Plugin/TfaValidation/TfaTestValidationPlugin.php
TfaTestValidationPluginSetupPlugin.php in tests/modules/tfa_test_plugins/src/Plugin/TfaSetup/TfaTestValidationPluginSetupPlugin.php
TfaTrustedBrowser.php in src/Plugin/TfaLogin/TfaTrustedBrowser.php

File

src/Plugin/TfaBasePlugin.php, line 18

Namespace

Drupal\tfa\Plugin
View source
abstract class TfaBasePlugin extends PluginBase {
  use DependencySerializationTrait;
  use TfaDataTrait;

  /**
   * The user submitted code to be validated.
   *
   * @var string
   */
  protected $code;

  /**
   * The allowed code length.
   *
   * @var int
   */
  protected $codeLength;

  /**
   * The error for the current validation.
   *
   * @var string[]
   */
  protected $errorMessages;

  /**
   * Whether the validation succeeded or not.
   *
   * @var bool
   */
  protected $isValid;

  /**
   * Whether the code has been used before.
   *
   * @var string
   */
  protected $alreadyAccepted;

  /**
   * Provides the user data service object.
   *
   * @var \Drupal\user\UserDataInterface
   */
  protected $userData;

  /**
   * The user id.
   *
   * @var int
   */
  protected $uid;

  /**
   * Encryption profile.
   *
   * @var \Drupal\encrypt\EncryptionProfileManagerInterface
   */
  protected $encryptionProfile;

  /**
   * Encryption service.
   *
   * @var \Drupal\encrypt\EncryptService
   */
  protected $encryptService;

  /**
   * Constructs a new Tfa plugin object.
   *
   * @param array $configuration
   *   The plugin configuration.
   * @param string $plugin_id
   *   The plugin id.
   * @param mixed $plugin_definition
   *   The plugin definition.
   * @param \Drupal\user\UserDataInterface $user_data
   *   User data object to store user specific information.
   * @param \Drupal\encrypt\EncryptionProfileManagerInterface $encryption_profile_manager
   *   Encryption profile manager.
   * @param \Drupal\encrypt\EncryptServiceInterface $encrypt_service
   *   Encryption service.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, UserDataInterface $user_data, EncryptionProfileManagerInterface $encryption_profile_manager, EncryptServiceInterface $encrypt_service) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);

    // Default code length is 6.
    $this->codeLength = 6;
    $this->isValid = FALSE;

    // User Data service to store user-based data in key value pairs.
    $this->userData = $user_data;

    // Encryption profile manager and service.
    $encryptionProfileId = \Drupal::config('tfa.settings')
      ->get('encryption');
    $this->encryptionProfile = $encryption_profile_manager
      ->getEncryptionProfile($encryptionProfileId);
    $this->encryptService = $encrypt_service;
    $this->uid = $this->configuration['uid'];
  }

  /**
   * Determine if the plugin can run for the current TFA context.
   *
   * @return bool
   *   True or False based on the checks performed.
   */
  public abstract function ready();

  /**
   * Get error messages suitable for form_set_error().
   *
   * @return array
   *   An array of error strings.
   */
  public function getErrorMessages() {
    return $this->errorMessages;
  }

  /**
   * Submit form.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   *
   * @return bool
   *   Whether plugin form handling is complete. Plugins should return FALSE to
   *   invoke multi-step.
   */
  public function submitForm(array $form, FormStateInterface &$form_state) {
    return $this->isValid;
  }

  /**
   * Validate code.
   *
   * Note, plugins overriding validate() should be sure to set isValid property
   * correctly or else also override submitForm().
   *
   * @param string $code
   *   Code to be validated.
   *
   * @return bool
   *   Whether code is valid.
   */
  protected function validate($code) {
    if (hash_equals((string) $code, (string) $this->code)) {
      $this->isValid = TRUE;
      return TRUE;
    }
    else {
      return FALSE;
    }
  }

  /**
   * Encrypt a plaintext string.
   *
   * Should be used when writing codes to storage.
   *
   * @param string $data
   *   The string to be encrypted.
   *
   * @return string
   *   The encrypted string.
   *
   * @throws \Drupal\encrypt\Exception\EncryptException
   */
  protected function encrypt($data) {
    return $this->encryptService
      ->encrypt($data, $this->encryptionProfile);
  }

  /**
   * Decrypt a encrypted string.
   *
   * Should be used when reading codes from storage.
   *
   * @param string $data
   *   The string to be decrypted.
   *
   * @return string
   *   The decrypted string.
   *
   * @throws \Drupal\encrypt\Exception\EncryptionMethodCanNotDecryptException
   * @throws \Drupal\encrypt\Exception\EncryptException
   */
  protected function decrypt($data) {
    return $this->encryptService
      ->decrypt($data, $this->encryptionProfile);
  }

  /**
   * Store validated code to prevent replay attack.
   *
   * @param string $code
   *   The validated code.
   */
  protected function storeAcceptedCode($code) {
    $code = preg_replace('/\\s+/', '', $code);
    $hash = Crypt::hashBase64(Settings::getHashSalt() . $code);

    // Store the hash made using the code in users_data.
    $store_data = [
      'tfa_accepted_code_' . $hash => \Drupal::time()
        ->getRequestTime(),
    ];
    $this
      ->setUserData('tfa', $store_data, $this->uid, $this->userData);
  }

  /**
   * Whether code has already been used.
   *
   * @param string $code
   *   The code to be checked.
   *
   * @return bool
   *   TRUE if already used otherwise FALSE
   */
  protected function alreadyAcceptedCode($code) {
    $hash = Crypt::hashBase64(Settings::getHashSalt() . $code);

    // Check if the code has already been used or not.
    $key = 'tfa_accepted_code_' . $hash;
    $result = $this
      ->getUserData('tfa', $key, $this->uid, $this->userData);
    if (!empty($result)) {
      $this->alreadyAccepted = TRUE;
      return TRUE;
    }
    return FALSE;
  }

  /**
   * Get the plugin label.
   *
   * @return string
   *   The plugin label.
   */
  public function getLabel() {
    return $this->pluginDefinition['label'] ?: '';
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DependencySerializationTrait::$_entityStorages protected property An array of entity type IDs keyed by the property name of their storages.
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function 1
DependencySerializationTrait::__wakeup public function 2
PluginBase::$configuration protected property Configuration information passed into the plugin. 1
PluginBase::$pluginDefinition protected property The plugin implementation definition. 1
PluginBase::$pluginId protected property The plugin_id.
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition 3
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
PluginBase::isConfigurable public function Determines if the plugin is configurable.
TfaBasePlugin::$alreadyAccepted protected property Whether the code has been used before.
TfaBasePlugin::$code protected property The user submitted code to be validated.
TfaBasePlugin::$codeLength protected property The allowed code length.
TfaBasePlugin::$encryptionProfile protected property Encryption profile.
TfaBasePlugin::$encryptService protected property Encryption service.
TfaBasePlugin::$errorMessages protected property The error for the current validation.
TfaBasePlugin::$isValid protected property Whether the validation succeeded or not.
TfaBasePlugin::$uid protected property The user id.
TfaBasePlugin::$userData protected property Provides the user data service object.
TfaBasePlugin::alreadyAcceptedCode protected function Whether code has already been used.
TfaBasePlugin::decrypt protected function Decrypt a encrypted string.
TfaBasePlugin::encrypt protected function Encrypt a plaintext string.
TfaBasePlugin::getErrorMessages public function Get error messages suitable for form_set_error().
TfaBasePlugin::getLabel public function Get the plugin label.
TfaBasePlugin::ready abstract public function Determine if the plugin can run for the current TFA context. 4
TfaBasePlugin::storeAcceptedCode protected function Store validated code to prevent replay attack.
TfaBasePlugin::submitForm public function Submit form. 1
TfaBasePlugin::validate protected function Validate code. 1
TfaBasePlugin::__construct public function Constructs a new Tfa plugin object. Overrides PluginBase::__construct 2
TfaDataTrait::deleteUserData protected function Deletes data stored for the current validated user account.
TfaDataTrait::getUserData protected function Returns data stored for the current validated user account.
TfaDataTrait::setUserData protected function Store user specific information.
TfaDataTrait::tfaGetTfaData protected function Get TFA data for an account.
TfaDataTrait::tfaSaveTfaData public function Save TFA data for an account.