ASP.NET and the Secret Store

I’ve lost count of the number of times I’ve checked in something I shouldn’t have. The ClientSecret to my Auth0 app configuration, an embedded Administrator password, or worse. It’s all gone into Git and then been synced to GitHub. I’ve mentioned numerous times to ensure you add some JSON file or other to .gitignore. I was rather pleased when ASP.NET5 beta5 came out. It had a solution to my problem in the form of UserSecrets. In this tutorial, I’m going nuts to bolts on user secrets.

Step 1: Install DNVM

The Getting Started with ASP.NET 5 and DNX page suggests that the “latest preview of Visual Studio 2015” installs dnvm. Well, not for me. I had to install DNVM on my own. TO do this, I opened up a PowerShell prompt and did the following:

&{$Branch='dev';iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/aspnet/Home/dev/dnvminstall.ps1'))}

This says it is adding things to your path. It didn’t. I added the resulting path – C:\Users\adrian\.dnx\bin – to my PATH in my profile.ps1 file. Specifically, I added the following:

Add-Path "$(${env:HOME})\.dnx\bin"

You can find out about my PathUtils module elsewhere on my blog.

Once I’d got dnvm installed, I could download the latest version of DNX:

dnvm upgrade

Step 2: Install SecretManager

Once you have dnx installed, you can install the SecretManager:

dnu commands install SecretManager

This will allow you to run a command called user-secret:

user-secret --help

If you get this far, you are all set.

Step 3: Create an ASP.NET5 Application

I’m going to create a simple ASP.NET5 WebAPI application for the purposes of demonstration. It will have one route – /api/settings – that will output the information I need to configure Auth0 in the browser. The idea is that my browser application will download this config as a JSON document and then use the information in there to configure the Auth0 authentication. To test it, I’m going to use Postman which is a plug-in for Google Chrome. Let’s start with an Empty ASP.NET5 application and do a quick tour of the code. First off, the project.json file:

{
    "webroot": "wwwroot",
    "version": "1.0.0-*",

    "dependencies": {
        "Microsoft.AspNet.Mvc": "6.0.0-beta5",
        "Microsoft.AspNet.Server.IIS": "1.0.0-beta5",
        "Microsoft.AspNet.Server.WebListener": "1.0.0-beta5",
        "Microsoft.Framework.Configuration.Json": "1.0.0-beta5"
    },

    .....
}

I haven’t reproduced the entire file – just the bits that matter – the dependencies. Just two new packages are absolutely required here. Now the Startup.cs file:

using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.Framework.Configuration;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Runtime;

using UserSecretWeb.Settings;

namespace UserSecretWeb
{
    public class Startup
    {
        public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
        {
            var configBuilder = new ConfigurationBuilder(appEnv.ApplicationBasePath);
            configBuilder.AddJsonFile("config.json", optional: true);
            configBuilder.AddJsonFile($"config.{env.EnvironmentName}.json", optional: true);
            configBuilder.AddEnvironmentVariables();

            Configuration = configBuilder.Build();
        }

        public IConfiguration Configuration
        {
            get;
            private set;
        }

        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<Auth0Settings>(this.Configuration.GetConfigurationSection("Auth0"));

            services.AddMvc();
        }

        public void Configure(IApplicationBuilder app)
        {
            app.UseMvc();
        }
    }
}

This comes directly from my Configuration and Dependency Injection article. I’ve got an Settings/Auth0Settings class to hold my configuration – it’s basically a model:

namespace UserSecretWeb.Settings
{
    public class Auth0Settings
    {
        public string Domain
        {
            get;
            set;
        }

        public string ClientID
        {
            get;
            set;
        }

        public string ClientSecret
        {
            get;
            set;
        }
    }
}

I also have a controller to expose the /api/settings WebAPI – that’s in Controllers/SettingsController.cs:

using Microsoft.AspNet.Mvc;
using Microsoft.Framework.OptionsModel;
using UserSecretWeb.Settings;

namespace UserSecretWeb.Controllers
{
    [Route("api/[controller]")]
    public class SettingsController : Controller
    {
        private Auth0Settings auth0Settings = null;

        public SettingsController(IOptions<Auth0Settings> settings)
        {
            this.auth0Settings = settings.Options;
        }

        // GET: api/settings
        [HttpGet]
        public Auth0Settings Get()
        {
            return auth0Settings;
        }
    }
}

Finally, I need some configuration to send, so here is my config.json file.

{
    "Auth0": {
        "Domain": "YOUR-DOMAIN.auth0.com",
        "ClientID": "YOUR-CLIENT-ID",
        "ClientSecret": "YOUR-CLIENT-SECRET"
    }
}

Note that this is the default settings. I always want something in there so that the application doesn’t blow up. This also provides documentation on what the settings should be and the format of those settings.

Run this project and add api/settings to the end of the URI and you get the following:

blog-08092015-1

My JSON is just as I would expect it. I could, of course, ensure that the secret isn’t transmitted (but still available to the backend). However, this is good enough to test on. If you want to start here, you can download the entire project from my GitHub Repository.

Step 4: Integrate UserSecrets

Integrating User Secrets into the process is remarkably easy. It’s a single line change to the Startup.cs constructor:

        public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
        {
            var configBuilder = new ConfigurationBuilder(appEnv.ApplicationBasePath);

            configBuilder.AddJsonFile("config.json", optional: true);
            configBuilder.AddJsonFile($"config.{env.EnvironmentName}.json", optional: true);
            configBuilder.AddUserSecrets();
            configBuilder.AddEnvironmentVariables();

            Configuration = configBuilder.Build();
        }

You do need to add the Microsoft.Framework.Configuration.UserSecrets package to your project.json:

{
    "webroot": "wwwroot",
    "version": "1.0.0-beta5",
    "userSecretsId": "UserSecretsDemo",

    "dependencies": {
        "Microsoft.AspNet.Mvc": "6.0.0-beta5",
        "Microsoft.AspNet.Server.IIS": "1.0.0-beta5",
        "Microsoft.AspNet.Server.WebListener": "1.0.0-beta5",
        "Microsoft.Framework.Configuration.UserSecrets": "1.0.0-beta5",
        "Microsoft.Framework.Configuration.Json": "1.0.0-beta5"
    },

Note the userSecretsId – in the final version of Visual Studio, this is likely to be auto-generated for you. Right now, you have to do it yourself. It’s a bucket for your secrets. If you have multiple projects that all share the same secrets, you only have to set them once.

Step 5: Set up personal user secrets

Let’s set up a personal user-secret for the Domain and ClientID of our configuration file:

cd ~\GitHub\blog-code\UserSecretWeb
user-secret set Auth0:Domain shellmonger.auth0.com
user-secret set Auth0:ClientID "something with a space in it"

Note that I have to be in the project directory. More specifically, I need to be in the directory containing the project.json file. Also, you need to have the userSecretsId in the project.json file. If you don’t have that, it will complain.

You can do a user-secret list to list out the contents of the user secrets store. You can also get and destroy individual keys.

When you run your code now and go to that same /api/settings URI, you will get the following:

blog-08092015-2

However, the secrets you want to conserve will never be checked in because they are not in the git area.

Step 6: Investigate

So, where are the secrets stored? Well, with these settings, my secrets were stored in the following: %APPDATA%\Microsoft\UserSecrets\UserSecretsDemo in a file called secrets.json. There was no encryption involved, so you can just display the file.

Finally, I mentioned you might not want to show the ClientSecret – that’s for internal use and you shouldn’t be passing that around. However, the model on the server still needs it. ASP.NET uses Newtonsoft JSON.NET as a serializer, so I can tell the serializer to ignore it using a decorator in the model Settings/Auth0Settings.cs:

using Newtonsoft.Json;

namespace UserSecretWeb.Settings
{
    public class Auth0Settings
    {
        public string Domain
        {
            get;
            set;
        }

        public string ClientID
        {
            get;
            set;
        }

        [JsonIgnore]
        public string ClientSecret
        {
            get;
            set;
        }
    }
}

You can get this code, as always, from my GitHub Repository.

Introducing my new Side Project

With all the research and blogging about my research, one could wonder what’s the point of it all. Well, I have a point and that point is my side project. I have been a sometimes developer for a long time. I’m definitely not the one you want to be writing the next blockbuster application, but I get by; mostly by struggling for hours with simple code. This year I decided that I would actually spend the time to become at least as proficient as a college graduate programmer. I learn by doing so I decided I would direct my attention at a particular side project.

That side project is an online application that emulates a Dungeons and Dragons Character Sheet. Since Dungeons and Dragons is a tabletop paper and pencil game generally, the character sheets, where you write down all the statistics about your character, are similarly paper driven. I figured this would be a good time to update this for a tablet world. There are likely to be three parts to this application:

  1. An online portal that you can use to view and manage your characters
  2. A Web API so that I can write other (offline, perhaps) applications to use the data
  3. A Windows “Modern” application for a tablet experience

All of this, of course, should use the absolutely latest and greatest technologies. I will use ASP.NET vNext for the backend with Entity Framework 7 doing the database work for me. I’ll host the application in Azure App Services so that it is always available.

The front end work also will get the latest and greatest treatment. All the code will use ECMAScript 6, style sheets will be coded in LESS and I’ll use the latest thinking in Web Components with perhaps a touch of Polymer.

In terms of build environment, I’m opting for Visual Studio 2015 for my main IDE; jspm for my module handling; gulp for my client-side build automation. I’ll use babel, autoprefixer and other tools as they are appropriate.

Starting with Identity

My starting point was the recent ASP.NET Identity Tutorial that I wrote. There are nine parts to it:

  1. Setting up the Database
  2. The Login Process
  3. Registration
  4. The Registration Callback
  5. Forgotten Passwords
  6. Refactoring for Areas
  7. Logging
  8. Transient Services for the User Profile
  9. Wrapping up some bugs

If you are following along, I suggest you start with these nine articles as they have all been included in the character sheet initial version. Aside from that, I’ve done some styling work to make my Account screens look like the application I envision.

Where is the Code

Each section check-in will be tagged in the blog-code repository on GitHub. In addition, the version will be revved for each major section. Right now, I’m at cs-0.0.1. The project name is called CharacterSheet

Cloning the Repository

You can clone the repository directly within Visual Studio. Just use View -> Team Explorer. Click on the green plug (Connect to Team Projects). You should see a section for Local Git Repositories. Click on Clone:

blog-code-0412-1

Enter the information as above, selecting the location on your disk (not mine). By default, Visual Studio will pick a good place for you. Currently, the repository is small so it won’t take too long to clone. Once that is done, you can double-click on the repository to be taken to the Solutions:

blog-code-0412-2

Double-click on the CharacterSheet.sln solution to open up the project. You will need to manually select the Solution Explorer after you have done this.

Preparing the Solution

Visual Studio 2015 CTP 6 does not have support for jspm. The package restore won’t happen automatically as a result. You have to do it. To do this, open up a PowerShell prompt and install jspm, then run jspm install. Make sure you add it to your PATH or set up an alias for jspm as you will need to drop down to a command prompt to install new packages. I’ll let you know when this has to happen.

Visual Studio Extensions

I have a few Visual Studio Extensions installed. All of these extensions can be installed from the Tools -> Extensions and Updates menu option.

  1. Bootstrap Snippet Pack
  2. CommentsPlus
  3. Grunt Launcher
  4. Indent Guides
  5. jQuery Code Snippets
  6. Open Command Line
  7. Regex Tester
  8. Trailing Whitespace Visualizer
  9. Web Essentials 2015.0 CTP 6
  10. SideWaffle Template Pack

I will likely add to this list. Extensions like these make development easier, so I’ll blog about the useful extensions I find along the way as well.

Target Browsers

It’s all well and good developing good responsive design, but you have to test everywhere. For my main machine I have Windows 10 Technical Preview (on the fast track) with the following browsers installed:

  1. Google Chrome 41
  2. Internet Explorer 11
  3. Project Spartan

In addition I have an iPad 3 and a Dell Venue 8 as my tablets. I’ll install other browsers and operating systems on my “other boxes”. I have a Mac Mini for running mac browsers and a Hyper-V box that I can run random operating systems and their browsers on.

Running in Azure

I don’t run my development stuff in Azure. Firstly, it costs money. More importantly, the code is likely to be unstable. I’ll have to figure out the pushing to Azure piece, especially with the database in the mix. I’ll post another blog about that process when I actually do it. I do have an Azure account though; this blog is run out of Azure App Services.

That’s pretty much it for the run-down of my side project. I hope you’ll join me on my journey through web applications and developing my Side Project.

ASP.NET vNext Identity: Part 8 – Accessing the Identity

Over the last week I’ve discussed how to get the identity stuff going with a breakdown of what the Starter Project does. I’ve then refactored it into Areas and added logging to the mix. How about extending the Identity? My users have a real name, not an email address, for instance. The purpose of this post is:

  1. Extend my IdentityUser with a new field
  2. Display that field in my Layout

Let’s start with the model. I already have subclassed the IdentityUser model when I was creating the ApplicationDbContext. Extending the model with another field means adding a property to that class. I now have the following in the ApplicationUser class:

    public class ApplicationUser : IdentityUser
    {
        public string DisplayName { get; set; }
    }

I also need to set a value for the field in my admin user when the database is created. This is done in IdentityDbOptions.cs:

            // if the user does not exist, create it.
            logger.Trace(String.Format("CreateAdminUser: Ensuring User {0} exists", options.DefaultAdminUserName));
            var user = await userManager.FindByNameAsync(options.DefaultAdminUserName);
            if (user == null)
            {
                logger.Trace("CreateAdminUser: User does not exist - creating");
                user = new ApplicationUser { UserName = options.DefaultAdminUserName, DisplayName = "Administrator" };
                var userCreationResult = await userManager.CreateAsync(user, options.DefaultAdminPassword);

I can just delete the existing database since I am just using a test database right now. I’d need to look at Entity Framework Migrations if I were doing this to a production application. Migrations allow you to make changes to the structure of your models and then have the back end database updated to reflect the new model.

Now that I have a new field in the model, I want to use it in my layout. Specifically, I want to add a greeting that shows the display name. The method I am using for this is called Transient Service Injection. Step 1 is to create a service injection class. This is just a regular old class whose constructor takes the service provider. In this case I’m creating a UserProfile service:

using System;
using System.Threading.Tasks;
using AspNetIdentity.Models;
using Microsoft.AspNet.Identity;
using Microsoft.Framework.DependencyInjection;

namespace AspNetIdentity.Services
{
    public class UserProfile
    {
        public UserProfile(IServiceProvider services)
        {
            UserManager = services.GetRequiredService<UserManager<ApplicationUser>>();
        }

        public UserManager<ApplicationUser> UserManager { get; set; }

        public async Task<string> DisplayName(string username)
        {
            ApplicationUser result = await UserManager.FindByNameAsync(username);
            return result.DisplayName;
        }
    }
}

I use the constructor to obtain a reference to my UserManager. Then, when requested, I asynchronously find the given user by name and return the display name. Next step is to inject this service into the ASP.NET services list. The services list is set up in the ConfigureServices method of Startup.cs:

        public void ConfigureServices(IServiceCollection services)
        {
            // Entity Framework Service backed by SQL Server
            services.AddEntityFramework()
                .AddSqlServer()
                .AddDbContext<ApplicationDbContext>(options =>
                    options.UseSqlServer(Configuration.Get("Database:ConnectionString")));

            // Configure the identity service based on our configuration
            services.Configure<IdentityDbContextOptions>(options =>
            {
                options.DefaultAdminUserName = Configuration.Get("AdminUser:Username");
                options.DefaultAdminPassword = Configuration.Get("AdminUser:Password");
            });

            // Now add the entity framework backed identity service
            services.AddIdentity<ApplicationUser, IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders();

            // Configure the Email Service
            EmailService.Instance.SetConfiguration(Configuration);

            // ASP.NET MVC6 Service
            services.AddMvc();

            // Add a Transient Service
            services.AddTransient<UserProfile>();
        }

The addition is the last line of the method. I can now inject that service into any Razor view I care to. For example, my MainSite.cshtml file is my layout page for the site. Maybe I want to include the Display Name in the header:

@inject AspNetIdentity.Services.UserProfile UserProfile
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css">
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap-theme.min.css">
    <link rel="stylesheet" href="~/Style/StyleSheet.css">
    <title>@ViewBag.Title</title>

    <!-- Polyfills -->
    <script src="~/lib/webcomponentsjs/webcomponents.min.js"></script>
</head>
<body>
    <div class="container">
        <div class="navbar-header">
            <ul class="nav navbar-nav">
                <li>Welcome @await UserProfile.DisplayName(User.Identity.Name)</li>
                <li>@Html.ActionLink("Log Out", "Logout", "Login", new { area = "Account" })</li>
            </ul>
        </div>
    </div>
    <section id="body">
        @RenderBody()
    </section>
    <section id="scripts">
        <script src="~/lib/requirejs/require.js" data-main="Scripts/application"></script>
    </section>
</body>
</html>

There are two changes here. Firstly, The @inject statement at the top injects the UserProfile into the page so I can use it. Secondly, I use it like this:

@await UserProfile.DisplayName(User.Identity.Name)

The @await means the method is called asynchronously – this matches the definition of the method I am calling. I also pass in the current username which is available in the User.Identity object.

There is still work to be done. I need to add a profile page so that a user can edit the display name, for example, or update the registration page to ask for the name up front. In addition, I need to handle the case where the user does not enter a display name.

For now, my current code is on my GitHub Repository.

ASP.NET vNext Identity Part 7 – Logging

There are still some rough edges to Visual Studio 2015 CTP 6 and one of the biggest is problems with NuGet packages that don’t conform to newly revised requirements. This isn’t really surprising given that the developers are trying to move to an open source and multi-platform environment. But it’s a little painful.

One of the elements that I was having problems with is logging. Every application of any size needs logging. I could rant for hours on proper logging and how it helps support diagnose problems plus provide meaningful usage statistics and allow you to concentrate development in places that matter. That’s a post for another time.

In order to really implement logging I turn to libraries. Either Log4Net or NLog as the fancy strikes me. Both are open source libraries that are distributed via NuGet. However in both cases there is something in there that Visual Studio 2015 CTP 6 doesn’t like. When you install the library into your project – by editing project.json, using the NuGet Packaging Manager or the Package Manager Console, you will see a little yellow triangle of doom in the references:

blog-code-0408-1

If you go to your error list you will see the following reason:

blog-code-0408-2

I know that once Visual Studio 2015 goes GA this problem will be resolved. It’s just too big to be ignored, even if it’s painful for me now. But I want to continue developing. There are two options:

  1. Write Debug.WriteLine everywhere and integrate the library by editing every file again later
  2. Write a wrapper class for the logging library and use that, then refactor one class later

I like option 2. In my Services directory, I’m going to add a class that implements logging. The below isn’t the entire file – I’ve left only the important bits in:

using System;
using System.Text;

namespace AspNetIdentity.Services
{
    public class Logger
    {
        private string _className;

        /// <summary>
        /// Create a new Logger instance
        /// </summary>
        /// <param name="className"></param>
        public Logger(string className)
        {
            this._className = className;
        }

        #region Logging Methods
        public void Trace(string fmt, params string[] list)
        {
            Log("TRACE", fmt, list);
        }

        // Other logging routines here

        public void Enter(string method, params string[] list)
        {
            var m = new StringBuilder(String.Format("{0}(", method));
            for (int i = 0; i < list.Length; i++)
            {
                if (i != 0) m.Append(",");
                m.Append("\"" + list[i] + "\"");
            }
            m.Append(")");
            Log("ENTER", m.ToString());
        }

        public void Leave(string method)
        {
            Log("LEAVE", method);
        }
        #endregion

        private void Log(string lvl, string fmt, params string[] list)
        {
            string h = String.Format("### {0} [{1}]:", _className, lvl);
            string m = String.Format(fmt, list);
            System.Diagnostics.Debug.WriteLine(h + " " + m);
        }

        public static Logger GetLogger(string className)
        {
            return new Logger(className);
        }
    }
}

Basic functionality is that I create a logger as a static variable at the start of your class and then use it to call .Trace, .Enter, etc. to write logs out. This all consolidates down to using .Log which does a Debug.WriteLine. When I do the refactor for a logging library, this is the only class I have to touch. Everything else just uses this class.

Let’s say I wanted to instrument my EmailService class. At the top of the class I would place the following:

private static Logger logger = Logger.GetLogger(typeof(EmailService).Name);

Then all my Debug.WriteLine calls can be changed to logger.Trace calls.

Even with this (and any other logging library), the Output Debug window is liable to be cluttered. This is, fortunately, easy to fix. Go to the Quick Launch and type in Debug Output. You will see a result Debugging => Output Window. Select that to get something like the below:

blog-code-0408-3

You definitely want to leave All debug output and Exception Messages turned on – those are a vital part of the functionality you need to diagnose issues. However you can probably turn the rest of the entries under the General Output Settings off.

Right now I still get a bunch of Loaded… messages. Still it was less than I was getting before and it allows me to see my tracing messages much more easily.

Want things to improve? Check out this UserVoice suggestion and consider voting for it. While you are there, consider looking at other ideas and voting for the ones you think should be implemented.

In the meantime, I’ve checked in my code and you can check it out at my GitHub Repository.

ASP.NET vNext Identity Part 6 – Refectoring for Areas

Over the past 5 days I’ve implemented a fairly reasonable account login system that allows for logging in and out, handling registrations and handling forgotten passwords. I do have a major problem architecturally with this codebase though. My views, view models and controller for this logic is intermingled with my main application code. It’s not really a problem within this application since the actual application isn’t doing anything, but it can be a major pain in bigger applications. A similar case could be made for management and configuration code vs. the main application. I’d rather have the views, controller and view models all in their own separate area.

ASP.NET MVC has had a concept called Areas for this in the past. It’s configured a little bit differently than in the old ASP.NET but is the same concept. I get to put the pieces that make up the view and controller system in its own separate area.

This article is about doing this for the account login system I’ve been working on for the last five days. Explicitly, I want:

  1. A login and logout controller that just do that
  2. A registration controller that just does that
  3. A forgotten password controller that just does that

This way each of my workflows are separated from the other workflows with their own views and controllers. Let’s get started.

Configuring Areas

To configure the application to handle areas, I need to change the route mapping in Startup.cs. This is the new code:

            // Configure ASP.NET MVC6
            app.UseMvc(routes =>
                {
                    routes.MapRoute(
                        name: "areaDefault",
                        template: "{area:exists}/{controller}/{action=Index}/{id?}");

                    routes.MapRoute(
                        name: "default",
                        template: "{controller=Home}/{action=Index}/{id?}"
                    );
                });

The default route was already there from my prior work. The areaDefault is new. You can see that it isn’t much different. It just has that {area:exists} in the front. If I create an area called Account, then a controller called Login and an action method called Index, it can be accessed via /Account/Login/Index or /Account/Login since Index is the default action. Note that the ASP.NET Identity Framework re-directs to /Account/Login when authentication is needed, so this seems like a perfect solution.

Creating an Area

All my areas live in a new folder called Areas. My new area is called Account. Within the Account area are folders for Controllers, ViewModels and Views. Once I’ve done this, my folder layout looks like the below:

blog-code-0407-1

Creating the Login Controller and Views

Since I am splitting my AccountController into three pieces, I will want three controllers. I am only showing you one of the three controllers in this article. You can refactor the AccountController to do the other two yourself or look at the resulting code at the end on my GitHub Repository.

The LoginController.cs file lives in Areas\Account\Controllers and looks like this:

using System.Threading.Tasks;
using AspNetIdentity.Areas.Account.ViewModels;
using AspNetIdentity.Models;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Mvc;

namespace AspNetIdentity.Areas.Account.Controllers
{
    [Area("Account")]
    public class LoginController : Controller
    {
        public LoginController(
            UserManager<ApplicationUser> userManager,
            SignInManager<ApplicationUser> signInManager)
        {
            UserManager = userManager;
            SignInManager = signInManager;
        }

        public UserManager<ApplicationUser> UserManager
        {
            get;
            private set;
        }

        public SignInManager<ApplicationUser> SignInManager
        {
            get;
            private set;
        }

        // GET: /Account/Login/Index
        [HttpGet]
        [AllowAnonymous]
        public IActionResult Index()
        {
            return View();
        }

        // POST: /Account/Login/Index
        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Index(LoginViewModel model, string returnUrl = null)
        {
            ViewBag.ReturnUrl = returnUrl;
            if (ModelState.IsValid)
            {
                var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);
                if (result.Succeeded)
                {
                    if (Url.IsLocalUrl(returnUrl))
                    {
                        return Redirect(returnUrl);
                    }
                    else
                    {
                        return RedirectToAction("Index", "Home");
                    }
                }
                if (result.IsLockedOut)
                {
                    ModelState.AddModelError("", "Locked Out");
                }
                else if (result.IsNotAllowed)
                {
                    ModelState.AddModelError("", "Not Allowed");
                }
                else if (result.RequiresTwoFactor)
                {
                    ModelState.AddModelError("", "Requires Two-Factor Authentication");
                }
                else
                {
                    ModelState.AddModelError("", "Invalid username or password.");
                }
                return View(model);
            }

            // If we got this far, something failed - redisplay the form
            return View(model);
        }

        // (GET|POST): /Account/Login/Logout
        public IActionResult Logout()
        {
            SignInManager.SignOut();
            return RedirectToAction("Index", "Home");
        }

    }
}

You might be saying “Wait a minute – that’s all the same code as before!” You would be right. There are a couple of differences. Firstly, I’ve added an [Area("Account")] decorator to the class. This indicates to the MVC framework that this is an area and needs to go through the routing that we’ve just established. I’ve also renamed the methods to Index so this can be accessed through /Account/Login. This does have a ViewModel called LoginViewModel that is needed. This is placed in the Areas/Account/ViewModels directory and looks exactly the same:

using System.ComponentModel.DataAnnotations;

namespace AspNetIdentity.Areas.Account.ViewModels
{
    public class LoginViewModel
    {
        [Required]
        [Display(Name = "User name")]
        public string UserName { get; set; }

        [Required]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }

        [Display(Name = "Remember me?")]
        public bool RememberMe { get; set; }
    }
}

The only thing that has changed here is the namespace – it’s now in the Areas namespace rather than the top level namespace.

As I move along this process I am removing the code from the AccountController and the classes I no longer need from their locations. This prevents confusion as to where I am in the refactoring process.

For the view, I’ve created a Login folder underneath Areas\Account\Views since I’m working with the LoginController. I’ve copied over the Views\Layouts\LoginPage.cshtml and placed it in Areas\Account\Views\Layout.cshtml I’ve also created a ViewStart.cshtml file. I did some cosmetic moving around and updating of the paths. Here is the _ViewStart.cshtml file:

@{ Layout = "~/Areas/Account/Views/Layout.cshtml"; }

Note that each area can have it’s own _ViewStart.cshtml file, so it can have its own dedicated layout. In the prior 5 articles, I had to specify the “login code layout” everywhere. Now I don’t have to do that – I can specify it centrally.

And here is the Layout.cshtml file:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="~/lib/font-awesome/css/font-awesome.min.css" rel="stylesheet">
    <link rel="stylesheet" href="~/Style/Login.css">
    <title>@ViewBag.Title</title>
</head>
<body>
  <div class="flex-container">
    <div class="login-outer-form">
      @RenderBody()
    </div>
  </div>
  <section id="scripts" style="visibility:hidden;">
    @RenderSection("scripts", required: false)
  </section>
