Windows Identity Foundation (WIF) By Example Part III – How To Implement Claims Based Authorization For ASP.NET Application

This post is based on what I am reading now in Vittorio’s new book Programming Windows Identity Foundation (Dev - Pro).

To complete this example I assume you have working claims aware ASP.NET application. If you do not – complete one of these before you proceed (15 minutes or less):

The rest of the post is a step-by-step walkthrough of creating claims based authorization for existing claims aware ASP.NET Web Application. Summary of steps:

  • Step 1 – Implement Claims Authorization Library
  • Step 2 – Configure ASP.NET Application to use the Claims Authorization Library
  • Step 3 – Configure Authorization Policy
  • Step 4 – Test your work

Step 1 – Implement Claims Authorization Library

  • Make sure you run Visual Studio in Administrator mode.
  • Right click on the solution in Solution Explorer and add new Class Library project. Give it a name, for example, MyClaimsAuthorizationManager.
  • Delete default Class1.cs.
  • Add new class and give it a name, for example, ZipClaimsAuthorizationManager. I will implement an authorization based on postal codes.
  • Add reference to Microsoft.IdentityModel and to System.Web assemblies.
  • Add the following using declarations

using System.IO;
using System.Xml;
using Microsoft.IdentityModel.Claims;
using Microsoft.IdentityModel.Configuration;

  • Extend  ClaimsAuthorizationManager  class overriding its AccessCheck method and implementing a constructor to your ZipClaimsAuthorizationManager class. Your code should look similar to this:

namespace MyClaimsAuthorizationManager
{
    class ZipClaimsAuthorizationManager : ClaimsAuthorizationManager
    {
        private static Dictionary<string, int> m_policies = new Dictionary<string, int>();

public ZipClaimsAuthorizationManager(object config)
        {
            XmlNodeList nodes = config as XmlNodeList;
            foreach (XmlNode node in nodes)
            {
                {
                    //FIND ZIP CLAIM IN THE POLICY IN WEB.CONFIG AND GET ITS VALUE
                    //ADD THE VALUE TO MODULE SCOPE m_policies
  XmlTextReader reader = new XmlTextReader(new StringReader(node.OuterXml));
                    reader.MoveToContent();
                    string resource = reader.GetAttribute("resource");
                    reader.Read();
             string claimType = reader.GetAttribute("claimType");
                    if (claimType.CompareTo(ClaimTypes.PostalCode) == 0)
                    {
                        throw new ArgumentNullException("Zip Authorization is not specified in policy in web.config");
                    }
                    int zip = -1;
                    bool success = int.TryParse(reader.GetAttribute("Zip"),out zip);
                    if (!success)
                  {
                        throw new ArgumentException("Specified Zip code is invalid - check your web.config");
                    }
                    m_policies[resource] = zip;
                }
            }
        }

        public override bool CheckAccess(AuthorizationContext context)
        {
            //GET THE IDENTITY
            //FIND THE POSTALCODE CLAIM'S VALUE IN IT
            //COMPARE WITH THE POLICY
            int allowedZip = -1;
            int requestedZip = -1;
            Uri webPage = new Uri(context.Resource.First().Value);
            IClaimsPrincipal principal = (IClaimsPrincipal)HttpContext.Current.User;
            if (principal == null)
            {
                throw new InvalidOperationException("Princiapl is not populate in the context - check configuration");
            }
            IClaimsIdentity identity = (IClaimsIdentity)principal.Identity;
            if (m_policies.ContainsKey(webPage.PathAndQuery))
            {
                allowedZip = m_policies[webPage.PathAndQuery];
                requestedZip = -1;
                int.TryParse((from c in identity.Claims
                                        where c.ClaimType == ClaimTypes.PostalCode
                                        select c.Value).FirstOrDefault(), out requestedZip);
            }
            if (requestedZip!=allowedZip)
            {
                return false;
            }
            return true;
        }
    }
}

  • Compile the solution to make sure there is no compilation errors.
  • Locate the compiled library, in my case MyClaimsAuthorizationManager.dll. It will need to be dropped into bin folder of the ASP.NET web application.

Step 2 – Configure ASP.NET Application to use the Claims Authorization Library

To proceed further you need to to have working Claims Aware ASP.NET application. Consider these walkthroughs to quickly build one:

Next steps are performed in your ASP.NET web application. Do not add reference to your Claims Authorization Manager library you created in previous step. Your ASP.NET web application should be “unaware” of it except web.config.

  • Configure your ASP.NET web application to include WIF’s ClaimsAuthorizationModule in its pipeline by adding the following entry to HttpModules section in web.config (valid for development web server that ships with Visual Studio, for IIS7 it is modules section under system.webServer node)

<add name="ClaimsAuthorizationModule"
     type="Microsoft.IdentityModel.Web.ClaimsAuthorizationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

Step 3 – Configure Authorization Policy

SelfSTS used for ASP.NET claims based authoprization

  • Click save and then click on big green Start button so it turns red.
  • Configure the ASP.NET application to use your newly developed authorization manager by adding the following section to  service node that is located inside microsoft.identityModel node.
  • Add authorization policy to express what Zip code is allowed to access the site, the result should look similar to this:

<claimsAuthorizationManager type="MyClaimsAuthorizationManager.ZipClaimsAuthorizationManager, MyClaimsAuthorizationManager" >
  <policy resource="/default.aspx">
    <claim claimType="https://schemas.xmlsoap.org/ws/2005/05/identity/claims/postalcode" Zip="11111" />
  </policy>
</claimsAuthorizationManager>

Step 4 – Test your work

  • Notice that in previous step the claim that’s being issued for me by SelfSTS has the value of 12345 and the policy requires Zip’s value of 11111.
  • Run the application by pressing Ctrl+F5.
  • Assuming that the start page is default.aspx you should get blank screen.
  • Now configure either the policy in web.config or the postalcode claim issued by SelfSTS to the same value and run the application once again, you should see the default.aspx page code executed and produces expected results, similar to the following:

Claims Based AAuthorization for ASP.NET application in action

Notice, this exercise is not complete authorization solution – it only showcases the technology and how its pieces worlk altogether.

More Info