We are experiencing some issues to mock authentication in our .NET 6 WebAPI integration testing.
The adopted approach is exactly the one described on this integration test guide from Microsoft:
factory = new WebApplicationFactory<Startup>();
var client = factory.WithWebHostBuilder(builder =>
{
builder
.UseTestServer()
.ConfigureTestServices(services =>
{
services.AddAuthentication("Test")
.AddScheme<AuthenticationSchemeOptions, TestAuthHandler>(
"Test", options => {});
});
})
.CreateClient(new WebApplicationFactoryClientOptions
{
AllowAutoRedirect = false,
});
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Test");
var result = await client.GetAsync($"{client.BaseAddress}/api/mycontroller/{par1}/{par2}");
Please note that the mocked authentication schema "Test" is set as the default one in the client authorization header.
And this is how the authentication handler is defined:
public class TestAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
public TestAuthHandler(IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
: base(options, logger, encoder, clock)
{
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
var claims = new[] { new Claim(ClaimTypes.Name, "Test user") };
var identity = new ClaimsIdentity(claims, "Test");
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, "Test");
var result = AuthenticateResult.Success(ticket);
return Task.FromResult(result);
}
}
The API method has the [Authorize] attribute and works fine with production client code (default bearer tokens setup) authenticated requests.
On test execution, the result of GetAsync call is 302. This is expected for unauthenticated calls, since redirect was disabled during test setup.
Question is why mocked authentication handler (HandleAuthenticateAsync method) is not called?
If I explicitly authorize "Test" schema on the WebAPI, then authentication is properly called.
//[Authorize]
[Authorize(AuthenticationSchemes = "Test")]
I have also tried to temporarily remove authentication from the startup class, but could not see any effect.
Can someone please help understand why mocking is not working here?
What else could I check or try so I can properly mock authentication?
While looking for a solution, I came across this related issue.
Despite not exactly my use case, I got a hint about missing authorization. So I did the web application factory creating by:
var client = factory.WithWebHostBuilder(builder =>
{
builder
.UseTestServer()
.ConfigureTestServices(services =>
{
services.AddAuthentication("Test")
.AddScheme<AuthenticationSchemeOptions, TestAuthHandler>(
"Test", options => { });
services.AddAuthorization(opts =>
{
opts.DefaultPolicy = new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes("Test")
.RequireAuthenticatedUser()
.Build();
});
});
})
.CreateClient(new WebApplicationFactoryClientOptions
{
AllowAutoRedirect = false,
});
That seems to be enough. At least my sample test cases now passes and I can debug through the TestAuthHandler. Sample repo is now updated.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With