Claims-based authentication in MVC4 with .NET4.5 C# part 1: Claims transformation

This post will look into how Claims can be introduced in an MVC4 internet application.

We will build on the basics of claims we discussed in previous posts:

I will make references to those posts and if you have absolutely no experience with Claims-based auth in .NET4.5 then I suggest you take a look at them as well.

Start Visual Studio and create a new MVC4 internet application with .NET4.5 as the underlying framework.

The template will set up a good starting point for an MVC web app including forms based authentication. Run the application and click the ‘Register’ link in the top right hand corner of the screen. You’ll be redirected to a page where you can fill out the user name and password:

Register link in basic MVC4 web app

Fill in the textboxes, press the ‘Register’ button and there you are, you’ve created a user. You’ll see that you were also automatically logged on:

User automatically logged in upon registration

A short aside on forms-based auth in MVC4

The default structure of creating and authenticating users in the basic template MVC4 app is far from ideal. I wrote two posts on forms-based auth in MVC4 here and here where you can learn more on this topic and how you can transform the template to something that’s a more suitable starting point.

For now just accept that the user you created in the previous step is saved in an attached local SQL Express database that was created for you. You can view this database by looking at the Server Explorer (Ctrl W, L). There you should see a database called DefaultConnection:

Default connection database

Open that node and you’ll see several tables that .NET created for you when the first user was registered. You’ll find a detailed discussion on what they are and how they were created in the posts on forms-based auth I mentioned above. For now it’s enough to say that the user was saved in two different tables. One’s called webpages_Membership, where the password is stored in a hashed form. The table UserProfile stores the user name. Right-click that table and select ‘Show table data’ from the context menu. There you should see the user with user id = 1:

Registered user in DB

Open the membership table as well to view how the password is stored.

In case you’re wondering about what connection string was used you can see it in web.config:

<connectionStrings>
    <add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=aspnet-ClaimsInMvc4-20130130200447;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnet-ClaimsInMvc4-20130130200447.mdf" providerName="System.Data.SqlClient"/>
 </connectionStrings>

Claims transformation in MVC4

If you recall from part 3 we registered a claims transformation logic in our simple Console application. Our goal is to do the same in our web app.

Right-click the web project in the Solution Explorer and add a new class file called CustomClaimsTransformer. The class must derive from ClaimsAuthenticationManager in the System.Security.Claims namespace. You will have add two references to your project: System.IdentityModel and System.IdentityModel.Services. The skeleton of the class will look like this:

public class CustomClaimsTransformer : ClaimsAuthenticationManager
    {
    }

We will override the Authenticate method:

public class CustomClaimsTransformer : ClaimsAuthenticationManager
    {
        public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
        {
            return base.Authenticate(resourceName, incomingPrincipal);
        }
    }

This structure should look familiar from Part 3 of Claims basics. The resource name is an optional variable to describe the resource the user is trying to access. The incoming ClaimsPrincipal object is the outcome of the authentication; it represents the User that has just been authenticated on the login page. Now we want to ‘dress up’ the claims collection of that user.

Our first check is to see if the ClaimsPrincipal has been authenticated.

public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
        {
            if (!incomingPrincipal.Identity.IsAuthenticated)
            {
                return base.Authenticate(resourceName, incomingPrincipal);
            }
        }

If the user is anonymous then we let the base class handle the call. The Authenticate method in the base class will simply return the incoming principal so an unauthenticated user will not gain access to any further claims and will stay anonymous.

You will typically not have access to a lot of claims right after authentication. You can count with the bare minimum of the UserName and often that’s all you get in a forms-based login scenario. So we will simulate a database lookup based on the user name. The user’s claims are probably stored somewhere in some storage. We’ll start with a skeleton:

public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
        {
            if (!incomingPrincipal.Identity.IsAuthenticated)
            {
                return base.Authenticate(resourceName, incomingPrincipal);
            }

            return DressUpPrincipal(incomingPrincipal.Identity.Name);
        }

        private ClaimsPrincipal DressUpPrincipal(String userName)
        {

        }

However, in case the application is expecting more Claims than the name claim at this stage then this is the time to check the claims collection. If you need access to an “age” claim then you can check its presence through the Claims property of the ClaimsPrincipal:

incomingPrincipal.Claims.Where(c => c.Type == "age").FirstOrDefault();

Then if the age claim is missing then you can throw an exception.

Fill in the DressUpPrincipal method as follows:

private ClaimsPrincipal DressUpPrincipal(String userName)
        {
            List<Claim> claims = new List<Claim>();

            //simulate database lookup
            if (userName.IndexOf("andras", StringComparison.InvariantCultureIgnoreCase) > -1)
            {
                claims.Add(new Claim(ClaimTypes.Country, "Sweden"));
                claims.Add(new Claim(ClaimTypes.GivenName, "Andras"));
                claims.Add(new Claim(ClaimTypes.Name, "Andras"));
                claims.Add(new Claim(ClaimTypes.Role, "IT"));
            }
            else
            {
                claims.Add(new Claim(ClaimTypes.GivenName, userName));
                claims.Add(new Claim(ClaimTypes.Name, userName));
            }

            return new ClaimsPrincipal(new ClaimsIdentity(claims, "Custom"));
        }

So we add some claims based on the user name. Here you would obviously do some check in your data storage. If you have Roles in your web app, which is probably true for 99% of all .NET web apps with .NET4 and lower, then you can still use them by the ‘Role’ property of ClaimTypes. You can run the good old Roles.GetRolesForUser(string userName) method of ASP.NET Membership and assign the resulting string array to the Claims.

Finally we return a new ClaimsPrincipal which includes the result of our datastore lookup. Keep in mind that you need to specify the authentication type with a string to make the ClaimsPrincipal authenticated. Here we assigned “Custom” to that value, but it’s up to you.

Now we need to invoke our custom auth logic. We will do that at application start-up in Global.asax. The method that we want to implement is called PostAuthenticationRequest.

First we need to get hold of the current principal, i.e. the one that has just logged in:

protected void Application_PostAuthenticateRequest()
        {
            ClaimsPrincipal currentPrincipal = ClaimsPrincipal.Current;
        }

We will then reference our custom auth manager, pass in the current principal, retrieve the transformed principal and set the transformed principal to the current thread and current user:

protected void Application_PostAuthenticateRequest()
        {
            ClaimsPrincipal currentPrincipal = ClaimsPrincipal.Current;
            CustomClaimsTransformer customClaimsTransformer = new CustomClaimsTransformer();
            ClaimsPrincipal tranformedClaimsPrincipal = customClaimsTransformer.Authenticate(string.Empty, currentPrincipal);
            Thread.CurrentPrincipal = tranformedClaimsPrincipal;
            HttpContext.Current.User = tranformedClaimsPrincipal;
        }

Set a breakpoint at the first row within Application_PostAuthenticateRequest and run the application. Code execution should stop at the breakpoint. Step through the code using F11. As the user is anonymous base.Authenticate will be invoked within CustomClaimsTransformer.Authenticate. The anonymous user will be set as the current principal of the thread with no claims attached.

Remove the breakpoint from within the Application_PostAuthenticateRequest(), we don’t need that. Instead set a new breakpoint within CustomClaimsTransformer.Authenticate where you call the DressUpPrincipal method. We only want to stop code execution if something interesting happens.

Now use the user created before to log in. Code execution should stop within the Authenticate method as the user is not anonymous any more. Use F11 to step through the code line by line. You should see that the user receives the assigned claims and is set as the current user of the current thread and HttpContext.

Let the rest of the code run and… …you may be greeted with a mystical InvalidOperationException:

A claim of type ‘http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier&#8217; or ‘http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider&#8217; was not present on the provided ClaimsIdentity. To enable anti-forgery token support with claims-based authentication, please verify that the configured claims provider is providing both of these claims on the ClaimsIdentity instances it generates. If the configured claims provider instead uses a different claim type as a unique identifier, it can be configured by setting the static property AntiForgeryConfig.UniqueClaimTypeIdentifier.

It turns out the AntiForgeryToken is expecting BOTH the NameIdentifier and IdentityProvider claim even if the exception message says OR. If you recall our implementation of DressUpPrincipal then we omitted both. So let’s go back and include the NameIdentifier:

//simulate database lookup
            if (userName.IndexOf("andras", StringComparison.InvariantCultureIgnoreCase) > -1)
            {
                claims.Add(new Claim(ClaimTypes.Country, "Sweden"));
                claims.Add(new Claim(ClaimTypes.GivenName, "Andras"));
                claims.Add(new Claim(ClaimTypes.Name, "Andras"));
                claims.Add(new Claim(ClaimTypes.NameIdentifier, "Andras"));
                claims.Add(new Claim(ClaimTypes.Role, "IT"));
            }
            else
            {
                claims.Add(new Claim(ClaimTypes.GivenName, userName));
                claims.Add(new Claim(ClaimTypes.Name, userName));
                claims.Add(new Claim(ClaimTypes.NameIdentifier, userName));
            }

Note the ClaimTypes.NameIdentifier in the claims collection. If you run the application now you should still get the same exception which proves the point that by default BOTH claims are needed for the AntiForgeryToken. You can avoid adding both claims by adding the following bit of code in Application_Start within Global.asax:

AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;

Re-run the application and you should be able to log in without getting the exception.

You’ll notice that the text where it says ‘Register’ changes to Hello, [username] upon successful login. Where is that value coming from? Navigate to Views/Shared/_Layout.cshtml in the Solution Explorer and locate the following element:

<section id="login">

This element includes a reference to a partial view “_LoginPartial”. You’ll find _LayoutPartial.cshtml in the same folder. At the top of that file you’ll see the following code:

@if (Request.IsAuthenticated) {
    <text>
        Hello, @Html.ActionLink(User.Identity.Name, "Manage", "Account", routeValues: null, htmlAttributes: new { @class = "username", title = "Manage" })!
        @using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm" })) {
            @Html.AntiForgeryToken()
            <a href="javascript:document.getElementById('logoutForm').submit()">Log off</a>
        }
    </text>
}

Note the call to User.Identity.Name after ‘Hello’. This is a conservative approach as the MVC4 template has no way of knowing in advance whether you’re planning to make you application claims-aware. User is an IPrincipal and Identity is an IIDentity so it will work with pre-.NET4.5 claims auth identity types as well. However, we know that we use claims, so let’s replace User.Identity.Name with:

System.Security.Claims.ClaimsPrincipal.Current.FindFirst(System.IdentityModel.Claims.ClaimTypes.GivenName).Value

Run the web app, log in and you should see the GivenName claim instead of the generic IPrincipal.Name.

Since the web app is now claims-aware you can use the claims to show the email claim after login or the user’s favourite colour or what have you, as long as that particular Claim is present. This was not so easily available with the good old GenericPrincipal and WindowsPrincipal objects.

Note an important thing: do you recall that we hooked up our custom auth manager in Global.asax by overriding Application_PostAuthenticateRequest()? In fact what happens is that our custom Authenticate method in CustomClaimsTransformer.cs runs with every single page request. Set a breakpoint within the method and code execution will stop every time you navigate to a page in the web app. The real implementation of the Authenticate method will most likely involve some expensive DB lookup which then also runs with every page request. That’s of course not maintainable.

How can we solve that problem? By caching the outcome of the Authenticate method in a built-in authentication session.
That’s what we’ll look at in the next blog post.

You can view the list of posts on Security and Cryptography here.

Advertisements

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

