ASP.NET Applications Integration
The article shows an example of setting up the two-factor authentication connection for the sites built on the ASP.NET MVC platform. It is based on an ASP.NET web application (.NET Framework) template project.
Operational Principle
The site:
- Verifies login and password provided by a user.
- After successful first-factor authentication, it generates [multifactor authentication API access request](/docs/api#generation of request) and redirects the user to the multifactor access page.
- Receives an access token from the Multifactor platform and verifies the signature, issue time, and validity period.
- If the token is valid, it authorizes the user.
Additional Libraries
Install the JWT package from NUGET to validate the access token. https://www.nuget.org/packages/JWT
Configuration file
Configure a connection to the Multifactor API in the web.config file by adding the following parameters in the appSettings section:
<!-- mfa settings-->
<add key="mfa-api-url" value="https://api.multifactor.ru" />
<add key="mfa-api-key" value="" />
<add key="mfa-api-secret" value="" />
The API Key
and API Secret
values are available in your account in "Resources" -> "Parameters" section.
Next, create a class that will load the configuration settings:
public class MultiFactorSettings
{
public string ApiUrl { get; set; }
public string ApiKey { get; }
public string ApiSecret { get; }
public MultiFactorSettings()
{
ApiUrl = ConfigurationManager.AppSettings["mfa-api-url"];
ApiKey = ConfigurationManager.AppSettings["mfa-api-key"];
ApiSecret = ConfigurationManager.AppSettings["mfa-api-secret"];
}
}
API Client
Add a service client to interact with the Multifactor API.
API connection parameters are passed to the class constructor, which are taken from the web.config configuration file. The method CreateRequest generates a request to [Access Requests API](/docs/api#generation of request) to get the access page address.
/// <summary>
/// Multifactor Web Client
/// </summary>
public class MultiFactorWebClient
{
private MultiFactorSettings _settings;
public MultiFactorWebClient(MultiFactorSettings settings)
{
_settings = settings ?? throw new ArgumentNullException(nameof(settings));
}
public string CreateRequest(string login, string postbackUrl)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//payload
var json = JsonConvert.SerializeObject(new
{
Identity = login,
Callback = new
{
Action = postbackUrl,
Target = "_self"
}
});
var requestData = Encoding.UTF8.GetBytes(json);
byte[] responseData = null;
//basic authorization
var auth = Convert.ToBase64String(Encoding.ASCII.GetBytes(_settings.ApiKey + ":" + _settings.ApiSecret));
using (var web = new WebClient())
{
web.Headers.Add("Content-Type", "application/json");
web.Headers.Add("Authorization", "Basic " + auth);
responseData = web.UploadData(_settings.ApiUrl + "/access/requests", "POST", requestData);
}
json = Encoding.UTF8.GetString(responseData);
var response = JsonConvert.DeserializeObject<MultiFactorWebResponse<MultiFactorAccessPage>>(json);
return response.Model.Url;
}
}
public class MultiFactorWebResponse<TModel>
{
public bool Success { get; set; }
public TModel Model { get; set; }
}
public class MultiFactorAccessPage
{
public string Url { get; set; }
}
AccountController
As most necessary preparational steps have been taken, it remains for us to finalize our authentication form and the logic behind access token acquisition and verification.
Let's assume that your project has a class AccountController that takes care of a user log in process.
Include this string to allow communication with Multifactor API.
private MultiFactorSettings _settings = new MultiFactorSettings();
Request multifactor authentication after verifying login and password:
[HttpPost]
public ActionResult Login(LoginModel model)
{
if (ModelState.IsValid)
{
//verify login and password here
if (model.Email == "user@example.com" && model.Password == "123")
{
return RedirectToMfa(model.Email);
}
ModelState.AddModelError(string.Empty, "Invalid credentials");
}
return view(model);
}
Then, send the user to multifactor authentication page URL:
private ActionResult RedirectToMfa(string login)
{
var postbackUrl = Url.Action("PostbackFromMfa", "Account", null, Request.Url.Scheme);
var client = new MultiFactorWebClient(_settings);
var url = client.CreateRequest(login, postbackUrl);
return RedirectPermanent(url);
}
Return the user to your site with an access token from Multifactor.
This mehod validates the access token and authorizes the user in case validation passes:
[HttpPost]
public ActionResult PostbackFromMfa(string accessToken)
{
//Postback from Multifactor
try
{
var userParams = new JwtBuilder()
.WithSecret(_settings.ApiSecret)
.WithAlgorithm(new HMACSHA256Algorithm())
.MustVerifySignature()
.Decode<IDictionary<string, object>>(accessToken);
var login = userParams["sub"] as string;
FormsAuthentication.SetAuthCookie(login, false);
return RedirectToAction("Index", "Home");
}
catch (TokenExpiredException)
{
//log: Token has expired
return RedirectToAction("Login");
}
catch (SignatureVerificationException)
{
//log: Token has invalid signature
return RedirectToAction("Login");
}
}
See also: