Вызов стороннего контейнера с помощью TestHost/TestServer ядра .net через SSL: Обойти проверку SSL с помощью метода Testservers CreateClient()
Я пытаюсь добавить keycloak в качестве testcontainer к моим интеграционным тестам .net core (5) с использованием библиотеки dotnet-testcontainers .
Моя проблема в том, что я борюсь с поддержкой HTTPS, имеющей контейнер, использующий самозаверяющие сертификаты и TestServer-Class для моих интеграционных тестов.
Чтобы быть точным, я использую класс Microsofts TestServer для создания реальных запросов API с конфигурацией в памяти для использования keycloak-testcontainer с открытым портом 8443 и его самозаверяющим сертификатом.
Проблема в том, что я не могу добавить
HttpClientHandler
в TestServers HttpClient(созданный через
serverCreateClient()
), чтобы разрешить недоверенные сертификаты в этом обработчике. Я создал конкретный пример здесь, в ветке apitests-https. Неудачный тест можно найти здесь , в
SucceedsWhenGetRequestWithTokenReturnsListOfArticles
Метод испытания. Я добавил несколько комментариев к классу и Startup.cs DemoApi - Project, который показывает, что я пробовал.
В результате внутреннее промежуточное ПО Jwt TestServers использует 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 ---
Я уже пробовал несколько вещей, которые прокомментированы в коде, чтобы заставить его работать.
DemoApi/Startup.cs
: Пытался добавить мою собственную среду "Тестирования" со следующим кодом:ServicePointManager.Expect100Continue = true;ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls| SecurityProtocolType.Tls11| SecurityProtocolType.Tls12;ServicePointManager.ServerCertificateValidationCallback +=(отправитель, сертификат, цепочка, sslPolicyErrors) => true;
используя это через
UseEnvironment("Testing")
при создании TestServer-Instance в Api Test. Отладка показывает, что код вызывается, но все же возникает исключение.
-
DemoApiTestsApi/BaseFixture.cs
илиDemoApiTests/Infrastructure/Persistence/KeycloakTest.cs
: См. Здесь рабочую реализацию моего собственного HttpClient с обработчиком для получения токена в целом (это работает в ветке) -GetTestToken
это метод в BaseFixture.
Итак, честно говоря, у меня немного нет идей, как заставить это работать с 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")
если я нахожусь в интеграционном тесте, и для этого я мог бы обойти проверку ssl, установив jwt BackChannelHandler вручную.
Код:
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
};
}
});
Я должен признать, что это кажется хакерским, и в лучшем случае мне бы хотелось не трогать какой-либо код, связанный с приложением, чтобы этот тест работал. Лучшим решением было бы получить сертификат из моего testcontainer keycloak и автоматически добавить его в доверенные сертификаты экземпляра TestServers Application. Если бы кто-нибудь мог дать другой ответ / намек, как с этим справиться, я был бы рад это увидеть. Но пока это то, что работает лучше всего.