11 Responses to Claims-based authentication in MVC4 with .NET4.5 C# part 1: Claims transformation

  1. Vinney Kelly says:

    Thanks for this really detailed account! I’m bookmarking this page for sure 🙂

  2. nenke says:

    I just tried the example, but for me NameIdentifier could not be found.
    So I just changed to
    AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Name;
    instead of
    AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;

  3. M.P says:

    Nice article! thanks.

  4. Matt says:

    Hi Andras,

    Thanks for putting this series together, I’ve been following along to build up the authentication and authorization module(s) of an intranet app I am building. One quick question:

    Do you suggest that claims be stored in the database? We are first authenticating against AD using Forms Authentication, and from there we will need to handle authorization at the Identity/User level. Your thoughts on this type of setup would be appreciated!

    • Andras Nemes says:

      Hi Matt,
      I haven’t worked with AD and intranet apps before so I cannot really speak from experience. It probably depends on if you can add custom claims to AD directly. If not then storing claims in a database is always a good option, so I would go with that.
      //Andras

      • Matt says:

        Andras,

        Thanks for the fast reply!

        In our situation, we have little control over AD directly so the next option is to “decorate” our authenticated users with custom claims specific to the application. I am now wondering the best way to store this information in a data store for maximum scalability. I am thinking I could simply store a list of resources and actions in the database, link them to our users table, and call it a day (the application would query this at run time to build out the identity model). Then, my controller / api controller methods could be tagged with the authorize attribute accordingly. Do you think that might work, or is it too simplistic?

      • Andras Nemes says:

        Matt,

        That sounds like a good strategy. A claims-based solution doesn’t need to be any more difficult than storing the claims in the data store. We put all our claims in different tables in our database (MS SQL) as well and access is quick. There’s a service that collects the claims based on the username. You can check out my post on how claims are set up in MVC 5. It is nothing more than storing the keys and the values.

        You can put the claims in your database as you’ve described and then load test the application to see if claims extraction causes a bottleneck. If it does then you can e.g. optimise the query, add caching etc., but storing claims in a database is always option #1 I think. The next step is to decide on factors such as the database type – MS SQL? MongoDb? Oracle? – , the need for short-term caching, query optimisation by way of stored procedures etc.

        //Andras

  5. mandarpatki says:

    Hi Andras,
    Excellent article,
    However I am stuck at one critical point in this implementation.

    In Application_Authenticate(), I am literally authenticating the request by checking header set by calling application. If it fails to read expected values from header, then I want to redirect to Unauthorized page. To redirect to Unauthorized (Response.RedirectToRoute(“UnAuthRoute”)) I have created hard coded route as /

    However, it again enters Application_Authenticate(). Now, I don’t have any logic to execute hence I simply “return” if Request.RawUrl is for Unauthorize.
    The moment “return” executed, it again!?? enters Application_Authenticate() with Request.RawUrl as /Account/Login?ReturnUrl=%2f%2f

    I have no clue how to handle this.

    I tried with removing setting from web.config and also by setting it up to “None”.

    Please guide.

    Thanks,
    Mandar

  6. Pingback: Custom Claims-based Windows Authentication in ASP.net MVC 5 « My Tech Notes My Tech Notes

  7. magiak says:

    //Much better solution if you dont want to lose incoming principal.
    private ClaimsPrincipal DressUpPrincipal(String userName, ClaimsPrincipal incomingPrincipal)
    {
    // Get claims
    ((ClaimsIdentity)incomingPrincipal.Identity).AddClaims(claims);
    return incomingPrincipal;
    }

  8. Pingback: Persist Claims Transformation in a cookie with MVC and OWIN - Matt DuFeu

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

ultimatemindsettoday

A great WordPress.com site

Elliot Balynn's Blog

A directory of wonderful thoughts

Robin Sedlaczek's Blog

Developer on Microsoft Technologies

HarsH ReaLiTy

A Good Blog is Hard to Find

Softwarearchitektur in der Praxis

Wissenswertes zu Webentwicklung, Domain-Driven Design und Microservices

the software architecture

thoughts, ideas, diagrams,enterprise code, design pattern , solution designs

Technology Talks

on Microsoft technologies, Web, Android and others

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

Anything around ASP.NET MVC,WEB API, WCF, Entity Framework & AngularJS

Cyber Matters

Bite-size insight on Cyber Security for the not too technical.

Guru N Guns's

OneSolution To dOTnET.

Johnny Zraiby

Measuring programming progress by lines of code is like measuring aircraft building progress by weight.

%d bloggers like this: