ASP.NET MVC6 Identity Part 5 – Form Validation

In the last few articles, I’ve covered the following:

  1. Creating an ASP.NET Identity Database
  2. Data Annotations and Custom Validators for Models
  3. A WebAPI Authenticator
  4. An ECMAScript 6 Modal Dialog
  5. AJAX Authentication

In the middle of all that, I left out client-side validation. We still need server-side validation – after all, how much do you trust those people who are not your primary users? The hackers, the would be hackers, and the downright malicious? I don’t trust them very much, so I definitely want to continue doing server-side validation. Client-side validation is provided so you can provide a responsive experience to your users. Server-side validation is to protect you against the hackers.

While you were gone, I tidied up my LoginModal class a bit. I abstracted three functions from the submit() method:

    /**
     * Deactivate the login form and add a spinner to show activity
     */
    deactivateForm() {
        this.submitButton.disabled = true;
        this.submitButton.innerHTML = this.spinner + this.submitButton.innerHTML;
        return;
    }

    /**
     * Deactivate the login form and add a spinner to show activity
     */
    activateForm() {
        this.submitButton.disabled = false;
        this.submitButton.innerHTML = this.submitButton.innerHTML.slice(this.spinner.length);
        this.modal.querySelector("input[name=Email]").focus();
        return;
    }

    /**
     * Display an error message in a form field.  If the field provided is
     * empty, display a general form error.
     */
    setErrorMessage(field, value) {
        let fieldSelector = this.modal.querySelector("#errorForSignInModal");
        if (field !== "") {
            fieldSelector = this.modal.querySelector("#errorFor" + field);
        }
        fieldSelector.innerHTML = value;
        return;
    }

I’ve also updated the submit() method to use ES6 fat arrow functions to ensure that the this class identifier variable is preserved in event handlers – particularly in the ajaxPost call:

        ajaxPost("/api/login", requestArgs)
            .catch(() => {
                this.setErrorMessage("", "Error transmitting credentials - try later");
                this.setErrorMessage("Email", "");
                this.setErrorMessage("Password", "");
                this.activateForm();
            })
            .then((response) => {
                if (response.status === 200) {
                    // We got a 200 Success back, so refresh the page
                    location.reload();
                } else if (response.status === 400) {
                    let r = JSON.parse(response.response);

                    // If there were errors, then add them to the appropriate areas on
                    // the form.  If there weren't errors, make sure those same areas
                    // don't have errors (handles multiple submissions)
                    this.setErrorMessage("", r[""] ? r[""][0] : "");
                    this.setErrorMessage("Email", r.Email ? r.Email[0] : "");
                    this.setErrorMessage("Password", r.Password ? r.Password[0] : "");
                    this.activateForm();
                }
            });

Now, on to validation. I like to write somewhat semantically – the code should be readable once I’ve completed it. One could argue that’s the precise purpose of the Promise format – do something then do something else. With that in mind, I decided on the following format:

        // Client Side Validation
        let validation = true;

        // Check the Email field
        try {
            let emailValidator = new Validator(requestArgs.Email);
            emailValidator.required().minLength(4).maxLength(254).isApplicationUser();
        } catch (validatorError) {
            console.error("Validation Error: ", validatorError);
            validation = false;
            this.setErrorMessage("Email", validatorError);
        }

        // Check the Password field
        try {
            let passValidator = new Validator(requestArgs.Password);
            passValidator.required().minLength(4).maxLength(254);
        } catch (validatorError) {
            validation = false;
            this.setErrorMessage("Password", validatorError);
        }

        // If either validation failed, then activate the form and continue
        if (validation === false) {
            this.activateForm();
            return;
        }

Take a look at the email field. I create a new validator and then I say “this field is required, has a minimum length of 4, a maximum length of 254 and must be an application user”. If any of those conditions do not hold true, throw an error which is caught and an error message is set. If validation failed for any reason at the end, activate the form again and return (without submitting the form).

I’ve created a new class in file Static/js/validator.js with the following contents:

"use strict";

class Validator {
    constructor(s) {
        this.s = s;
    }

    /**
     * Provided string is a string and has non-zero length
     */
    required() {
        if (typeof this.s !== "string" || this.s.length === 0) {
            throw "Field is required";
        }
        return this;
    }

