diff -u b/src/Form/EntryForm.php b/src/Form/EntryForm.php --- b/src/Form/EntryForm.php +++ b/src/Form/EntryForm.php @@ -147,18 +147,17 @@ $form['#cache'] = ['max-age' => 0]; } - // Get current validation plugin form. + // Instantiate the validation plugin. $this->tfaValidationPlugin = $this->tfaValidationManager->createInstance($validation_plugin, ['uid' => $user->id()]); + if ($this->tfaValidationPlugin instanceof TfaValidationSendInterface) { + $this->tfaValidationManager->begin($validation_plugin); + } + // Get current validation plugin form. $form = $this->tfaValidationPlugin->getForm($form, $form_state); + // Get the re-send button if one exists. if ($this->tfaValidationPlugin instanceof TfaValidationSendInterface) { - $sent = $this->getRequest()->getSession()->get('validation_plugin_begin'); - - if (empty($sent[$validation_plugin])) { - $this->tfaValidationPlugin->begin(); - $sent[$validation_plugin] = 1; - $this->getRequest()->getSession()->set('validation_plugin_begin', $sent); - } + // @TODO Consider how best to add the re-send button. } $this->tfaLoginPlugins = $this->tfaLoginManager->getPlugins(['uid' => $user->id()]); @@ -287,7 +286,6 @@ // TODO Should finalize() be after user_login_finalize or before?! // TODO This could be improved with EventDispatcher. - $this->getRequest()->getSession()->remove('validation_plugin_begin'); $this->finalize(); $this->flood->clear('tfa.failed_validation', $this->floodIdentifier); $form_state->setRedirect(''); diff -u b/src/Form/TfaLoginForm.php b/src/Form/TfaLoginForm.php --- b/src/Form/TfaLoginForm.php +++ b/src/Form/TfaLoginForm.php @@ -8,6 +8,7 @@ use Drupal\Core\Render\RendererInterface; use Drupal\Core\Routing\RedirectDestinationInterface; use Drupal\Core\Url; +use Drupal\tfa\Plugin\TfaValidationSendInterface; use Drupal\tfa\TfaContext; use Drupal\tfa\TfaDataTrait; use Drupal\tfa\TfaLoginTrait; @@ -174,6 +175,15 @@ return parent::submitForm($form, $form_state); } + // Instantiate the validation plugins. + $validation_plugin_definitions = $this->tfaValidationManager->getDefinitions(); + foreach ($validation_plugin_definitions as $plugin_id => $plugin_definition) { + $plugin_instance = $this->tfaValidationManager->createInstance($plugin_definition, ['uid' => $user->id()]); + if ($plugin_instance instanceof TfaValidationSendInterface) { + $this->tfaValidationManager->reset($plugin_instance); + } + } + // Setup TFA. if ($this->tfaContext->isReady()) { $this->loginWithTfa($form_state); reverted: --- b/src/Plugin/TfaValidationSendInterface.php +++ /dev/null @@ -1,20 +0,0 @@ -alterInfo('tfa_validation'); $this->setCacheBackend($cache_backend, 'tfa_validation'); $this->userData = $user_data; $this->encryptService = $encrypt_service; + $this->tempStore = $temp_store; $this->encryptionProfileManager = $encryption_profile_manager; } @@ -91,4 +109,46 @@ class TfaValidationPluginManager extends DefaultPluginManager { return $plugin; } + /** + * Returns the key used to record whether the plugin needs to be initiated. + * + * @param \Drupal\tfa\Plugin\TfaValidationSendInterface $validation_plugin + * The validation plugin being initiated. + * + * @return string + */ + protected function getInitiationKey(TfaValidationSendInterface $validation_plugin) { + return implode(':', [self::VALIDATION_BEGIN, $validation_plugin->getPluginId()]); + } + + /** + * Initiate any functionality that needs to run when the plugin is first + * loaded, and mark the plugin as begun. + * + * @param \Drupal\tfa\Plugin\TfaValidationSendInterface $validation_plugin + * The validation plugin being initiated. + */ + public function begin(TfaValidationSendInterface $validation_plugin) { + if ($this->tempStore->get($this->getInitiationKey($validation_plugin))) { + $validation_plugin->begin(); + + // Mark this plugin as initiated. + $this->tempStore->set($this->getInitiationKey($validation_plugin), FALSE); + } + } + + /** + * Mark the validation plugin as ready to begin. + * + * @param \Drupal\tfa\Plugin\TfaValidationSendInterface $validation_plugin + * The validation plugin being reset. + */ + public function reset(TfaValidationSendInterface $validation_plugin) { + if (!method_exists($validation_plugin, 'begin')) { + return; + } + + $this->tempStore->set($this->getInitiationKey($validation_plugin), TRUE); + } + }