How to claim role for HttpContext.User.IsInRole method check in integration test?

1000 Views Asked by At

I have following code for integration test

TestAuthenticationHandler

This handler is setting up the Test user named John Doe

public class TestAuthenticationSchemeOptions : AuthenticationSchemeOptions
{
    public string Role { get; set; }
}

public class TestAuthenticationHandler : AuthenticationHandler<TestAuthenticationSchemeOptions>
{
    public TestAuthenticationHandler(IOptionsMonitor<TestAuthenticationSchemeOptions> 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"),
            new Claim(ClaimTypes.NameIdentifier, Guid.NewGuid().ToString()),
            new Claim("MemberId", Options.Role),
            new Claim("MemberForename", "John"),
            new Claim("MemberSurname", "Doe")
        };

        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);
    }
}

Test method

This method is using the handler above to register the user and it also assign an Admin role

[Theory]
[InlineData("/home/index")]
public async Task GetServerSideRenderedPage_ReturnsOk(string url)
{
    // Arrange
    HttpClient client = _factory.WithWebHostBuilder(builder =>
    {
        builder.ConfigureTestServices(services =>
        {
            services.AddAuthentication("Test")
                    .AddScheme<TestAuthenticationSchemeOptions, TestAuthenticationHandler>("Test", 
                        options => options.Role = "Admin");
        });
    }).CreateClient();

    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Test");

    // Act
    var response = await client.GetAsync(url);

    // Assert
    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
    Assert.NotNull(response.Content);
    Assert.Equal("text/html", response.Content.Headers.ContentType.MediaType);
    Assert.True(response.Content.Headers.ContentLength > 0);
}

Startup.cs

Enabling authentication (No need for this in production)

app.UseAuthentication();   

Controller action I need to test

In production HttpContext is NOT NULL, but in test it is NULL. So I had to add IHttpContextAccessor which is populated via AuthenticationHandler (HttpContext is still NULL, but IHttpContextAccessor.HttpContext is OK)

public class HomeController : Controller
{
    private readonly IHttpContextAccessor _httpContext;

    public HomeController(IHttpContextAccessor httpContext)
    {
        _httpContext = httpContext;
    }

    [HttpGet]
    public IActionResult Index()
    {
        var allowed = _httpContext.HttpContext.User.IsInRole("Admin");

        return View();
    }
}

The issue I am facing is that allowed property is false, but I claimed the Admin role to the user.

enter image description here

In production it works because the app is running on the IIS server and the Admin role (named differently in the production) is domain security group. So the HttpContext is checking if the connected user is member of domain group, but I don't know how to fake/mock the IsInRole() method in the test. Do I have to add some additional claims in the TestAuthenticationHandler?

The settings described here works when using [Authorize(Roles = "Admin")] attribute but I also need to use the IsInRole() method.

Do you have any idea?

Solution

The missing part here was specific role claim

var claims = new[]
{
    new Claim(ClaimTypes.Name, "Test"),
    new Claim(ClaimTypes.NameIdentifier, Guid.NewGuid().ToString()),
    new Claim(ClaimTypes.Role, Options.Role), // <-- this line was missing
    new Claim("MemberId", Options.Role),
    new Claim("MemberForename", "John"),
    new Claim("MemberSurname", "Doe")
};

enter image description here

enter image description here

0

There are 0 best solutions below