    /**
     * Provided string is of minimum length
     */
    minLength(len) {
        if (this.s.length < len) {
            throw "No more than " + len.toString() + " characters allowed";
        }
        return this;
    }

    /**
     * Provided string is a valid email address
     */
    isApplicationUser() {
        // references: RFC 5321, RFC 5322, RFC 1035, plus errata.
        /*eslint-disable quotes*/
        let atom = '[A-Z0-9!#%&\+-=^_{|}~]+';
        let dot = '\.';
        let dnsLabel = '[A-Z]([A-Z0-9-]{0,61}[A-Z0-9])?';
        /*eslint-enable quotes*/

        let localPart = atom + "(" + dot + atom + ")*";
        let domain = dnsLabel + "(" + dot + dnsLabel + ")*";

        let userAccountPattern = new RegExp("^[a-z]+$", "i");
        let emailAddressPattern = new RegExp("^" + localPart + "@" + domain + "$", "i");

        if (!userAccountPattern.test(this.s) && !emailAddressPattern.test(this.s)) {
            throw "A valid RFC5321 email address is required";
        }
        return this;
    }
}

export { Validator };

Most of this is fairly obvious. The non-obvious parts (in my mind) are as follows:

  1. I return this to the calling routine. this is a reference to the current object and returning this allows for chaining.
  2. For each test (and I can add more), I check the condition and throw an error if the condition is not met. This is caught during the try…catch clause in the LoginModal
  3. The isApplicationUser is a slightly modified version of the same test in the ApplicationUserAttribute.cs validator that is used server-side. I’ve removed some special characters for ease of writing the regular expression. As a result, this regular expression is a little more constrained than the validator one.

In the isApplicationUser() test, I’ve also not embedded my admin user – I just allow any sequence of alpha characters to be a “normal username” – if someone is trying to hack your application, the last thing you want to do is give them a clue to the default username.

Final Thoughts

Someone is going to berate me for not using one of the fine Javascript Validation libraries out there – and there are many. However, you should always take some time out to understand what those libraries are doing for you. Are they actually providing enough value that it’s worth bringing in the size? What I presented here was a very minimal solution. Bringing in a generalized library would almost certainly cost more in bandwidth than my modest efforts here.

ASP.NET MVC6 Identity Part 2 – WebAPI

I’ve got this vague thought at the moment. To make my web site truly responsive I need to lose the round trip to the server to load the login page. With that in mind, I’m investigating adding a WebAPI to my application to handle logging in.

The idea is relatively simple. The layout (and hence the home page) will contain the login form. When the user clicks on the login button to submit the form, an AJAX request is sent to the server to validate the response. The server will log the person in and send back whatever is required to actually authenticate the user. The application then stores this (in a cookie or something similar) and refreshes the page. If the user is not authenticated, then immediate feedback can be provided in terms of the validation errors.

Of course, this requires that I provide a WebAPI. I’m going to create a new AccountController class in Areas/Public/Controllers for this purpose. Fortunately, I don’t need any additional packages – the WebAPI stuff is included in MVC6.

My First WebAPI

Let’s start with a pretty basic example – in fact, let’s make it as basic as I can:

using Microsoft.AspNet.Mvc;

namespace Grumpy.Wizards.Areas.Public.Controllers
{
    public class AccountController : Controller
    {
        [Route("api/login")]
        [HttpPost]
        public IActionResult Login([FromBody] LoginViewModel model)
        {
            return new HttpStatusCodeResult(200);
        }
    }
}

This listens on the route /api/login and returns a 200 response to any POST request. I’m not validating the request at this point. I want to get to the point where I can send requests and receive a response back.

if you are confused by the terminology, requests and response codes, you should read a primer – I like the Tuts+ primer.

To test this, I will run the application and then bring up Postman for the testing of the service. Here is a look at the interface configured to send the request:

blog-code-0602-1

I’ve included the actually body as well. Although I don’t check it with the code right now, I’m going to be using that soon so I may as well get the request correct now.

Validating the Model

Of course, this API doesn’t do anything other than respond. To do more, we need to validate the request. The logic is simple enough. If the model is good, then return a 200 response. If the model is bad, return a 400 Bad Request response and a JSON response that provides details on why the model failed validation.

In the ASP.NET code, I use ModelState.IsValid to determine if the model follows the rules I’ve set. I introduced the LoginViewModel and its annotations that implement the validation in my last article. I need a little more code to return those validation errors to the front-end application:

using Grumpy.Wizards.Areas.Public.ViewModels;
using Microsoft.AspNet.Mvc;

namespace Grumpy.Wizards.Areas.Public.Controllers
{
    public class AccountController : Controller
    {
        [Route("api/login")]
        [HttpPost]
        public IActionResult Login([FromBody] LoginViewModel model)
        {
            if (!ModelState.IsValid)
            {
                return new BadRequestObjectResult(ModelState);
            }

            return new HttpStatusCodeResult(200);
        }
    }
}

Let’s try getting through this with a non-valid model. The model uses the ApplicationUser validator that returns success if the provided value is RFC-5321 or our admin user, so I’m going to use a non-compliant username to test the validation:

blog-code-0602-2

If I change back to “admin” as the username or I put in a valid email address, I get the 200 Success response back. This means my data validation is working.

The second part of the process is verification and that’s where ASP

using System.Threading.Tasks;
using Grump.yWizards.Areas.Public.ViewModels;
using Grumpy.Wizards.Database;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Mvc;

namespace Grumpy.Wizards.Areas.Public.Controllers
{
    public class AccountController : Controller
    {
        private UserManager userManager = null;
        private SignInManager signInManager = null;

        public AccountController(UserManager userManager, SignInManager signInManager)
        {
            this.userManager = userManager;
            this.signInManager = signInManager;
        }

Next we want to authenticate the user. This is the same logic that we used the last time we covered Identity:

        /// <summary>
        /// Authenticate the supplied user
        /// </summary>
        /// The Login ViewModel
        /// Result of the login action
        [Route("api/login")]
        [HttpPost]
        [AllowAnonymous]
        public async Task Login([FromBody] LoginViewModel model)
        {
            // Verify that the model is valid according to the validation rules
            // in the model itself.  If it isn't valid, return a 400 Bad Request
            // with some JSON reviewing the errors
            if (!ModelState.IsValid)
            {
                return new BadRequestObjectResult(ModelState);
            }

            // Find the user in our database.  If the user does not exist, then
            // return a 400 Bad Request with a general error.
            var user = await userManager.FindByNameAsync(model.Email);
            if (user == null)
            {
                ModelState.AddModelError("", "Invalid Username or Password");
                return new BadRequestObjectResult(ModelState);
            }
            // If the user has not confirmed his/her email address, then return a
            // 400 Bad Request with a request to activate the account.
            if (!user.EmailConfirmed)
            {
                ModelState.AddModelError("Email", "Please activate your account");
                return new BadRequestObjectResult(ModelState);
            }
            // Authenticate the user with the Sign-In Manager
            var result = await signInManager.PasswordSignInAsync(model.Email, model.Password, false, shouldLockout: false);
            // If the authentication failed, add the same error that we add when
            // we can't find the user (so you can't tell the difference between
            // a bad username and a bad password) and return a 400 Bad Request
            if (!result.Succeeded)
            {
                ModelState.AddModelError("", "Invalid Username or Password");
                return new BadRequestObjectResult(ModelState);
            }

            return new HttpStatusCodeResult(200);
        }

After doing a few tests, I got this:

blog-code-0602-3

Oops – this actually is a security concern. I give away the fact that the user has an account even though the password is wrong. To fix this, I moved the EmailConfirmed below the sign in test. This does bring up an interesting problem – I need to activate the admin account when I’m creating the database. To do this, I adjust the ApplicationDbContext.cs file:

                user = new ApplicationUser {
                    UserName = options.DefaultUsername,
                    EmailConfirmed = true
                };

After I deleted the database and restart the server, I could get all the way through the WebAPI. You need the Postman Interceptor installed to see cookies, but once you do that, you’ll get the following:

blog-code-0602-4

There are actually three cookies generated:

  1. .AspNet.Microsoft.AspNet.Identity.Application
  2. 8lk97XBCwt0 (or more correctly, something completely random)
  3. connect.sid

All I need to do in my web application is to transcribe those cookies that I received to my web session and refresh the page. The ASP.NET application should then recognize me as authenticated as a particular user and display the Signoff link instead of the Signon link.

In my next article, I’m going to use this WebAPI to do exactly that inside of the ASP.NET Layout.

Note that there is nothing different about these techniques from the last time I did Identity. If you want to do Identity the same way I did last time, please feel free – there is no difference.

ASP.NET MVC6 Identity Part 1 – The Database

About a month ago, I published a series of nine articles that tackled ASP.NET Identity in the ASP.NET MVC5 framework using Beta-3 of the framework. Well, Beta-4 is now out, along with Visual Studio 2015 RC and things have changed. As a result, the next five articles will go through the same process as before.

As a reminder, this is what we want to achieve:

