Needs work
Project:
Two-factor Authentication (TFA)
Version:
2.x-dev
Component:
Code
Priority:
Normal
Category:
Task
Assigned:
Unassigned
Reporter:
Created:
13 Dec 2017 at 15:31 UTC
Updated:
14 Oct 2022 at 08:23 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #2
daggerhart commentedComment #3
daggerhart commentedComment #4
cslevy commentedHi, I created a patch with the Send Plugin API. I didn't have time to handle the test as well.
Here is my patch
Comment #5
jonas139 commentedComment #6
jonas139 commentedComment #7
brentschuddinck commentedComment #8
kalpaitch commentedIn regards to: * Tease out TfaSendInterface.php. Is begin() the only necessary method?
I'm not sure begin() is the right method even. I see send() as the main method, the reason for this is that it doesn't have to happen at the beginning of the validation process. Most send plugins will use a 'resend' button and having this fire the begin() method all over again seems potentially odd.
Or it might be that a user has two methods enabled, but an authenticator otp code is the default, in this situation you might not want to send unnecessary codes until the user explicitly choose the SMS verification, or some other time of a user's choosing.
On top of this I'm wondering if there aren't things that happen once at the beginning but not when re-sending a code, or vice versa.
Anyway, re-rolled the patch and added some tests to start with.
Comment #9
daggerhart commented@kalpaitch Thanks for taking a look at this.
I haven't had the time to look at implementing this API thoughtfully, which is why it's not implemented, but I like your line of thinking about the begin() vs send() methods and general needs for this new API.
If you want to propose the API as you think it should be done, I'm all ears and welcome the discussion. I believe the begin() method is how the send api in tfa 7.x is implemented, which is the only reason why I bring it up at all. We don't have to follow that approach if we think something else makes more sense.
Comment #10
kalpaitch commentedI'm going to add this comment here although it is broader than just the send plugin. I see a few things holding back the send plugins with the current setup, let me know what you think...
I've attached a little ditty scribble to try and get across these thoughts.

