My current single-sign server, that utilizes OWIN, does not store information regarding users’ identity. On the back-end, it makes LDAP queries to Active Directory to authenticate users and then makes additional LDAP queries to determine roles and authorization.
Since I’ve been playing with Azure lately, I wanted to re-tool this solution to allow toggling between a data-store for user identity information and Active Directory.
In addition to switching to a data-store approach, I also wanted to reuse my exiting IRepository;<T;> code and patterns. Since I’ve played with ASP.NET Identity before, it made sense to me to extend and reuse its models and database schema. That isn’t to say that I wanted to “use” Identity directly, I only wanted its structure. I still didn’t really plan to use Identity’s UserManager or other mechanisms directly. Why bother you say? Well, re-purposing Identity’s structure means that if I did ever want to use the full-blown Identity framework, it would be possible without huge code changes.
Identity is based on Entity Framework. This makes it pretty easy to at least get the database schema. All that’s required is spinning up a new .NET 4.6.x web project, enabling migrations, and then creating an initial migration based on the default Application context that the web project template creates.
When creating the new web project, individual user accounts must be selected to ensure that all of the Identity references and DbContext are created:
After the project is created, I change the “DefaultConnection” connection string to point to my local SQL instance rather than LocalDb. Once that is changed, we can get the Identity database created with only a few commands in the Package Manager console using EF migrations.
Identity is extensible out of the box. You can inherit from the its classes and set the key type that you want and update your database with additional migrations accordingly. By default, all of the Identity objects are strings. For my purposes, though, I want them to be integers that are SQL Identity keys. To accomplish this, I actually modify the EF initial migration. For any string keys referred to as c.String, I replace them with c.Int. Effectively, the old migration class goes from this:
To something like this:
If you wanted your Ids to be GUIDS, you could make a similar change to the Database schema. The good thing here is that, as I mentioned, since Identity is extensible, changing the key types in the schema won’t break Identity.
Once we are don’t modifying web.config and the initial.cs migration, and run the migrations, our tables will be available in our local SQL instance and viewable via SSMS.
At this point, to keep things simple, we use Visual Studio’s code generation tools to create our models from the DbSchema. Bringing up the “Add New Items” dialog, we want to add a new ADO.NET Entity Data Model from our schema:
Once all of that is done, we will have a new DbContext, models, and everything we need to instantiate an IRepository;<T;> from our concrete implementation, if that implementation is based on EF. My implementation is, so I can start using the models and database immediately.
In my single sign-on injection, I only need to create a new Validation service that utilizes the Identity models in the same manner that Identity itself uses the schema. Since my previous implementation didn’t allow user registration, I would probably now use a flag to indicate that user registration is possible and create views similar to Visual Studio’s default template. Also, Identity is open-source so it’s possible to replicate the password hash/salt generation to allow hashed passwords we save to continue to be compatible with Identity. Overall, this approach opens up possibilities of being “compatible” with Identity and being somewhat future-proof, while not becoming totally bound to ASP.NET Identity.
The reason why I currently wouldn’t use ASP.NET Identity directly is because of its deep hooks into the .NET pipeline and its attempts to fully manage security. As I wrote in another blog post, its UserManager tries to do too much and is too restrictive. Its approach may be fine for small demo/test websites, but for more robust applications, I don’t think it scales well or is very manageable. In fact, it comes with no user management tools. While you could easily create your own user management with MVC5/6’s built-in scaffolding, I even find that built-in scaffolding to be somewhat limited.
On a side note, here’s is Microsoft’s guidance on changing the key types used with ASP.NET Identity.
That particular article is a little out of date. It doesn’t cover everything that must be changed in the default controllers that are created, but those changes (mainly GetUserId methods) readily identifiable due to compiler errors when attempting to build.