DNVM, DNX, and DNU - Understanding the ASP.NET 5 Runtime Options

Posted on May 17 2015 08:13 PM by jatten in ASP.Net, ASP.NET MVC, C#   ||   Comments (4)

give-my-regards-to-mr-escher-240ASP.NET 5 introduces a new runtime model for the .NET framework which allows us to employ a "pay-as-you-go" approach, building composable applications using only those framework components our application needs, without relying upon a central, monolithic library repository present on the host machine.

This new model also provides us with command line tools for managing our .NET version selection, library packages, and execution environment outside of Visual Studio. It is now possible to develop cross-platform ASP.NET applications using a text editor and command line (either CMD or Powershell on Windows) without ever opening Visual Studio.

Image by César Astudillo  |  Some Rights Reserved

Understanding the relationship between the .NET Version Manager (DNVM), the .NET Execution Environment (DNX) and .NET Development Utilities (DNU) is fundamental to developing with ASP.NET 5. In this post we will look at installing and using DNVM, DNX, and DNU on to work with ASP.NET from the command line.

DNVM - The .NET Version Manager

DNVM is a version manager tool for the command line. As its name implies, DNVM provides the functionality needed to configure your .NET runtime. We can use DNVM to specify which version of the .NET Execution Environment to use at the process, user, or machine level.

DNX - The .NET Execution Environment

What is this DNX, anyway? From the ASP.NET Documentation site:

The .NET Execution Environment (DNX) is a software development kit (SDK) and runtime environment that has everything you need to build and run .NET applications for Windows, Mac and Linux. It provides a host process, CLR hosting logic and managed entry point discovery. DNX was built for running cross-platform ASP.NET Web applications, but it can run other types of .NET applications, too, such as cross-platform console apps.

Broadly speaking, different DNX runtime versions are available which reflect which .NET framework version you want to use in your application. At a basic level, there are different versions for:

  • .NET Framework - The familiar .NET framework we all know and love.
  • .NET Core - A subset of the .NET Framework which includes a modular runtime and library implementation and is managed via Nuget. .NET Core is cross-platform, open source, and includes the Core libraries in CoreFX, and a Core runtime in CoreCLR.
  • Mono - Using Mono, we can create ASP.NET application which compile and run on OSX and Linux machines.

We can use the .NET Version Manager to select which DNX version we want to use with our application.

DNU - .NET Development Utilities

DNU is a command-line tool which provides a variety of utility functions to assist with development in ASP.NET. Most commonly, we will use DNU to install and manage library packages in our application, and/or to package and publish our own application.

DNU uses Nuget behind the scenes for package management and deployment.

Getting Started - Installing DNVM

If you have installed Visual Studio 2015 (currently available as a Release Candidate HERE), you already have the .NET Version Manager installed.

UPDATE: According to the ASP.NET team  (thanks Glenn!) DNX/DNVM isn't actually installed until you run File -> New after VS 2015 is installed, so if you have VS 2015 installed but have not cracked open a new file yet, you won't have it on your machine yet.

If you want to upgrade to the most recent version of DNVM, or if you want to work with ASP.NET, but don't want to install Visual Studio, you can download the DNVM script as follows from either the Windows Command prompt (CMD) or using Powershell:

Install or Upgrade DNVM Using CMD:
@powershell -NoProfile -ExecutionPolicy unrestricted -Command "&{$Branch='dev';iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/aspnet/Home/dev/dnvminstall.ps1'))}"

 

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

 

Once we have DNVM on our machine, we should be able to fire up the Windows command prompt, and get started.

At the command line (or Powershell prompt) run the following to see that DNVM is, in fact, installed on your machine:

Run DNVM without Arguments:
> dnvm

 

If all has gone well to this point, you should see the following (we're going to stick with CMD for this post, to keep things simple):

Console Output from Running DNVM without Arguments:

run-dnvm-no-args

Now that we have DNVM installed and running, let's see which DNX versions we have available, and how to install DNX versions if we need.

Working with DNVM - List the Available .NET Runtimes

To examine the runtime options available to us, we can run the following command from the Console:

List Available DNX Runtimes Using DNVM List:
> dnvm list

 

I had previously installed Visual Studio 2015 on my machine, which also installed a few DNX versions, so when I runt he above I see the following output:

Console Output from DNVM List:

run-dnvm-list

Because I had installed Visual Studio 2015 already, there are DNX versions available for .NET Framework (the beta4 clr in the image above) and also .NET Core (the coreclr above) for both 32 and 64 bit architectures.

If you have NOT installed Visual Studio 2015, your list is very likely empty. Installing DNVM does not, in and of itself, install any DNX versions on your machine. No worries, we'll take care of that next.

Working with DNVM - Installing DNX Runtime Versions

If you just installed DNVM fresh, or if you want to get the latest version of a particular DNX implementation, we can use the the dnvm install command with some appropriate arguments:

By default, DNVM will work with the basic .NET framework, and assume the x86 architecture. For example, if we do the following:

DNVM Install Latest:
> dnvm install latest

 

DNVM will download and install the latest stable version of the regular .NET framework for the x86 architecture. If we run dnvm list again, we see the following:

Installed DNX Runtimes after Running DNVM Install Latest:

run-dnvm-install-latest-noargs

If we want to specify a different runtime (say, the CoreCLR instead of the .NET Framework, and/or specify the x64 version, we need to add the -r ( -runtime ) and/or -arch ( -architecture ) flags, and values:

DNVM Install Latest for Specific Runtime/Architecture:
> dnvm install latest -r coreclr -arch x64

 

Once the above is finished running, we have now added the latest version of the full .NET Framework for the x86 architecture, and CoreCLR for the x64 architecture to our available runtimes list:

Installed DNX Runtimes:

run-dnvm-list-after-install

DNVM Upgrade VS. DNVM install

DNVM also has an upgrade command, which behaves just a little differently than Install.

DNVM Install fetches the specified version, and makes it active in the current Command process by adding it to the process PATH variable. The selection is "Active" is only for the duration of our terminal session. Once the current terminal session is closed, the active selection will revert to none, or whatever had been previously persisted in our User PATH variable as the default.

DNVM Upgrade does essentially the same thing, but also adds it to the User's PATH variable as the default active version, and updates the default alias. For example, if we used dnvm upgrade to install the latest 64 bit version of the .NET framework clr:

Upgrade .NET Framework CLR to Latest Version Using DNVM Upgrade:
> dnvm upgrade -r clr -arch x64

 

After running the above, our Console output tells us that the latest version of dnx-clr-win-x64 has been added not only to the current process PATH, but also to our User PATH. In addition, the "default" alias has been updated to point to the just-installed version:

Console Output from DNVM Upgrade:

dnvm-upgrade

Note that dnvm upgrade pulls down the latest stable release from Nuget. If you want to work on the bleeding edge with the latest unstable (development) release, you can use:

Upgrading to Latest Unstable (development) Runtime Releases:
> dnvm upgrade -u

 

In the above, you can specify runtime/architecture as previously using the -r and -arch flags.

5/17/2015 - NOTE: If you installed Visual Studio 2015, the system environment PATH variable likely points to C:\Program Files\Microsoft DNX\Dnvm\. As of this writing, the Visual Studio version of DNVM does not recognize the -u (-unstable ) flags. Even if you installed DNVM using the shell scripts at the beginning of this article, the Visual Studio variable will be found first. In order to use the -u flag, you will need to either change the order in which the PATH variables occur, or remove the Visual Studio PATH and add DNVM using one of the scripts above.

Working with DNVM - Selecting or Changing the Active DNX Runtime

Notice in the previous section the asterisk that appears in the "Active" column of the console output once we started installing new DNX runtime versions. When we use dnvm Install, DNVM makes the just-installed version the default active version for the current process (in other words, for the current terminal session only).

As noted previously, when we run dnvm upgrade, DNVM makes the just-installed version the default active version not only for the current process, but also at the User level.

We can switch to a different DNX runtime by using the dnvm use command. By default, dnvm use changes the active selection for the current Command process. For example, given the current active runtime in the console output from the previous section (1.0.0-beta4-11566 clr x64), we could decide we want to switch to the latest 64 bit coreclr version for our current terminal session instead:

Select or Switch to a Different Runtime for the Current Process:
> dnvm use 1.0.0-beta4-11566 -r coreclr -arch x64

 

If we run the above command, and then run dnvm list again, we see our active version has changed:

New Active DNX Runtime Selected for Current Process:

switch-dnx-version-for-process-path

If we look closely at the console output above though, we see that the new version was added to the process PATH, meaning, the selection will persist for the current Console process only. If we close the console window, and open another, the default set in our User PATH will be selected again.

If we want to set our user default, we could run the command just like we did previously, but instead we can add the -p ( -persistent) flag, which will cause the selection to be added to our user path instead of the process path:

Select or Switch to a New DNX Runtime Default for User PATH:
> dnvm use 1.0.0-beta4-11566 -r coreclr -arch x64 -p

 

Now, our selection will persist as the default between Command sessions. We can still select a different version per process just like we did previously, but until we make additional changes, the default active DNX runtime in a Command session will be the beta 4 CoreCLR from build 11566.

Remove Runtime References from PATH Variables

If we want to remove all runtime references from the process path (in other words, return to a state where no runtime is set as "Active" we can run:

Remove DNX Runtime References from Process PATH Variable:
> dnvm use none

 

If we want to remove any defaults we have set in our User PATH variable, we can add the -p flag:

Remove DNX Runtime References from User PATH Variable:
> dnvm use none -p

 

Use Aliases to Make Typing Easier

If you have been working through the examples so far, you may have noticed how painful it can be typing out the full, semantic version names each time you want to refer to a runtime version. DNVM affords us the ability to assign aliases to the different installed versions. We can do this during install or upgrade using the -a ( -alias ) flag, or we can set aliases for existing installed versions using the alias command.

For example, we already have an alias, default, which in my case was set up when I installed Visual Studio. It was originally assigned to the regular x86 .NET framework CLR, and then was re-assigned when we ran dnvm upgrade in the previous section. As of now, the alias default on my machine points to the latest (build 11566) x64 bit version of the .NET CLR.

I can set an alias for the latest x64 version of CoreCLR like so:

Assign an Alias to a DNX Runtime:
> dnvm alias core-64-latest 1.0.0-beta4-11566 -r coreclr -arch x64

 

Having done that, I can now refer to that particular runtime by its alias, for example:

Select or Switch to a new DNX Runtime Using an Alias:
> dnvm use core-64-latest

 

5/17/2015 - NOTE: There is currently a bug (see issue #175 / PR #248 at the DNVM Repo on Github) in which referring to a CoreClr runtime by alias does not work. As of this writing, the PR has not yet been merged, but things are supposed to work as described here. Until the issue is resolved, it is still necessary to refer to any CoreClr runtime by its full version name…

We can re-assign a previously set alias by simply using the dnvm alias command, and assigning the alias to a different DNX Runtime.

DNX and DNU - Working with an Example Project from the Command Line

To get a feel for how DNVM, DNU, and DNX work together, we'll put together a very basic example project, using only the Windows Command Prompt and a text editor (for this post, I'm going to use Sublime Text 3, but we could just as easily use Visual Studio Code, or Notepad).

First, let's create a project directory, and then open the folder in Sublime Text:

Create a Project Directory and Navigate into the Directory using CMD:
C:\Users\John> mkdir dnx_demo
C:\Users\John> cd dnx_demo

 

Then, open the directory folder in Sublime text. First, we'll add a project.json file:

Add project.json File:
{
  "version": "1.0.0-*",
  "description": "Silly demo project",
  "commands": {
    "runme": "dnx_demo"
  },
  "frameworks": {
    "dnx451": { },
    "dnxcore50": {
      "dependencies": {
        "System.Console": "4.0.0-beta-22816",
        "Microsoft.CSharp": "4.0.0-beta-22816"
      }
    }
  }
}

 

In the above, note we have defined a command, "runme" which refers to the project name. We can invoke this command from the Command Line using dnx to run our project. Also note, we have specified both the traditional .NET Framework (dnx451) as well as the .NET Core (dnxcore50) as compilation targets, so our application wioll be cross-compiled for both DNX runtimes and frameworks.

Next, add a file named Program.cs and paste in the following code:

The Program.cs File:
using System;
namespace dnx_demo
{
    public class Program
    {
        public void Main(string[] args)
        {
            Console.WriteLine("No Visual Studio Here!!");
            Console.Read();
        }
    }
}

 

By simply adding these two files, we have (almost) everything we need to run a very basic, but complete, .NET Console application. Save the two files above, and return to the Command prompt.

Use DNU Restore to Restore Packages

Our project.json file specifies the target frameworks and dependencies our project requires. Note that for this project, there are no packages to be pulled down when we run against the standard .NET framework 4.5.1 - the required references are already present in the .NET framework itself.

We will need to restore packages before we can run against the .NET Core framework and CoreCLR. Remember, .NET Core is all about "pay as you go." In other words, We pull in only those libraries we need for our application to run, and leave out everything else.

We can restore library packages by simply running dnu restore from within our project directory:

Use DNU Restore to Restore Library Package Dependencies:
C:\Users\John\dnx_demo> dnu restore

 

Run the Example Application Using DNX

With our package dependencies restored, we can run our application using DNX. We can now run the application, after we select which DNX runtime we want to use.

In my case, we set the default active runtime to the latest .NET Core CLR / x64 in a previous example, so we can run the application straight away from within our project directory:

Run the Example Application Using DNX:
C:\Users\John\dnx_demo> dnx . runme

 

Take a close look there. Since I am already in the project directory, I can simply type dnx, and use a period to indicate the current directory. DNX will parse the command, runme, we set up in our project.json file, and use that to run the project.

dnx-run-example-using-command

We could also simply reference the project by name:

Run the Example by Referencing the Project Directory Name:
C:\Users\John\dnx_demo> dnx . dnx_demo

 

Or, as long as we are in the project directory, we could keep it REAL SIMPLE and just use dnx . run

Run the Example Using dnx . run:
C:\Users\John\dnx_demo> dnx . run

 

Now, let's switch runtimes from .NET Core to the traditional .NET Framework. Recall, we had previously used dnvm upgrade to install the latest x64 binaries for the .NET framework, and when we did that, our default alias was assigned to that runtime:

Switch to the .NET Framework Runtime Using DNVM Use:
C:\Users\John\dnx_demo> dnvm use default

We can check to make sure we are now targeting the .NET CLR instead of CoreCLR, and then run our application again:

Running the Example Using the .NET Framework and Standard CLR:

dnx-run-example-using-clr

 

Summing Up

So far, we've examined the basics of using the .NET Version Manager, the .NET Development Utility (DNU), and the .NET Execution Environment in order to get a basic application up and running in the new ASP.NET environment.

In our simple example above, we compiled and executed our project in memory. There is no generation of binaries as part of the dnx run process. DNX, and DNU offer a wealth of additional features, such outputting binaries as a part of the build process (dnu build), creating Nuget packages (dnu pack) and other useful commands.

DNU, DNX, and DNVM are currently in active development, and things are changing daily. Keep your eye on the ASP.NET 5 repo, and watch for updates here and elsewhere.

We will explore more in upcoming posts

Additional Resources and Items of Interest

 

Posted on May 17 2015 08:13 PM by jatten     

Comments (4)

ASP.NET Web API: Understanding OWIN/Katana Authentication/Authorization Part III: Adding Identity

Posted on February 15 2015 06:19 PM by jatten in ASP.NET MVC, ASP.Net, C#, CodeProject   ||   Comments (7)

eyball-500This is the third post in a series in which we have built up a minimal, self-hosted, OWIN-based Web Api application essentially from scratch. Our objective has been to develop a better understanding of how the various components fir together and interact in an OWIN-based environment, and to do so without creating any dependencies on IIS or the heavy weight System.Web.dll.

Up to this point, we have created a basic Web Api, and implemented our own authentication/authorization, using basic OWIN authorization, and our own set of models. What we have built so far represents a bare-bones model of how authentication and authorization work in an OWIN-based application. We have taken some architectural shortcuts in the name of maintaining a simple, easy to understand structure as again, our goal so far has emphasized concept over details.

Image by alles-schlumpf  |  Some Rights Reserved

Previous posts, in order:

In this post, we are going pull in the ASP.NET Identity framework, and ideally, we will again achieve a better understanding of how Identity fits in to a general Web Api application, and we will allow Identity to perform some of the heavy lifting for us when it comes to difficult, hard-to-get-right-even-for-the-experts details such as crypto and security details.

Source Code for Examples

We are building up a project over a series of posts here. In order that the source for each post make sense, I am setting up branches that illustrate the concepts for each post:

On Github, the branches of the Web Api repo so far look like this:

  • Branch: Master - Always the most current, includes all changes
  • Branch: auth-db - The code we build up in the course of the previous post, adding a persistence layer for our authentication system.
  • Branch: auth-identity - the code we will build out in the course of this post. We will start where we left off in the previous post, and modify to bring in a minimal implementation using Identity Framework.

The code for the API client application is in a different repo, and the branches look like this:

  • Branch: Master - Always the most current, includes all changes
  • Branch: owin-auth - Added async methods, and token-based authentication calls to the Web Api application. The code for the client application remains unchanged, except when we need to switch out user credentials.

In the previous article, we created create the classes MyUser and MyUserClaim classes in order to implement our authorization and authentication mechanism in the OWIN/Katana environment, and which also became our code-first models for database persistence via Entity Framework. We also created the MyUserStore class, which contained the methods necessary to save and retreive user authentication data from our backing store.

We had assembled these very rudimentary classes into a functioning authentication and authorization framework of sorts, using them in our application to perform the basic functions needed to properly authenticate a user, and establish a minimal authorization mechanism based upon the role claims possessed by each user.

In this post, we are going to use ASP.NET Identity instead, and replace our crude, homebuilt mechanism with a fully-functioning, if basic, auth system.

Core Identity Framework

To understand how Identity will fit into our application, and the OWIN/Katana environment, it is useful to examine the structure of Identity framework itself.

The actual core Identity library is Microsoft.AspNet.Identity.Core. This library defines a host of interfaces upon which the function of Identity is based, and a smaller number of concrete implementation classes which are expressed in terms of these interfaces. We actually already have this library in our project, because we pulled in the Microsoft.AspNet.Identity.Owin library previously via Nuget. We haven't used any of the identity components to this point, but we made use of some items from dependent libraries included in that Nuget package, such as Microsoft.Owin.Security and Microsoft.Owin.OAuth

In general, the models which might need to be consumed in an application are expressed as interfaces, and the internals of the framework provide implementation for those interfaces. It is up to the application, and/or any other frameworks pulled in, to provide the concrete implementations for these model interfaces.

For example, the core Identity framework provides us with a pair of interfaces to represent a User:

Two Versions of the IUser Interface:
// Interface with generic type argument for the Key:
public interface IUser<out TKey>
{
    TKey Id
    {
        get;
    }
 
    string UserName
    {
        get;
        set;
    }
}
// Interface derived from IUser<Tkey> Specifying string Key:
public interface IUser : IUser<string> { }

 

In a similar manner, most of the interfaces defined in the core Identity framework to represent persistence models are expressed in a manner which allows us to specify the type for the key to be used.

Additionally, many of the Identity interfaces are dependent on other interfaces in the framework. In these cases, the interface is expressed in terms of a generic type argument representing the concrete implementation of the dependency. For example, core Identity framework provides two interfaces to represent a UserStore:

Two Versions of the IUserStore Interface:
// Interface with generic type arguments for User, and the User Key:
public interface IUserStore<TUser, in TKey> : IDisposable
where TUser : class, IUser<TKey>
{
    Task CreateAsync(TUser user);
    Task DeleteAsync(TUser user);
    Task<TUser> FindByIdAsync(TKey userId);
    Task<TUser> FindByNameAsync(string userName);
    Task UpdateAsync(TUser user);
}
// Interface expressing IUserStore in terms of generic User type, 
// and specifying a string User Key
public interface IUserStore<TUser> : IUserStore<TUser, string>, IDisposable
where TUser : class, IUser<string>
{
}

 

If you explore the Microsoft.AspNet.Identity.Core library using a free tool such as Telerik's fine Just Decompile, you can explore the various interfaces and concrete classes available, and develop an understanding of how they relate. However, a quick look using even the VS Object Browser will reveal that there are no concrete implementations of the basic model interfaces we need in order to implement Identity in our application. For this, we either need to roll our own, or pull in another library which provides ready-to-use implementations.

Since we are already using Entity Framework, in our case this is easy.

Identity and Entity Framework

The Microsoft.AspNet.Identity.EntityFramework library provides concrete implementation classes needed to use Identity from an application using Entity Framework. In this library we find some model classes we can use as-is, or which we can extend and customize as needed. For example, the IdentityUser class provides a concrete implementation for IUser<Tkey> :

The Base IdentityUser Class:
// Base implements IUser<TKey> and is expressed with generic type arguments
// for other model types required by Identity Framework:
public class IdentityUser<TKey, TLogin, TRole, TClaim> : IUser<TKey>
    where TLogin : IdentityUserLogin<TKey>
    where TRole : IdentityUserRole<TKey>
    where TClaim : IdentityUserClaim<TKey>
{
    public IdentityUser()
    {
        this.Claims = new List<TClaim>();
        this.Roles = new List<TRole>();
        this.Logins = new List<TLogin>();
    }
 
    public virtual TKey Id { get; set; }
    public virtual string UserName { get; set; }
    public virtual string Email { get; set; }
    public virtual bool EmailConfirmed { get; set; }
    public virtual string PhoneNumber { get; set; }
    public virtual bool PhoneNumberConfirmed { get; set; }
 
    public virtual string SecurityStamp { get; set; }
    public virtual bool TwoFactorEnabled { get; set; }
    public virtual string PasswordHash { get; set; }
 
    public virtual int AccessFailedCount { get; set; }
    public virtual bool LockoutEnabled { get; set; }
    public virtual DateTime? LockoutEndDateUtc { get; set; }
 
    public ICollection<TLogin> Logins { get; set; }
    public ICollection<TRole> Roles { get; set; }
    public ICollection<TClaim> Claims { get; set; }
}
 
 
// Alternate implementation derives from Generic implementation, 
// and expresses Generic model types in terms of classes defined 
// within Identity.EntityFrameowrk Library: 
public class IdentityUser : IdentityUser<string, IdentityUserLogin, 
    IdentityUserRole, IdentityUserClaim>, IUser, IUser<string>
{
    public IdentityUser()
    {
        this.Id = Guid.NewGuid().ToString();
    }
 
    public IdentityUser(string userName) : this()
    {
        this.UserName = userName;
    }
}

 

We can see in the above example that there is a lot of functionality ready to go in the basic IdentityUser implementation. Also, note that the various generic type arguments provided in the base implementation are again provided such that we might extend our Identity model classes with custom implementations, for example, if we wanted to use integer keys instead of strings.

The Identity.EntityFramework library provides similar implementations for the other interfaces defined in Identity.Core. In addition, as we might expect, Identity.EntityFramework also includes the IdentityDbContext class, which knits together the various model classes, ready for use in a EF/Code-First application.

What is important here is understanding that the Identity.Core library provides the interfaces we need, and implements the interactions between those interfaces. It is up to us to provide the implementation for those interfaces, either by rolling our own, or by using a library specific to our persistence model such as Identity.EntityFramework.

Add Identity.EntityFramework Library Via Nuget

Since we are using Entity Framework in our minimal OWIN Web Api project, we will pull in the Identity.EntityFramework package we discussed above to take advantage of the ready-made Identity implementation afforded by the Identity team.

NOTE: This post assumes you are working with ASP.NET < 5.0, and Identity 2.1. As of this publication date, the newest package for this library is a pre-release of Identity 3.0 which targets ASP.NET 5. Unless you are working with ASP.NET 5.0 ("vNext") you want to make sure you are pulling in version 2.1

Add the Microsoft.AspNet.Identity.EntityFramework Nuget Package:
PM> Install-Package Microsoft.AspNet.Identity.EntityFramework -Version 2.1.0

 

We already have the Identity.Core library in our example project, because it was included when we pulled in the Identity.Owin Nuget package in Part I of this series.

Add Identity to the Self-Hosted Web Api - Models and Stores

To get started, we will be picking up where we left off in the previous post. Recall that we had added an AuthModels.cs file, and coded up a MyUser class, a MyUserClaim class, a MyPasswordHasher class, and a MyUserStore class.

We can get rid of all that now, delete the AuthModels.cs file.

In order to add the (mostly) ready-to-use Identity framework to our project, let's add a new code file named IdentityModels.cs, and add the following code:

Add Identity Models:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
// Add using statements:
using Microsoft.Owin;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.AspNet.Identity.EntityFramework;
 
namespace MinimalOwinWebApiSelfHost.Models
{
    public class ApplicationUser : IdentityUser
    {
        // A default Constructor:
        public ApplicationUser() { }
        
        public ApplicationUser(string email) : base(email)
        {
            // Use the email for both user name AND email:
            UserName = email;
        }
    }
 
 
    public class ApplicationUserManager 
        : UserManager<ApplicationUser>
    {
        public ApplicationUserManager(IUserStore<ApplicationUser> store) 
            : base(store) { }
 
 
        public static ApplicationUserManager Create(
            IdentityFactoryOptions<ApplicationUserManager> options,
            IOwinContext context)
        {
            return new ApplicationUserManager(
                new UserStore<ApplicationUser>(
                    context.Get<ApplicationDbContext>()));
        }
    }
}

 

Now, let's take a good hard look at what's going on in the above code.

First, we have added an ApplicationUser class, which derives from IdentityUser. IdentityUser is a concrete implementation if the Identity.Core IUser interface, and is provided by the Identity.EntityFramework library we discussed previously. We aren't doing much in this derived class at this point, but we will be adding to it later.

Next, we have the ApplicationUserManager class, which derives from UserManager. Unlike IdentityUser, the UserManager class is a part of the Identity.Core library. In other words, any application using the Identity framework can expect to have access to UserManager, or a derivation similar to what we have done above.

Notice that our ApplicationUserManager expects an argument of IUserStore as a constructor parameter. What's this?

We'll take a short detour to discuss UserManager and UserStore, and the purpose behind each.

UserManager and UserStore - What's the Difference?

The core Identity framework defines the UserManager class to implement various functionality required to, well, manage user information according to business rules and configuration established either by Identity framework itself, or as part of configuration options set up during development.

These framework "rules" and configuration items are independent of the specific persistence store used to save and retrieve the user identity data. In other words, the UserManager understands and works with Identity model objects, without concern for the concrete database underlying the application.

Examples of the sorts of functionality afforded by UserManager include methods such as:

  • CreateAsync(TUser user, string Password)
  • AddToRoleAsync(TKey userId, string role)
  • AddClaimAsync(Tkey userId, Claim claim)

The UserManager class is defined in terms of various interfaces which represent abstractions over database-specific implementation models. As an example, the basic UserManager is defined with a generic type argument for the IUser implementation, which must be specified. The UserManager class also requires a constructor argument which implements the IUserStore interface.

A concrete implementation of IUserStore represents the underlying persistence layer of the application. In other words, a UserStore implementation knows how to "talk" to a specific data store (such as MongoDb, SQL Server, RavenDb, Etc.).

In our code, we are using the default UserStore implementation provided by EntityFramework (which is, itself, an abstraction over our SQL CE or SQL Server database…).

The idea behind defining a UserManager base class in Identity.Core in terms of an interface IUserStore is to achieve a clean separation between the business rules governing how authentication and authorization occurs between Identity model objects, and the details of the application's specific backing store.

Within out application proper, when we use Identity we should generally be using the UserManager (or a derived version of it) the work directly with our identity model objects. We rarely have need to consume an instance of UserStore directly, except for the purpose of injecting it as a constructor argument to UserManager.

UserManager, UserStore, and Identity:

usermanager-userstore

Also notice in our code, we have added a static method, Create(). We'll discuss this momentarily as well. But first, we will update the code for our database context.

Update the DbContext to Inherit from IdentityDbContext

When we finished the last article in this series, we had updated our ApplicationDbContext code file to look like this:

The Previous DbContext:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
// Add using:
using System.Data.Entity;
using System.Security.Claims;
 
namespace MinimalOwinWebApiSelfHost.Models
{
    public class ApplicationDbContext : DbContext
    {
        public ApplicationDbContext()
            : base("MyDatabase")
        {
 
        }
 
        static ApplicationDbContext()
        {
            Database.SetInitializer(new ApplicationDbInitializer());
        }
 
        public IDbSet<Company> Companies { get; set; }
        public IDbSet<MyUser> Users { get; set; }
        public IDbSet<MyUserClaim> Claims { get; set; }
    }
 
 
    public class ApplicationDbInitializer 
        : DropCreateDatabaseAlways<ApplicationDbContext>
    {
        protected async override void Seed(ApplicationDbContext context)
        {
            context.Companies.Add(new Company { Name = "Microsoft" });
            context.Companies.Add(new Company { Name = "Apple" });
            context.Companies.Add(new Company { Name = "Google" });
            context.SaveChanges();
 
            // Set up two initial users with different role claims:
            var john = new MyUser { Email = "john@example.com" };
            var jimi = new MyUser { Email = "jimi@Example.com" };
 
            john.Claims.Add(new MyUserClaim 
            { 
                ClaimType = ClaimTypes.Name, 
                UserId = john.Id, 
                ClaimValue = john.Email 
            });
            john.Claims.Add(new MyUserClaim 
            { 
                ClaimType = ClaimTypes.Role, 
                UserId = john.Id, 
                ClaimValue = "Admin" 
            });
 
            jimi.Claims.Add(new MyUserClaim 
            { 
                ClaimType = ClaimTypes.Name, 
                UserId = jimi.Id, 
                ClaimValue = jimi.Email 
            });
            jimi.Claims.Add(new MyUserClaim 
            { 
                ClaimType = ClaimTypes.Role, 
                UserId = john.Id, 
                ClaimValue = "User" 
            });
 
            var store = new MyUserStore(context);
            await store.AddUserAsync(john, "JohnsPassword");
            await store.AddUserAsync(jimi, "JimisPassword");
        }
    }
}

 

In the same code file, we had defined both our ApplicationDbContext, and a database initializer.

Now that we have access to the Identity.Core and Identity.EntityFramework libraries, we can simplify this somewhat.

First of all, Identity.EntityFramework provides us with IdentityDbContext, which, as its name implies, is an Identity-specific implementation of the DbContext. There is a little more going on under the hood than we will cover here, but essentially, IdentityDbContext provides us with a base class from which we can inherit, and which provides a DbContext implementation which works with the base Identity.EntityFramework models we will be working with.

First, we are going to modify the code for our ApplicationDbContext above to derive from IdentityDbContext. Then, we will update the ApplicationDbInitializer to work with our new DbContext and Identity models.

Modify DbContext to Derive from IdentityDbContext:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
// Add using:
using System.Data.Entity;
using System.Security.Claims;
 
// Add THESE to use Identity and Entity Framework:
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
 
namespace MinimalOwinWebApiSelfHost.Models
{
    // Derive from IdentityDbContext:
    public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        public ApplicationDbContext()
            : base("MyDatabase") { }
 
 
        static ApplicationDbContext()
        {
            Database.SetInitializer(
                new ApplicationDbInitializer());
        }
 
 
        // Add a static Create() method:
        public static ApplicationDbContext Create()
        {
            return new ApplicationDbContext();
        }
 
 
        // We still need a DbSet for our Companies 
        // (and any other domain objects):
        public IDbSet<Company> Companies { get; set; }
    }
 
 
    public class ApplicationDbInitializer 
        : DropCreateDatabaseAlways<ApplicationDbContext>
    {
        protected async override void Seed(ApplicationDbContext context)
        {
            context.Companies.Add(new Company { Name = "Microsoft" });
            context.Companies.Add(new Company { Name = "Apple" });
            context.Companies.Add(new Company { Name = "Google" });
            context.SaveChanges();
 
            // Set up two initial users with different role claims:
            var john = new ApplicationUser 
            { 
                Email = "john@example.com", 
                UserName = "john@example.com" 
            };
            var jimi = new ApplicationUser 
            { 
                Email = "jimi@Example.com", 
                UserName = "jimi@example.com" 
            };
 
            // Introducing...the UserManager:
            var manager = new UserManager<ApplicationUser>(
                new UserStore<ApplicationUser>(context));
 
            var result1 = await manager.CreateAsync(john, "JohnsPassword");
            var result2 = await manager.CreateAsync(jimi, "JimisPassword");
 
            // Add claims for user #1:
            await manager.AddClaimAsync(john.Id, 
                new Claim(ClaimTypes.Name, "john@example.com"));
 
            await manager.AddClaimAsync(john.Id, 
                new Claim(ClaimTypes.Role, "Admin"));
 
            // Add claims for User #2:
            await manager.AddClaimAsync(jimi.Id, 
                new Claim(ClaimTypes.Name, "jimi@example.com"));
 
            await manager.AddClaimAsync(jimi.Id, 
                new Claim(ClaimTypes.Role, "User"));
        }
    }
}

 

In the above code, notice that we have now implemented our ApplicationDbContext by deriving from IdentityDbContext<ApplicationUser> . In so doing, we have specified a DbContext implementation which will be ready to use, and already work with our ApplicationUser class.

We have also updated our ApplicationDbInitializer, making use of the handy interface afforded by our ApplicationUserManager to easily add our test users, and related user claims.

Pay close attention here. Remember previously, how we went ahead and create a mock password hasher, and all that nonsense about implementing a proper crypto mechanism for hashing passwords? here, Identity has taken care of all that for us. No mocking needed. Just the way we like it, we have left the details of the crypto to folks who know what they are doing. Remember, crypto is hard, even for the experts, and it is a solved problem.

Now, before we go much further, we are going to take another short detour. Notice how, like we did with ApplicationUserManager, we also defined a static Create() method on our ApplicationDbContext? We're going to take a look at why we did that now.

Context per Request and CreatePerOwinContext

From the standpoint of our data model, we want to make sure that we are always working with the same instance of our database context, and hence, with the same set of objects. For example, if two separate instances of ApplicationDbContext (or, similarly, UserStore or UserManager) are created while processing the same HTTP request, it is possible we could introduce changes to two instances of the same  user data.

We want to make sure that when we retreive a user object, it will always refer to the same instance of that user's data within the context of a single HTTP request.

The Microsoft.AspNet.Identity.Owin library provides an extension method by which we can ensure a single instance of an object is created per OwinContext. The CreatePerOwinContext() method allows us to pass in a generic type argument, and a function reference which returns an instance of the desired object. We set this up during the Owin Configuration() method. Then, when the OwinContext object is created for each incoming HTTP request, a discreet instance of the desired object will be created per OWIN context.

For a deeper look at this concept, see Per request lifetime management for UserManager class in ASP.NET Identity

In our application, we want to make sure that during request processing, we are only ever working against the same instance of ApplicationDbContext, as well as ApplicationUserManager. We achieve this by adding those state Create() methods on ApplicationDbContext and ApplicationUserManager respectively, and then passing references to them to CreatePerOwinContext() during the Owin Configuration() method.

We will want to add the following code to our ConfigureAuth() method in our Startup class:

Create ApplicationDbContext and ApplicationUserManager per Owin Context:
private void ConfigureAuth(IAppBuilder app)
{
    // Create per OWIN Context:
    app.CreatePerOwinContext<ApplicationDbContext>(ApplicationDbContext.Create);
    app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
 
    var OAuthOptions = new OAuthAuthorizationServerOptions
    {
        TokenEndpointPath = new PathString("/Token"),
        Provider = new ApplicationOAuthServerProvider(),
        AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
 
        // Only do this for demo!!
        AllowInsecureHttp = true
    };
    app.UseOAuthAuthorizationServer(OAuthOptions);
    app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());

 

Recall from our previous explorations of OWIN and Katana that when we pass function references like this, the function itself is not executed at this point in our code. Instead, a reference to the function is added to the Owin Environment Dictionary, which will then be Invoked each time a new Owin context is created in response to an incoming HTTP request.

We can see some of the logic to all this if we take a closer look at the static Create() method we defined on our ApplicationUserManager class:

The Create() Method from ApplicationUserManager:
public static ApplicationUserManager Create(
    IdentityFactoryOptions<ApplicationUserManager> options,
    IOwinContext context)
{
    return new ApplicationUserManager(
        new UserStore<ApplicationUser>(
            context.Get<ApplicationDbContext>()));
}

 

Notice how even here, we are initializing an instance of UserStore and passing in a reference to ApplicationDbContext by retrieving it from the OwinContext instance? This way we ensure that even here, we are using the single DbContext object instance created specifically for each request.

Update OAuth Server Provider for Identity

Now that we have implemented a very basic Identity model, we can modify our ApplicationOauthServerProvider. In the call to GrantResourceOwnerCredentials(), we can avail ourselves of our ApplicationUserManager and Identity models to simplify the grant process.

Add Microsoft.AspNet.Identity.Owin to the using statements at the top of the file, and then replace the existing code as follows:

Update the code for GrantResourceOwnerCredentials for Identity:
using System.Threading.Tasks;
 
// Add Usings:
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.OAuth;
using System.Security.Claims;
using MinimalOwinWebApiSelfHost.Models;
 
// Add to use Identity:
using Microsoft.AspNet.Identity.Owin;
 
namespace MinimalOwinWebApiSelfHost.OAuthServerProvider
{
    public class ApplicationOAuthServerProvider 
        : OAuthAuthorizationServerProvider
    {
        public override async Task ValidateClientAuthentication(
            OAuthValidateClientAuthenticationContext context)
        {
            // This call is required...
            // but we're not using client authentication, so validate and move on...
            await Task.FromResult(context.Validated());
        }
 
 
        public override async Task GrantResourceOwnerCredentials(
            OAuthGrantResourceOwnerCredentialsContext context)
        {
            // ** Use extension method to get a reference 
            // to the user manager from the Owin Context:
            var manager = context.OwinContext.GetUserManager<ApplicationUserManager>();
 
            // UserManager allows us to retrieve use with name/password combo:
            var user = await manager.FindAsync(context.UserName, context.Password);
            if (user == null)
            {
                context.SetError(
                    "invalid_grant", "The user name or password is incorrect.");
                context.Rejected();
                return;
            }
 
            // Add claims associated with this user to the ClaimsIdentity object:
            var identity = new ClaimsIdentity(context.Options.AuthenticationType);
            foreach (var userClaim in user.Claims)
            {
                identity.AddClaim(new Claim(userClaim.ClaimType, userClaim.ClaimValue));
            }
 
            context.Validated(identity);
        }
    }
}

 

Once again, see in the above how we made sure to grab a reference to the ApplicationUserManager instance from the context object? The context object helpfully provides a GetUserManager() extension method.

Also note how the ApplicationUserManager makes it very convenient to retrieve a user object with a user name and password. If the password fails to match, null will be returned, and the invalid grant error returned.

Update the CompaniesController to Use the DbContext per Request

We don't HAVE to do this, but we can. We might update our CompaniesController to take advantage of the Context-per-Request strategy afforded by Identity here.

Make sure to add Microsoft.AspNet.Identity.Owin to the using statements at the top of the CompaniesController file.

Update CompaniesController to Use Context per Request:
public class CompaniesController : ApiController
{
    // Ditch THIS:
    //ApplicationDbContext dbContext = new ApplicationDbContext();
 
    // Replace with something like THIS:
    ApplicationDbContext dbContext
    {
        get
        {
            return Request.GetOwinContext().Get<ApplicationDbContext>();
        }
    }
 
    ... All the rest of the controller code....
 
}

 

With that, we can give our new and improved application a test run, using the same Api Client application from our previous post.

Running the Application with Identity in Place

If we spin up our Web Api, all should look well:

Running the Web Api Application - All is Well:

run-web-api-application

Next, if we run the API Client application, making sure we use our valid user credentials (they should match the credentials for the Admin user in the Seed() method), everything should work as before:

Running the API Client Application:

run-api-client-application-with-identity

Similarly, if we modify the code in our client application and pass an invalid password, we get an invalid grant error:

Invalid Password Submitted by Client Returns Invalid Grant Error:

run-api-client-application-with-identity-invalid-grant

And, if we change the client credentials to those of the user in the plain old User role (which does NOT have authorization to access our CompaniesController), we receive a 401/Unauthorized error:

API Client with Insufficient Authorization:

run-api-client-application-with-identity-unauthorized

Summing it Up

In the course of the last four articles, we have hopefully developed a better idea of how the pieces fit together in an OWIN-based Web Api application. The lines between the various frameworks become blurry as an application grows, and my objective was to break things down in a manner that would bring some clarity to what happens where, and why.

The structure of our example application is crude, and if you were to take this a few steps further, you would definitely want to change some things, do some refactoring, and implement a great deal more exception and error handling.

Similarly, our console-based API Client application is sufficient only to the task of exercising our Web Api for demonstration purposes.

From here, we could go a long ways further in developing a claims-based authorization model. As it stands, our little sample application does use claims, but relies on the in-build ability of [Authorize] attribute to perform a role-based authorization check. We will explore claims more extensively in an upcoming post.

As always, feedback is most welcome, especially if you noticed me doing something stupid, or find outright errors in the code. Pull Requests are welcome against the sample repo, so long as they address improvements or bug fixes. For obvious reasons, I want to keep the code samples in sync with the articles.

Additional Resources and Items of Interest

 

Posted on February 15 2015 06:19 PM by jatten     

Comments (7)

ASP.NET Web Api: Understanding OWIN/Katana Authentication/Authorization Part II: Models and Persistence

Posted on January 25 2015 09:23 AM by jatten in ASP.Net, ASP.NET MVC, C#   ||   Comments (6)

authorized-personnel-only-320In the previous post in this series we learned how the most basic authentication and authorization elements fit together in an OWIN-based Web Api application. We have seen how to authenticate a user using an Authentication Server embedded within our application, and how to add an elementary claim to use with the [Authorize] attribute.

To this point, we have been avoiding using the ready-built Identity framework, and instead we have been focusing on understanding how these pieces interrelate. We will continue this approach (for now) here, by adding some concrete authorization models to our application, and a persistence layer to store important user data.

Image by clement127  |  Some Rights Reserved

Once again, we will be doing most of this "from scratch," in a pretty minimal fashion. I want to explore the relationships between project components without too many distractions. So we're not attempting to design the optimal auth system here or demonstrate the latest best practices. But hopefully we will come away with a better understanding of how a fully developed authentication/authorization system such as Identity works in the context of our application. Understanding THAT gives empowers us to utilize tools like Identity more effectively.

From the Ground Up

In this series of posts we started with concepts, and are building slowly build from there.

  • Part I (last post) - We will examine the basic OAuth Resource Owner Flow model for authentication, and assemble to most basic components we need to implement authentication using this model. We will not be concerning ourselves with the cryptographic requirements of properly hashing passwords, or persisting user information to a database. We will also not be using Identity, instead implementing security using the basic components available in the Microsoft.Owin libraries.
  • Part II (this post) - We will mock up some basic classes needed to model our user data, and a persistence model to see how storage of user data and other elements works at a fundamental level.
  • Part III - We will replace our mock objects with Identity 2.0 components to provide the crypto and security features (because rolling your own crypto is not a good idea).

Source Code for Examples

We are building up a project over a series of posts here. In order that the source for each post make sense, I am setting up branches that illustrate the concepts for each post:

On Github, the branches of the Web Api repo so far look like this:

The code for the API client application is in a different repo, and the branches look like this:

  • Branch: Master - Always the most current, includes all changes
  • Branch: owin-auth - Added async methods, and token-based authentication calls to the Web Api application. This is where we left the code in the last post.

Adding Auth Models to the Minimal Web Api

We'll be starting from where we left off in the last post. Recall that We had set up a basic embedded authorization server in our application which would process HTTP POST requests made by a client to the token endpoint, validate the user credentials/password received, and return an access token. From there, the client could submit the access token with subsequent requests to authenticate, and access whichever resources are available for the given identity and/or role.

If we review our existing code for the ApplicationOAuthServerProvider, we see in the GrantOwnerResourceCredentials() method that we are performing a mock credentials check. In order to keep things simple, we just checked to see if the password submitted matched the string literal "password" and moved on:

The Existing GrantOwnerResourceCredentials Method:
public override async Task GrantResourceOwnerCredentials(
    OAuthGrantResourceOwnerCredentialsContext context)
{
    // DEMO ONLY: Pretend we are doing some sort of REAL checking here:
    if (context.Password != "password")
    {
        context.SetError(
            "invalid_grant", "The user name or password is incorrect.");
        context.Rejected();
        return;
    }
    // Create or retrieve a ClaimsIdentity to represent the 
    // Authenticated user:
    ClaimsIdentity identity = 
        new ClaimsIdentity(context.Options.AuthenticationType);
    identity.AddClaim(new Claim("user_name", context.UserName));
    identity.AddClaim(new Claim(ClaimTypes.Role, "Admin"));
  
    // Identity info will ultimatly be encoded into an Access Token
    // as a result of this call:
    context.Validated(identity);
}

 

In reality, we would most likely check to see if there was a user in our backing store which matched whatever credentials were submitted, and then also check to see if the password submitted was valid. But not by checking against a plain text representation from our backing store!

In order to flesh out this method, we need to model our authorization objects, and we need to persist some user data in our database.

First, let's add some basic models. Add a new code file to the Models folder in the project, and then add the following code:

The AuthModels.cs Code File:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
// Add usings:
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;
using System.Security.Claims;
 
namespace MinimalOwinWebApiSelfHost.Models
{
    public class MyUser
    {
        public MyUser()
        {
            Id = Guid.NewGuid().ToString();
            Claims = new List<MyUserClaim>();
        }
 
        [Key]
        public string Id { get; set; }
        public string Email { get; set; }
        public string PasswordHash { get; set; }
        public ICollection<MyUserClaim> Claims { get; set; }
    }
 
 
    public class MyUserClaim
    {
        public MyUserClaim()
        {
            Id = Guid.NewGuid().ToString();
        }
        [Key]
        public string Id { get; set; }
        public string UserId { get; set; }
        public string ClaimType { get; set; }
        public string ClaimValue { get; set; }
    }
 
 
    public class MyPasswordHasher
    {
        public string CreateHash(string password)
        {
            // FOR DEMO ONLY! Use a standard method or 
            // crypto library to do this for real:
            char[] chars = password.ToArray();
            char[] hash = chars.Reverse().ToArray();
            return new string(hash);
        }
    }
}

 

Above, we see a few basic models. We expect to have a user representation, and we do, in the form of the MyUser class. While you may have been expecting to see a MyRole class, we have instead opted to carry on with the claims implementation we were using in our original project. Therefore, we have added a MyUserClaim class instead. We'll discuss this further shortly.

Finally, we have that odd-looking MyPasswordHasher class. As you may have guessed from the comment in the code, we are really only going to mock a proper hashing mechanism here. As before, we're going to keep things simple for our example. In reality, one would apply a proven crypto library to this task, and proven, tried and true methods for properly hashing a password. Or, of course, use a library for such things, like Identity.

Adding The Models to the ApplicationDbContext

Now that we have our auth-related entity models, we can add them to the existing ApplicationDbContext so that they can be modeled in the database, and we can access the data they represent from the context.

Recall that we set this particular example application up to use a local, file-based database (SQL CE) however, everything we are doing here would work just fine with SQL Server as well.

Add the Auth-Related Models to the ApplicationDbContext:
public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext()
        : base("MyDatabase")
    {
    }
 
 
    static ApplicationDbContext()
    {
        Database.SetInitializer(new ApplicationDbInitializer());
    }
 
 
    public IDbSet<Company> Companies { get; set; }
    public IDbSet<MyUser> Users { get; set; }
    public IDbSet<MyUserClaim> Claims { get; set; }
}

 

Tying the Models Together - The User Store

For our simple model set, and to keep concept straightforward, we are going to implement a simple MyUserStore class, and add sufficient functionality to get our application working and no more.

Add the following class (I added this to the AuthModels.cs file, but you can add it in its own if you want):

The UserStore Class:
public class MyUserStore
{
    ApplicationDbContext _db;
    public MyUserStore(ApplicationDbContext context)
    {
        _db = context;
    }
 
 
    public async Task AddUserAsync(MyUser user, string password)
    {
        if (await UserExists(user))
        {
            throw new Exception(
                "A user with that Email address already exists");
        }
        var hasher = new MyPasswordHasher();
        user.PasswordHash = hasher.CreateHash(password).ToString();
        _db.Users.Add(user);
        await _db.SaveChangesAsync();
    }
 
 
    public async Task<MyUser> FindByEmailAsync(string email)
    {
        var user = _db.Users
            .Include(c => c.Claims)
            .FirstOrDefaultAsync(u => u.Email == email);
        return await _db.Users
            .FirstOrDefaultAsync(u => u.Email == email);
    }
 
 
    public async Task<MyUser> FindByIdAsync(string userId)
    {
        return await _db.Users
            .FirstOrDefaultAsync(u => u.Id == userId);
    }
 
 
    public async Task<bool> UserExists(MyUser user)
    {
        return await _db.Users
            .AnyAsync(u => u.Id == user.Id || u.Email == user.Email);
    }
 
 
    public async Task AddClaimAsync(string UserId, MyUserClaim claim)
    {
        var user = await FindByIdAsync(UserId);
        if(user == null)
        {
            throw new Exception("User does not exist");
        }
        user.Claims.Add(claim);
        await _db.SaveChangesAsync();
    }
 
 
    public bool PasswordIsValid(MyUser user, string password)
    {
        var hasher = new MyPasswordHasher();
        var hash = hasher.CreateHash(password);
        return hash.Equals(user.PasswordHash);
    }
}

 

In the code above, we have assembled a few basic methods to deal with persisting and retrieving User information. Note in the AddUserAsync() method, we perform some minimal validation (make sure a user with the same email address does not already exist). Also, see that we use our super-secret, super-secure MyPasswordHasher to hash, salt, re-hash, etc. our user password, and then we persist the hashed value (NEVER the clear-text password). In other words, at no point are we saving the user-submitted clear-text password to disk, anywhere.

Similarly, we provide a simple PasswordIsValid() method which again uses the MyPasswordHasher class to compare the hash of the password submitted with that of a user record (which for now, would be submitted as an argument after being previously retrieved elsewhere in our code).

The MyUserStore class provides simplistic examples of how one might implement some of this. There is minimal validation and exception handling here. This class works well for our example, and to demonstrate the concepts we are dealing with, but is not likely how you would do this in a production application.

Initialize the Database with User Data

Now all we really need to do is update our ApplicationDbInitializer to seed the database with some initial user data. Recall, we had already set this up (in the same code file as the ApplicationDbContext) to seed our Company table with some starting data. Update the code as follows. You will also need to add System.Security.Claims to the using statements at the top of your code file:

Update ApplicationDbInitializer to Seed Application with Initial User Data:
public class ApplicationDbInitializer 
    : DropCreateDatabaseAlways<ApplicationDbContext>
{
    protected async override void Seed(ApplicationDbContext context)
    {
        context.Companies.Add(new Company { Name = "Microsoft" });
        context.Companies.Add(new Company { Name = "Apple" });
        context.Companies.Add(new Company { Name = "Google" });
        context.SaveChanges();
 
        // Set up two initial users with different role claims:
        var john = new MyUser { Email = "john@example.com" };
        var jimi = new MyUser { Email = "jimi@Example.com" };
 
        john.Claims.Add(new MyUserClaim 
        { 
                ClaimType = ClaimTypes.Name, 
                UserId = john.Id, 
                ClaimValue = john.Email 
        });
        john.Claims.Add(new MyUserClaim 
        { 
                ClaimType = ClaimTypes.Role, 
                UserId = john.Id, 
                ClaimValue = "Admin" 
        });
 
        jimi.Claims.Add(new MyUserClaim 
        { 
            ClaimType = ClaimTypes.Name, 
            serId = jimi.Id, 
            ClaimValue = jimi.Email 
        });
        jimi.Claims.Add(new MyUserClaim 
        { 
            ClaimType = ClaimTypes.Role, 
            UserId = john.Id, 
            ClaimValue = "User" 
        });
 
        var store = new MyUserStore(context);
        await store.AddUserAsync(john, "JohnsPassword");
        await store.AddUserAsync(jimi, "JimisPassword");
    }
}

 

As we see above, we have taken advantage of the methods exposed on our new MyUserStore class to add two users, along with appropriate claims, to the database.

Also recall we are deriving our initializer from DropDatabaseCreateAlways so that the database will be re-created and re-seeded each time we run the application.

Find the User and Authenticate the Token Request

All that's left to do now is update our GrantResourceOwnerCredentials() method to avail itself of our new user entities and data to perform its function.

Validate and Authenticate a User in GrantResourceOwnerCredentials() Method:
public override async Task GrantResourceOwnerCredentials(
    OAuthGrantResourceOwnerCredentialsContext context)
{
    // Retrieve user from database:
    var store = new MyUserStore(new ApplicationDbContext());
    var user = await store.FindByEmailAsync(context.UserName);
 
    // Validate user/password:
    if(user == null || !store.PasswordIsValid(user, context.Password))
    {
        context.SetError(
            "invalid_grant", "The user name or password is incorrect.");
        context.Rejected();
        return;
    }
 
    var identity = new ClaimsIdentity(context.Options.AuthenticationType);
    foreach(var userClaim in user.Claims)
    {
        identity.AddClaim(new Claim(userClaim.ClaimType, userClaim.ClaimValue));
    }
     
    context.Validated(identity);
}

 

Here, we retrieve a user record from our store (if there is a record for the user credentials in the request), and then we create a new ClaimsIdentity for that user, much the same as before. This time, however, we also have a record of the various claims for this user, and we add those as well.

In this case, we really only have the user's name, and the role(s) our application recognizes for the user, but we could implement a more complex claims model if we needed. For now, we will stick with user name and roles, because the default authorization scheme, using the [Authorize] attribute, is pre-configured to work with user names and roles. We will look at customizing this in a later post.

The Api Client Application

We can leave our Api Client application pretty much as-is at the moment. If you don't have the client application set up, you can pull down the source for the project from the Github repo. Make sure to checkout the branch owin-auth (not master!).

Recall that we has set up our application to request a token from our Api, and then make some Api calls to the CompaniesController:

Abbreviated Client Code Showing the Token Request:
static async Task Run()
{
    // Create an http client provider:
    string hostUriString = "http://localhost:8080";
    var provider = new apiClientProvider(hostUriString);
    string _accessToken;
    Dictionary<string, string> _tokenDictionary;
    try
    {
        // Pass in the credentials and retrieve a token dictionary:
        _tokenDictionary = await provider.GetTokenDictionary(
            "john@example.com", "JohnsPassword");
        _accessToken = _tokenDictionary["access_token"];
 
        // Write the contents of the dictionary:
        foreach (var kvp in _tokenDictionary)
        {
            Console.WriteLine("{0}: {1}", kvp.Key, kvp.Value);
            Console.WriteLine("");
        }
 
        // Create a company client instance:
        var baseUri = new Uri(hostUriString);
        var companyClient = new CompanyClient(baseUri, _accessToken);
 
        // ... a bunch of code calling to API and writing to console...
    }
    catch (AggregateException ex)
    {
        // If it's an aggregate exception, an async error occurred:
        Console.WriteLine(ex.InnerExceptions[0].Message);
        Console.WriteLine("Press the Enter key to Exit...");
        Console.ReadLine();
        return;
    }
    catch (Exception ex)
    {
        // Something else happened:
        Console.WriteLine(ex.Message);
        Console.WriteLine("Press the Enter key to Exit...");
        Console.ReadLine();
        return;
    }
}

 

The only thing we have changed in the above code is the password we are passing in with the token request - we have changed it to match the password for the user record we created in our Seed() method.

Running the Application with an Authenticated User

If we run our Web Api application, and then run the client, everything should work swimmingly. The Web Api application spins up the same as it always has, and the client output should look familiar:

Console Output from Client Application:

client-with-authneticated-user

Everything looks the same as it did when we wrapped up the previous post, because we haven't changed anything the affects how the client application does its job. We've only changed the internals of our Web Api so that the embedded authorization server now knows how to retrieve user data from our database in order to authenticate a user, and perform a basic authorization check against the roles available to that user.

Let's see what happens when things go wrong.

Improper Authentication - Invalid Credentials

First, let's see what happens if we try to request a token with the wrong password. In the client application, change the password we are using in our token request to something other than "JohnsPassword":

Using Incorrect Password for Client Token Request:
// Pass in the credentials and retrieve a token dictionary:
_tokenDictionary = await provider.GetTokenDictionary(
    "john@example.com", "SomePassword");
_accessToken = _tokenDictionary["access_token"];

 

If we run the client again, we see all is not well:

Running the Client with Invalid Credentials:

client-with-invalid-password

In this case, were get back an "Invalid Grant" because the client could not properly authenticate with the credentials provided.

On the other hand, things look a little different is we request a token for a user which can be authenticated, but who is not authorized access to the resource requested.

Insufficient Authorization

Recall that in our Web Api application, we protected the CompaniesController resource using the [Authorize] attribute, and we restricted access to users in the role "Admin":

The CompaniesController is Protected Using [Authorize]:
[Authorize(Roles="Admin")]
public class CompaniesController : ApiController
{
    // ... blah blah Controller Methods etc...
    
}

 

Also recall that we seeded two users in our database. The user "jimi" does not have a claim for the "Admin" role, but instead claims the "User" role. Let's change the code in our client application to request an access token for "jimi" instead, and then see what happens.

Change Client Token Request for Alternate User:
// Pass in the credentials and retrieve a token dictionary:
_tokenDictionary = await provider.GetTokenDictionary(
    "jimi@example.com", "JimisPassword");
_accessToken = _tokenDictionary["access_token"];

 

Running the client application now produces a slightly different result:

Running the Client with Valid Credentials but Insufficient Authorization:

client-with-insufficient-authorization

Unlike previously, we did not receive an invalid grant error, because the user credentials were properly authenticated. However, the user does not possess the proper Role claim in our system to access the protected resource.

In reality, the default implementation of [Authorize] limits our ability to leverage claims to the fullest extent. [Authorize] recognizes claims for user names, and roles. What if we want more granular control over our application permissions?

We're not going to go into that in this post. However, keep this in mind, as leveraging Claims, and customizing authentication using claims instead of simple roles can become important for more complex application which require fine-grained control of permissions.

What Next?

In this post we created a "quick and dirty" implementation which performs some very basic authentication and authorization for our application.

In the real world, we would definitely tend to some critical details, such as proper crypto for hashing passwords. We would also probably want to beef up our design by applying some common patterns of abstraction. Notice, we have coded everything here directly to the implementation class. Also, we have rather tightly coupled our logical processing to our persistence model.

Lastly, we have put in place only the most rudimentary validation and exception handling.

We could go down a long road exploring how to better separate our persistence mechanism from our authentication logic, and more effectively handling exceptions and errors. However, those details are often application-specific, and/or require a long, long post.

Instead, we could now take everything we have learned, and pull in some ready-made components which already provide all of this, and more.

If the work we have done so far has been beginning to look a little familiar, that is no accident.

In the next post, we will implement our own authentication and authorization using the Identity 2.1 Framework.

NEXT:  Understanding OWIN/Katana Authentication/Authorization Part III: Adding Identity

Additional Resources and Items of Interest

Articles by others I have found invaluable:

 

Posted on January 25 2015 09:23 AM by jatten     

Comments (6)

About the author

My name is John Atten, and my "handle" on many of my online accounts is xivSolutions. I am Fascinated by all things technology and software development. I work mostly with C#, JavaScript/Node, and databases of many flavors. Actively learning always. I dig web development. I am always looking for new information, and value your feedback (especially where I got something wrong!). You can email me at:

johnatten at typecastexception dot com

Web Hosting by