Allow bypassing default authentication plugin

Created on 27 September 2023, about 1 year ago

Problem/Motivation

(I file this as "feature request", I'm not sure the current behaviour is intended).

Context: we are implementing a custom email authentication plugin to be used along the main one (TOTP) in order to provide our users with alternative methods to access TFA: the user will be able to setup a specific TFA method, or both if they want.

When setting up TFA, the module requires setting a default authentication plugin.

If the user does not then setup the default plugin (eg, they don't use any TOTP application, they just want email OTP) the main module will try to use it anyway (eg, in "src/Form/EntryForm.php@buildForm" and "src/TfaLoginContextTrait.php@isReady"), miss a proper setup and fail.

  // src/TfaLoginContextTrait.php
  // The user has a validation plugin set, but not the default one;
  // $validation_plugin->ready() fails, and the module acts as the user has not set TFA yet. 
  public function isReady() {
    // If possible, set up an instance of tfaValidationPlugin and the user's
    // list of plugins.
    $default_validation_plugin = $this->tfaSettings->get('default_validation_plugin');
    if (!empty($default_validation_plugin)) {
      /** @var \Drupal\tfa\Plugin\TfaValidationInterface $validation_plugin */
      try {
        $validation_plugin = $this->tfaPluginManager->createInstance($default_validation_plugin, ['uid' => $this->user->id()]);
        if (isset($validation_plugin) && $validation_plugin->ready()) {
          return TRUE;
        }
      }
      catch (PluginException $e) {
        return FALSE;
      }
    }

    return FALSE;
  }
public function buildForm(array $form, FormStateInterface $form_state, $uid = NULL, string $hash = '') {
    $alternate_plugin = $this->getRequest()->get('plugin');
    $validation_plugin_definitions = $this->tfaPluginManager->getValidationDefinitions();
    $user_settings = $this->userData->get('tfa', $uid, 'tfa_user_settings');
    $user_enabled_validation_plugins = $user_settings['data']['plugins'] ?? [];

    // Default validation plugin, then check for enabled alternate plugin.
    $validation_plugin = $this->tfaSettings->get('default_validation_plugin');

    if ($alternate_plugin && !empty($validation_plugin_definitions[$alternate_plugin]) && !empty($user_enabled_validation_plugins[>
      $validation_plugin = $alternate_plugin;
      $form['#cache'] = ['max-age' => 0];
    }
    // [...] 

Steps to reproduce

  • Setup and enable the main TFA module
  • Enable the "TOTP" and "HOTP" authentication plugins
  • Set "TOTP" as default authentication plugin
  • Login with a non-admin user, and just setup HOTP
  • Logout and login again

The user sees the Authentication Code form for the selected method (in this case, HOTP)

The user is logged in, and is promped to "set-up a TFA method"; if implemented, the TFA lock-out counter is engaged ("You have X logins left before your account is locked")

Proposed resolution

Instead of always using the default plugin (and after checking if a specific method is requested via request parameter) "src/Form/EntryForm.php@buildForm" and "src/TfaLoginContextTrait.php@isReady" first check if the user has authentication plugins set, and uses the first one available.

Feature request
Status

Active

Version

2.0

Component

Code

Created by

🇩🇪Germany giuspe Berlin

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Production build 0.71.5 2024