- 🇳🇱Netherlands Maico de Jong
Rerolled the latest patch against 2.x-dev:
- Removed support for 'remaining skips' when forced 2FA is selected for now, Makes it a lot easier to implement and communicate.
- Rewritten the EventSubscriber and functional tests, reused the available TfaLoginContextTrait.
- Excluded all 2FA and user login/logout/password paths from forced 2FA redirect.
Maybe it's a good idea to move extra functionalities like configurable whitelist or remaining skips integration (needs new messages) to new tickets and focus on the basics first.
- Status changed to Needs review
almost 2 years ago 8:46pm 6 February 2023 The last submitted patch, 11: 3223327-implement-force_tfa_setup-11.patch, failed testing. View results →
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.- Status changed to Needs work
almost 2 years ago 9:03pm 6 February 2023 - Status changed to Needs review
almost 2 years ago 9:08pm 6 February 2023 - 🇳🇱Netherlands Maico de Jong
Excluded user edit routes for password reset support
- 🇮🇳India Madhu Kumar M E
Trying to applying latest patch not applying. Added screenshot for reference.
- 🇳🇱Netherlands Maico de Jong
@Madhu Kumar M E
Patch should work, tests also passed. Please make sure you are applying the patch correctly: through composer-patches or manually at the tfa module root using the 2.x-dev branch. Looking at your screenshot the patch was not applied to the tfa module directory.
- 🇮🇳India Madhu Kumar M E
@Maico de Jong
I made a mistake, i didn't checked my directory properly.
Verified the patch #16 and tested it on Drupal version 10.1.x. The patch works fine also and I have added the screenshots for reference.Thanks for reminding me.
- Status changed to RTBC
over 1 year ago 7:22am 1 March 2023 - 🇦🇺Australia malks
I was just testing this and noticed that when "Force TFA setup" is selected the text box for "Skip Validation" is hidden. Is this as designed?
- Status changed to Needs work
over 1 year ago 7:42pm 29 June 2023 - 🇺🇸United States cmlara
-
+++ b/src/EventSubscriber/ForceTfaSetup.php @@ -0,0 +1,134 @@ + $user = $this->userStorage->load($this->currentUser->id()); + $this->setUser($user); + + if ($this->isReady() || !$this->forceTFASetup()) { + return; + } +
This can be VERY heavy latency. While the built in plugins can get this with just a few database queries, on a test(non performance tuend) laptop redirect() this ends up being ~10% of the request time (22ms) for the front page to load.
With other authentication plugins isReady() could trigger a network query which will add even more latency and network dependency, see https://git.drupalcode.org/project/tfa_vault_totp/-/blob/0.x/src/Plugin/... for an example.
I've been experimenting with using the request_session and parameter bags, perhaps similar may be a good fit here?.
-
+++ b/src/EventSubscriber/ForceTfaSetup.php @@ -0,0 +1,134 @@ + $ignored_route_names = [
I'm debating if we should we include system.403 and system.404 and system.4xx in here as well? I hit 📌 Inform admin that role does not have permission to setup own tfa Fixed and ended up in an endless redirect loop. Ideally this shouldn't ever happen when redirecting to the TFA setup page, and fixing that issue would solve this concern here, however I can't help wondering if there might be other hidden problems and that exempting these paths might be wise.
✨ Redirect to validation setup after login without tfa Needs work would appear to be a related request.
-
- 🇦🇺Australia yeniatencio
Rerolling #16 as patch is not applying clean anymore.
- 🇦🇺Australia yeniatencio
Missed the EventSubscriber and functional test on #23.
Adding patch again.
- 🇦🇺Australia yeniatencio
Re-rolling #25 as failing to applied on 8.x-1.2
- 🇦🇺Australia yeniatencio
Missed the service and the unit test on last patch. Re-rolling patch for version 8.x-1.x
- 🇺🇸United States cmlara
Following up on my comments from #22
In 📌 Inform admin that role does not have permission to setup own tfa Fixed we did not actually prevent an access denied error as the action to require TFA is different from being permitted to setup TFA, as such at the system.403 should be exempted (at least for the TFA setup page) to prevent a loop.
- 🇦🇺Australia yovince Melbourne
The patch prevents generating CSS and JS aggregation in Drupal 10.1.x. fixed by excluding the CSS and JS asset routes from the list.
- 🇮🇳India itsbakiya
@yovince I used your patch but same issue happening again. JS aggragation not working Drupal 10.1.x
- 🇦🇺Australia dpi Perth, Australia
- 🇳🇴Norway neslee canil pinto India
Rerolled patch for latest 2.x verison
- 🇮🇳India narendragupta
Patch is not getting applied for 8.x-1.5 tfa module version.
specifically to src/TfaLoginContextTrait.php file. - 🇬🇧United Kingdom alexharries
Hello all,
I've spotted four issues with the patch in #35:
- Hunk in tfa.schema.yml doesn't apply because indentation of two subsequent lines is missing a space
- Indentation is 4 spaces instead of two
- Hiding the Allowed Validation plugins field when "force redirection" is enabled seems like a bad idea to me; when hidden, the administrator can't change which validation plugins are selected, and because this field is below the "force" checkbox, users working from top to bottom down the form might never see the allowed validation plugins field.
- A typo; "FTA"
Attaching a patch which:
- Fixes broken indentation - bad:
@@ -11,6 +11,9 @@ tfa.settings: sequence: type: string label: 'Role' + forced: + type: integer + label: 'Force required roles to setup when on last validation skip' send_plugins: type: sequence label: 'Enabled send plugins'
Good (i.e. the last two lines):
@@ -11,6 +11,9 @@ tfa.settings: sequence: type: string label: 'Role' + forced: + type: integer + label: 'Force required roles to setup when on last validation skip' send_plugins: type: sequence label: 'Enabled send plugins'
- Fixes indents - bad:
+ public function __construct(RouteMatchInterface $route_match, MessengerInterface $messenger, AccountProxyInterface $current_user, ConfigFactoryInterface $config_factory, + EntityTypeManagerInterface $entity_type_manager, UserDataInterface $user_data, TfaValidationPluginManager $tfa_validation_manager, TfaLoginPluginManager $tfa_plugin_manager) { + $this->messenger = $messenger; + $this->routeMatch = $route_match; + $this->currentUser = $current_user; + $this->userStorage = $entity_type_manager->getStorage('user'); + $this->tfaSettings = $config_factory->get('tfa.settings'); + $this->userData = $user_data; + $this->tfaValidationManager = $tfa_validation_manager; + $this->tfaLoginManager = $tfa_plugin_manager; + } + + /** + * Redirect users to TFA overview when no remaining skips. + * + * @param \Symfony\Component\HttpKernel\Event\RequestEvent $event + * The request event. + */ + public function redirect(RequestEvent $event): void { + /** @var \Drupal\user\UserInterface $user */ + $user = $this->userStorage->load($this->currentUser->id()); + $this->setUser($user); + + if ($this->isReady() || !$this->forceTFASetup()) { + return; + } + + $this->messenger->addWarning(t('You need to enable Two Factor Authentication.')); + + // Don't redirect the user if on password/profile edit page, + // as it is possible the user used one-time login URL + // and need to change the password. + $ignored_route_names = [ + 'user.login', + 'user.logout', + 'user.pass', + 'user.edit', + 'entity.user.edit_form', + 'user.reset.login', + 'user.reset', + 'user.reset.form', + 'user.well-known.change_password', + 'tfa.entry', + 'tfa.login', + 'tfa.overview', + 'tfa.validation.setup', + 'tfa.disable', + 'tfa.plugin.reset', + ]; + if (in_array($this->routeMatch->getRouteName(), $ignored_route_names)) { + return; + } + + $tfa_overview_url = Url::fromRoute('tfa.overview', ['user' => $this->user->id()]); + $event->setResponse(new RedirectResponse($tfa_overview_url->toString())); + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() { + $events[KernelEvents::REQUEST][] = ['redirect', 32]; + return $events; + } + +}
Good:
+ public function __construct(RouteMatchInterface $route_match, MessengerInterface $messenger, AccountProxyInterface $current_user, ConfigFactoryInterface $config_factory, + EntityTypeManagerInterface $entity_type_manager, UserDataInterface $user_data, TfaValidationPluginManager $tfa_validation_manager, TfaLoginPluginManager $tfa_plugin_manager) { + $this->messenger = $messenger; + $this->routeMatch = $route_match; + $this->currentUser = $current_user; + $this->userStorage = $entity_type_manager->getStorage('user'); + $this->tfaSettings = $config_factory->get('tfa.settings'); + $this->userData = $user_data; + $this->tfaValidationManager = $tfa_validation_manager; + $this->tfaLoginManager = $tfa_plugin_manager; + } + + /** + * Redirect users to TFA overview when no remaining skips. + * + * @param \Symfony\Component\HttpKernel\Event\RequestEvent $event + * The request event. + */ + public function redirect(RequestEvent $event): void { + /** @var \Drupal\user\UserInterface $user */ + $user = $this->userStorage->load($this->currentUser->id()); + $this->setUser($user); + + if ($this->isReady() || !$this->forceTFASetup()) { + return; + } + + $this->messenger->addWarning(t('You need to enable Two Factor Authentication.')); + + // Don't redirect the user if on password/profile edit page, + // as it is possible the user used one-time login URL + // and need to change the password. + $ignored_route_names = [ + 'user.login', + 'user.logout', + 'user.pass', + 'user.edit', + 'entity.user.edit_form', + 'user.reset.login', + 'user.reset', + 'user.reset.form', + 'user.well-known.change_password', + 'tfa.entry', + 'tfa.login', + 'tfa.overview', + 'tfa.validation.setup', + 'tfa.disable', + 'tfa.plugin.reset', + ]; + if (in_array($this->routeMatch->getRouteName(), $ignored_route_names)) { + return; + } + + $tfa_overview_url = Url::fromRoute('tfa.overview', ['user' => $this->user->id()]); + $event->setResponse(new RedirectResponse($tfa_overview_url->toString())); + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() { + $events[KernelEvents::REQUEST][] = ['redirect', 32]; + return $events; + } + +}
- Removes the behaviour to hide allowed validation plugins - i.e. this chunk:
@@ -186,7 +194,14 @@ class SettingsForm extends ConfigFormBase { '#default_value' => $config->get('allowed_validation_plugins') ?: ['tfa_totp'], '#description' => $this->t('Plugins that can be setup by users for various TFA processes.'), // Show only when TFA is enabled. - '#states' => $enabled_state, + '#states' => [ + 'visible' => [ + [ + ':input[name="tfa_enabled"]' => ['checked' => TRUE], + ':input[name="tfa_forced"]' => ['checked' => FALSE], + ], + ], + ], '#required' => TRUE, ]; $form['tfa_validate'] = [
- Fixes the typo "FTA":
+ '#description' => $this->t('Force TFA setup on login, redirect user to FTA overview page.'),
... to:
+ '#description' => $this->t('Force TFA setup on login, redirect user to TFA overview page.'),
- 🇬🇧United Kingdom alexharries
Found another incorrect indent - updated patch attached.
- 🇬🇧United Kingdom alexharries
Playing whack-a-mole with indentation... [facepalm.gif]
- 🇺🇸United States cmlara
Generally development should occur on the latest branch first (2.x) and be backported to older branches once complete. This helps prevent a feature or bugfix being lost in newer versions. Addtionaly it reduces overall effort of maintaining multiple branches at once.
Leaving issue as needs-work per #22 and #29 comments.
Note: As part of the DrupalCi deprecation process the TFA project has already been migrated to only use GitLabCI for testing of the D8+ development branches. Due to this change we need contributors to utilize the MR workflow going forward as patches are no longer testable in the TFA project.
Contributors will likely encounter this with other projects as the patch workflow as DrupalCi has already been significantly limited as of Febuary 2024 and will be fully disabled for all D.O. hosted projects on July 1st. See https://www.drupal.org/about/core/blog/drupalci-and-all-patch-testing-wi... → for more information.
- 🇬🇧United Kingdom alexharries
Hi @cmlara, apologies - I provided the patch in #38 in good faith to fix the broken patch in #35. I'm not working with the 2.x branch due to SA-CONTRIB-2024-003, so wasn't able to provide a patch against that branch.
Hopefully the patch at #38 will help those still on 8.x-1.x ¯\_(ツ)_/¯
/A
Hi all!
I tried to update the patch from #30 the the new rerolled patch added in #38. I noticed a major difference (2 lines hehe), and thats in the $ignored_routes array. As both css and JS are not ignored, your assest will not be loaded in. Basicly #30 comment got reversed. Please reroll the patch of #38, but with the systems routes added in :)
- 🇬🇧United Kingdom alexharries
Hi MarcellinoStroosnijder,
> Please reroll the patch of #38, but with the systems routes added in :)
I'm away from that project now so won't be able to do this, but feel free to do the re-roll yourself :)
/Alex
- First commit to issue fork.
- 🇮🇱Israel jkdev
Dear friends,
I have created a merge request 89 (MR) incorporating the various patches. You can review the MR and apply it as a patch. It is based on the 2.x branch.
This is the initial commit, so I would appreciate your feedback on whether it makes sense and if everything looks correct.
Please let us know if any parts are missing or if there are additional tasks that need to be addressed.
Thank you.
- 🇺🇸United States cmlara
Provided feedback in the MR. Leaving as MR for concerns.
- 🇮🇱Israel jkdev
Can you please read through the logic, let me know if I missed something:
Adding
event_subscriber
which listens toKernelEvents::REQUEST
, make some checks, and if needed - redirect the user to TFA overview page - preventing navigating to other pages in the site.The checks are:
- Is TFA is enabled?
- Is the current route applicable for redirect? (we should allow logging-out, running-cron, css/js/images assets, and setting up the TFA)
- Is user logged in? (anonymous users are irrelevant)
- Is TFA setting force user to setup TFA?
- Does TFA has at least one validation plugin enabled?
At this point we should set a warning in messenger: "You must setup TFA".
Further checks:
- Is this route applicable for a Redirect?
- If not, should we block the request altogether?
- Are there situations that we would allow bypassing this behavior?
At this point we should Issue the redirect for TFA overview page.
The order of the checks are not final, and should sorted by their complexity and latency impact.