ASP.NET Web Api and Identity 2.0 - Customizing Identity Models and Implementing Role-Based Authorization

Posted on October 26 2014 03:23 PM by jatten in ASP.Net, C#, ASP.NET MVC, CodeProject   ||   Comments (9)

hermself 240In a previous post, we took a high-level look at using Identity 2.0 in the context of a Web Api application. We essentially poked and prodded the default Visual Studio Web Api project template, learned where things live, and got a basic sense for how it all is supposed to work.

However, the VS project template is very basic, using Bearer Tokens as the primary authentication mechanism, and does not offer any out-of-the-box support for advanced authorization scenarios. In a nutshell, the VS Project template affords us basic token-based authentication, and that's about it.

Additionally, the User model is simplistic, and there are no Role models defined. This may be intentional, since in some cases you may be using a Web Api project as a simple authentication service. In other scenarios, though, you may want to customize the User model and/or add Role-Based Authentication to the mix.

Image by madamepsychosis  | Some Rights Reserved

We have previously looked at customizing User and Role models in the context of an ASP.NET MVC application, and how we need to modify the stock MVC project to accommodate these customizations. In this post, we will do the same for a Web Api project.

You can find the source code for the example Web Api project on Github:

Consider Your Use Case Before Deciding on Your Auth Strategy

There are a number of options for Authentication and Authorization strategies in a Web Api project. Use of Bearer tokens and Role-Based Authentication is relatively simple to implement, but is not the most advanced architecture for an authorization solution. Before deciding upon traditional Role-Based Authorization, you may want to examine the scope of your authentication and authorization needs, and determine if something simpler, or something more advanced, may be warranted. 

ASP.NET Web Api can take full advantage of Claims-Based Authorization, which, for more complex systems, may be a better choice. Similarly, as mentioned previously, if the primary purpose of your Web Api is to act as an Authentication Service, you may want to go with a more robust token system (for example, shared private keys as opposed to the bearer tokens used by default), and do away with authorization at this level.

Role-Based Authorization is a good fit in a project where there exists a modest need for different levels of authorization/access, and possibly the Web Api is a part of, or associated with, a larger MVC or other ASP.NET site where Roles are used to govern authorization. Consider a standard MVC project, in which a few roles are sufficient to manage authorization, and which serves web pages as well as offers API access.

Applying What We've Learned Previously

Fortunately, much of what we are about to do, we have seen previously, and we can even borrow bits and pieces of code we've already written. If you are just getting familiar with Identity 2.0, feel free to review previous posts in which we performed some similar customization of Users and Roles in the context of an ASP.NET MVC project:

Now that we have some idea what we are dealing with, let's see how we can apply it in the Web Api context.

Getting Started - Create a New ASP.NET Web Api Project

First, in Visual Studio, create a new ASP.NET Web Api project. Once the project is created, update the Nuget packages in the solution, either using Manage Packages for Solution in the context menu for Solution Explorer, or by using Update-Package in the Package Manager Console.

This will update all the nuget packages, and specifically update Web Api to version 2.2.

Adding a Role Model, and Customizing ApplicationUser

To get started, let's take another look at the Models => IdentityModes.cs file. Currently, there is not a lot there:

The Default IdentityModels.cs File in Web Api:
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity.Owin;
 
namespace AspNetIdentity2WebApiCustomize.Models
{
    public class ApplicationUser : IdentityUser
    {
        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(
        		UserManager<ApplicationUser> manager, string authenticationType)
        {
            // Note the authenticationType must match the one defined in 
            // CookieAuthenticationOptions.AuthenticationType
            var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
            // 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();
        }
    }
}

 

As we did in our ASP.NET MVC examples, we begin by modifying and adding to the existing models defined in Models => IdentityModels.cs. In fact, since we did a lot of the work previously, we will start by stealing the IdentityModels.cs code from the ASP.NET Extensible Template Project. Careful here. We can save ourselves some pain by pasting the classes into the existing namespace defined in the current code file, and leaving the using statements as they are for the moment:

Updated IdentityModels.cs Code:
// You will not likely need to customize there, but it is necessary/easier to create our own 
// project-specific implementations, so here they are:
public class ApplicationUserLogin : IdentityUserLogin<string> { }
public class ApplicationUserClaim : IdentityUserClaim<string> { }
public class ApplicationUserRole : IdentityUserRole<string> { }
 
// Must be expressed in terms of our custom Role and other types:
public class ApplicationUser 
    : IdentityUser<string, ApplicationUserLogin, 
    ApplicationUserRole, ApplicationUserClaim>
{
    public ApplicationUser()
    {
        this.Id = Guid.NewGuid().ToString();
 
        // Add any custom User properties/code here
    }
 
 
    public async Task<ClaimsIdentity>
        GenerateUserIdentityAsync(ApplicationUserManager manager)
    {
        var userIdentity = await manager
            .CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        return userIdentity;
    }
}
 
 
// Must be expressed in terms of our custom UserRole:
public class ApplicationRole : IdentityRole<string, ApplicationUserRole>
{
    public ApplicationRole() 
    {
        this.Id = Guid.NewGuid().ToString();
    }
 
    public ApplicationRole(string name)
        : this()
    {
        this.Name = name;
    }
 
    // Add any custom Role properties/code here
}
 
 
// Must be expressed in terms of our custom types:
public class ApplicationDbContext 
    : IdentityDbContext<ApplicationUser, ApplicationRole, 
    string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
    public ApplicationDbContext()
        : base("DefaultConnection")
    {
    }
 
    static ApplicationDbContext()
    {
        Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
    }
 
    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }
    // Add additional items here as needed
}
 
// Most likely won't need to customize these either, but they were needed because we implemented
// custom versions of all the other types:
public class ApplicationUserStore 
    :UserStore<ApplicationUser, ApplicationRole, string,
        ApplicationUserLogin, ApplicationUserRole, 
        ApplicationUserClaim>, IUserStore<ApplicationUser, string>, 
    IDisposable
{
    public ApplicationUserStore()
        : this(new IdentityDbContext())
    {
        base.DisposeContext = true;
    }
 
    public ApplicationUserStore(DbContext context)
        : base(context)
    {
    }
}
 
 
public class ApplicationRoleStore
: RoleStore<ApplicationRole, string, ApplicationUserRole>,
IQueryableRoleStore<ApplicationRole, string>,
IRoleStore<ApplicationRole, string>, IDisposable
{
    public ApplicationRoleStore()
        : base(new IdentityDbContext())
    {
        base.DisposeContext = true;
    }
 
    public ApplicationRoleStore(DbContext context)
        : base(context)
    {
    }
}

 

Now, we need to add a few additional using statements at the top of the code file to bring in some references we need with the new code. Add the following to the using statements at the top of the file:

Additional Using Statements Added to IdentityModels.cs:
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;
using System;

 

There are two immediate problems with the code we just pasted in there. The first is probably obvious, because the VS compiler is probably telling you that there is no DBInitializer class defined. Also, if you Build the project, a few other problems will surface in the VS error list. We'll take care of that in a moment.

The other is not so obvious. The code we pasted in here is from an MVC project. For the most part this is fine. However, our ApplicationUser class defines a method GenerateUserIdentityAsync. The code we stole from our MVC project has this method, but defines it in terms of a single parameter of type ApplicationUserManager. Recall the code we pasted over, which defined ApplicationUser with two constructor parameters. The missing parameter in our newly copied method is of type string, and represents the authenticationType.

This is important, because GenerateUserIdentityAsync is called when we need to retrieve a user's ClaimsIdentity, which represents the various claims the specific user has within our system.

Confused yet? We don't need to worry about the details of ClaimsIdentity just yet. What we DO need to do is update the GenerateUserIdentityAsync method defined on ApplicationUser to accept a string parameter representing the authenticationType.

Update ApplicationUser for Web Api

To make our ApplicationUser class ready for use in a Web Api context, we can replace the code for the GenerateUserIdentityAsync  method with the following:

Update GenerateUserIdentityAsync with Authentication Type Parameter:
// ** Add authenticationtype as method parameter:
public async Task<ClaimsIdentity>
    GenerateUserIdentityAsync(ApplicationUserManager manager, string authenticationType)
{
    // Note the authenticationType must match the one defined 
    // in CookieAuthenticationOptions.AuthenticationType
    var userIdentity = 
        await manager.CreateIdentityAsync(this, authenticationType);
    // Add custom user claims here
    return userIdentity;
}

 

                            Adding a DBInitializer and Other Identity Config Items

                            We mentioned earlier, and the compiler is helpfully pointing out to you, that the code we stole from the Identity Extensible Template project is attempting to use a DBInitializer class that doesn't exist (yet) in our Web Api project. Also, you probably notice (if you have built the project since adding the additional Identity Models), that there appear to be some problems with our new ApplicationUser class.

                            We will resolve most of these issues by once again stealing select bits of code from the Identity Extensible Template project.

                            If we look at the App_Start => IdentityConfig.cs file in our Web Api project, we see that, as with the original IdentityModels.cs file, there is not much there:

                            The Default Identity.config File from a Web Api Project:
                            using System.Threading.Tasks;
                            
                            using Microsoft.AspNet.Identity;
                            
                            using Microsoft.AspNet.Identity.EntityFramework;
                            
                            using Microsoft.AspNet.Identity.Owin;
                            
                            using Microsoft.Owin;
                            
                            using AspNetIdentity2WebApiCustomize.Models;
                            
                             
                            
                            namespace AspNetIdentity2WebApiCustomize
                            
                            {
                            
                                // Configure the application user manager used in this application. UserManager 
                            
                                // is defined in ASP.NET Identity and is used by the application.
                            
                                public class ApplicationUserManager : UserManager<ApplicationUser>
                            
                                {
                            
                                    public ApplicationUserManager(IUserStore<ApplicationUser> store)
                            
                                        : base(store)
                            
                                    {
                            
                                    }
                            
                             
                            
                                    public static ApplicationUserManager Create(
                            
                                            IdentityFactoryOptions<ApplicationUserManager> options, 
                            
                                            IOwinContext context)
                            
                                    {
                            
                                        var manager = 
                            
                                                new ApplicationUserManager(
                            
                                                        new UserStore<ApplicationUser>(
                            
                                                                context.Get<ApplicationDbContext>()));
                            
                             
                            
                                        // Configure validation logic for usernames
                            
                                        manager.UserValidator = new UserValidator<ApplicationUser>(manager)
                            
                                        {
                            
                                            AllowOnlyAlphanumericUserNames = false,
                            
                                            RequireUniqueEmail = true
                            
                                        };
                            
                                        // Configure validation logic for passwords
                            
                                        manager.PasswordValidator = new PasswordValidator
                            
                                        {
                            
                                            RequiredLength = 6,
                            
                                            RequireNonLetterOrDigit = true,
                            
                                            RequireDigit = true,
                            
                                            RequireLowercase = true,
                            
                                            RequireUppercase = true,
                            
                                        };
                            
                                        var dataProtectionProvider = options.DataProtectionProvider;
                            
                                        if (dataProtectionProvider != null)
                            
                                        {
                            
                                            manager.UserTokenProvider = 
                            
                                                    new DataProtectorTokenProvider<ApplicationUser>(
                            
                                                            dataProtectionProvider.Create("ASP.NET Identity"));
                            
                                        }
                            
                                        return manager;
                            
                                    }
                            
                                }
                            
                            }

                             

                            In order to work with Roles in our Web Api project, we will need an ApplicationRoleManager, and as mentioned previously, we will be adding the ApplicationDbInitializer from the Extensible Template project.

                            First, we need the following using statements at the top of the IdentityConfig.cs file:

                            Using Statements for the IdentityConfig.cs File:
                            using AspNetIdentity2WebApiCustomize.Models;
                            
                            using Microsoft.AspNet.Identity;
                            
                            using Microsoft.AspNet.Identity.EntityFramework;
                            
                            using Microsoft.AspNet.Identity.Owin;
                            
                            using Microsoft.Owin;
                            
                            using System.Data.Entity;
                            
                            using System.Web;

                             

                            Now, add the ApplicationRoleManager and ApplicationDbInitializer classes from the Extensible Template project to our IdentityConfig.cs file:

                            Add ApplicationRoleManager and ApplicationDbInitializer to IdentityConfig.cs:
                            using AspNetIdentity2WebApiCustomize.Models;
                            
                            using Microsoft.AspNet.Identity;
                            
                            using Microsoft.AspNet.Identity.EntityFramework;
                            
                            using Microsoft.AspNet.Identity.Owin;
                            
                            using Microsoft.Owin;
                            
                            using System.Data.Entity;
                            
                            using System.Web;
                            
                             
                            
                             
                            
                            namespace AspNetIdentity2WebApiCustomize
                            
                            {
                            
                                public class ApplicationUserManager : UserManager<ApplicationUser>
                            
                                {
                            
                                    public ApplicationUserManager(IUserStore<ApplicationUser> store)
                            
                                        : base(store)
                            
                                    {
                            
                                    }
                            
                             
                            
                                    public static ApplicationUserManager Create(
                            
                                        IdentityFactoryOptions<ApplicationUserManager> options, 
                            
                                        IOwinContext context)
                            
                                    {
                            
                                        var manager = new ApplicationUserManager(
                            
                                            new UserStore<ApplicationUser>(
                            
                                                context.Get<ApplicationDbContext>()));
                            
                             
                            
                                        // Configure validation logic for usernames
                            
                                        manager.UserValidator = new UserValidator<ApplicationUser>(manager)
                            
                                        {
                            
                                            AllowOnlyAlphanumericUserNames = false,
                            
                                            RequireUniqueEmail = true
                            
                                        };
                            
                                        // Configure validation logic for passwords
                            
                                        manager.PasswordValidator = new PasswordValidator
                            
                                        {
                            
                                            RequiredLength = 6,
                            
                                            RequireNonLetterOrDigit = true,
                            
                                            RequireDigit = true,
                            
                                            RequireLowercase = true,
                            
                                            RequireUppercase = true,
                            
                                        };
                            
                                        var dataProtectionProvider = options.DataProtectionProvider;
                            
                                        if (dataProtectionProvider != null)
                            
                                        {
                            
                                            manager.UserTokenProvider = 
                            
                                                new DataProtectorTokenProvider<ApplicationUser>(
                            
                                                    dataProtectionProvider.Create("ASP.NET Identity"));
                            
                                        }
                            
                                        return manager;
                            
                                    }
                            
                                }
                            
                             
                            
                             
                            
                                public class ApplicationRoleManager : RoleManager<ApplicationRole>
                            
                                {
                            
                                    public ApplicationRoleManager(IRoleStore<ApplicationRole, string> roleStore)
                            
                                        : base(roleStore)
                            
                                    {
                            
                                    }
                            
                             
                            
                                    public static ApplicationRoleManager Create(
                            
                                        IdentityFactoryOptions<ApplicationRoleManager> options, 
                            
                                        IOwinContext context)
                            
                                    {
                            
                                        return new ApplicationRoleManager(
                            
                                            new ApplicationRoleStore(context.Get<ApplicationDbContext>()));
                            
                                    }
                            
                                }
                            
                             
                            
                             
                            
                                public class ApplicationDbInitializer 
                            
                                    : DropCreateDatabaseAlways<ApplicationDbContext>
                            
                                {
                            
                                    protected override void Seed(ApplicationDbContext context)
                            
                                    {
                            
                                        InitializeIdentityForEF(context);
                            
                                        base.Seed(context);
                            
                                    }
                            
                             
                            
                                    //Create User=Admin@Admin.com with password=Admin@123456 in the Admin role        
                            
                                    public static void InitializeIdentityForEF(ApplicationDbContext db)
                            
                                    {
                            
                                        var userManager = HttpContext.Current
                            
                                            .GetOwinContext().GetUserManager<ApplicationUserManager>();
                            
                             
                            
                                        var roleManager = HttpContext.Current
                            
                                            .GetOwinContext().Get<ApplicationRoleManager>();
                            
                             
                            
                                        const string name = "admin@example.com";
                            
                                        const string password = "Admin@123456";
                            
                                        const string roleName = "Admin";
                            
                             
                            
                                        //Create Role Admin if it does not exist
                            
                                        var role = roleManager.FindByName(roleName);
                            
                                        if (role == null)
                            
                                        {
                            
                                            role = new ApplicationRole(roleName);
                            
                                            var roleresult = roleManager.Create(role);
                            
                                        }
                            
                             
                            
                                        var user = userManager.FindByName(name);
                            
                                        if (user == null)
                            
                                        {
                            
                                            user = new ApplicationUser { UserName = name, Email = name };
                            
                                            var result = userManager.Create(user, password);
                            
                                            result = userManager.SetLockoutEnabled(user.Id, false);
                            
                                        }
                            
                             
                            
                                        // Add user admin to Role Admin if not already added
                            
                                        var rolesForUser = userManager.GetRoles(user.Id);
                            
                                        if (!rolesForUser.Contains(role.Name))
                            
                                        {
                            
                                            var result = userManager.AddToRole(user.Id, role.Name);
                            
                                        }
                            
                                    }
                            
                                }
                            
                            }

                             

                            Now, we need to make a few changes to our ApplicationUserManager. Since we have added our customizable models, including modified versions of UserStore and RoleStore, we need to adapt the ApplicationUserManager to play nice. We have expressed our models with different type arguments than the default implementation expected by the Web Api project. Specifically, we have employed a customized implementation of IUserStore. Rather than the concrete UserStore defined in Microsoft.AspNet.Identity.EntityFramework, we have implemented our own ApplicationUserStore, which is expressed in terms of specific type arguments.

                            We now need to tune up our ApplicationUserManager to work with our ApplicationUserStore.

                            Change the code for ApplicationUserManager in IdentityConfig.cs to the following:

                            Modified ApplicationUserManager:
                            public class ApplicationUserManager 
                            
                                : UserManager<ApplicationUser, string>
                            
                            {
                            
                                public ApplicationUserManager(IUserStore<ApplicationUser, string> store)
                            
                                    : base(store)
                            
                                {
                            
                                }
                            
                             
                            
                                public static ApplicationUserManager Create(
                            
                                    IdentityFactoryOptions<ApplicationUserManager> options, 
                            
                                    IOwinContext context)
                            
                                {
                            
                                    var manager = new ApplicationUserManager(
                            
                                        new UserStore<ApplicationUser, ApplicationRole, string, 
                            
                                            ApplicationUserLogin, ApplicationUserRole, 
                            
                                            ApplicationUserClaim>(context.Get<ApplicationDbContext>()));
                            
                             
                            
                                    // Configure validation logic for usernames
                            
                                    manager.UserValidator = new UserValidator<ApplicationUser>(manager)
                            
                                    {
                            
                                        AllowOnlyAlphanumericUserNames = false,
                            
                                        RequireUniqueEmail = true
                            
                                    };
                            
                             
                            
                                    // Configure validation logic for passwords
                            
                                    manager.PasswordValidator = new PasswordValidator
                            
                                    {
                            
                                        RequiredLength = 6,
                            
                                        RequireNonLetterOrDigit = true,
                            
                                        RequireDigit = true,
                            
                                        RequireLowercase = true,
                            
                                        RequireUppercase = true,
                            
                                    };
                            
                                    var dataProtectionProvider = options.DataProtectionProvider;
                            
                                    if (dataProtectionProvider != null)
                            
                                    {
                            
                                        manager.UserTokenProvider = 
                            
                                            new DataProtectorTokenProvider<ApplicationUser>(
                            
                                                dataProtectionProvider.Create("ASP.NET Identity"));
                            
                                    }
                            
                                    return manager;
                            
                                }
                            
                            }

                             

                            With that, the very minimal basics are in place for us to use our new, extensible model classes (including Roles, which were not directly available to us in the default Web Api implementation) in our Web Api project.

                            We do need to clean up one more issue though. The AccountController still appears to rely on Microsoft.AspNet.Identity.EntityFramework.IdentityUser, and we need it to use our new implementation ApplicationUser.

                            Modify AccountController to Use ApplicationUser

                            We can easily correct this last remaining issue. Open the AccountController class, and locate the GetManageInfo() method. We can see where a local variable user is declared, explicitly types as IdentityUser.

                            Below that, we can see in the foreach() loop, we explicitly declare an iterator variable linkedAccount as type IdentityUserLogin.

                            Existing Code in the Web Api AccountController GetManageInfo() Method:
                            [Route("ManageInfo")]
                            
                            public async Task<ManageInfoViewModel> GetManageInfo(
                            
                                string returnUrl, bool generateState = false)
                            
                            {
                            
                                IdentityUser user = 
                            
                                    await UserManager.FindByIdAsync(User.Identity.GetUserId());
                            
                                if (user == null)
                            
                                {
                            
                                    return null;
                            
                                }
                            
                             
                            
                                List<UserLoginInfoViewModel> logins = new List<UserLoginInfoViewModel>();
                            
                                foreach (IdentityUserLogin linkedAccount in user.Logins)
                            
                                {
                            
                                    logins.Add(new UserLoginInfoViewModel
                            
                                    {
                            
                                        LoginProvider = linkedAccount.LoginProvider,
                            
                                        ProviderKey = linkedAccount.ProviderKey
                            
                                    });
                            
                                }
                            
                             
                            
                                if (user.PasswordHash != null)
                            
                                {
                            
                                    logins.Add(new UserLoginInfoViewModel
                            
                                    {
                            
                                        LoginProvider = LocalLoginProvider,
                            
                                        ProviderKey = user.UserName,
                            
                                    });
                            
                                }
                            
                             
                            
                                return new ManageInfoViewModel
                            
                                {
                            
                                    LocalLoginProvider = LocalLoginProvider,
                            
                                    Email = user.UserName,
                            
                                    Logins = logins,
                            
                                    ExternalLoginProviders = GetExternalLogins(returnUrl, generateState)
                            
                                };
                            
                            }

                             

                            In both cases we have implemented our own versions of these types. Here, we can either change the declaration in each case to use the var keyword, which relieves us of the type constraint on the variable (but, some would argue, makes our code a bit ambiguous), or we can change the explicit type declaration in each case to use our own implementation.

                            For now, let's change the explicit type declaration to use our own implementations:

                            Modified Code for GetManageInfo() Method:
                            [Route("ManageInfo")]
                            
                            public async Task<ManageInfoViewModel> GetManageInfo(
                            
                                string returnUrl, bool generateState = false)
                            
                            {
                            
                                ApplicationUser user = 
                            
                                    await UserManager.FindByIdAsync(User.Identity.GetUserId());
                            
                                if (user == null)
                            
                                {
                            
                                    return null;
                            
                                }
                            
                             
                            
                                List<UserLoginInfoViewModel> logins = new List<UserLoginInfoViewModel>();
                            
                                foreach (ApplicationUserLogin linkedAccount in user.Logins)
                            
                                {
                            
                                    logins.Add(new UserLoginInfoViewModel
                            
                                    {
                            
                                        LoginProvider = linkedAccount.LoginProvider,
                            
                                        ProviderKey = linkedAccount.ProviderKey
                            
                                    });
                            
                                }
                            
                             
                            
                                if (user.PasswordHash != null)
                            
                                {
                            
                                    logins.Add(new UserLoginInfoViewModel
                            
                                    {
                            
                                        LoginProvider = LocalLoginProvider,
                            
                                        ProviderKey = user.UserName,
                            
                                    });
                            
                                }
                            
                             
                            
                                return new ManageInfoViewModel
                            
                                {
                            
                                    LocalLoginProvider = LocalLoginProvider,
                            
                                    Email = user.UserName,
                            
                                    Logins = logins,
                            
                                    ExternalLoginProviders = GetExternalLogins(returnUrl, generateState)
                            
                                };
                            
                            }

                             

                            Above, we have simply changed the declared type for the local user variable from IdentityUser to ApplicationUser, and the iterator variable linkedAccount from IdentityUserLogin to ApplicationUserLogin.

                            Add Initialization for ApplicationRoleManager in Startup.Auth

                            Recall from our high-level exploration of ASP.NET Web Api and Identity that initialization and configuration of Identity 2.0 occurs in the Startup class defined in App_Start => Startup.Auth.

                            As we have seen, the original VS Web Api template did not really provide for Role-Based anything, and consequently, provides no configuration or initialization for our recently added ApplicationRoleManager at startup. We need to add a line of initialization code to our Startup.Auth file:

                            Add Initialization for ApplicationRoleManager in Statup.Auth:
                            public void ConfigureAuth(IAppBuilder app)
                            
                            {
                            
                                app.CreatePerOwinContext(ApplicationDbContext.Create);
                            
                                app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
                            
                                app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
                            
                             
                            
                                app.UseCookieAuthentication(new CookieAuthenticationOptions());
                            
                                app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
                            
                             
                            
                                // Configure the application for OAuth based flow
                            
                                PublicClientId = "self";
                            
                                OAuthOptions = new OAuthAuthorizationServerOptions
                            
                                {
                            
                                    TokenEndpointPath = new PathString("/Token"),
                            
                                    Provider = new ApplicationOAuthProvider(PublicClientId),
                            
                                    AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
                            
                                    AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
                            
                                    AllowInsecureHttp = true
                            
                                };
                            
                             
                            
                                // Enable the application to use bearer tokens to authenticate users
                            
                                app.UseOAuthBearerTokens(OAuthOptions);
                            
                             
                            
                                // ... Code for third-part logins omitted for brevity ...
                            
                            }

                             

                            We've added a single line, which initializes an instance of ApplicationRoleManager for each incoming request.

                            About the ApplicationDbInitializer

                            With the changes we've introduced so far, we should be able to take our new and improved Web Api project for a test spin to see if the most basic functionality works.

                            Before we do, though, we need to recognize that we have fundamentally changed how the EF/Code-First database generation has been changed with the introduction of our custom ApplicationDbInitializer.

                            Recall from our explorations of customizing an MVC project with extensible models, the ApplicationDbInitializer allows us to specify some options for how and when the database behind our application is generated, and to provide some initial data to work with.

                            As we move towards Role-Based Authorization and a more restrictive security model for our Api, this becomes important.

                            The way we currently have ApplicationDbInitializer configured, it derives from DbDropCreateDatabaseAlways, which means every time we run our application, the backing store will be destroyed, and re-created from scratch. We also have it set up to create a default User, and we assign that user to the Admin role. In this manner, we start our application with a user with Admin-level access permissions.

                            The default VS Web Api project doesn't take advantage of this out of the box. If we look at the class declaration for AccountController we see that the class itself is decorated with a simple [Authorize] attribute. What this essentially does is restrict access to all of the Action methods on the class to authorized users (except those methods specifically decorated with an [AllowAnonymous] attribute).

                            In other words, for now, any user who is registered, and who successfully signs in and presents a valid Bearer Token can access any of the Action methods on AccountController.

                            We'll take a closer look at implementing Role-Based Authentication momentarily, First, we will extend our ApplicationUser and ApplicationRole classes with some custom properties.

                            Adding Custom Properties to ApplicationUser and ApplicationRole

                            As we saw when we examine customizing Users and Roles within an MVC project, we will add a few simple properties to our ApplicationUser and ApplicationRole models. Modify the code for each as follows:

                            Add Custom Properties to ApplicationUser and ApplicationRole:
                            // Must be expressed in terms of our custom Role and other types:
                            
                            public class ApplicationUser
                            
                                : IdentityUser<string, ApplicationUserLogin,
                            
                                ApplicationUserRole, ApplicationUserClaim> 
                            
                            {
                            
                                public ApplicationUser()
                            
                                {
                            
                                    this.Id = Guid.NewGuid().ToString();
                            
                                }
                            
                             
                            
                             
                            
                                public async Task<ClaimsIdentity>GenerateUserIdentityAsync(
                            
                                    ApplicationUserManager manager, string authenticationType)
                            
                                {
                            
                                    // Note the authenticationType must match the one 
                            
                                    // defined in CookieAuthenticationOptions.AuthenticationType
                            
                                    var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
                            
                             
                            
                                    // Add custom user claims here
                            
                                    return userIdentity;
                            
                                }
                            
                             
                            
                                // Add Custom Properties:
                            
                                public string Address { get; set; }
                            
                                public string City { get; set; }
                            
                                public string PostalCode { get; set; }
                            
                            }
                            
                             
                            
                             
                            
                            // Must be expressed in terms of our custom UserRole:
                            
                            public class ApplicationRole : IdentityRole<string, ApplicationUserRole> 
                            
                            {
                            
                                public ApplicationRole() 
                            
                                {
                            
                                  this.Id = Guid.NewGuid().ToString();
                            
                                }
                            
                             
                            
                                public ApplicationRole(string name) : this() 
                            
                                {
                            
                                  this.Name = name;
                            
                                }
                            
                             
                            
                                // Add Custom Property:
                            
                                public string Description { get; set; }
                            
                            }

                             

                            Here, we have added an Address and related properties to ApplicationUser, and a simple Description property to ApplicationRole.

                            Now, let's update our ApplicationDbInitializer to set some sample values for these new properties. Update the code for the InitializeIdentityForEF() method as follows:

                            Set Initial Values for Custom Properties in ApplicationDbInitializer:
                            public static void InitializeIdentityForEF(ApplicationDbContext db)
                            
                            {
                            
                                var userManager = HttpContext.Current
                            
                                    .GetOwinContext().GetUserManager<ApplicationUserManager>();
                            
                             
                            
                                var roleManager = HttpContext.Current
                            
                                    .GetOwinContext().Get<ApplicationRoleManager>();
                            
                             
                            
                                const string name = "admin@example.com";
                            
                                const string password = "Admin@123456";
                            
                             
                            
                                // Some initial values for custom properties:
                            
                                const string address = "1234 Sesame Street";
                            
                                const string city = "Portland";
                            
                                const string state = "OR";
                            
                                const string postalCode = "97209";
                            
                             
                            
                                const string roleName = "Admin";
                            
                                const string roleDescription = "All access pass";
                            
                             
                            
                                //Create Role Admin if it does not exist
                            
                                var role = roleManager.FindByName(roleName);
                            
                                if (role == null)
                            
                                {
                            
                                    role = new ApplicationRole(roleName);
                            
                             
                            
                                    // Set the new custom property:
                            
                                    role.Description = roleDescription;
                            
                                    var roleresult = roleManager.Create(role);
                            
                                }
                            
                             
                            
                                var user = userManager.FindByName(name);
                            
                                if (user == null)
                            
                                {
                            
                                    user = new ApplicationUser { UserName = name, Email = name };
                            
                             
                            
                                    // Set the new custom properties:
                            
                                    user.Address = address;
                            
                                    user.City = city;
                            
                                    user.State = state;
                            
                                    user.PostalCode = postalCode;
                            
                             
                            
                                    var result = userManager.Create(user, password);
                            
                                    result = userManager.SetLockoutEnabled(user.Id, false);
                            
                                }
                            
                             
                            
                                // Add user admin to Role Admin if not already added
                            
                                var rolesForUser = userManager.GetRoles(user.Id);
                            
                                if (!rolesForUser.Contains(role.Name))
                            
                                {
                            
                                    var result = userManager.AddToRole(user.Id, role.Name);
                            
                                }
                            
                            }

                             

                            With that, we should be ready to see if everything at least works correctly . . .

                            Create a Simple Web Api Client Application

                            To see if everything is working properly to this point, we will create a simple console application as an Api client.

                            In Visual Studio, create a new Console Application, and the use the Manage Nuget Packages for Solutions to add the Microsoft Asp.NET Web Api 2.2 Client Libraries, or use the Package Manager Console and do:

                            Add Web Api 2.2 via the Nuget Package Manager Console:
                            PM> Install-Package Microsoft.AspNet.WebApi.Client

                             

                            Now that we have the required Web Api Client Libraries in our project, open the Program.cs file.

                            Make sure the following using statements are present at the top of the file. Note we have added references to System.Net.Http and Newtonsoft.Json, ad well as System.Threading:

                            Required Using Statements for Console Api Client Application:
                            using System;
                            
                            using System.Collections.Generic;
                            
                            using System.Linq;
                            
                            using System.Text;
                            
                            using System.Threading.Tasks;
                            
                            using System.Net.Http;
                            
                            using Newtonsoft.Json;

                             

                            Next, let's add some very basic client code used to retrieve a token from the token endpoint of our Web Api. Add the following within the Program class:

                            Add Client Code to Retreive Response from Web Api Token Endpoint:
                            // You will need to substitute your own host Url here:
                            
                            static string host = "http://localhost:63074/";
                            
                             
                            
                            static void Main(string[] args)
                            
                            {
                            
                                Console.WriteLine("Attempting to Log in with default admin user");
                            
                             
                            
                                // Get hold of a Dictionary representing the JSON in the response Body:
                            
                                var responseDictionary = 
                            
                                    GetResponseAsDictionary("admin@example.com", "Admin@123456");
                            
                                foreach(var kvp in responseDictionary)
                            
                                {
                            
                                    Console.WriteLine("{0}: {1}", kvp.Key, kvp.Value);
                            
                                }
                            
                                Console.Read();
                            
                            }
                            
                             
                            
                             
                            
                            static Dictionary<string, string> GetResponseAsDictionary(
                            
                                string userName, string password)
                            
                            {
                            
                                HttpClient client = new HttpClient();
                            
                                var pairs = new List<KeyValuePair<string, string>>
                            
                                            {
                            
                                                new KeyValuePair<string, string>( "grant_type", "password" ), 
                            
                                                new KeyValuePair<string, string>( "username", userName ), 
                            
                                                new KeyValuePair<string, string> ( "Password", password )
                            
                                            };
                            
                                var content = new FormUrlEncodedContent(pairs);
                            
                             
                            
                                // Attempt to get a token from the token endpoint of the Web Api host:
                            
                                HttpResponseMessage response =
                            
                                    client.PostAsync(host + "Token", content).Result;
                            
                                var result = response.Content.ReadAsStringAsync().Result;
                            
                                // De-Serialize into a dictionary and return:
                            
                                Dictionary<string, string> tokenDictionary =
                            
                                    JsonConvert.DeserializeObject<Dictionary<string, string>>(result);
                            
                                return tokenDictionary;
                            
                            }
                            

                             

                            Note, at this point, we have added code the the Main() method, which calls out to a single, rather contrived method GetResponseAsDictionary() . All we are basically doing here is submitting an HTTP POST to the Token endpoint of our Web Api, and then de-serializing the JSON response body into a Dictionary<string, string> .

                            Once we have the Dictionary, we are iterating over each Key/Value pair, and writing the contents to the Console.

                            If everything has worked the way we expect, our Console output should be something along the lines of the following:

                            Console Output from Token Endpoint Response:
                            Attempting to Log in with default admin user
                            
                            access_token: AuzOQkgG3BYubP1rlljcPhAzW7R7gA4Vew8dHy_MScMn2-Rs3R6dNlwCU_SuFwKveq
                            
                            uf5rflB7PCfamlcT_-KJ4q3lfx7kiFNpSF9SdMLwKP_mCSOXGbrxrK3jXfH7bum3sZdl7w8k5irLa27i
                            
                            Bvp_RqtXgkSmgpcNWitCU8RBz7aOaHr8r-FCklg4wUkLNE26qlR6Sl42DAAiBZNLpUZUt-M7vaOs8TZB
                            
                            W4YehAzrqFAuTX3peMJBQB8K8_XxaTkRnEhSEMz9DnUnqzQjjVr5rnSdFSGxQmrQA8dBBwq4RaUfwbCU
                            
                            7au787CMn7EGiDO9KRcGHAsGHOJqb8P8Z7A-ssV7tfEqJayrNH-F_Z2p5kiasDODQrG53CZNUE0vuDT6
                            
                            Fp4_xOavE6wkYcHTfXWZJWFEMokE4NB9mtAl3lReYSZQyzKkcHWFNQCMAj3LoNGSdnEVVM_jzZtRSfWj
                            
                            IG2OmhyR1wZNRCHY_6NwEMOIHGLpA_L-kFFAJPgwQWi-WljeV-X2KiMQIeYlGGdskaNw
                            
                            token_type: bearer
                            
                            expires_in: 1209599
                            
                            userName: admin@example.com
                            
                            .issued: Sun, 26 Oct 2014 13:21:03 GMT
                            
                            .expires: Sun, 09 Nov 2014 13:21:03 GMT

                             

                            We've seen this before, in our overview article. The de-serialized JSON above represents the content of the response to our POST to the Token endpoint of our Web Api. The important part of the response is and access_token itself.

                            This Doesn't Look Any Different Than Before . . .

                            At this point, that de-serialized JSON response doesn't look any different than it did in our previous post, before we added all our fancy new Roles and custom properties. Shouldn't it have some new information in it now? Roles, and Addresses and stuff?

                            No.

                            A Little More On the Nature of Bearer Tokens (but only a little)

                            We had a really, really brief look Bearer Tokens in our Introduction to Identity in Web Api. As mentioned there, we will undertake a more in-depth exploration of Tokens in another post.

                            For our purposes here today, we are simply going to expand a little on what we learned previously, sufficient to understand how the access_token we retrieved as part of our JSON response above fits into the scheme of our newly modified Web Api project.

                            Bearer Tokens are, by design, "opaque" to the client. In other words, they are encoded (and sometimes encrypted) on the server, and can be decoded (and potentially decrypted) by the server. They are not designed to be decoded/decrypted by the client.

                            Recall from exploring the basic structure of an ASP.NET Web Api project, the ApplicationOauthProvider class, defined in the Providers => ApplicationOauthProvider.cs file.

                            When you POST a request to the Token endpoint of the ASP.NET Web Api application (at least, in the way we have it configured here), the server validates the credentials you present (in this case, user name + Password) by calling the GrantResourceOwnersCredentials() method defined on the ApplicationOauthProvider class:

                            The GrantResourceOwnersCredentials() Method from ApplicationOAuthProvider:
                            public override async Task GrantResourceOwnerCredentials(
                            
                                OAuthGrantResourceOwnerCredentialsContext context)
                            
                            {
                            
                                var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
                            
                                ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
                            
                             
                            
                                if (user == null)
                            
                                {
                            
                                    context.SetError("invalid_grant", "The user name or password is incorrect.");
                            
                                    return;
                            
                                }
                            
                             
                            
                                ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
                            
                                   OAuthDefaults.AuthenticationType);
                            
                                ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager,
                            
                                    CookieAuthenticationDefaults.AuthenticationType);
                            
                             
                            
                                AuthenticationProperties properties = CreateProperties(user.UserName);
                            
                                AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
                            
                                context.Validated(ticket);
                            
                                context.Request.Context.Authentication.SignIn(cookiesIdentity);
                            
                            }

                             

                            We can see that this code attempts to find a user with credentials matching those presented. If a valid user is found, the method calls the GenerateUserIdentityAsync() method defined on the ApplicationUser class to obtain an instance of ClaimsIdentity representing the user, and any claims the user may make within our system.

                            The ClaimsIdentity is then used to create an AuthenticationTicket.

                            In the code for GrantResourceOwnersCredentials(), above, when Validated() is called on the OAuthGrantResourceOwnerCredentialsContext, the OWIN middleware serializes the ClaimsIdentity into an encoded and signed token, to be returned in the HTTP Response header as a result of our request.

                            All of the above is a long-winded way of saying, the important user information, including user roles, and anything else we decide needs to be a part of our token, is present in the token when it is received by the client.

                            The Client just can't get to it.

                            A Note About Bearer Tokens and Security

                            As mentioned in our previous posts, using bearer tokens, and submitting credentials to obtain the token from the token endpoint should only be done over SSL/STL in a production system. Bearer tokens are exactly what their name implies - anyone presenting a valid bearer token will be granted access to the system, with whatever privileges the actual "owner" of the token has.

                            OAuth Bearer tokens represent a fairly simple authentication/authorization scheme, In building out your Web Api, consider all of the alternatives, and make the best choice for your application.

                            As mentioned previously, we will take a more thorough look at Claims Identity, and token authentication/authorization in later posts.

                            Adding Role-Based Authorization to the Web Api Application

                            Now that we understand how to authenticate ourselves using a bearer token, let's look at how we can use our new Role-Based Authorization capability within our application.

                            To start, let's look at the two primary controllers present in the Web Api application, AccountController and ValuesController (we are ignoring the HomeController, since it serves no purpose for our needs here).

                            We've already seen that AccountController is decorated with an [Authorize] attribute. This means that only authenticated users may access the action methods defined on this controller (unless, of course, the method itself is decorated with an [AllowAnonymous] attribute).

                            Let's look at the simplistic ValuesController. ValuesController is provided as a simple example of how one might add a basic CRUD-style functionality. ValuesController is similarly decorated with the [Authorize] attribute. Again, only authenticated users are able to access the Action methods defined on ValuesController.

                            As we saw in previous posts about implementing Role-Based Authorization in an MVC project, we can modify the access permissions for our Web Api, at either the Controller level, or the Action method level, by expanding on our use of [Authorize] .

                            Consider, we might want to restrict access to AccountController only to users who are in the Admin role, but allow access to ValuesController, and the functionality it provides, to any authenticated user.

                            In this case, we will want to make some modifications to our Web Api configuration.

                            Add a Vanilla Users Role as a Default in ApplicationDbInitializer

                            First, let's make sure we have two distinct Roles available in our application - the "Admin" role we already create as an initial value during configuration, and a new "Users" role. Update the InitializeDatabaseForEF() method as follows:

                            Add a Users Role and a Default User to InitializeDatabaseForEF() Method:
                            public static void InitializeIdentityForEF(ApplicationDbContext db)
                            
                            {
                            
                                var userManager = HttpContext.Current
                            
                                    .GetOwinContext().GetUserManager<ApplicationUserManager>();
                            
                             
                            
                                var roleManager = HttpContext.Current
                            
                                    .GetOwinContext().Get<ApplicationRoleManager>();
                            
                             
                            
                                // Initial Admin user:
                            
                                const string name = "admin@example.com";
                            
                                const string password = "Admin@123456";
                            
                             
                            
                                // Some initial values for custom properties:
                            
                                const string address = "1234 Sesame Street";
                            
                                const string city = "Portland";
                            
                                const string state = "OR";
                            
                                const string postalCode = "97209";
                            
                             
                            
                                const string roleName = "Admin";
                            
                                const string roleDescription = "All access pass";
                            
                             
                            
                                //Create Role Admin if it does not exist
                            
                                var role = roleManager.FindByName(roleName);
                            
                                if (role == null)
                            
                                {
                            
                                    role = new ApplicationRole(roleName);
                            
                             
                            
                                    // Set the new custom property:
                            
                                    role.Description = roleDescription;
                            
                                    var roleresult = roleManager.Create(role);
                            
                                }
                            
                             
                            
                                // Create Admin User:
                            
                                var user = userManager.FindByName(name);
                            
                                if (user == null)
                            
                                {
                            
                                    user = new ApplicationUser { UserName = name, Email = name };
                            
                             
                            
                                    // Set the new custom properties:
                            
                                    user.Address = address;
                            
                                    user.City = city;
                            
                                    user.State = state;
                            
                                    user.PostalCode = postalCode;
                            
                             
                            
                                    var result = userManager.Create(user, password);
                            
                                    result = userManager.SetLockoutEnabled(user.Id, false);
                            
                                }
                            
                             
                            
                                // Add user admin to Role Admin if not already added
                            
                                var rolesForUser = userManager.GetRoles(user.Id);
                            
                                if (!rolesForUser.Contains(role.Name))
                            
                                {
                            
                                    userManager.AddToRole(user.Id, role.Name);
                            
                                }
                            
                             
                            
                                // Initial Vanilla User:
                            
                                const string vanillaUserName = "vanillaUser@example.com";
                            
                                const string vanillaUserPassword = "Vanilla@123456";
                            
                             
                            
                                // Add a plain vannilla Users Role:
                            
                                const string usersRoleName = "Users";
                            
                                const string usersRoleDescription = "Plain vanilla User";
                            
                             
                            
                                //Create Role Users if it does not exist
                            
                                var usersRole = roleManager.FindByName(usersRoleName);
                            
                                if (usersRole == null)
                            
                                {
                            
                                    usersRole = new ApplicationRole(usersRoleName);
                            
                             
                            
                                    // Set the new custom property:
                            
                                    usersRole.Description = usersRoleDescription;
                            
                                    var userRoleresult = roleManager.Create(usersRole);
                            
                                }
                            
                             
                            
                                // Create Vanilla User:
                            
                                var vanillaUser = userManager.FindByName(vanillaUserName);
                            
                                if (vanillaUser == null)
                            
                                {
                            
                                    vanillaUser = new ApplicationUser 
                            
                                    { 
                            
                                        UserName = vanillaUserName, 
                            
                                        Email = vanillaUserName 
                            
                                    };
                            
                             
                            
                                    // Set the new custom properties:
                            
                                    vanillaUser.Address = address;
                            
                                    vanillaUser.City = city;
                            
                                    vanillaUser.State = state;
                            
                                    vanillaUser.PostalCode = postalCode;
                            
                             
                            
                                    var result = userManager.Create(vanillaUser, vanillaUserPassword);
                            
                                    result = userManager.SetLockoutEnabled(vanillaUser.Id, false);
                            
                                }
                            
                             
                            
                                // Add vanilla user to Role Users if not already added
                            
                                var rolesForVanillaUser = userManager.GetRoles(vanillaUser.Id);
                            
                                if (!rolesForVanillaUser.Contains(usersRole.Name))
                            
                                {
                            
                                    userManager.AddToRole(vanillaUser.Id, usersRole.Name);
                            
                                }
                            
                            }
                            

                             

                            Above, we have added a new role "Users" and another initial sample user.

                            Next, let's modify the [Authorize] attribute on our AccountController class, and add a Role argument:

                            Modified [Authorize] Attribute for AccountController:
                            [Authorize(Roles= "Admin")]
                            
                            [RoutePrefix("api/Account")]
                            
                            public class AccountController : ApiController
                            
                            {
                            
                                // ... All the Code ...
                            
                            }

                             

                            Now, we just need to change up our client code to attempt to access some methods from each of the two controllers to see how our Role-Based Authorization is working for us.

                            Modify Client Code to Attempt Controller Access

                            Here, we will simply set up some client code to attempt to retreive some basic data from both AccountController and ValuesController. We will do this as a user in the Admin Role, and then also as a user in the Users Role.

                            Change the code in your Console application to match the following:

                            Modified Client Code to Access Both Controllers with Different Roles:
                            class Program
                            
                            {
                            
                                // You will need to substitute your own host Url here:
                            
                                static string host = "http://localhost:63074/";
                            
                             
                            
                                static void Main(string[] args)
                            
                                {
                            
                                    // Use the User Names/Emails and Passwords we set up in IdentityConfig:
                            
                                    string adminUserName = "admin@example.com";
                            
                                    string adminUserPassword = "Admin@123456";
                            
                             
                            
                                    string vanillaUserName = "vanillaUser@example.com";
                            
                                    string vanillaUserPassword = "Vanilla@123456";
                            
                             
                            
                                    // Use the new GetToken method to get a token for each user:
                            
                                    string adminUserToken = GetToken(adminUserName, adminUserPassword);
                            
                                    string vaniallaUserToken = GetToken(vanillaUserName, vanillaUserPassword);
                            
                             
                            
                                    // Try to get some data as an Admin:
                            
                                    Console.WriteLine("Attempting to get User info as Admin User");
                            
                                    string adminUserInfoResult = GetUserInfo(adminUserToken);
                            
                                    Console.WriteLine("Admin User Info Result: {0}", adminUserInfoResult);
                            
                                    Console.WriteLine("");
                            
                             
                            
                                    Console.WriteLine("Attempting to get Values info as Admin User");
                            
                                    string adminValuesInfoResult = GetValues(adminUserToken);
                            
                                    Console.WriteLine("Admin Values Info Result: {0}", adminValuesInfoResult);
                            
                                    Console.WriteLine("");
                            
                             
                            
                                    // Try to get some data as a plain old user:
                            
                                    Console.WriteLine("Attempting to get User info as Vanilla User");
                            
                                    string vanillaUserInfoResult = GetUserInfo(vaniallaUserToken);
                            
                                    Console.WriteLine("Vanilla User Info Result: {0}", vanillaUserInfoResult);
                            
                                    Console.WriteLine("");
                            
                             
                            
                                    Console.WriteLine("Attempting to get Values info as Vanilla User");
                            
                                    string vanillaValuesInfoResult = GetValues(vaniallaUserToken);
                            
                                    Console.WriteLine("Vanilla Values Info Result: {0}", vanillaValuesInfoResult);
                            
                                    Console.WriteLine("");
                            
                             
                            
                                    Console.Read();
                            
                                }
                            
                             
                            
                             
                            
                                static string GetToken(string userName, string password)
                            
                                {
                            
                                    HttpClient client = new HttpClient();
                            
                                    var pairs = new List<KeyValuePair<string, string>>
                            
                                                {
                            
                                                    new KeyValuePair<string, string>( "grant_type", "password" ), 
                            
                                                    new KeyValuePair<string, string>( "username", userName ), 
                            
                                                    new KeyValuePair<string, string> ( "Password", password )
                            
                                                };
                            
                                    var content = new FormUrlEncodedContent(pairs);
                            
                             
                            
                                    // Attempt to get a token from the token endpoint of the Web Api host:
                            
                                    HttpResponseMessage response =
                            
                                        client.PostAsync(host + "Token", content).Result;
                            
                                    var result = response.Content.ReadAsStringAsync().Result;
                            
                             
                            
                                    // De-Serialize into a dictionary and return:
                            
                                    Dictionary<string, string> tokenDictionary =
                            
                                        JsonConvert.DeserializeObject<Dictionary<string, string>>(result);
                            
                                    return tokenDictionary["access_token"];
                            
                                }
                            
                             
                            
                             
                            
                                static string GetUserInfo(string token)
                            
                                {
                            
                                    using (var client = new HttpClient())
                            
                                    {
                            
                                        client.DefaultRequestHeaders.Authorization =
                            
                                        new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
                            
                                        var response = client.GetAsync(host + "api/Account/UserInfo").Result;
                            
                                        return response.Content.ReadAsStringAsync().Result;
                            
                                    }
                            
                                }
                            
                             
                            
                             
                            
                                static string GetValues(string token)
                            
                                {
                            
                                    using (var client = new HttpClient())
                            
                                    {
                            
                                        client.DefaultRequestHeaders.Authorization =
                            
                                        new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
                            
                             
                            
                                        var response = client.GetAsync(host + "api/Values").Result;
                            
                                        return response.Content.ReadAsStringAsync().Result;
                            
                                    }
                            
                                }
                            
                            }

                             

                            In the above, we changed our code up a bit. We now have a GetToken() method, which accepts a User Name/Password as arguments, and returns only the access_token string from the request to the Token endpoint of our Web Api.

                            Next, we added two different calls to our Web Api. One method calls the GetUserInfo() method on the AccountController, and the other calls the Get() method on our ValuesController.

                            If we spin up our Web Api, and, after it has spun up, run our client application, we should see the following output in our Console:

                            Console Output from Access Permissions Comparison:
                            Attempting to get User info as Admin User
                            
                            Admin User Info Result: {"Email":"admin@example.com","HasRegistered":true,"Login
                            
                            Provider":null}
                            
                            Attempting to get Values info as Admin User
                            
                            Admin Values Info Result: ["value1","value2"]
                            
                            Attempting to get User info as Vanilla User
                            
                            Vanilla User Info Result: {"Message":"Authorization has been denied for this req
                            
                            uest."}
                            
                            Attempting to get Values info as Vanilla User
                            
                            Vanilla Values Info Result: ["value1","value2"]

                             

                            Note the output from that third attempt. We are trying to call into GetUserInfo() as a plain vanilla User, in the Users Role. Appropriately, our Web Api has returned an authorization error, since Users are not allowed access to the method by virtue of the [Authorize(Roles="Admin")] attribute on the class declaration for AccountController.

                            In contrast, both users are able to access the Get() method on ValuesController, since this controller is decorated with a simple [Authorize] attribute, which requires only an authenticated user for access.

                            Accessing Custom User Properties

                            We have also added some custom properties to our ApplicationUserModel. Let's take a look and see if we can work with those in the context of our examples here.

                            If we look more closely at the GetUserInfo() method on AccountController, we find that the actual return type for this method is UserInfoViewModel, which is found in the Models => AccountViewModels.cs file. Now, in our crude, simple Console application we are not going to all the effort of de-serializing the JSON from our GET request into an object, but we COULD.

                            For our purposes, here, it will be sufficient to modify the UserInfoViewModel to reflect the additional properties we want to return, and then update the GetUserInfo() method to suit.

                            Add our custom User properties to the UserInfoViewModel class:
                            public class UserInfoViewModel
                            
                            {
                            
                                public string Email { get; set; }
                            
                                public bool HasRegistered { get; set; }
                            
                                public string LoginProvider { get; set; }
                            
                             
                            
                                // Add our custom properties from ApplicationUser:
                            
                                public string Address { get; set; }
                            
                                public string City { get; set; }
                            
                                public string State { get; set; }
                            
                                public string PostalCode { get; set; }
                            
                            }

                             

                            Next, update the GetUserInfo() method to provide values for the additional properties we just added to UserInfoViewModel:

                            Update GetUserInfo() Method on AccountController with Custom Properties:
                            public UserInfoViewModel GetUserInfo()
                            
                            {
                            
                                ExternalLoginData externalLogin 
                            
                                    = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);
                            
                             
                            
                                // We wouldn't normally be likely to do this:
                            
                                var user = UserManager.FindByName(User.Identity.Name);
                            
                                return new UserInfoViewModel
                            
                                {
                            
                                    Email = User.Identity.GetUserName(),
                            
                                    HasRegistered = externalLogin == null,
                            
                                    LoginProvider = externalLogin != null ? externalLogin.LoginProvider : null,
                            
                             
                            
                                    // Pass the custom properties too:
                            
                                    Address = user.Address,
                            
                                    City = user.City,
                            
                                    State = user.State,
                            
                                    PostalCode = user.PostalCode
                            
                                };
                            
                            }

                             

                            Above, we have called out to UserManager to retreive an instance of our user, so we can get at the new properties we have added. We then set the corresponding values on the UserInfoViewModel before returning.

                            This example is a little contrived, and we most likely would NOT do this in a production application this way. But for now, it will serve to demonstrate that our new and improved ApplicationUser indeed has the custom properties we added to the model, and that we are retrieving them from the database as expected.

                            If we run our Console Client application one last time, we should see the following output:

                            Output from the Console Application with Custom User Properties:
                            Attempting to get User info as Admin User
                            
                            Admin User Info Result: {"Email":"admin@example.com","HasRegistered":true,"Login
                            
                            Provider":null,"Address":"1234 Sesame Street","City":"Portland","State":"OR",
                            
                            "PostalCode":"97209"}
                            
                            Attempting to get Values info as Admin User
                            
                            Admin Values Info Result: ["value1","value2"]
                            
                            Attempting to get User info as Vanilla User
                            
                            Vanilla User Info Result: {"Message":"Authorization has been denied for this 
                            
                            request."}
                            
                            Attempting to get Values info as Vanilla User
                            
                            Vanilla Values Info Result: ["value1","value2"]

                             

                            And we see, our custom user properties are returned with the JSON response.

                            Role-Based Authorization Versus Claims-Based Authorization

                            In this post, we have looked briefly at implementing Role-Based Authorization in the context of an ASP.NET Web Api project, and we had the briefest look at how Bearer Tokens work. It is important to note though, that for any but the simplest of authorization/access control schemes, Role-Based Authorization ("RBA") is rapidly being overshadowed by Claims-Based Authorization.

                            Claims-Based Identity offers greater flexibility, and more effectively separates the Authentication and Authorization mechanism from your code. Note, in this example project, we need to specify, as part of the [Authorize] attribute, precisely which Roles are allowed access to which controllers and/or methods.

                            Claims-Based Auth is more complex than RBA, but is generally going to be a more natural fit for a Web Api scenario, unless your needs are fairly simple.

                            We will examine Tokens, and Claims-Based Identity, in an upcoming post.

                            Additional Resources and Items of Interest

                             

                            Posted on October 26 2014 03:23 PM by jatten     

                            Comments (9)

                            Setting Up for Mono Development in Linux Mint/Ubuntu

                            Posted on October 19 2014 06:08 PM by jatten in Linux, Learning Linux, C#   ||   Comments (5)

                            follow-the-yerllow-mint-roadI recently needed to create a cross-platform C# library which needs to work across Windows, OSX, and Linux. Obviously, getting a .NET library running on Windows presented no great difficulties. Getting the same library working under Mono on a Linux platform was a little more involved.

                            The folks at Xamarin have brought Mono, and the development tools available for Mono, a long ways. Xamarin Studio is a beautiful IDE which, while it differs from Visual Studio in some important ways, is a joy to work with. Xamarin's focus is building mobile application development tools. However, Xamarin Studio and Mono both lend themselves fairly well to working with C# code on either Windows or OSX.

                            Image by Neil Fowler  | Some Rights Reserved

                            There are some notable things missing (you can't work directly with Windows Forms, for example, nor is there significant support for ASP.NET), but overall, working with strictly library code presented only minor hurdles (not the least of which is a different workflow and navigation scheme from VS).

                            However, Xamarin Studio is only available for Windows and OSX - there is not currently any support for direct Linux platforms (yes, I know a shiny veneer on top of what amounts to Linux under the hood).

                            Getting things working on my Linux machine took a little more work.

                            Mono Development on Linux Using MonoDevelop

                            Xamarin Studio represents a "Super-Set" of the original, cross-platform Mono IDE, MonoDevelop. The Xamarin team have generously pushed a good number of improvements back to the MonoDevelop source. However, the most recent changes are not directly available as packages to all Linux distros.

                            Specifically, while the most recent version of MonoDevelop is 5.0.1.3, the most recent package available to Ubuntu, and Ubuntu-based systems from the MonoDevelop site is version 2.6.0.1.

                            In this article, we will look at how to get a proper Mono development environment set up on Ubuntu-based systems, including the most recent (as of this writing) release of MonoDevelop. We will also look at getting Nuget, and Nuget package restore, working properly in this environment.

                            Got Linux?

                            If you don't have a Linux box, set up a VM to work through this post. I prefer using Linux Mint for my Linux-based activity. I found that all of the following steps worked fine in the most recent version of Ubuntu. However, I DON'T like Ubuntu itself. I prefer Linux mint. The last version of Mint I was using (Mint 13 with the KDE desktop) did not work very well with the most recent version of MonoDevelop. I found the the most recent stable release of Mint 17, using the Cinnamon desktop, worked great, with none of the bloat I found with Ubuntu.

                            See the following for detailed instructions if you need to set up a Linux VM:

                            For the purpose of this post, we will assume you are starting with a reasonably fresh VM, and do not already have Mono or MonoDevelop Installed.

                            As mentioned previously, the links on the MonoDevelop download site don't get you the most recent Mono release for Ubuntu-based systems. Fortunately, there are some great Personal Package Archives out there which DO.

                            Install Mono

                            Your machine may or may not already have Mono installed. Either way, we are going to pull down the most recent, complete version.

                            Open a terminal in your home folder, and do the following:

                            Update Everything:
                            $ sudo apt-get update

                             

                            Install Mono:
                            $ sudo apt-get install mono-complete

                            Once the Mono Installation completes, update again before moving forward:

                            Update Everything Again:
                            $ sudo apt-get update

                             

                            The most recent Mono release is now installed on your machine. Now, let's get all the goodness of the most recent MonoDevelop release.

                            Add the Personal Package Archive (PPA) for Latest Stable MonoDevelop Release

                            To get the most recent stable release of MonoDevelop, we can thank Eberhard Beilharz for making the Stable Version of MonoDevelop PPA at Launchpad.Net.

                            To get the most recent version of MonoDevelop on our machine, we simply need to add the PPA to our Synaptic Package Manager's list of sources, and then use synaptic to pull it down.

                            Add the MonoDevelop PPA to Synaptic:
                            $ sudo add-apt-repository ppa:ermshiperete/monodevelop

                             

                            Update to refresh Synaptic:

                            Update Everything Yet Again:
                            $ sudo apt-get update

                             

                            Install MonoDevelop

                            Now that we have added the PPA, we can use Synaptic just like any other package:

                            Install MonoDevelop from PPA:
                            $ sudo apt-get install monodevelop-current

                             

                            Again, update everything:

                            Update Everything One More Time:
                            $ sudo apt-get update

                             

                            Now, as indicated on the MonoDevelop PPA site, the install we just completed placed a shell script at /opt/monodevelop/bin/monodevelop-launcher.sh

                            Let's add an alias for this, so that we don't have to deal with that big long path every time we want to open MonoDevelop.

                            If this is a fresh install of Mint 17 on your machine, you will need to add a .bashrc file. If you already have a .bashrc file (or a .bash_profile file - in Mint they are functionally the same), add one:

                            Add a .bashrc File in your Home Directory:
                            $ touch .bashrc

                             

                            Next, add an alias to .bashrc pointing to and executing the shell script:

                            Add Alias to Execute MonoDevelop-Launcher Script:
                            $ echo >> .bashrc "alias monodev=Exec=\"sh /opt/monodevelop/bin/monodevelop-launcher.sh\""

                             

                            Close the terminal, and open a new terminal instance. You should now be able to open MonoDevelop from the terminal by typing, simply "monodev"

                            With that, we have successfully installed the most recent release of MonoDevelop on our Mint 17 or Ubuntu machine. However, we are likely to find that Nuget, and Nuget package restore, give us difficulties in this out-of-the box scenario.

                            Making Nuget Package Restore Work in MonoDevelop

                            Out-of-the-box, Nuget works a little differently in MonoDevelop than we are accustomed to in Visual Studio (this is true of much about MonoDevelop, actually…).

                            To see what I mean, use your new terminal alias and open MonoDevelop. Then, create a new Console project. Once that's done, take a moment to get oriented.

                            We can add Nuget packages by right-clicking on individual projects within the solution in the tree to the left:

                            Add Nuget Packages in MonoDevelop:

                            add-nuget-packages

                            However, if we try to add Nuget packages right now, we get a big FAIL:

                            Add Nuget Packages Fails in MonoDevelop:

                            add-packages-fail

                            WAT?

                            What's equally confounding is that, if we were to open and build an existing project which required Nuget Package Restore, the Package Manager would is not always able to connect to Nuget to pull down the packages, and an error would result.

                            This doesn't affect all packages, but enough to be annoying. In particular, several NUnit-related packages and a few others, appear to be affected, and your project can't be properly built.

                            As it turns out, we are missing some important SSL certificates. The fix is simple, and we can do it from our terminal.

                            Add Required SSL Certificates for Nuget to Work in MonoDevelop

                            Since we are using our current terminal instance to run MonoDevelop, we will either need to quit MonoDevelop, or open a new terminal instance, and then execute the following to import a number of important SSL certificates:

                            Import SSL Certificates from mozroots:
                            $ mozroots --import --sync

                             

                            Once we have run this command, we should be able to add Nuget packages at will. Also, Update Packages, and Restore Packages commands from the Solution context menu both should work with no problems.

                            Additional Resources and Items of Interest

                             

                            Posted on October 19 2014 06:08 PM by jatten     

                            Comments (5)

                            Setting Up Linux in a Virtual Machine for Windows Users

                            Posted on October 19 2014 10:04 AM by jatten in Linux, Learning Linux   ||   Comments (0)

                            photozel-linux-mint-18142If you have spent most of your computing life using Windows, odds are good you may find yourself in unfamiliar territory when if comes to setting up a Linux box. Even for some experienced technical folks, the differences between the platforms can have you feeling like a noob from the very start.

                            Setting Linux up in a virtual machine can save some time and pain, but comes with the added overhead of understanding how the particular virtualization software works.

                            In this post, we will look at setting up a basic Linux environment in a virtual machine, and look at some of the trouble-shooting you may need to do along the way.

                            Image by Photozel  |  Some Rights Reserved

                            Note, I am not a Linux expert. I have been learning my way through Linux for most of the past year or so, but there is a lot to learn. I find I really, really enjoy using Linux, and once I got past the initial learning curve, things began to make sense rather quickly.

                            Learn Linux the Hard Way

                            Most of the recommended introductory Linux distributions ("distro's") feature a GUI to varying degrees. It is possible to do much of what you set out to do without cracking open a terminal. However, when I started down the golden Linux path, a determined to use the terminal wherever possible, and patiently become proficient with this OS in the terms under which, ultimately, it was designed to be used.

                            I strongly recommend you do the same. Not only will you gain a deeper, better understanding of Unix-based systems, but of how your machine works in general. Unlike the Windows world in which I grew up, Linux/Unix is first and foremost a command-line driven platform, and is optimized as such. In fact, it's fair to say that, unlike Windows, in *nix OS's, anything you can do from the GUI, you can also do from the terminal, usually more efficiently (once you know how, and depending on your typing proficiency).

                            If you are stuck on how to do something from the terminal, Google is you friend. If your are still stuck, you can probably do it from the GUI until you find an answer. As I said, though, I strongly recommend using the terminal for everything you can. It will feel incredibly clumsy at first, but like all things, the more you do, the better you get.

                            The article linked below was focused on getting to know Git for folks with a Windows background, but there are a number of handy bash references you may find helpful:

                            Virtualization Software

                            Before we can set up a virtual machine, we need some virtualization software. I tend towards the free and open source VirtualBox solution. Despite lacking some of the polish associated with VMWare, I find that VirtualBox meets my needs nicely.

                            In this article we will be using VirtualBox as our virtualization environment.

                            Download and Install the appropriate VirtualBox package for your PC from the VirtualBox Downloads page.

                            Linux Mint

                            While Ubuntu is the most popular "beginner" Linux distro, I prefer Linux Mint. Newer releases of Ubuntu seem slow and bloated to me, and oriented more directly at desktop users, with many of the more advanced tools well hidden. Also note that Linux Mint is derived from Ubuntu.

                            Mint seems to more effectively consider both desktop/GUI users, as well as more technical folk. While the full desktop GUI is available (and well-done, compared to some), the terminal is a short context menu away.

                            At the time of this writing, Linux Mint 17 is the most recent stable release, and is targeted for long-term support.

                            Downloading the Linux Mint ISO

                            Linux Mint is available with a number of different desktop options. Until recently, I have been using Mint with the KDE desktop, but have just switched to the newer Cinnamon desktop to check it out. Also, I had issues getting MonoDevelop working in the KDE implementation.

                            You can download the stable Linux Mint release with the Cinnamon desktop from one of the mirrors on this page:

                            Once you have downloaded the Linux Mint ISO, save the file somewhere safe. You will need this shortly.

                            Configure a new Virtual Machine in VirtualBox

                            Once you have installed VirtualBox on your PC, select the "New" button from the top menu. You should be greeted with the Create Virtual Machine window like so:

                            VirtualBox Configuration - The Create Virtual Machine Window

                            create-virtual-machine

                            Choose a unique and descriptive name for the VM you intend to create. I tend to follow a convention of OS-RAM-HDD specs, but how you do it may depend on what you plan to do with the VM.

                            Next choose the type (Linux), and the version. In this case, Linux Mint is not one of the options. However, Mint is a descendant of Ubuntu, so Ubuntu will work here.

                            Allocating Resources to the Virtual Machine

                            Once you click next, you will be asked to select how much RAM your virtual machine will have. Note that your VM will be sharing RAM with your physical host machine. VirtualBox will offer up a "recommended" amount of RAM to allocate. However, I tend to push this up, as I have physical RAM in abundance on my PC. You can see here I selected 4Gb of RAM, which is likely more than I will ever need.

                            Allocate RAM to the Virtual Machine:

                            allocate-ram

                            Clicking next again, you will be asked if you want to create a virtual hard drive. The default (VDI) is the best bet here. You will also be asked if you want this to be fixed size, or dynamically allocated. I generally go with dynamically allocated.

                            Once you select these parameters, you will have the opportunity to specify the "size"  and location of the disk to be created. The recommended size if 8Gb. I generally bump this up to 20Gb, which is probably overkill. However, you will want to consider your intended use for the VM, and allocate disk space accordingly. If you plan to be working with lots of images or video, for example, you will want more disk space than if you plan to simply play with the terminal and familiarize yourself with Linux.

                            Allocate Disk Space to the Virtual Machine:

                            allocate-hdd

                            Once we hit the Create button, we are returned to the VirtualBox Management window. However, we are not done preparing our VM.

                            Other VM Settings

                            Now that we are back in the VirtualBox Management window, we can adjust the various settings for individual VM's by clicking on the appropriate heading to the right.

                            We want to change a few of the default settings here before we proceed.

                            Enable 3D Video Acceleration

                            If we click on the "Display" heading, we are greeted with the Display settings window. Here, we may want to increase the amount of Video RAM available to our VM. I generally push this up to 32 Mb.

                            Also, in order to get acceptable graphics performance, we will enable 3D acceleration.

                            Adjust Display Settings:

                            display-settings

                            Share Folder(s) Between the VM and Physical Host

                            We may want to share files between our host machine (our physical PC) and our VM. We can do this by specifying a folder on the host to be shared. I generally have a dedicated folder named "VM Share" that I use for this.

                            To set up a folder to be shared between the host and your VM(s), select the "Shared Folders" header in the settings window. Then, click the folder icon (top right) to select/create a folder to share.

                            add-shared-folder

                            For our purposes, the other settings for network, USB, and such are generally good with the default settings.

                            Start the VM and Install Linux Mint

                            The first time you start your VM, you will be prompted to select a startup disk. At this point, navigate to the Linux Mint ISO you downloaded previously. Click on the folder icon to the right of the drop-down list to navigate your file system.

                            Select Startup Disk:

                            select-startup-disk

                            The system will boot into the Linux Mint OS on the ISO. When Mint is done loading, note the CD icon on the Mint desktop:

                            Mint Desktop when Booted from ISO:

                            mint-boot-from-iso

                            Double click the CD icon, and follow the installation instructions to install Linux Mint on your VM.

                            NOTE: Linux will only accept lower-case user names, but the password you enter during set-up is case-sensitive.

                            If you enter a mixed-case username, it will be down-cased when it is saved.

                            When the installation completes, you will be asked to re-start the VM. Do this. If your VM hangs during the shutdown process (mine did), Simply close the VM window. When you are prompted to indicate how you want the machine to shut down, select the simple "Power Down the Machine" option.

                            Now, start the machine again using the "Start" icon in the VirtualBox Manager window. As soon as the window comes up, go to the "Devices" menu, eject the Mint Installation ISO:

                            Startup and Eject the Mint Installation ISO:

                            remove-disk-from-virtual-drive

                            If everything has worked properly to this point, you should be greeted with a login screen to log in to Linux Mint.

                            Enter the user name and password you specified during installation (remember, your username will be all lower-case), and you should be off and running.

                            Additional Resources and Items of Interest

                             

                            Posted on October 19 2014 10:04 AM by jatten     

                            Comments (0)

                            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:

                            jatten at typecastexception dot com

                            Web Hosting by