JonPSmith / AuthPermissions.AspNetCore

This library provides extra authorization and multi-tenant features to an ASP.NET Core application.
https://www.thereformedprogrammer.net/finally-a-library-that-improves-role-authorization-in-asp-net-core/
MIT License
770 stars 158 forks source link

Needs example of sociable unit testing/integration testing using WebApplicationFactory<Startup> #6

Closed kcaswick closed 2 years ago

kcaswick commented 2 years ago

I've been unable to figure out how to mock authenticate in my existing sociable unit tests that use CustomWebApplicationFactory<Startup> to create a TestServer. They were working fine with role based authorization.

I tried following example 2 in Unit Test your AuthP app, and while that was working for getting services from factory.Services, it is not working when using factory.CreateClient().GetAsync("url").

I thought I could use a token created like in TestGenerateJwtTokenAsyncOk as a bearer token, but once I finally got the token generated, I got status code Unauthorized, WWW-Authenticate: Bearer error="invalid_token", error_description="The signature key was not found"

My Startup is applying the following configuration for this service:

            services.RegisterAuthPermissions<Permissions>()
                .AzureAdAuthentication(AzureAdSettings.AzureAdDefaultSettings(true))
                //... database method left out

After that my CustomWebApplicationFactory is applying the following configuration for this service:

                services.RegisterAuthPermissions<Permissions>(opt => opt.ConfigureAuthPJwtToken = CreateTestJwtSetupData())
                        .UsingInMemoryDatabase()
                        .SetupForUnitTestingAsync();
JonPSmith commented 2 years ago

Hi @kcaswick,

I haven't tried mocking authentication so I can't really advise you, but I can see the benefits of mocking authentication. At the moment I build runnable examples, but unit tests would be great so I will try to help.

One thing I did when working on JWT Token is that the signature used for creating the token and the signature for checking the token are different, and I don't know why (which worries me) - see this here. Could that be creating your error??

Some question:

Not sure that helps but its all I have at this stage.

kcaswick commented 2 years ago

The 2 blocks are the standard, non-testing registration (in Startup.ConfigureServices), and then the testing registration (in CustomWebApplicationFactory.ConfigureWebHost). The testing registration runs second, since for the database side Microsoft's documentation has it remove the standard DbContextOptions to replace it with one configured to UseInMemoryDatabase().

I'm not certain where the error comes from, somewhere outside my code, but when I turn logging all the way up to trace I get this:

Information [1]: Failed to validate the token.
   Information [1]: Microsoft.IdentityModel.Tokens.SecurityTokenSignatureKeyNotFoundException: IDX10503: Signature validation failed. Token does not have a kid. Keys tried: 'System.Text.StringBuilder'.
Exceptions caught:
 'System.Text.StringBuilder'.
token: 'System.IdentityModel.Tokens.Jwt.JwtSecurityToken'.
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
   at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()

After adding that exception to the Break When Thrown settings, it looks like it may be coming from something configured by the AAD authentication.

Currently I've set this branch aside and I'm trying to implement my own AuthPolicy instead. In researching for that, I suspect part of the problem may be that I am not un-registering the old auth, nor using a different name for the test auth scheme. Perhaps a better path would be to skip the token entirely, and just add the claims directly via the TestAuthHandler,

JonPSmith commented 2 years ago

First thing: the exception in Microsoft's code, not AuthP code but I do wonder if its because AuthP code uses the recommended SecurityAlgorithms.HmacSha256Signature and not SecurityAlgorithms.HmacSha256. Worth a check.

Yep, this code is complex and any way you can simplify is going to help.

I'll close this for now, but if you want to reopen it again I happy to help.