Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
80f3325
[SD-1482] Added text changes to the tfa overview page.
MdNadimHossain Jan 29, 2026
bd28573
[SD-1482] Updated tfa and tfa email otp module.
MdNadimHossain Jan 29, 2026
ba29307
[SD-1482] Added changes for tfa setup form and enabaled view password…
MdNadimHossain Feb 1, 2026
8c5cfdc
[SD-1482] Added Email setup from changes.
MdNadimHossain Feb 1, 2026
4b02a1e
[SD-1482] Added breadcrumb changes and some label, title and descript…
MdNadimHossain Feb 2, 2026
fdda4c9
[SD-1482] Updated dashboard module to redirect to tfa setup form afte…
MdNadimHossain Feb 3, 2026
bcda8e0
[SD-1482] Fixed type miss match error during build and lint fix.
MdNadimHossain Feb 4, 2026
4eb2a59
[SD-1482] Fixed type miss match error during build for view password …
MdNadimHossain Feb 4, 2026
0388028
[SD-1482] Added custom messages and replaced tfa module messages.
MdNadimHossain Feb 5, 2026
96916a5
Merge branch 'develop' into feature/SD-1482-mfa-setup-enhancements
MdNadimHossain Feb 9, 2026
bc30872
lint fix.
MdNadimHossain Feb 9, 2026
1831efc
[SD-1483] Added Multifactor authentication verification enhancements.
MdNadimHossain Feb 10, 2026
f8ca4a4
[SD-1483] lint fix.
MdNadimHossain Feb 10, 2026
dd66227
Added hook to update email templates for TFA and TFA email otp.
MdNadimHossain Feb 11, 2026
c63adb0
Merge branch 'develop' into feature/SD-1482-mfa-setup-enhancements
MdNadimHossain Feb 11, 2026
4598c7a
lint fix.
MdNadimHossain Feb 11, 2026
da7e68c
Added bheat test for the multi-faction authentication enhancements.
MdNadimHossain Feb 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions behat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ default:
- '%paths.base%/modules/tide_webform/tests/behat/features'
- '%paths.base%/modules/tide_publication/tests/behat/features'
- '%paths.base%/modules/tide_alert/tests/behat/features'
- '%paths.base%/modules/tide_tfa/tests/behat/features'
contexts:
- Tide\Tests\Context\FeatureContext
- Drupal\DrupalExtension\Context\MinkContext
Expand Down
7 changes: 4 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@
"drupal/smtp": "^1.2",
"drupal/stage_file_proxy": "^2.0",
"drupal/tablefield": "2.4",
"drupal/tfa": "1.9",
"drupal/tfa_email_otp": "^1.0@beta",
"drupal/tfa": "^1.12",
"drupal/tfa_email_otp": "^1.0",
"drupal/token_conditions": "dev-compatible-with-d10",
"drupal/token_filter": "^2.0",
"drupal/twig_field_value": "^2.0",
Expand Down Expand Up @@ -124,7 +124,8 @@
"drupal/shield": "^1.8",
"drupal/media_alias_display": "^2.1",
"drupal/search_api_exclude_entity": "^3.0",
"drupal/default_paragraphs": "^2.0"
"drupal/default_paragraphs": "^2.0",
"drupal/view_password": "^6.0"
},
"repositories": {
"drupal": {
Expand Down
29 changes: 29 additions & 0 deletions modules/tide_dashboard/tide_dashboard.module
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
* Tide Dashboard.
*/

use Drupal\Core\Breadcrumb\Breadcrumb;
use Drupal\Core\Link;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;

/**
* Implements hook_toolbar_alter().
*
Expand Down Expand Up @@ -39,3 +44,27 @@ function tide_dashboard_user_login() {
$request->query->set('destination', '/admin/workbench');
}
}

/**
* Implements hook_system_breadcrumb_alter().
*/
function tide_dashboard_system_breadcrumb_alter(Breadcrumb &$breadcrumb, RouteMatchInterface $route_match, array $context) {
$links = $breadcrumb->getLinks();

if (!empty($links)) {
// Check if the first link is the Home link.
if ($links[0]->getUrl()->isRouted() && $links[0]->getUrl()->getRouteName() === '<front>') {

$new_url = Url::fromUserInput('/admin/workbench');
$new_link = Link::fromTextAndUrl($links[0]->getText(), $new_url);

// Swap the first link to workbench.
$links[0] = $new_link;

$reflection = new \ReflectionClass($breadcrumb);
$property = $reflection->getProperty('links');
$property->setAccessible(TRUE);
$property->setValue($breadcrumb, $links);
}
}
}
149 changes: 149 additions & 0 deletions modules/tide_tfa/src/Form/TideTfaOverviewForm.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
<?php

namespace Drupal\tide_tfa\Form;

use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\tfa\Form\TfaOverviewForm;
use Drupal\user\UserInterface;

/**
* Provides a customised TFA overview form for Tide.
*
* Extends the core TFA overview form to alter the presentation and behaviour
* of multi-factor authentication setup and status within the Tide CMS.
*/
class TideTfaOverviewForm extends TfaOverviewForm {

/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state, UserInterface $user = NULL) {
$output = [];
$output['info'] = [
'#type' => 'markup',
'#markup' => '<p>' . $this->t('Multi-factor authentication provides
additional security for your account.</br>With multi-factor authentication enabled,
you log in to the CMS with a verification code in addition to your username and
password.') . '</p>',
];
// $form_state['storage']['account'] = $user;.
$config = $this->config('tfa.settings');
$user_tfa = $this->tfaGetTfaData($user->id(), $this->userData);
$enabled = isset($user_tfa['status']) && $user_tfa['status'];

if ($config->get('enabled')) {
$enabled = isset($user_tfa['status'], $user_tfa['data']) && !empty($user_tfa['data']['plugins']) && $user_tfa['status'];
$enabled_plugins = $user_tfa['data']['plugins'] ?? [];

$validation_plugins = $this->tfaValidation->getDefinitions();
if ($validation_plugins) {
$output['validation'] = [
'#type' => 'details',
'#title' => $this->t('Validation plugins'),
'#open' => TRUE,
];

foreach ($validation_plugins as $plugin_id => $plugin) {
if (!empty($config->get('allowed_validation_plugins')[$plugin_id])) {
$output['validation'][$plugin_id] = $this->tfaPluginSetupFormOverview($plugin, $user, !empty($enabled_plugins[$plugin_id]));
}
}
}

if ($enabled) {
$login_plugins = $this->tfaLogin->getDefinitions();
if ($login_plugins) {
$output['login'] = [
'#type' => 'details',
'#title' => $this->t('Login plugins'),
'#open' => TRUE,
'#access' => FALSE,
];

foreach ($login_plugins as $plugin_id => $plugin) {
if (!empty($config->get('login_plugins')[$plugin_id])) {
$output['login'][$plugin_id] = $this->tfaPluginSetupFormOverview($plugin, $user, TRUE);
$output['login']['#access'] = TRUE;
}
}
}

$send_plugins = $this->tfaSend->getDefinitions();
if ($send_plugins) {
$output['send'] = [
'#type' => 'details',
'#title' => $this->t('Send plugins'),
'#open' => TRUE,
];

foreach ($send_plugins as $plugin_id => $plugin) {
if (!empty($config->get('send_plugins')[$plugin_id])) {
$output['send'][$plugin_id] = $this->tfaPluginSetupFormOverview($plugin, $user, TRUE);
}
}
}
}

// Moved it inside to show the status if only TFA is enabled.
if (!empty($user_tfa)) {
if ($enabled && !empty($user_tfa['data']['plugins'])) {
$disable_url = Url::fromRoute('tfa.disable', ['user' => $user->id()]);
if ($disable_url->access()) {
$status_text = $this->t('Status: <strong>Multi-factor authentication enabled</strong>, set
@time. <a href=":url">Disable Multi-factor authentication</a>', [
'@time' => $this->dateFormatter->format($user_tfa['saved']),
':url' => $disable_url->toString(),
]);
}
else {
$status_text = $this->t('Status: Multi-factor authentication enabled');
}
}
else {
$status_text = $this->t('Status: Multi-factor authentication disabled');
}
$output['status'] = [
'#type' => 'markup',
'#markup' => '<p>' . $status_text . '</p>',
];
}

if (!$config->get('forced')) {
$validation_skipped = $user_tfa['validation_skipped'] ?? 0;

$output['validation_skip_status'] = [
'#type' => 'markup',
'#markup' => '<p>' . $this->t(
'Authentication setup: @remaining logins remain before multi-factor authentication is required',
[
'@remaining' => $config->get('validation_skip') - $validation_skipped,
]
) . '</p>',
];
}
}
else {
$output['disabled'] = [
'#type' => 'markup',
'#markup' => '<b>Currently there are no enabled plugins.</b>',
];
}

if ($this->canPerformReset($user)) {
$output['actions'] = ['#type' => 'actions'];
$output['actions']['reset_skip_attempts'] = [
'#type' => 'submit',
'#value' => $this->t('Reset skip validation attempts'),
'#submit' => ['::resetSkipValidationAttempts'],
];
$output['account'] = [
'#type' => 'value',
'#value' => $user,
];
}

return $output;
}

}
12 changes: 9 additions & 3 deletions modules/tide_tfa/src/Plugin/TfaSetup/TideTfaEmailOtpSetup.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,16 @@ public function getSetupForm(array $form, FormStateInterface $form_state) {
$params = $form_state->getValues();
$userData = $this->userData->get('tfa', $params['account']->id(), 'tfa_email_otp');

$form['email_otp_heading'] = [
'#type' => 'html_tag',
'#tag' => 'h2',
'#value' => $this->t('Email authentication for login'),
];

// [SD-294] Changing the title and description.
$form['enabled'] = [
'#type' => 'checkbox',
'#title' => $this->t('Yes, email me a verification code every time I log in'),
'#title' => $this->t('I agree to be sent a verification code via email each time I log in.'),
'#description' => $this->t('Each single-use verification code expires after use, or after 10 minutes if not used.'),
'#required' => TRUE,
'#default_value' => $userData['enable'] ?? 0,
Expand All @@ -58,7 +64,7 @@ public function getOverview(array $params) {
// [SD-294] Modify the description.
$description = '';
if ($params['enabled']) {
$description .= $this->t('<p><b>Enabled</b></p>');
$description .= $this->t('<p><b>Multi-factor authentication enabled</b></p>');
}
$output = [
'heading' => [
Expand All @@ -77,7 +83,7 @@ public function getOverview(array $params) {
'#access' => !$params['enabled'],
'#links' => [
'admin' => [
'title' => $this->t('Enable two-factor authentication via email'),
'title' => $this->t('Enable multi-factor authentication via email'),
'url' => Url::fromRoute('tfa.validation.setup', [
'user' => $params['account']->id(),
'method' => $params['plugin_id'],
Expand Down
Loading