</body>
</html>

The only real difference here is cosmetic. Every single one of my views was wrapped inside of the flex-container and login-outer-form. Rather than put them inside of each view, I’ve promoted that to the layout. The Index.cshtml file looks almost like a copy of the old Login.cshtml; like this:

@model AspNetIdentity.Areas.Account.ViewModels.LoginViewModel
@{ ViewBag.Title = "Log In"; }

<div class="login-type-selector">
    <h4 id="localLoginSelector" class="active">Local</h4>
    <h4 id="socialLoginSelector">Social</h4>
</div>
<div class="login-form-area">
    <div id="localLogin">
        @using (Html.BeginForm("Index", "Login", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { id = "login-form", area = "Account" }))
        {
            @Html.AntiForgeryToken()
            @Html.ValidationSummary(true)
            <div class="form-group">
                <div class="control-label"><span class="fa fa-envelope"></span></div>
                <div class="form-control">
                    @Html.TextBoxFor(m => m.UserName)
                    @Html.ValidationMessageFor(m => m.UserName)
                </div>
            </div>
            <div class="form-group">
                <div class="control-label"><span class="fa fa-key"></span></div>
                <div class="form-control">
                    @Html.PasswordFor(m => m.Password)
                    @Html.ValidationMessageFor(m => m.Password)
                </div>
            </div>
            <div class="form-group">
                <div class="checkbox">
                    @Html.CheckBoxFor(m => m.RememberMe)
                    @Html.LabelFor(m => m.RememberMe)
                </div>
            </div>
            <div class="submit-btn" id="login-btn">Login</div>
        }
        <div class="login-form-options">
            <div class="register-link">
                <a href="/Account/Register">Register<br>Account</a>
            </div>
            <div class="forgot-link">
                <a href="/Account/Forgot">Forgot<br>Password</a>
            </div>
        </div>
    </div>

    <div id="socialLogin">
        <h4>COMING SOON!</h4>
    </div>
</div>


@section scripts
{
    <script src="~/lib/jquery/dist/jquery.min.js"></script>

    <script>
        $(document).ready(function () {

            function activate(on) {
                var off = (on === "local") ? "social" : "local",
                    onSelector = $("#" + on + "LoginSelector"),
                    offSelector = $("#" + off + "LoginSelector"),
                    onBlock = $("#" + on + "Login"),
                    offBlock = $("#" + off + "Login");

                offSelector.removeClass("active");
                onSelector.addClass("active");
                offBlock.hide();
                onBlock.show();
            }

            activate("local");
            $("#socialLoginSelector").click(function () { activate("social"); });
            $("#localLoginSelector").click(function () { activate("local"); });
            $("#login-btn").click(function () { $("#login-form").submit(); });
        });
    </script>
}

The changes here are minor. I’ve removed the flex-container and login-form-outer wrapping. I’ve changed the namespace of the ViewModel at the top so that it points to the new location. I’ve removed the Layout as it is now handled for me. The important change is in the Html.BeginForm I’ve isolated that change below:

@using (Html.BeginForm("Index", "Login", 
    new { ReturnUrl = ViewBag.ReturnUrl }, 
    FormMethod.Post, 
    new { id = "login-form", area = "Account" }))

Firstly, the first two parameters have been reflected to the new controller and action names. Secondly, the area has been specified in the options area.

I also had to do a small change as a result of the HTML movement between view and layout. Specifically, there are two rules wrapped in a #login – I removed the #login wrapper.

Change your other (dependent) views

In the Views\Layout\MainSite.cshtml, there is a link to log out. I’ve changed that link to /Account/Login/Logout since it’s in an area now. I need to make a similar change to the Home view for it to work. In my case, I converted the form to an ActionLink – it’s in the middle of the new MainSite.cshtml file:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css">
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap-theme.min.css">
    <link rel="stylesheet" href="~/Style/StyleSheet.css">
    <title>@ViewBag.Title</title>

    <!-- Polyfills -->
    <script src="~/lib/webcomponentsjs/webcomponents.min.js"></script>
</head>
<body>
    <div class="container">
        <div class="navbar-header">
            <ul class="nav navbar-nav navbar-right">
                <li>@Html.ActionLink("Log Out", "Logout", "Login", new { area = "Account" })</li>
            </ul>
        </div>
    </div>
    <section id="body">
        @RenderBody()
    </section>
    <section id="scripts">
        <script src="~/lib/requirejs/require.js" data-main="Scripts/application"></script>
    </section>
</body>
</html>

Wrapping Up

I love Areas. They assist in code organization and keep the views, view models and controllers for associated content together, rather than spread across the project. I highly recommend their use.

Check out the code after I’ve done all the re-factoring at my GitHub Repository.

ASP.NET vNext Identity Part 5 – Forgotten Passwords

Before I start this article, I promised that I would be styling the login box and associated registration screens so that they look good. Four hours later and I’ve pretty much done what I wanted. I’m not a CSS whizz-kid, so I had to use css-tricks several times and go back and forth on registrations. Finally I accomplished what I set out to do – make the login screen look nicer. I also added a Disabled field into the Email section of config.json so that I can disable the email part of the registration completely during development. You can check out the code at my GitHub Repository.

If you take a look at the new code you will see that I’ve added a couple of things that were not there before. First off, there is a Social link with an ominous Coming Soon notice. That section is where I’ll be adding social logins and is the subject for a different article. The second item is that there is a Forgot Password? link at the bottom of the sign-in form, right next to the register button:

blog-code-0406-1

That link goes to the /Account/Forgot action and is for when the user forgets the password. I want the user to be able to enter their username and – if they are registered – they will be sent a link to reset their password. Once the user clicks on the link, he/she get a password change prompt and then get redirected back to the login screen. It’s a fairly common workflow for this subject.

Since I’ve got a link to the /Account/Forgot action, let’s start there. I need a controller action, which is, as is normal for the start of a workflow, very simple. This is in the AccountController.cs controller:

        [HttpGet]
        [AllowAnonymous]
        public IActionResult Forgot()
        {
            return View();
        }

Incidentally, I put my workflows within the AccountController inside a #region – this allows me to group and collapse the actions related to a workflow and means they don’t interfere with one another when I’m developing. Pro Tip: Use #region.

@model AspNetIdentity.ViewModels.ForgotPasswordViewModel

@{
    Layout = "~/Views/Layout/LoginPage.cshtml";
    ViewBag.Title = "Forgot Password";
}

<div class="flex-container">
    <div class="login-form-outer" id="register">
        <h4>Forgot Password</h4>
        <p>Enter your email below and we will send a link via email so you can reset your password.</p>
        @using (Html.BeginForm("Forgot", "Account", FormMethod.Post, new { id = "forgot-form", role = "form" }))
        {
            @Html.AntiForgeryToken()
            @Html.ValidationSummary(true)
            <div class="form-group">
                <div class="control-label"><span class="fa fa-envelope"></span></div>
                <div class="form-control">
                    @Html.TextBoxFor(m => m.Email)
                    @Html.ValidationMessageFor(m => m.Email)
                </div>
            </div>
            <div class="submit-btn" id="forgot-btn">Email Link</div>
        }
    </div>
</div>

@section scripts
{
    <script src="~/lib/jquery/dist/jquery.min.js"></script>

    <script>
        $(document).ready(function () {
            $("#forgot-btn").click(function () {
                $("#forgot-form").submit();
            });
        });
    </script>
}

This is the same sort of form that I used in the Registration workflow. I ask for some information and then submit the information (via the form and a ViewModel) back to the controller for processing. I do need a ViewModel to receive the data. This is as easy as the action, really:

using System.ComponentModel.DataAnnotations;

namespace AspNetIdentity.ViewModels
{
    public class ForgotPasswordViewModel
    {
        [Required]
        [Display(Name = "Email")]
        public string Email { get; set; }
    }
}

So much for the easy stuff. Now comes the hard stuff, but it isn’t really that much harder. When the form gets posted back to the server, it will call the /Account/Forgot action as a POST (as opposed to a GET), so I need to handle the form in a new method:

         [HttpPost]
         [AllowAnonymous]
         [ValidateAntiForgeryToken]
         public async Task<IActionResult> Forgot(ForgotPasswordViewModel model)
        {
            if (ModelState.IsValid)
            {
                Debug.WriteLine("Forgot: Checking for user ID = " + model.Email);
                var user = await UserManager.FindByNameAsync(model.Email);
                // If the user does not exist or the user has not confirmed their email,
                // then say we confirmed, but don't actually do anything.
                if (user == null || !(await UserManager.IsEmailConfirmedAsync(user)))
                {
                    Debug.WriteLine("Forgot: User does not exist - lying to the user");
                    return View("ForgotConfirmation");
                }

                // If we found a user and it's valid, then work out the code and send
                // it via email.
                var code = await UserManager.GeneratePasswordResetTokenAsync(user);
                Debug.WriteLine("Forgot: Code = " + code);
                var callBackUrl = Url.Action("ResetPassword", "Account",
                    new { userId = user.Id, code = code },
                    protocol: Context.Request.Scheme);
                Debug.WriteLine("Forgot: Link = " + callBackUrl);
                await EmailService.Instance.SendEmailAsync(model.Email, "Reset Password",
                    "We received a request to reset your password.  If you did not request a " +
                    "password change, then please dis-regard this email with our apologies.\n\n" +
                    "To reset your password, click here: <a href=\"" + callBackUrl + "\">link</a>");
                return View("ForgotConfirmation");
            }

            // If the model was not valid, re-display the form
            return View(model);
        }

I hope you are getting the sense of the patterns in workflows now. I start with a HTTP GET entry-point for the workflow. This displays a View to gather data using a form that is accepted to a POST action via a ViewModel unique to the form. The controller Action, ViewModel and View all have distinct patterns that I can repeat over and over.

This controller action is very similar to the Registration action. I make sure the user doesn’t exist. I don’t want to let on that the user may or may not exist, so if the user doesn’t exist, then I will output the exact same message as if the user did exist. When the user exists, however, I generate a code – the Identity Framework has a routine for this – and send the code to the user (maybe) using exactly the same method that I use to send out the registration message. Check out my last article for a discussion on the email technique.

Here is the ForgotConfirmation.cshtml view that goes along with this action:

@{
    Layout = "~/Views/Layout/LoginPage.cshtml";
    ViewBag.Title = "Forgot Password";
}

<div class="flex-container">
    <div class="login-form-outer" id="forgotconfirm">
        <h4>Check Your Email</h4>
        <p>
            We have sent a reset password link to your email.  Please check your email
            and click on the link in that email to reset your password.
        </p>
    </div>
</div>

Just like the registration process, I’m going to print out the link to the Debug window so I can cut and paste it into my browser. This code will not work until that receiving action exists. In the middle of the Forgot POST action is a call to Url.Action for /Account/ResetPassword The ASP.NET code is reasonable enough to barf there if the target action doesn’t exist. I need to write a receiver for this action:

        /**
         * GET /Account/ResetPassword
         */
        [HttpGet]
        [AllowAnonymous]
        public async Task<IActionResult> ResetPassword(string userId = null, string code = null)
        {
            Debug.WriteLine("ResetPassword: Checking for userId = " + userId);
            if (userId == null || code == null)
            {
                Debug.WriteLine("ResetPassword: Invalid Parameters");
                return View("ResetPasswordError");
            }
            Debug.WriteLine("ResetPassword: Looking for userId");
            var user = await UserManager.FindByIdAsync(userId);
            if (user == null)
            {
                Debug.WriteLine("ResetPassword: Could not find user");
                return View("ResetPasswordError");
            }
            return View();
        }

If you are thinking you recognize this code, you might be right. I copied a lot of this from the /Account/ConfirmEmail action that was developed during the registration process. I’ve got a new view – ResetPasswordError – just in case you have an error. The error message should not give away anything about the user id.

@{
    Layout = "~/Views/Layout/LoginPage.cshtml";
    ViewBag.Title = "Confirm Email: Error";
}

<div class="flex-container">
    <div class="login-form-outer">
        <h4>Reset Password Failed</h4>
        <p>
            We could not reset your password.
        </p>
    </div>
</div>

I also need a ResetPassword view for the successful lookup side of things:

@model AspNetIdentity.ViewModels.ResetPasswordViewModel

@{
    Layout = "~/Views/Layout/LoginPage.cshtml";
    ViewBag.Title = "Reset Password";
}

<div class="flex-container">
    <div class="login-form-outer" id="resetpassword">
        <h4>Reset Password</h4>
        @using (Html.BeginForm("ResetPassword", "Account", FormMethod.Post, new { id="resetpw-form", role = "form" }))
        {
        @Html.AntiForgeryToken()
        @Html.ValidationSummary(true)
        @Html.HiddenFor(model => model.Code)
        <div class="form-group">
            <div class="control-label"><span class="fa fa-envelope"></span></div>
            <div class="form-control">
                @Html.TextBoxFor(m => m.Email)
                @Html.ValidationMessageFor(m => m.Email)
            </div>
        </div>
        <div class="form-group">
            <div class="control-label"><span class="fa fa-key"></span></div>
            <div class="form-control">
                @Html.PasswordFor(m => m.Password)
                @Html.ValidationMessageFor(m => m.Password)
            </div>
        </div>
        <div class="form-group">
            <div class="control-label"><span class="fa fa-key"></span></div>
            <div class="form-control">
                @Html.PasswordFor(m => m.ConfirmPassword)
                @Html.ValidationMessageFor(m => m.ConfirmPassword)
            </div>
        </div>
        <div class="submit-btn" id="resetpw-btn">Reset Password</div>
        }
    </div>
</div>

@section scripts
{
<script src="~/lib/jquery/dist/jquery.min.js"></script>

<script>
        $(document).ready(function () {
            $("#resetpw-btn").click(function () {
                $("#resetpw-form").submit();
            });
        });
</script>
}

… which means I also need a ResetPasswordViewModel.

using System.ComponentModel.DataAnnotations;

namespace AspNetIdentity.ViewModels
{
    public class ResetPasswordViewModel
    {
        [Required]
        [EmailAddress]
        [Display(Name = "Email")]
        public string Email { get; set; }

        [Required]
        [StringLength(100, MinimumLength = 6, ErrorMessage = "Password must be at least 6 characters.")]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }

        [DataType(DataType.Password)]
        [Display(Name = "Confirm password")]
        [Compare("Password", ErrorMessage = "The password and confirmation do not match.")]
        public string ConfirmPassword { get; set; }

        public string Code { get; set; }
    }
}

Note that the system does not fill in the email address for the user. If the email message is intercepted on the way through then attacker already has the email address and so can enter it easily. If the user has clicked on the link then the email address should already be loaded in. In both cases, I don’t see a compelling reason to not fill in the email address. You can fix this at the bottom of the HttpGet version of ResetPassword(). Instead of returning View(), return a View with a model:

        [HttpGet]
        [AllowAnonymous]
        public async Task<IActionResult> ResetPassword(string userId = null, string code = null)
        {
            Debug.WriteLine("ResetPassword: Checking for userId = " + userId);
            if (userId == null || code == null)
            {
                Debug.WriteLine("ResetPassword: Invalid Parameters");
                return View("ResetPasswordError");
            }
            Debug.WriteLine("ResetPassword: Looking for userId");
            var user = await UserManager.FindByIdAsync(userId);
            if (user == null)
            {
                Debug.WriteLine("ResetPassword: Could not find user");
                return View("ResetPasswordError");
            }

            ResetPasswordViewModel model = new ResetPasswordViewModel();
            model.Email = user.UserName;
            return View(model);
        }

It’s now time to process the password reset. The user has filled in the form and clicked on the password reset button to submit the form. The form is submitted as a POST to /Account/ResetPassword and processed like this:

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> ResetPassword(ResetPasswordViewModel model)
        {
            if (ModelState.IsValid)
            {
                Debug.WriteLine("ResetPassword: Checking for user = " + model.Email);
                var user = await UserManager.FindByNameAsync(model.Email);
                if (user == null)
                {
                    Debug.WriteLine("ResetPassword: User does not exist - lie to the user");
                    return RedirectToAction("ResetConfirmation", "Account");
                }
                var result = await UserManager.ResetPasswordAsync(user, model.Code, model.Password);
                if (result.Succeeded)
                {
                    Debug.WriteLine("ResetPassword: Password is reset - confirm to the user");
                    return RedirectToAction("ResetConfirmation", "Account");
                }
                foreach (var error in result.Errors)
                {
                    Debug.WriteLine(string.Format("Register: Adding Error: {0}:{1}", error.Code, error.Description));
                    ModelState.AddModelError("", error.Description);
                }
                return View(model);
            }
            Debug.WriteLine("ResetPassword: Model is invalid - just re-state the form");
            return View(model);
        }

Look familiar again? It should as this is pretty much the same code as our confirm email. I need a controllaction for the password reset:

        [HttpGet]
        [AllowAnonymous]
        public IActionResult ResetConfirmation()
        {
            return View();
        }

And I need a view called ResetConfirmation.cshtml:

@{
    Layout = "~/Views/Layout/LoginPage.cshtml";
    ViewBag.Title = "Reset Password";
}

<div class="flex-container">
    <div class="login-form-outer" id="resetconfirm">
        <h4>Password Reset Successful</h4>
        <p>
            Please @Html.ActionLink("click here to log in", "Login", "Account", routeValues: null)
        </p>
    </div>
</div>

This, again, is similar to the ConfirmEmail view. The registration and forgotten password workflows have many similarities, so it is expected that they share a lot of characteristics.

Designing Workflows

Most of these processes were adapted from the originals for MVC5 and if you are familiar with MVC5 you will note that these were pretty much the same. I found the way that they were presented in the starter kits was confusing which was why I ripped them apart and put them back together again. By doing that over the last five days I feel I now understand them.

When I am designing a workflow, I got through a process. First, I draw the interaction on a white board. I have a white board book just for this sort of thing. Writing the interactions down helps me visualize what I need to have in terms of controller actions, views and models. Each time a user fills in a form there is the following:

  1. A HttpGet controller action for presenting the form
  2. A view for presenting the form
  3. A ViewModel for receiving the data when the user pushes Submit
  4. A HttpPost controller action for processing the form data
  5. One or more views to present success or failure

If you can identify those up front, the code becomes a lot of boiler plate except where you are adding in the logic for what the workflow needs to do.

Pro Tip: The white board is your friend.

Want the code? Check out the resultant code from the last 5 articles on my GitHub Repository.

ASP.NET vNext Identity Part 4 – Registration Confirmation

In my last post I allowed people to register but the registration process was not very robust. The account controller just accepted whatever you put in. It didn’t even attempt to validate that your email was correct. Today I am going to correct that oversight and see about doing the normal confirmation. Firstly, I will validate that the email address is of the correct form, then I’ll wire up a process whereby the user has to confirm their email by clicking on a link in an email that is sent to them.

