DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
Building Scalable Real-Time Apps with AstraDB and Vaadin
Register Now

Trending

  • How To Scan and Validate Image Uploads in Java
  • Security Challenges for Microservice Applications in Multi-Cloud Environments
  • Constructing Real-Time Analytics: Fundamental Components and Architectural Framework — Part 2
  • Exploring the Capabilities of eBPF

Trending

  • How To Scan and Validate Image Uploads in Java
  • Security Challenges for Microservice Applications in Multi-Cloud Environments
  • Constructing Real-Time Analytics: Fundamental Components and Architectural Framework — Part 2
  • Exploring the Capabilities of eBPF
  1. DZone
  2. Coding
  3. Frameworks
  4. Secure Account Activation with ASP.NET Identity

Secure Account Activation with ASP.NET Identity

Anders Abel user avatar by
Anders Abel
·
Jun. 14, 15 · Interview
Like (0)
Save
Tweet
Share
7.02K Views

Join the DZone community and get the full member experience.

Join For Free

Distribution of credentials to new users of a system is often done in an insecure way, with passwords being sent over unsecure e-mail. With ASP.NET Identity, the password recovery functionality can be used to create a secure account activation mechanism.

The scenario for ASP.NET Identity, in the default MVC template is to let users self register. Then there are mechanisms to confirm the e-mail address, to make sure that the user actually is in control of the given e-mail address. There are also support for letting the user associate the account with external sign on solutions such as Google, Facebook and Twitter. That’s perfectly fine, but not for most applications I build.

I’m building line of business applications. They are actually often exposed on the Internet as they need to be available for partners. But, they are not meant to be available through self registration for anyone on the Internet. Those applications are invite only. That means that a user account is created for a new user. Then that user somehow has to be notified that the account has been created. The usual way to do that is to create the account, set a good password like “ChangeMe123″ and send the user a mail with the new credentials. There are two problems with this

  1. A lot of users don’t get the hint and keep the “ChangeMe123″ password.
  2. The e-mail can be sitting unread for a long time in the inbox, until someone gets hold of it – and the account.

Fortunately, there is a much more secure way to do account activation with ASP.NET Identity without much coding at all – by reusing the password recovery mechanism.

Password Recovery in ASP.NET Identity

To recover a password in ASP.NET Identity a password recovery token is used. It is a one time secret, that can be used to reset the password. It has a built in expiry mechanims that is set to 24 hours by default. I think the password recovery mechanism is quite good and follows best practice.

The code required for password recovery is present in the default template, but it is commented out. To get it running, the provided empty e-mail service must first be activated. It is located in IdentityConfig.cs and looks like this.

public class EmailService : IIdentityMessageService
{
  public Task SendAsync(IdentityMessage message)
  {
    ont-style: italic;">// Plug in your email service here to send an email.
    return Task.FromResult(0);
  }
}

To make the EmailService actually send e-mails, a few lines of code are needed.

public async Task SendAsync(IdentityMessage message)
{
  using (var client = new SmtpClient())
  using (var mailMessage = new MailMessage())
  {
    mailMessage.Body = message.Body;
    mailMessage.To.Add(message.Destination);
    mailMessage.Subject = message.Subject;
    mailMessage.IsBodyHtml = true;
 
    await client.SendMailAsync(mailMessage);
  }
}

I’ve used the built in SmtpClient to send the mails. I don’t understand why that code can’t be in the default template. I’ve also added the necessary config lines to my web.config.

<system.net>
  <mailSettings>
    <smtp deliveryMethod="SpecifiedPickupDirectory" from="noreply@example.com">
      <specifiedPickupDirectory pickupDirectoryLocation="c:\temp"/>
    </smtp>
  </mailSettings>
</system.net>

To activate the password recovery, confirmation of the e-mail address on registration has to be activated by activating the commented out lines in AccountController.Register(RegisterViewModel) and in AccountController.ForgotPassword(ForgotPasswordViewModel).

Once the password recovery is working, it can be reused for account activation. In fact, it is very much the same scenario: A legitimate user, that has access to their mail should be let in to the system without knowing the password. Let’s (ab)use the password recovery to build a secure account activation system.

Implementing the Secure Account Activation

2015-05-16 21_53_07-Create User - My ASP.NET ApplicationInstead of the user registration form, we need a user creation form that allows an administrator to add a user. It’s a simple form with just one field, for the user’s e-mail address.

When posted, the account should be created and an activation mail sent. The functionality is quite similar to the one in the existing registration form with a user being created. But instead of sending a mail to confirm the email address, we’re sending an activation mail to the user. I’ve also set the EmailConfirmed to true right from the start, to make it possible for the user to request a new activation/password reset token in case the first one expires.

[HttpPost]
public async Task<ActionResult> Create(CreateUserModel model)
{ 
  if(ModelState.IsValid)
  {
    var user = new ApplicationUser { UserName = model.Email, Email = model.Email, EmailConfirmed = true };
    var result = await UserManager.CreateAsync(user); ont-style: italic;">// Create without password.
    if(result.Succeeded)
    {
      await SendActivationMail(user);
      return RedirectToAction("CreateConfirmation");
    }
    foreach(var error in result.Errors)
    {
      ModelState.AddModelError("", error);
    }
  }
  return View(model);
}
 
private async Task SendActivationMail(ApplicationUser user)
{
  string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
 
  ont-style: italic;">// Using protocol param will force creation of an absolut url. We
  ont-style: italic;">// don't want to send a relative URL by e-mail.
  var callbackUrl = Url.Action(
    "ResetPassword", 
    "Account", 
    new { userId = user.Id, code = code}, 
    protocol: Request.Url.Scheme);
 
  string body = @"<h4>Welcome to my system!</h4>
<p>To get started, please <a href=""" + callbackUrl + @""">activate</a> your account.</p>
<p>The account must be activated within 24 hours from receving this mail.</p>";
 
  await UserManager.SendEmailAsync(user.Id, "Welcome to my system!", body);
}

That’s all that’s needed. The administrator can create a user, without ever having to bother with a password. The user gets an automatic welcome mail, which has a secure expiry of 24 hours.

But there’s one more thing that I prefer to add, to make the activation process a bit more user friendly.

Automatic Sign In After Activation

One thing that I always find frustrating with password recovery mechanisms is when they immediately force me to sign in with the new password. I can’t understand why that is necessary. I’ve just proved my identity through the e-mailed token and I’ve just entered a new password. Just let me in.

To fix this in the default MVC template, one line is needed in the AccountController.ResetPassword(ResetPasswordViewModel) method.

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ResetPassword(ResetPasswordViewModel model)
{
  if (!ModelState.IsValid)
  {
    return View(model);
  }
  var user = await UserManager.FindByNameAsync(model.Email);
  if (user == null)
  {
    ont-style: italic;">// Don't reveal that the user does not exist
    return RedirectToAction("ResetPasswordConfirmation", "Account");
  }
  var result = await UserManager.ResetPasswordAsync(user.Id, model.Code, model.Password);
  if (result.Succeeded)
  {
    ont-style: italic;">// Automatic sign in after password has been reset.
    SignInManager.SignIn(user, false, false);
    return RedirectToAction("ResetPasswordConfirmation", "Account");
  }
  AddErrors(result);
  return View();
}

It is also a good idea to adjust the message shown in ResetPasswordConfirmation.cshtml to indicate that the user is now signed on.

That’s all for now. We have a working, secure account activation solution, built on the password recovery functionality. To make things a bit more user friendly, a separate action can be used for the account activation, showing a better user welcome screen. In my opinion there’s actually quite a lot of room for improving both the user interface and the e-mail messages sent by the default template. But that’s okay for me – the template is a template – not something that is meant to be a complete, working solution out of the box.

A complete working project with the solution described in the post is available on my GitHub Account.

ASP.NET security

Published at DZone with permission of Anders Abel, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Trending

  • How To Scan and Validate Image Uploads in Java
  • Security Challenges for Microservice Applications in Multi-Cloud Environments
  • Constructing Real-Time Analytics: Fundamental Components and Architectural Framework — Part 2
  • Exploring the Capabilities of eBPF

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com

Let's be friends: