Unit Testing Custom Authorization Filter in .NET Core

“Not everything needs to be unit-tested” but you shouldn’t make the previously mentioned phrase as an excuse to not to do unit tests. When it comes to C# filters even though you’re using them your actions in the controller when doing unit-tests their execution logic will not be considered as you’re directly invoking the actions. In most cases, integration tests are performed to make sure the filters such as authorization filter ([Authorization]) and/or other attributes are taken into consideration.

In case of writing your own custom filter in some cases, as it was written by you, you are responsible to make sure that unit (the class itself which is derived from any filter interfaces (eg: IAuthorizationFilter) and Attribute abstract class) is tested.

In this post, let’s see how we can unit test a custom authorization filter, which is used to authorize an action based on a pre-defined API key which is stored in the application settings. lets start writing the unit tests. We are going to use Xunit and Moq for this purpose.

Planning the Unit Test
OnAuthorization method of the concrete implementation of our custom filter which derives from IAuthorizationFilter interface is the method that needs to be tested in the case of authorization, as this method will be invoked when the framework calls the particular action in the controller.

We can set the result of the given http context to UnauthorizedResult if the expected Authorization header is not present or present with wrong value in the action called by the client, which will eventually be the final result if over-ridden as unauthorized.

This method, as per the given definition, expects an object of type AuthorizationFilterContext as the parameter. So we need to construct the object first. The constructor of the AuthorizationFilterContext class expects two parameters:

  1. ActionContext object
  2. List of items derived from IFilterMetadata interface

Arrange

For this, we need to create an ActionContext object, while one of the constructor of the ActionContext class gives the possibility to have the HttpContext object which eventually carries the header information for authorization along with some other parameters such as route data and action descriptor. Using this constructor to construct the ActionContext will be the most suitable way as we can define the Authorization header using that.

Mocking AppSettings
Since we’re checking for the API key from the app settings, we should mock the AppSettings (consider, we have only one object in the app settings called “ApiKey”) using moq framework as below:

var optionsMock = new Mock();
optionsMock.SetupGet(o => o.Value).Returns(new AppSettings
{
  ApiKey = "mockapikey"
});

HttpContext again can be mocked to have Authorization header as below:

var httpContextMock = new Mock();
httpContextMock
  .Setup(a => a.Request.Headers["Authorization"])
  .Returns("mock WRONG apikey");

Later using the above mocked httpContextMock.Object we can create a fake ActionContext object as below:

ActionContext fakeActionContext =
new ActionContext(httpContextMock.Object, 
  new Microsoft.AspNetCore.Routing.RouteData(), 
  new Microsoft.AspNetCore.Mvc.Abstractions.ActionDescriptor());

Finally, the AuthorizationFilterContext , a fake object can be created as below:

AuthorizationFilterContext fakeAuthFilterContext =
new AuthorizationFilterContext(fakeActionContext, 
  new List { });

Act

Now we’ve arranged all the dependencies, let’s perform the “act” now by creating the custom authorization filter class as below:

public class ApiKeyAuthorizeAttribute : Attribute, IAuthorizationFilter
{
  public AppSettings AppSettings { get; set; }

  public ApiKeyAuthorizeAttribute(IOptions appSettings)
  {
    AppSettings = appSettings.Value;
  }

  public void OnAuthorization(AuthorizationFilterContext context)
  {
    var apiKey = context.HttpContext.Request.Headers["Authorization"];

    if (!apiKey.Equals(AppSettings.ApiKey))
    {
      context.Result = new UnauthorizedResult();
    }
  }
}

and calling the OnAuthorization method of our custom authorization filter by passing the already arranged authFilterContext object of the ApiKeyAuthorizeAttribute type as below:

ApiKeyAuthorizeAttribute apikeyAuthAttribute = 
  new ApiKeyAuthorizeAttribute(optionsMock.Object);
apikeyAuthAttribute.OnAuthorization(fakeAuthFilterContext);

Assert

Finally, we can perform the assert by checking if this call sets the Result of the authFilterContext , which will be the actual result of the HTTP call – to the type UnauthorizedResult as per the given logic in the custom authorization attribute since we’ve defined a different API key in the mock header than the expected one which is mocked in the App Settings mock:

Assert.Equal(typeof(UnauthorizedResult), authFilterContext.Result.GetType());

Happy Coding!

6 thoughts on “Unit Testing Custom Authorization Filter in .NET Core

  1. this code block is not working
    var optionsMock = new Mock();
    and
    var httpContextMock = new Mock();

    error says that :
    Cannot create instance of abstract type or interface ‘Mock’

  2. second line is now throwing object reference null error. Please help

    public void OnAuthorization(AuthorizationFilterContext context)
    {
    var routeData = context.HttpContext.GetRouteData();

    var controllerName = routeData?.Values[“controller”]?.ToString();
    var controller = string.IsNullOrWhiteSpace(controllerName) ? string.Empty : controllerName;

    var actionName = routeData?.Values[“action”]?.ToString();
    var action = string.IsNullOrWhiteSpace(actionName) ? string.Empty : actionName;

Leave a Reply

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

WordPress.com Logo

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

Google photo

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

Twitter picture

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

Facebook photo

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

Connecting to %s