Search
Close this search box.

Implement custom Claim based Authorization in ASP.NET MVC Web Application

To download the source code please click here

Introduction

Claim-based authorization is a new model of authorization introduced in Windows Communication Foundation. This model addresses more scenarios than the popular role based  security model (IIdentity, IPrincipal). This is useful when an application requires complex and fine grained control on expressing access control decisions. Role based security model may not be powerful or flexible enough and is often too coarse when we reach complex scenarios – where custom roles are often necessary to represent different combinations of permissions or rights. For example – if you wanted to build a simple patient list page and wanted to have access control on CRUD operations based on roles you will end up creating several roles to support different combinations of access rights i.e. Administration clerks can only Add and Edit a patient but not Delete. Where the Supervisor can Add, Edit and Delete Patients. However you may want to restrict a Supervisor from certain access rights and then – end up creating custom roles depending on particular use cases. Claim based authorization framework attempts to address these limitations by providing a more generic model capable of addressing heterogeneous credential types, the ability to specify authorization policies through configuration at deployment time, and the flexibility to express arbitrary access control decisions based on the available evidence. .NET Framework starting in version 3.0 introduced a new identity and access-control API and can be found in the System.IdentityModel assembly and namespace.

Some of the terms and concepts that we need to get familiar with when we talk about claim based authorization – are: Claim, ClaimSet and IAuthorizationPolicy.

Claim : A claim is a piece of information that describes an individual right or action applicable to a particular resource. A claim consists of three pieces of information: a claim type, resources and right. The datastructure is represented by a class System.IdentityModel.Claims.Clam.

ClaimSet: A claim set is an enumeration of claims with a common issuer.

IAuthorizationPolicy: Authorization policyis an extensiblility point which allows new claim sets to be added to the context representing the web service or application. Claims are added to an EvaluationContext by authorization policies.

For more information please check “A Guide to Claims-Based Identity and Access Control” and “Building a Claims-Based Security Model in WCF”.

Claims are flexible and can be assigned based on authenticated users or authenticated user’s roles, although claims are guaranteed by a trusted issuer, which has added security benefits. The association between claim and the resources to which it grants rights seems to be more useful as it rarely changes, and the rules for how users and roles are assigned claims can freely change without impacting any authorization logics. For example one can design – Create, Read, Edit, Delete claims for Patients and can assign them to preferred list of users or roles freely.

FictitiousHospital.com

Today we will look at building custom Claim based Authorization in a ASP.NET MVC application. For this discussion I will keep the application requirements simple – we will build a simple patient list page that lists inpatients and outpatients – however when an user is not authenticated the patient list page do not display the user the options to create, edit or delete patients.

Fig 1 : FictitiousHospital.com

To build this application we will use the ASP.NET Membership and FormsAuthentication – to authenticate users. Then we will implement a custom authorization policy (that implements the type IAuthorizationPolicy ) to serve a “Issuer” and the “set of claims” that can be attached to the securitycontext. Finally we will hook up the claim based security model within the ASP.NET MVC by extending different parts of the MVC Framework.

Authentication

The project template of ASP.NET MVC Web Application ships with some basic pages for authentication, e.g. Login, Registration, Change Password etc. including the web.config file configured with ASP.NET Membership provider and FormsAuthentication. This is handy as the application is already configured and ready to use with Authentication in place. Just a change of connectionstring that points to the correct aspnetdb database makes us ready to start Authenticating the users and we can start concentrate on the next step – Authorization.

Fig 2: web.config

Fig 3: FormsAuthenticationService

Authorization

The first thing to identify is to what types of claims make sense for our fictitioushospital.com website. Lets think of claims as permissions that are required to access the features. If we consider patients as resources we may have (CRUD) permissions like Patient Create, Patient View, Patient Edit and Patient Delete. So the possible list of claims may be:

1. Patient Create

Right: http://schemas.xmlsoap.org/ws/2005/05/identity/right/possessproperty

Claim Type: http://schemas.fictitioushospital.com/2010/02/identity/claims/create

Resources: http://schemas.fictitioushospital.com/2010/02/identity/resources/patients

2. Patient View

Right: http://schemas.xmlsoap.org/ws/2005/05/identity/right/possessproperty

Claim Type: http://schemas.fictitioushospital.com/2010/02/identity/claims/read

Resources: http://schemas.fictitioushospital.com/2010/02/identity/resources/patients

3. Patient Edit

Right: http://schemas.xmlsoap.org/ws/2005/05/identity/right/possessproperty

Claim Type: http://schemas.fictitioushospital.com/2010/02/identity/claims/update

Resources: http://schemas.fictitioushospital.com/2010/02/identity/resources/patients

4. Patient Delete

Right: http://schemas.xmlsoap.org/ws/2005/05/identity/right/possessproperty

Claim Type: http://schemas.fictitioushospital.com/2010/02/identity/claims/delete

Resources: http://schemas.fictitioushospital.com/2010/02/identity/resources/patients

To work with these claims in code we define list of representative constants as follows:

Fig 4: Resources

Fig 5: ClaimTypes

We have already established our requirements for claims-based authorization for our fictitioushospital.com and now we are going to write an implementation of type System.IdentityModel.Policy.IAuthorizationPolicy interface (i.e. CustomAuthorizationPolicy). This interface requires us to implement properties, Id of type string, Issuer of type ClaimSet and the Evaluate() method that returns bool.

Fig 6: IAuthorizationPolicy interface

Fig 7: CustomAuthorizationPolicy

The CustomAuthorizationPolicy implements necessary interface. The Id property returns an unique identifier. The issuer property returns ClaimSet describing the issuer associated with this authorization policy, note that we have used issuerName = http://www.fictitioushospital.com/2010/02/issuer here. Finally the Evaluate() method that is the most important part of this implementation is responsible to inspect the claims based on the credentials provided.

Fig 6: Evaluate() method

Here we have written some code that decides to attach Create, Read, Update and Delete claims to the evaluationContext when the user is authenticated otherwise only attaches the Read claim. We can implement different other ways to figure out the associated claims for the particular User.Identity e.g. based on roles or based on predefined access rights that is stored in database or xml.

The hard part is quite done – now we have to hook up this CustomAuthorizationPolicy into our ASP.NET MVC pipeline to start performing claim based authorization. Step 1: to do this we start by defining our custom IUser interface that extends IPrincipal interface and wraps an extra property named “Issuer” of type ClaimSet within, that is intended to carry the Issuer details returned from the CustomAuthorizationPolicy.

Fig 8: IUser interface

Step 2: we implement the User class of our custom IUser interface.

Fig 9: User

Step 3: we implement a custom authorization filter of type System.Web.Mvc.IAuthorizationFilter interface. OnAuthorization() we instantiate our custom User (that implements IPrincipal) using the information obtained from “filterContext.HttpContext.User.Identity”. Then we create a list of AutorizationPolicy and add our CustomAuthorizationPolicy to create a default instance of AuthorizationContext (authContext), this under the hood goes and call the Evaluate() method of CustomAuthorizationPolicy and populates the authContext.ClaimSets. Then we iterate through the authContext.ClaimSets and locate the issuer that we are interested in and assign the issuer to our custom User object. We then replace the HttpContext.User and Thread.CurrentPrincipal with our custom User. Please also note that we keep the customUser in Session() to avoid repeatative calls to retrieve the claimSet on every single request. A ClaimSet may be retrieved from database and this may be an expensive call to perform on every single request, populating it once and storing it in session seems feasible.

Fig 10: AuthorizationFilter

Step 4: we add this custom AuthorizationFilter in the controllers AuthorizationFilters list  by extending the ControllerActionInvoker.

Fig 11: CustomControllerActionInvoker

The default implementation of IActionInvoker is ControllerActionInvoker and does quite a bit behind the scene. Firstly it obtains parameter values for the parameters on the action methods using the ModelBinder and then it executes various filters. There are different types of filters:

Authorization Filter – IAuthorizationFilter interface
Action Filter – IActionFilter interface
Result Filter – IResultFilter interface
Exception Filter – IExceptionFilter interface

and out of them Authorization filter is the first set of filters to be executed. This is where our custom AuthorizationFilter will get executed and that will replace the IPrincipal user identity with our custom custom User that we discussed above.

Step 5: we extend the DefaultControllerFactory and implement CustomControllerFactory, that assigns the controller.ActionInvoder to an instance of CustomControllerActionInvoker instead of  the ControllerActionInvoker.

Fig 12. CustomControllerFactory

Step 6: we tell our Mvc ControllerBuilder.Current.SetControllerFactory() to use the extended CustomControllerFactory insead of the default DefaultControllerFactory, and we normally do this once during the Application_Start as following.

Fig 13: Application_Start

Step 7: finally we are ready to check for claims during our Action invocation. Consider the PatientController, Index() action that returns list of patients. However this checks whether callers are granted to the Create, Edit and Delete role using the issuer.ContainsClaim() method and populates the PatientViewModel s CanCreate, CanEdit and CanDelete property, and the viewModel object is passed to the View.

Fig 14: PatientController Index() action.

Later on by checking the PatientViewModels properties in the View one can easily decide on what links to display or not.

Fig 15: View

I have mentioned earlier that the association between claim and resources are highly unlike to change frequently. Consider this example where the Create() action demands the PatientClaims.PatientCreate Claim before this allows to create a new Patient, and similar with Update() action where it demands the PatientClaims.PatientUpdate claim. And thus the rules for how users and roles are assigned claims can freely change without impacting any the authorization logics.

Fig 16 Create, Update example

Claims-Based Permission Demands

You can take this further and implement Claims-Based Permission Demands, thus you will be able to write something like this:

[CreatePatientsClaim(SecurityAction.Demand)]
public void Create()

{
  // protected code
}

[UpdatePatientsClaim(SecurityAction.Demand)]
public void Update()

{
  // protected code
}

[DeletePatientsClaim(SecurityAction.Demand)]
public void Delete()

{
  // protected code
}

Permission demands are implemented with the PrincipalPermission or PrincipalPermissionAttribute and relies on the security principal attached to the executing thread to authorize calls. The idea is that when the permission demand is invoked the security principal attached to the request thread checks necessary values. Like with the PrincipalPermission type, you can write your own custom implementation of ClaimsPrincipalPermission that implements IPermission, ISecurityEncodable and IUnrestrictedPermission interface. This article “Building a Claims-Based Security Model in WCF – Part 2” by Michele Leroux Bustamente explains this in great detail.

Conclusion

Here we looked at how to implement claims-based security model in an ASP.NET MVC application. So how all this works in ASP.NET MVC according to the above implementation is,

  1. OnApplication_Start we SetContollerFactory to use CustomControllerFactory.
  2. CustomControllerFactory assigns instance of CustomControllerActionInvoker to the controller.ActionInvoker property of every controller instances.
  3. CustomControllerActionInvoker adds our AuthorizationFilter to the controllers AuthorizationFilters list.
  4. OnAuthorization of AuthorizationFilter is always invoked as the first thing during “InvokeAction()”. This calls the CreateDefaultAuthorizationContext() passing the list of  IAuthorizationPolicies, i.e. the CustomAuthorizationPolicy. The CustomAuthorizationPolicy instantiates itself with an unique Id.
  5. The Evaluate method of the CustomAuthorizationPolicy is called and that retrieves the ClaimSet for particular issuer for a particular user.
  6. A custom user is created of type User (that implements IUser –> IPrincipal ). This custom user is assigned to the HttpContext.User and Thread.CurrentPrincipal.
  7. The controller gets the custom user ( of type User – that implements IUser –> IPrincipal ) in its context.
  8. The action methods decides on access rights using the User.Issuer.ContainClaims() method.

Claim based authorization model is not to replace the role based authorization model and in many cases role based authorization may turn out to be more than sufficient. Claim based authorization models definitely supports more complex scenarios and allows fine grained control on expressing access control decision. Thank you for being with me so far and I hope that this discussion will help you in some way during your implementation of claims based security model. Happy coding!

This article is part of the GWB Archives. Original Author: Shahed Khan

Related Posts