I'm setting up custom MFA providers for ADFS 3.0 by implementing IAuthenticationAdapter
, I want to add another step in to the authentication process whereby, for example with email-based OTP, the user is first prompted to confirm his or her email address before the code is sent and then the user is prompted to enter the OTP, or perhaps the user is prompted to verify some mobile digits before sending out an SMS OTP, however the workflow in the authentication pipeline seems quite rigid, you get BeginAuthentication
, OnError
and TryEndAuthentication
, but implementing additional steps seems much more involved.
So far I have some up with two possible solutions, and I'd like to hear if anyone as any comments or preferences, or hopefully a better way of doing this.
Call
TryEndAuthentication
more than once, passing a different context to represent which stage of the process should be rendered with anIAdaperPresentation
.Add jQuery and other custom scripts as text resources to the custom provider assembly and then inject them in to the
IAdapterPresentationForm.GetFormHtml
method to make the form dynamic and even do some in-line AJAX calls to a separate MVC / Web API service, and do the email verification before showing the user the authentication form, such that you end up with something like this...
Here's my custom script resource (Provider.txt):
function alertMe() {
$("#serviceResponse").html("It Works!");
}
And here's what I did in GetFormHtml
:
var jQuery2 = Properties.Resources.jQuery2;
var script = Properties.Resources.Provider;
result += "<script type=\"text/javascript\">";
result += jQuery2;
result += "</script>";
result += "<form method=\"post\" id=\"loginForm\" autocomplete=\"off\">";
...
result += " <input id=\"alertButton\" type=\"button\" name=\"Alert\" value=\"Alert Me\" onclick=\"alertMe();\" />";
result += " <div id=\"serviceResponse\" />";
...
result += " <input id=\"continueButton\" type=\"submit\" name=\"Continue\" value=\"Continue\" />";
result += "</form>";
result += "<script type=\"text/javascript\">";
result += script;
result += "</script>";
I've not tried the first method yet, and I'm not even sure if the ADFS authentication pipeline will allow this kind of workflow.
I have tried the second method and amazingly it does work, although, as I'm sure you'll agree that from a Developer's point-of-view it's nowhere near as clean as I'd like!
So what do you think, am I missing a simple setting or interface which I could cleanly implement to do this, or is this the only way?