通过 SSL 使用 .net 核心 TestHost/TestServer 调用第三方容器:使用 Testservers CreateClient() 方法绕过 SSL 验证

Calling thirdparty container with .net core TestHost/TestServer via SSL: Bypass SSL Validation using Testservers CreateClient() method

我正在尝试使用 dotnet-testcontainers 库将 keycloak 作为测试容器添加到我的 .net 核心 (5) 集成测试中。

我的问题是,我在使用自签名证书和 TestServer-Class 进行集成测试的容器的 HTTPS 支持上苦苦挣扎。

准确地说,我正在使用 Microsofts TestServer class 创建真实的 API 请求,其中包含一个内存配置,用于使用带有公开端口 8443 的 keycloak-testcontainer 及其自签名证书.

问题是:我无法将 HttpClientHandler 添加到 TestServers HttpClient(通过 serverCreateClient() 创建)以允许在此处理程序中使用不受信任的证书。我创建了一个具体示例 here on branch apitests-https. The failing test can be found here,它在 SucceedsWhenGetRequestWithTokenReturnsListOfArticles 测试方法中。我在 DemoApi 的 class 和 Startup.cs 添加了一些评论 - 显示我尝试过的项目。

因此,TestServers 内部 Jwt 中间件使用默认的 HttpClient 并抛出以下 AuthenticationException:

 ---> System.IO.IOException: IDX20804: Unable to retrieve document from: 'System.String'.
 ---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
 ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure: RemoteCertificateNameMismatch, RemoteCertificateChainErrors
   at System.Net.Security.SslStream.SendAuthResetSignal(ProtocolToken message, ExceptionDispatchInfo exception)
   at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](TIOAdapter adapter, Boolean receiveFirst, Byte[] reAuthenticationData, Boolean isApm)
   at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Boolean async, Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---

我已经尝试了很多方法来让它工作,这些在代码中有注释。

在 Api 测试中创建 TestServer-Instance 时通过 UseEnvironment("Testing") 使用它。调试显示调用了代码,但还是出现异常

所以,老实说,我对如何使用 TestServer 或其他方式使其工作有点不知所措。本质上,我需要在 BaseFixture.GetTestToken()/KeycloakTest.cs 中使用的处理程序也在我的 TestServer 实例中使用,但不能在不接受参数的 CreateClient() 中应用它。非常感谢任何帮助,它可能是解决此问题的解决方案或提示另一种方法。当有另一种方法解决这个问题时,TestServer 不一定是固定的。

好的,我解决了。恕我直言,这不是最好的解决方案,但只要我没有另一个解决方案,它就应该可行。我所要做的就是:

  1. IWebHostEnvironment 作为字段添加到 Startup.cs 并在 Startup() 构造函数中注入。

然后启动看起来像这样:

        private IWebHostEnvironment CurrentEnv { get; }

        public Startup(IWebHostEnvironment env, IConfiguration configuration)
        {
            Configuration = configuration;
            CurrentEnv = env;
        }

从这里开始,剩下的就很简单了。在我的 ConfigureServices() 方法中,我现在可以通过 CurrentEnv.IsEnvironment("Testing") 检查我是否在进行集成测试,对于这些我可以通过手动设置 jwt BackChannelHandler 来绕过 ssl 验证。

代码:

services.ConfigureJwtAuthentication(options =>
            {
                options.Audience = Configuration["Jwt:Audience"];
                options.Authority = Configuration["Jwt:Issuer"];
                options.TokenValidationParameters.ValidIssuer = options.Authority;

                if (CurrentEnv.IsEnvironment("Testing"))
                {
                    options.BackchannelHttpHandler = new HttpClientHandler()
                    {
                        ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true
                    };
                }
            });

我不得不承认,这感觉很老套,充其量我希望不需要接触任何与应用程序相关的代码来使这个测试工作。最好的解决方案是从我的 keycloak testcontainer 获取证书并将其自动添加到 TestServers Application 实例的受信任证书中。如果有人可以给出另一个答案/提示如何处理这个问题,我会很高兴看到它。但就目前而言,这是最有效的方法。