Comment #11
mwebaze commented@kalpaitch I have created a patch that can be used to send codes to email but also validate and also remove them incase they haven't been used with-in a specific period of time. I am open to helping out with this initiative.
Comment #12
mwebaze commentedI just realized patch 'create_the_send_plugin_api-2930532-11.patch' is an empty file. Please find attached create_the_send_plugin_api-2930532-12.patch
Thanks
Comment #13
mwebaze commentedAn updated patch. The last one missed out some new files I had added.
Comment #14
mwebaze commentedPatch create_the_send_plugin_api-2930532-13.patch is ready for review.
Comment #15
kalpaitch commentedThat's awesome, thanks that would be awesome, I'm sure we can pick the better parts of each patch. Before I get started though I think my comments from #2930532-10: Create the Send Plugin API with a working test still stand:
IMO these should both to be implemented, but the first point will require a re-work to how existing plugins (ga_login) validate, happy to provide these patches too though. @daggerhart what are your thoughts?
Comment #16
daggerhart commented@mwebaze thanks for the patch! This looks like a good place to get this patch moving with a working email plugin. I'm still reviewing the patch atm and will report back shortly.
@kalpaitch Yes to number 1, I think there should be a unified way to validate the plugin as soon as a user enables it for their account. In the case of ga_login, this is somewhat already happening since the setup of the user's authenticator is required to enable the plugin on their account. But that step isn't technically the same kind of validation you're talking about, and in other cases that step may not be as obvious and the tfa module would benefit from providing that immediate validation step. I like your idea for splitting the setup route into 2 distinct steps, one for configuration (setup plugin), and another for validation immediately after setup (validation plugin). In that scenario, we should require successful validation before the setup is considered to be complete and the plugin enabled for the account.
Regarding #2, yes! I completely agree that the send plugins should only `begin()` (or equivalent method) when the validation form is retrieved.
Comment #17
daggerhart commented@mwebaze This is really great, thanks! It looks like you started with the #8 patch, and worked from there. That is awesome and made half of this patch very easy to review. I've done a bit of manual testing and see that the email plugin works as well!
I think our next steps are to split this up into its three parts (noted below) and roll new patches for each part. IMO that will facilitate discussion and updates in a good way. Here we can focus on the ideal send plugin API, and the other issues can focus on the ideals for their parts. I'm going to make a pass at splitting this up immediately after I post this comment to facilitate moving that process forward.
1. (this issue) #2930532: Create the Send Plugin API with a working test
2. #2930537: Create an Email Send Plugin and test
3. #2930541: Create "Email one-time-code" Validation Plugin & related Setup Plugin
Comment #18
daggerhart commentedAttached is my pass at rerolling this focused on the send api only. I've made a few changes to the configuration name, added a simple test send plugin, and updated the tests to pass (hopefully).
@kalpaitch, this should look very familiar to you because @mwebaze started his work on top of your patch.
I'll update the other two issues soon.
Feedback always welcome.
Comment #19
daggerhart commentededit: removed previous comment because it was over complicated the approach... see below
Comment #20
mwebaze commentedThe ValidationSendableInterface is a good idea but I was wondering the usefulness of getSendPlugin() function. My thinking is that it would be applicable to any validation plugin a user has enabled. Also how do we use this with a service such as Authy in which the code is generated by another service?
Comment #21
daggerhart commentededit: deleted comment because it was overcomplicating the approach... see below
Comment #22
daggerhart commentedThis morning I realized I needed to look back at the D7 version of the module for a little guidance here and found that I had been over complicating the approach needed for Send plugins.
Looking at an example of a send plugin in tfa_basic, it's not seperate from a validation plugin -- https://git.drupalcode.org/project/tfa_basic/blob/7.x-1.x/includes/tfa_s...
That's makes a lot of sense, answers my questions, and makes it easy to move forward. Let's do that. I'm going to re-roll some patches and update related issues.
Comment #23
daggerhart commentedComment #24
daggerhart commentedI believe the confusion came from the D7 tfa module using the word "plugin" to mean "another means of extension for the tfa module". When the module was ported to D8, all the D7 tfa "plugin" concepts got brought over as D8 plugins. In most cases this was correct, but in the case of the Send plugins, this was unneccesary.
A send plugin is an interface that is applied to a validation plugin (it even says so in TfaSendInterface). It's not a unique type of thing that needs to be retrieved and managed by D8 independent of a validation plugin. All send plugins are validation plugins.
Apologies for my part in this confusion. I've certainly added to it.
Here is an updated patch that cleans up a Lot of the previous confusion around the Send plugin api. It basically removes the whole concept of a new type of Drupal 8 plugin that is a TFA "Send plugin".
The patch is failing 1 test (I predict), but I'm out of time this morning on tracking it down. Aside from that this is ready for review. If someone has time to review and fix the test that's great! Otherwise I'll continue working on it when I have time.
Remaining TODO:
- We need to get the begin() process happening in either EntryForm or TfaLoginForm. TfaLoginForm has a begin() method currently, but it is not being called anywhere I can see.
Comment #25
daggerhart commentedFixing tests, and moving the "begin()" concept into the EntryForm, and renamed the TfaSendInterface to TfaValidationSendInterface to clarify its purpose.
Ideally it would be nice if this control over the begin() concept could live in the TfaLoginForm, but due to how users can change which plugin they are using to validate in the EntryForm, the EntryForm must be responsible for the begin() method for now.
One thing to note is that the system needs to know whether or not the begin() method has been executed for a validation plugin, otherwise it will send an email/sms everytime the form is loaded. For the sake of getting this patch working I used session data, but I really don't like that approach and think we need a better mechanism. I tried setting it as a form_state value, but didn't have any luck with programmatically set values persisting through multiple form loads. Any thoughts?
Comment #26
daggerhart commentedComment #27
kalpaitch commentedI think this approach makes a lot more sense. I was going to say that send plugins are tied to a validation plugin in a one to one relationship, and this is probably the best way of representing this.
In terms of only sending the code once per form, I suspect we could either cache the form with the session context or store the hashed code in the session manager.
I agree that the begin() method is best suited to the EntryForm. Not that it bothers me either way but I don't see the need to change the send interface's name, while they might be part of the same plugin they do different things and naming the send interface off the validation interface might misrepresent it's function. But don't think it matters either way.
Comment #28
kalpaitch commentedIt's probably worth identifying when the validation plugin should begin again:
if the user closes the browser or logs in again then they should get the code again.
if the user goes to another TFA plugin form and comes back they should not get the code again.
if the user refreshes the page they should not get the code again.
if the user hits the re-send button then they should get the code again.
I think you're right to say that based on this the session is the only appropriate gate keeper for whether the resend the code.
If you don't want to set a variable in the session directly perhaps we could cache the method call with the session context. I briefly messed around with having a lazy loaded element on the validation form that calls begin(), really loose and experimental idea but:
Comment #29
daggerhart commentedGood point about needing to know when a validation plugin should begin again, and I think your list is a great start. I will update the issue description with your list so that it will be easy to refer to.
One thing to note is that I don't believe there is a "resend" button of any type implemented yet, but we do probably need this. Do you think we can make an assumption that across-the-board any time we're dealing with a plugin that implements the ValidationSendInterface, we provide a Re-send button? It makes sense to me, but I haven't sat down to try to come up with a scenario in which a validation plugin would not want a re-send button.
Regarding the data storage, @mwebaze suggested the `tempstore.private` service in slack (https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21TempStore...) and I liked that idea. It uses the session and handles edge cases when dealing with anonymous users (which is what we're always dealing with).
Comment #30
kalpaitch commentedSo long as the PrivateTempStore doesn't persist the session, which I guess it shouldn't for anonymous users (but does for identified users), then this probably is better, worth checking this explicitly I guess.
A second point to make is that currently we're setting the `dont' send marker` in the session when the plugin sends out the code (and then we remove it when the form is submitted. I wonder how this functions when the user doesn't submit the validation form and instead hits the back button and logs in again for example.
Perhaps a more hardy approach would be to set a `to be sent marker` on every plugin whenever the login form is submitted (this appears to be our refresh marker), this way the plugin can remove the marker as appropriate when it issues the code. At this point the only thing that could issue another code would be logging in again.
This might resolve issues like above where the persistence of the cache could be a problem.
Comment #31
kalpaitch commentedOk so I've made an attempt at updating this with the PrivateTempStore and flagging each ValidationSendPlugin as 'ready to send' upon login.
I'm still unsure as to how best to handle the creation of a re-send button. I feel that this should be consistent and therefore generated by a single method, however, I think it's something that we really should be able to override within a given validation plugin.
The obvious way to do this would be to have the base implementation defined in the a validation plugin base class, however, there doesn't seem to be a specific base class for each plugin which seems strange. Perhaps worth considering why all these plugins share a single base class, and perhaps whether there is another way for each plugin to share common logic like code generation etc.
Comment #32
kalpaitch commentedOops, I don't know why that last patch ignored some of the test files. Will make sure to get them back in the next patch.
Comment #33
mattdanger commentedAttached is a bug fix for the previous patch that fixes errors with the PrivateTempStore dependency.
Comment #35
piggito commentedRe-rolled and added some fixes + added back the removed tests.
Comment #37
piggito commentedFixing private temp store issue among other fixes.
Comment #38
wadator commentedRerolled patch #37 by lattest module version.
Comment #40
cantrellnm commented#38 reroll was missing changes to the
BasicOverviewformComment #42
cameron prince commentedRe-roll against the latest dev.
Comment #44
awset commentedThe #42 patch failed to apply, provided a re-roll for the same.
Comment #45
jcnventuraLet's try to re-roll again.
Comment #46
jcnventuraNow with some bytes in the patch file.
Comment #48
jcnventuraThis now seems to be a task for the 2.x branch which will use a single plugin type with different interfaces to distinguish the personalities. And looking at the proposed changes here I'm not even sure if there really should be a 'send' plugin, as it seems to be just a validation plugin with the 'begin' method.