Let’s take a look at the HTTP Post controller for /Account/Register. I need to validate the email address first. To do this, I changed the top of the method as follows:

        public async Task<IActionResult> Register(RegisterViewModel model)
        {
            if (ModelState.IsValid)
            {
                Debug.WriteLine("Register: Validating Email Address");
                if (!IsValidEmail(model.Email))
                {
                    Debug.WriteLine(string.Format("Register: Email Address {0} is not valid"));
                    ModelState.AddModelError("", "Invalid email address");
                    return View(model);
                }

I’ve delegated the checking of the email form to another method in the same class:

        public bool IsValidEmail(string s)
        {
            if (string.IsNullOrEmpty(s))
                return false;

            // Return true if strIn is in valid e-mail format.
            try
            {
                return Regex.IsMatch(s, @"^(?("")("".+?(?<!\\)""@)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])@))(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-\w]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))$",
                      RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(250));
            }
            catch (RegexMatchTimeoutException)
            {
                return false;
            }
        }

That long regular expression is from Microsoft and validates the email address. The method returns true or false depending on whether the string matches or not.

I now need to generate a link that the user can utilize to validate their email address. To do this, I change the POST /Account/Register routine again:

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Register(RegisterViewModel model)
        {
            if (ModelState.IsValid)
            {
                Debug.WriteLine("Register: Validating Email Address");
                if (!IsValidEmail(model.Email))
                {
                    Debug.WriteLine(string.Format("Register: Email Address {0} is not valid"));
                    ModelState.AddModelError("", "Invalid email address");
                    return View(model);
                }

                Debug.WriteLine("Register: Creating new ApplicationUser");
                var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
                Debug.WriteLine(string.Format("Register: New Application User = {0}", user.UserName));
                var result = await UserManager.CreateAsync(user, model.Password);
                Debug.WriteLine(string.Format("Register: Registration = {0}", result.Succeeded));
                if (result.Succeeded)
                {
                    Debug.WriteLine("Register: Sending Email Code");
                    var code = await UserManager.GenerateEmailConfirmationTokenAsync(user);
                    Debug.WriteLine(string.Format("Register: Email for code {0} is {1}", model.Email, code));
                    var callBackUrl = Url.Action("ConfirmEmail", "Account",
                        new { userId = user.Id, code = code },
                        protocol: Context.Request.Scheme);
                    await SendEmailAsync(model.Email,
                        "Confirm your account",
                        "Please confirm your account by clicking this link: <a href=\"" + callBackUrl + "\">link</a>");
                    ViewBag.Link = callBackUrl;
                    return View("RegisterEmail");
                }
                foreach (var error in result.Errors)
                {
                    Debug.WriteLine(string.Format("Register: Adding Error: {0}:{1}", error.Code, error.Description));
                    ModelState.AddModelError("", error.Description);
                }
                return View(model);
            }
            // Somethign went wrong, but we don't know what
            return View(model);
        }

When the user is created successfully, I use the Identity Framework to generate an email confirmation token. I then generate a Url for the request and send it via email. There is a flip side of this – the /Account/ConfirmEmail action is run when the user clicks on the link:

        /**
         * GET: /Account/ConfirmEmail
         */
        [HttpGet]
        [AllowAnonymous]
        public async Task<IActionResult> ConfirmEmail(string userId, string code)
        {
            Debug.WriteLine("ConfirmEmail: Checking for userId = " + userId);
            if (userId == null || code == null)
            {
                Debug.WriteLine("ConfirmEmail: Invalid Parameters");
                return View("ConfirmEmailError");
            }
            Debug.WriteLine("ConfirmEmail: Looking for userId");
            var user = await UserManager.FindByIdAsync(userId);
            if (user == null)
            {
                Debug.WriteLine("ConfirmEmail: Could not find user");
                return View("ConfirmEmailError");
            }
            Debug.WriteLine("ConfirmEmail: Found user - checking confirmation code");
            var result = await UserManager.ConfirmEmailAsync(user, code);
            Debug.WriteLine("ConfirmEmail: Code Confirmation = " + result.Succeeded.ToString());
            return View(result.Succeeded ? "ConfirmEmail" : "ConfirmEmailError");
        }

This method looks up the user and then checks with the Identity Framework (specifically the user manager) to see if the code is correct. It it’s correct, then the user gets a friendly “Please log in” notification. If not, an error message is generated.

I now need three views:

  1. Message that an email has been sent
  2. Message confirming successful activation
  3. Message indicating failed activation

I’ve created three crude views as follows:

RegisterEmail.cshtml

@{
    Layout = "~/Views/Layout/LoginPage.cshtml";
    ViewBag.Title = "Check Your Email";
}

<div class="login-form-outer">
    <h4>Check your email</h4>
    <p>
        We just tried to send you an email with an activation link.  When you get the email, click
        the link in the email to activate your account.
    </p>
</div>

ConfirmEmail.cshtml

@{
    Layout = "~/Views/Layout/LoginPage.cshtml";
    ViewBag.Title = "Confirm Email";
}

<div class="login-form-outer">
    <h4>Confirmation Successful</h4>
    <p>
        Thank you for confirming your email.
        Please @Html.ActionLink("click here to log in", "Login", "Account", routeValues: null)
    </p>
</div>

ConfirmEmailError.cshtml

@{
    Layout = "~/Views/Layout/LoginPage.cshtml";
    ViewBag.Title = "Confirm Email: Error";
}

<div class="login-form-outer">
    <h4>Confirmation Failed</h4>
    <p>
        We could not confirm your account.
    </p>
</div>

The project still won’t compile. That’s because I need a method in the AccountController for sending email async. I’ve got the following initially just to test things out:

        public static Task SendEmailAsync(string email, string subject, string message)
        {
            Debug.WriteLine("SendEmailAsync: " + message);
            return Task.FromResult(0);
        }

This version outputs the link that the user would be sent in the Debug Output window. I can now run the project and go through the process of registration. When it comes time to actually send the link, I can cut-and-paste it from the Debug Output window into my browser.

Sending Email via outlook.com

I have to pick an email provider for this next bit. I have an account on outlook.com so I will use that. The email settings for outlook.com are written in their site (see the settings for IMAP and SMTP) and are listed here:

  1. Host: smtp-mail.outlook.com
  2. Port: 587 or 25
  3. Authentication: Yes
  4. Security: TLS
  5. Username: Your email address
  6. Password: Your password

I’ve created a new section in the config.json file according to this specification:

"Email": {
"From": "Your-Account@outlook.com",
"Host": "smtp-mail.outlook.com",
"Port": "587",
"Security": "TLS",
"Username": "Your-Account@outlook.com",
"Password": "Your-Password"
}

Outlook.com doesn’t allow you to send generic emails through their system so the From: has to be your username. If you are using other systems, this may not be a restriction.

I’ve created a new namespace called AspNetIdentity.Services and created a new class called EmailService in there. First task is to take in a Configuration object and store the email data for later. I’m going to use a standard Singleton pattern for this. A Singleton pattern basically tells the system to create the object once and then return the same instance whenever asked. This means I can set the data once in the Startup routine and then access the same data all over the place. A typical Singleton pattern is like this:

        private static EmailService instance;

        private EmailService() { }

        public static EmailService
        {
            get
            {
                if (instance == null)
                {
                    instance = new EmailService();
                }
                return instance;
            }
        }

I’ve also created a bunch of properties and a SetConfiguration() routine that allows the startup object to set the configuration for me. Since it’s a lot of repetitive code for each property, I won’t repeat it here. You can check it out in the files on GitHub. I’ve added a single line to the Startup.cs ConfigureServices() method.

            // Configure the Email Service
            EmailProvider.Instance.SetConfiguration(Configuration);

Finally, I’ve removed the SendEmailAsync() method in the AccountControler and changed the call to SendEmailAsync() in the Register() post function to be:

                    try {
                        await EmailService.Instance.SendEmailAsync(model.Email,
                            "Confirm your account",
                            "Please confirm your account by clicking this link: <a href=\"" + callBackUrl + "\">link</a>");
                        ViewBag.Link = callBackUrl;
                        return View("RegisterEmail");
                    }
                    catch (SmtpException ex)
                    {
                        Debug.WriteLine("Could not send email: " + ex.InnerException.Message);
                        ModelState.AddModelError("", "Could not send email");
                        return View(model);
                    }

Now that I’ve got my configuration in the right place, I can concentrate on the task at hand – sending an email asynchronously with all the configuration. I’m going to do this using the standard System.Net.Mail.SmtpClient class:

        public Task SendEmailAsync(string email, string subject, string message)
        {
            if (!this.IsConfigured)
            {
                Debug.WriteLine("EmailService is not configured");
                Debug.WriteLine("SendEmailAsync: " + message);
                return Task.FromResult(0);
            }

            SmtpClient client = new SmtpClient(this.Hostname, this.Port);
            client.EnableSsl = this.Encryption.Equals("TLS");
            if (this.Authenticated) {
                client.Credentials = new System.Net.NetworkCredential(this.Username, this.Password);
            }

            MailAddress fromAddr = new MailAddress(this.FromAddress);
            MailAddress toAddr = new MailAddress(email);
            MailMessage mailmsg = new MailMessage(fromAddr, toAddr);
            mailmsg.Body = message + "\r\n";
            mailmsg.BodyEncoding = System.Text.Encoding.UTF8;
            mailmsg.Subject = subject;
            mailmsg.SubjectEncoding = System.Text.Encoding.UTF8;

            Debug.WriteLine("SendEmailAsync: Sending email to " + email);
            Debug.WriteLine("SendEmailAsync: " + message);
            return client.SendMailAsync(mailmsg);
        }

Troubleshooting Tips

Did you get it to work straight away? I didn’t. There are a bunch of things that could go wrong but they are all tied up in the SmtpException that gets returned. I set a breakpoint on the Debug.WriteLine statement immediately after the catch(SmtpException). Examine the InnerException which is usually where the problem lies. Some interesting issues:

  1. Cannot connect to remote host: Indicates that port 25 is blocked generally. My ISP blocks outbound port 25, so I have to use port 587 instead.
  2. Mailbox is inaccessible: No authentication: This indicates that the authentication failed or that you didn’t include authentication in your settings.

I’ve included enough debugging with the files to indicate the problem. You can take a look at the files on my GitHub Repository.

Now I’ve got some final clean-up to do, which I’ll do before the next post. I want to clean up the CSS and display of the various error messages that come back so that they look nicer. I also want to disable the Register button and put a spinner up when I click on Register. Finally, I need to clean up the email message that goes out so that the link is clickable and the email looks good.

In the next post, I’ll look at what to do about forgotten passwords.