ASP.NET Identity (Part 1)

Home / ASP.NET Identity (Part 1)

As anyone familiar with .NET web development is aware, Microsoft has tried to get security right many times.  We’ve gone from its ubiquitous Membership model to its “simple” providers.  Now, the latest, albeit it’s been around for a while, is its Identity framework.


Honestly, I had never used any of Microsoft’s providers other than the tried and true Membership and Role providers.  Frankly, they work well enough, despite lacking support for features like OAuth out of the box.

Microsoft, out of the box, likes to push its technologies for everything.  As such, if one creates a new MVC5 project in VS2013, you’ll immediately be signed up to use ASP.NET Identity and get a shiny local database for EntityFramework to be your best friend.

While I like Entity Framework, probably too much, and EF is great for new projects, it doesn’t really help anyone if you’re wanting to integrate with a legacy security system/model.

So, this is where my adventure began.
Again, looking at the default MVC5 project template, we can see Entity Framework gets utilize by defining our “ApplicationUser” as an “IdentityUser.” The IdentityUser comes from namespace/nuget packge Microsoft.AspNet.Identity.EntityFramework.

    // You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
    public class ApplicationUser : IdentityUser
    {
        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
        {
            // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
            var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
            // Add custom user claims here
            return userIdentity;
        }
    }

    public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        public ApplicationDbContext()
            : base("DefaultConnection", throwIfV1Schema: false)
        {
        }

        public static ApplicationDbContext Create()
        {
            return new ApplicationDbContext();
        }
    }

The first thing I did when I saw this was to just see if I could just leave it and simply hook into validating a user’s login without touching the default code. Digging further into the default code, I found that in the IdentitgConfig.cs that is created for us, we have an “ApplicationUserManager” created for us implemented as:

public class ApplicationUserManager : UserManager<ApplicationUser>

This is a lot of code with inline classes and such in a single file. Sometimes Microsoft’s SOC approach is completely lacking. At any rate, after some trial and error, I found the there were some easy places to intercept the validation without touching the underlying EF implementation. Overriding these methods in our ApplicationUserManager, initially, seemed to do the trick with version 2.1.0 of the Identity framework bits:

        public override Task<bool> CheckPasswordAsync(ApplicationUser user, string password)
        {
            var result = true;
            return Task.FromResult<bool>(result);
        }

        public override Task<ApplicationUser> FindByEmailAsync(string email)
        {
            return base.FindByEmailAsync(email);
        }

        public override Task<ApplicationUser> FindAsync(string userName, string password)
        {
            return base.FindAsync(userName, password);
        }

        public override Task<ApplicationUser> FindAsync(UserLoginInfo login)
        {
            return base.FindAsync(login);
        }

        public override Task<ApplicationUser> FindByIdAsync(string userId)
        {
            ApplicationUser user = new ApplicationUser()
            {
                Id = userId,
                Email = userId,
                UserName = userId,
                EmailConfirmed = true,
                SecurityStamp = RandomString()
            };
            return Task.FromResult<ApplicationUser>(user);
        }

Note the method I added for creating a random SecurityStamp. And, obviously, the CheckPasswordAsync is where you would/could hook into your legacy validation mechanism.

        public static string RandomString()
        {
            var random = new Random(Guid.NewGuid().GetHashCode());
            string alphabet = "abcdefghijklmnopqrstuvwxyz";
            var numbers = "0123456789";
            var result = string.Format("{0}-{1}",
                string.Concat(Enumerable.Range(5, 10).Select(x => alphabet[random.Next(0, alphabet.Length)])),
                string.Concat(Enumerable.Range(5, 10).Select(x => numbers[random.Next(0, numbers.Length)]))
                );
            return result;
        }

With just these changes in place, everything worked just fine. However, once I upgrade my nuget packages, everything broke. I’ll discuss that in another post….

Leave a Reply