  1. Setting up the Identity Database
  2. Logging in as a normal user
  3. Registering a new account
  4. Handling forgotten password requests
  5. Handling Social Logins

I didn’t do that last one the last time because the support from the framework wasn’t included yet. This time I’m definitely going to take a look at that. To start with, I have a base MVC5 project and you can download it at my GitHub Repository (Sorry – the newer versions of ASP.NET5 don’t allow this to compile, so I’ve deleted the repository to reduce confusion). This project currently has no identity provisions, except for a Sign In link that I haven’t filled in yet. You can run it and a Lorem Ipsum type home page will be displayed.

Setting up the Database

As before, I am going to need some packages. The new packages for supporting Identity are as follows:

  1. EntityFramework.Core
  2. EntityFramework.SqlServer
  3. Microsoft.AspNet.Identity
  4. Microsoft.AspNet.Identity.EntityFramework

As before, I’m going to be using Entity Framework v7 to handle the database functionality, and ASP.NET Identity for the authentication and authorization piece. There isn’t a whole lot of documentation about EF7 right now. Also, there are other packages that could be doing Identity – including Microsoft.AspNet.Security packages. This means that the end method hasn’t probably been settled yet and there may be more changes in the future.

Back to this release. I updated the Startup.cs file to include this:

        public Startup()
        {
            Configuration = new Configuration()
                .AddJsonFile("./config.json")
                .AddJsonFile("./config-local.json")
                .AddEnvironmentVariables();
        }

I’m going to check in the config.json file, but not the config-local.json file. If I include any credentials, I’ll put them in the config-local.json file. This allows me to check in something to show the structure but then override it with another configuration file. If you are following along, make sure you create a config-local.json file with a blank object in it.

I’ve added my database connection string to the config.json:

{
  "Mode": "Development",
  "Database": {
    "Connection": "Server=(localdb)\mssqllocaldb;Database=TestDb;Trusted_Connection=True;MultipleActiveResultSets=true"
  },
  "DefaultUser": {
    "Username": "admin",
    "Password": "Chang3Me!"
  }
}

Last time, I deliberately modified the password to be non-secure. Not so this time – I’ve got my strong password right from the start. Again – you can override the default user password in your own config-local.json file.

The next task is to configure an application database context, linking it to Entity Framework and ASP.NET Identity as well. This is done in the ConfigureServices method inside Startup.cs:

        public void ConfigureServices(IServiceCollection services)
        {
            // Configure our application database context to be Entity Framework backed by SQL Server
            services.AddEntityFramework()
                .AddSqlServer()
                .AddDbContext(options =>
                    options.UseSqlServer(Configuration.Get("Database:Connection")));

            // Specify the configuration of our Application database context
            services.Configure(options =>
            {
                options.DefaultUsername = Configuration.Get("DefaultUser:Username");
                options.DefaultPassword = Configuration.Get("DefaultUSer:Password");
            });

            // Configure ASP.NET Identity to use our Identity-based application context
            services.AddIdentity()
                .AddEntityFrameworkStores()
                .AddDefaultTokenProviders();

            services.AddMvc();
        }

Finally, we need to set up the application to use identity and call into our context to initialize the database. This is done in the Configure method in Startup.cs:

        public void Configure(IApplicationBuilder app)
        {
            app.UseErrorPage(ErrorPageOptions.ShowAll);
            app.UseStaticFiles();
            app.UseIdentity();

            app.UseMvc(r ==>
            {
                r.MapRoute(name: "default", template: "{area=Public}/{controller=Home}/{action=Index}/{id?}");
            });

            ApplicationDbContext.InitializeDatabaseAsync(app.ApplicationServices).Wait();
        }

So far (aside from needing EntityFramework.Core as a package), this is all the same as the beta-3 framework. I need to write the ApplicationDbContext class and its associated options class, plus my ApplicationUse model for the identity database. All my database code is going to go in the Grumpy.Wizards.Database namespace – this includes all three of these files. First up is Database/ApplicationUser.cs:

using Microsoft.AspNet.Identity.EntityFramework;

namespace Grumpy.Wizards.Database
{
    public class ApplicationUser : IdentityUser
    {
    }
}

Next is the Database/ApplicationDbContextOptions.cs file:

namespace Grumpy.Wizards.Database
{
    public class ApplicationDbContextOptions
    {
        public string DefaultUsername { get; set; }

        public string DefaultPassword { get; set; }
    }
}

These are identical to the classes that I used in Beta-3. The last time around, I split the database context into a static initialization class and a non-static context class. I’ve combined them this time into a single file Database/ApplicationDbContext.cs:

using System;
using System.Threading.Tasks;

using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.Data.Entity.SqlServer;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.OptionsModel;

namespace Grumpy.Wizards.Database
{
    public class ApplicationDbContext : IdentityDbContext
    {
        const string adminRole = "admin";

        public static async Task InitializeDatabaseAsync(IServiceProvider serviceProvider)
        {
            using (var db = serviceProvider.GetRequiredService())
            {
                var sqlDb = db.Database as SqlServerDatabase;
                if (sqlDb != null)
                {
                    await sqlDb.EnsureCreatedAsync();
                    await CreateAdminUser(serviceProvider);
                }
            }
        }

        private static async Task CreateAdminUser(IServiceProvider serviceProvider)
        {
            var options = serviceProvider.GetRequiredService<IOptions>().Options;
            var userMgr = serviceProvider.GetRequiredService<UserManager>();
            var roleMgr = serviceProvider.GetRequiredService<RoleManager>();

            if (!await roleMgr.RoleExistsAsync(adminRole))
            {
                await roleMgr.CreateAsync(new IdentityRole(adminRole));
            }

            var user = await userMgr.FindByNameAsync(options.DefaultUsername);
            if (user == null)
            {
                user = new ApplicationUser { UserName = options.DefaultUsername };
                var userCreationResult = await userMgr.CreateAsync(user, options.DefaultPassword);
                if (userCreationResult.Succeeded)
                {
                    await userMgr.AddToRoleAsync(user, adminRole);
                }
            }
        }
    }
}

The actual code for setting up the database is identical to the code used in beta-3. At this point, you are probably wondering why I didn’t just refer people to the other article. Well, I like tutorials to stand alone, especially when there is a sequence of articles. I also wanted to show off that you can integrate the creation of the database with the identity database context – there is no need for multiple classes here. Since these two elements deal with the same thing (the database), it’s appropriate that they are together.

Testing Your Work

Run the project and wait for the site to load (which it should do). Then use the View menu to bring up the SQL Server Object Explorer. Add the (localdb)mssqllocaldb database instance. Open up the Databases, then TestDb and take a look at the dbo.AspNetUsers table.

blog-code-0529-1

If you right click and View the data, you should see the admin user has been created. That’s all we can hope for right now as we have not wired up the login form as yet. More on that in the next article.

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 9 – Squashing Bugs

I decided to do some basic testing on my ASP.NET vNext Identity code before I move it into my side project (more on that later). I discovered three bugs that I thought were worth mentioning here.

  1. A user can log in without confirming the email address.
  2. When a user registers and then registers again (without confirming), nothing happens.
  3. When a user forgets the password without confirming the email, nothing happens.

Ok – only one of these (the first one) is a bona-fide bug. It’s fixed rather easily by logic within the LoginController.cs file. I’ve altered the top of the POST Index action as follows:

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Index(LoginViewModel model, string returnUrl = null)
        {
            logger.Trace("POST:Index: Checking ModelState is Valid");
            ViewBag.ReturnUrl = returnUrl;
            if (ModelState.IsValid)
            {
                logger.Trace("POST:Index - does user exist? finding the user");
                var user = await UserManager.FindByNameAsync(model.UserName);
                if (user == null) {
                    logger.Trace("POST:Index - user is not found");
                    ModelState.AddModelError("", "Invalid username or password.");
                    return View(model);
                }
                if (!user.EmailConfirmed) {
                    logger.Trace("POST:Index - user does not have a confirmed email");
                    ModelState.AddModelError("", "Invalid username or password");
                    return View(model);
                }

                logger.Trace("POST:Index - checking password");
                var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);

The additional logic looks up the user in the SQL database. If the user does not exist or the email is not confirmed, then the whole password sign-in is short-circuited and I just display the form with an “Invalid username or password” error.

For my second bug, one can consider this is the right thing to do. However it’s not very friendly. I don’t have any way of cleaning out un-confirmed accounts yet. What if the user had an email failure or accidentally deleted the email? I decided to add in some logic to the registration process so that if a user tried to register an account that was already registered but not confirmed then the user would be deleted and the new user record would be created. The code goes in RegisterController.cs in the POST Index action:

                logger.Trace("Register: Validating Email Address");
                if (!IsValidEmail(model.Email))
                {
                    logger.Trace(string.Format("Register: Email Address is not valid"));
                    ModelState.AddModelError("", "Invalid email address");
                    return View(model);
                }

                // Check to see if the user is confirmed or not. If the user is not
                // confirmed yet, then assume that the registration failed somehow,
                // delete the user and restart all over again.
                var user = await UserManager.FindByNameAsync(model.Email);
                if (user != null) {
                    logger.Trace("User {0} already exists - checking for confirmation", model.Email);
                    // If not confirmed and not an admin
                    if (!user.EmailConfirmed && !model.Email.Equals("admin")) {
                        logger.Trace("User {0} is not confirmed - resetting registration by deleting user", model.Email);
                        var deleted = await UserManager.DeleteAsync(user);
                        if (!deleted.Succeeded) {
                            logger.Error("Could not delete user {0}", model.Email);
                        }
                    }
                }

                logger.Trace("Register: Creating new ApplicationUser");
                user = new ApplicationUser { UserName = model.Email, Email = model.Email };

The new code is in the middle. As with the login logic update, I first of all look up the user in the SQL database. If the user exists then I check that the user does not have a confirmed email address. I also check to ensure the user is not my admin user. I’ll be adjusting this so that the “admin” is not a literal string at some point. If all the conditions are met, I delete the user via the user manager.

There is somewhat of a security race condition here. Let’s say user-1 is actually registering for the service, but user-2 (a bad user who has previously gained access to the email account of user-1) is also fraudulently registering for the service at the same time. It’s quite possible that the registration of one overwrites the registration of the other with the result that I cannot determine which user is correct. I believe this to be a small concern in the vast majority of web applications. If you have a web application where this is actually a problem, consider another form of registration.

My final bug needs some thinking about. The process is:

  • User registers an account but does not confirm the account
  • User clicks on the forgot password link

What should happen? The user registered an account and then went “what did I type?” My thought is that the user should be redirected to the registration page. The intent is probably to get another code for resetting of that password. Since the account does not fully exist and I have already implemented the code for what happens when registering over the top of an unconfirmed account, I can use this to implement the logic here. The logic is found in the ForgotPasswordController.cs in the POST Index action:

        // POST: /Account/ForgotPassword/Index
        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Index(ForgotPasswordViewModel model)
        {
            if (ModelState.IsValid)
            {
                logger.Trace("POST:Index: Checking for user ID = " + model.Email);
                var user = await UserManager.FindByNameAsync(model.Email);
                // If the user does not exist then say we confirmed, but don't actually do anything.
                if (user == null)
                {
                    logger.Trace("POST:Index: User does not exist - lying to the user");
                    return View("ConfirmationRequired");
                }
                // If the user is not confirmed, then redirect to registration
                if (!user.EmailConfirmed) {
                    logger.Trace("POST:Index: User is not confirmed - redirect to the Registration page");
                    return RedirectToAction("Index", "Register");
                }

                // 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);
                logger.Trace("POST:Index: Code = " + code);

I used to have a single if statement for when the user did not exist OR the email was not confirmed. Now these two elements are separated.

The short version of this exercise is to think about what users are going to do and what they mean when they do those things. Implement the logic of your workflow accordingly.

In this continuing series on getting Identity right, my code is on my GitHub Repository.

There is still more to be done for Identity. Here is my short list:

  1. Enabling Facebook, Twitter, Microsoft and Google Social Authentication
  2. Automatically cleaning out the dead confirmation records
  3. Utilizing a background task to send email
  4. Utilizing a templating email engine

All of these require features that are not quite available yet in the release branch of ASP.NET and Visual Studio 2015 CTP 6. I will revisit my Identity baseline in the coming months once these are available. Until then, it’s time to do some other stuff, so tomorrow I’ll be introducing my new Web Application.

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 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.