joydip_kanjilal
Contributor

How to bypass security in integration tests in ASP.Net Core

how-to
Feb 11, 20197 mins
App TestingC#Microsoft .NET

Take advantage of fake authentication/authorization checks to simplify integration tests in ASP.Net Core

Integration tests are used to check if the different parts of the application work as expected when they are assembled together. When working with integration tests, you will often want to skip authentication and authorization tests. For instance, you might be more interested in testing the controller methods, without authentication and authorization getting in the way.

In this article I will discuss how we can bypass such security checks when working with integration tests in ASP.Net Core.

Who needs secure integration tests?

You will often need to write integration tests for controller methods that have the [Authorize] tag on them. Let’s say that you are hitting an identity provider (that resides on another server) with this attribute. The problem is that your integration tests might fail if the identity server is down.

As such, it would be a good practice to bypass the authentication checks when running integration tests on the controller methods. After all, you want to test the application pipeline and not the availability of an external server. In the sections that follow, we will examine how we can bypass the [Authorize] attribute in integration tests.

Create an ASP.Net Core Web API project in Visual Studio

First off, let’s create an ASP.Net Core project. If Visual Studio 2017 is up and running in your system, follow the steps given below to create a new ASP.Net Core project in Visual Studio.

  1. Launch the Visual Studio 2017 IDE.
  2. Click on File > New > Project.
  3. Select “ASP.Net Core Web Application (.Net Core)” from the list of the templates displayed.
  4. Specify a name for the project.
  5. Click OK to save the project.
  6. A new window “New .Net Core Web Application…” is shown next.
  7. Select .Net Core as the runtime and ASP.Net Core 2.2 (or later) from the drop-down list at the top.
  8. Select API as the project template
  9. Ensure that the check boxes “Enable Docker Support” and “Configure for HTTPS” are unchecked as we won’t be using those features here.
  10. Ensure that “No Authentication” is selected as we won’t be using authentication either.
  11. Click OK.

This will create a new ASP.Net Core Web API project in Visual Studio.

bypassauthenticationinintegrationtests figure 1 IDG

Add authentication to the ConfigureServices method in ASP.Net Core

The Startup class in the Startup.cs file contains the ConfigureServices method. Note that the ConfigureServices method is called by the runtime—you can take advantage of this method to add services to the pipeline. Next, write the following code in the ConfigureServices method of the Startup.cs file.

 public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(options =>
            {
                options.Authority = "abcxyz.com";
                options.Audience = "abcxyz.com";
            });           
        }

Create a controller method in ASP.Net Core

Now create a controller named DefaultController that contains the following code.

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace BypassAuthentication.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class DefaultController : ControllerBase
    {
        [HttpGet]
        public string Get()
        {
            return "Hello World!";
        }
    }
}

We will take advantage of this controller to write integration tests later.

Create a test project in ASP.Net Core

Now that the ASP.Net Core Web API project has been created, let’s create a test project to write our integration tests. To do this, follow the steps given below.

  1. In the Visual Studio IDE, click on File > New > Project.
  2. Select .Net Core from the list of installed templates. 
  3. Select “xUnit Test Project (.Net Core)” from the list of templates displayed. 
  4. Specify a name for the project.
  5. Click OK to save.

Add the TestHost package to your test project in ASP.Net Core

ASP.Net Core includes a test host that you can add to your integration test projects via NuGet. The TestHost package provides you with an ASP.Net Core Web Server that you can take advantage of to write and execute tests.

To install the TestHost package, select the integration test project in the Solution Explorer window, right click, and select “Manage NuGet Packages…”. Then click on Browse, search for “Microsoft.AspNetCore.TestHost” package, and install the package. You should also install the Microsoft.AspNetCore.Diagnostics and Microsoft.AspNetCore.Mvc packages from NuGet (see the screen image below).

bypassauthenticationinintegrationtests figure 2 IDG

Create integration tests in your ASP.Net Core test project

When you created the test project in ASP.Net Core in the step above, a test class will be created in the project automatically. Replace the test class created by default with the following code.

public class MyTests
    {
        private readonly TestServer testServer;
        private readonly HttpClient httpClient;
        public MyTests()
        {
            testServer = new TestServer(new WebHostBuilder()
            .UseStartup<Startup>());
            httpClient = testServer.CreateClient();
        }
        [Fact]
        public async Task GetMessageTestAsync()
        {
            var response = await httpClient.GetAsync("http://localhost:13022/api/default");
            response.EnsureSuccessStatusCode();
            var result = await response.Content.ReadAsStringAsync();
            Assert.NotNull(result);
        }
    }

Note the usage of the TestServer and how the httpClient instance is configured in the constructor. The GetMessageTestAsync test method will run fine as long as there is no [Authorize] attribute on the controller or the controller method.

However, if the controller or the controller method has an [Authorize] tag, the GetMessageTestAsync test method will fail, stating that you are unauthorized to call the Get method of the controller. Let’s now examine how we can bypass this security check when running integration tests.

Bypass the authentication/authorization check in ASP.Net Core

To bypass the authentication/authorization check, we need to create a dummy Startup class. To do that, we should create a class that extends the Startup class and overrides its methods. First off, we should reorganize the ConfigureServices method so that we can override it later. Here’s the updated version of the ConfigureServices method.

public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
            ConfigureAuthentication(services);
        }
        protected virtual void ConfigureAuthentication(IServiceCollection services)
        {
            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(options =>
            {
                options.Authority = "abcxyz.com";
                options.Audience = "abcxyz.com";
            });
        }

Create a dummy Startup class in your ASP.Net Core test project

In the test project, create a dummy Startup class as shown in the code snippet given below.

public class FakeStartup : Startup
    {
        public FakeStartup(IConfiguration configuration) : base(configuration)
        {
        }
        protected override void ConfigureAuthentication(IServiceCollection services)
        {
            //Write your implementation of fake authentication here
        }
    }

Next, you should update the constructor of the MyTests class (this is our test class) with the following piece of code. Note that the TestServer now uses the FakeStartup class.

public MyTests()
        {
            testServer = new TestServer(new WebHostBuilder()
            .UseStartup<FakeStartup>());
            httpClient = testServer.CreateClient();
        }

Create a custom authentication handler class to fake authentication

Note that the test will still fail if you run it now because the authentication middleware hasn’t been specified in the FakeStartup class. To achieve this, you should create a custom authentication handler class that extends the AuthenticationHandler class and overrides the HandleAuthenticateAsync method. It is in this method that you can approve or reject an authentication request.

Lastly, you should specify the custom authentication middleware in the FakeStartup class we created earlier. I will leave this part for you to implement on your own.

And that’s all you need to do! Your integration tests will now run perfectly as the security checks will be bypassed.

Integration tests often need to take advantage of infrastructure concerns—database resources, file system resources, web requests and responses, etc. As such, you will not want your integration tests to check for authentication/authorization, especially if your security framework resides in an external server. By creating a dummy Startup class and dummy authentication middleware, you can get the job done. 

joydip_kanjilal
Contributor

Joydip Kanjilal is a Microsoft Most Valuable Professional (MVP) in ASP.NET, as well as a speaker and the author of several books and articles. He received the prestigious MVP award for 2007, 2008, 2009, 2010, 2011, and 2012.

He has more than 20 years of experience in IT, with more than 16 years in Microsoft .Net and related technologies. He has been selected as MSDN Featured Developer of the Fortnight (MSDN) and as Community Credit Winner several times.

He is the author of eight books and more than 500 articles. Many of his articles have been featured at Microsoft’s Official Site on ASP.Net.

He was a speaker at the Spark IT 2010 event and at the Dr. Dobb’s Conference 2014 in Bangalore. He has also worked as a judge for the Jolt Awards at Dr. Dobb's Journal. He is a regular speaker at the SSWUG Virtual Conference, which is held twice each year.

More from this author