Интеграционные тесты для WebApi, защищенного с помощью OATH через отдельный микросервис, на котором размещается IdentityServer.

Фон

У нас есть решение ASP.NET Core 2.1 с микросервисами, содержащими методы WebApi. Мы используем Identity Server 4 для аутентификации. У нас есть эти услуги, каждая в отдельном проекте.

  1. crm. Содержит различные методы WebAPI.
  2. мошенничество. Содержит различные методы WebAPI.
  3. уведомления. Содержит различные методы WebAPI.
  4. аутентификация. Содержит реализацию IdentityServer.

Служба аутентификации не имеет контроллера или методов WebAPI, это просто то, где настроен и реализован IdentityServer4. Ресурсы, клиенты, области и т. Д. Определены здесь, а в Startup также есть инициализация:

        // Identity Server
        services.AddIdentityServer()
            .AddSigningCredential(Configuration.GetValue<string>("Certificates:TokenCertificate"), System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine, NameType.Thumbprint)
            .AddInMemoryApiResources(Config.GetApiResources())
            .AddInMemoryClients(Config.GetClients(Configuration))
            .AddResourceOwnerValidator<ResourceOwnerPasswordValidator>()
            .AddProfileService<ProfileService>();

Наша аутентификация работает нормально, когда мы тестируем с помощью Postman, мы должны сначала подключиться к конечной точке токена службы аутентификации и запросить токен-носитель. Затем мы можем передать его в заголовке запроса авторизации, и он работает нормально.

Пришло время обновить наши интеграционные тесты, потому что все они терпят неудачу, поскольку мы внедрили аутентификацию, они возвращают статус Unauthorized, чего и следовало ожидать.

Вопрос

Как нам вызвать службу аутентификации из наших интеграционных тестов, если это отдельный микросервис?

Мы следовали стандартным методам создания интеграционных тестов для наших микросервисов. У нас есть один тестовый проект для каждого микросервиса, и один класс фикстур создает webHostBuilder, используя Startup этого микросервиса, и testServer HttpClient, который будет опрашиваться интеграционными тестами.

        var webHostBuilder = new WebHostBuilder()
               .UseEnvironment("Testing")
               .UseStartup<Startup>()
                .ConfigureTestServices(s =>
                {
                    addServices?.Invoke(s);
                })
               .ConfigureAppConfiguration((builderContext, config) =>
               {
                   Configuration = config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true).AddEnvironmentVariables().Build();
                   this.SignatureCertificate = CertificateHelper.FindCertificateByThumbprint(Configuration.GetValue<string>("Certificates:SignatureThumbprint"), StoreLocation.LocalMachine, StoreName.My);
                   this.EncryptionCertificate = CertificateHelper.FindCertificateByThumbprint(Configuration.GetValue<string>("Certificates:EncryptionThumbprint"), StoreLocation.LocalMachine, StoreName.My);
                   this.DecryptionCertificate = CertificateHelper.FindCertificateByThumbprint(Configuration.GetValue<string>("Certificates:DecryptionThumbprint"), StoreLocation.LocalMachine, StoreName.My);
                   this.ReadSignedCertificate = CertificateHelper.FindCertificateByThumbprint(Configuration.GetValue<string>("Certificates:ReadSignedThumbprint"), StoreLocation.LocalMachine, StoreName.My);
               });
        var testServer = new TestServer(webHostBuilder);

        this.Context = testServer.Host.Services.GetService(typeof(CrmContext)) as CrmContext;
        this.Client = testServer.CreateClient();

Но теперь наши интеграционные тесты должны сначала запросить токен из конечной точки токена. Но конечная точка не была запущена webHostBuilder, потому что наша интеграция с ID4 находится в отдельной службе.

Нужно ли нам создавать второй TestServer из второго WebHostBuilder, который использует запуск службы аутентификации ASP.NET Core?

Любая помощь приветствуется.


person Theo Kand.    schedule 12.07.2018    source источник


Ответы (1)


Нам пришлось создать класс фикстуры коллекции, который запускал бы отдельный WebHostBuilder с нашей службой аутентификации, и это приспособление стало доступным для всех интеграционных тестов путем внедрения его в конструктор.

Но это еще не все, когда мы вызывали методы аутентификации, тестовый сервер веб-API не мог получить доступ к серверу тестирования аутентификации. При использовании OATH для защиты веб-API этот веб-API должен иметь доступ к этому URL-адресу

http: ///.well-known/openid-configuration

Решением было использовать собственный JwtBackChannelHandler из параметров IdentityServer в конфигурации IdentityServer. Это при запуске нашего веб-API:

        //Authentication
        services.AddAuthentication("Bearer")
            .AddIdentityServerAuthentication(options =>
            {
                options.Authority = Configuration.GetValue<string>("Authentication:BaseUrl");
                options.RequireHttpsMetadata = false;
                options.ApiName = "Crm";

                if (CurrentEnvironment.IsEnvironment("Testing"))
                {
                    options.JwtBackChannelHandler = BackChannelHandler;
                }

            });

BackChannelHandler - это статическое свойство нашего веб-контроллера api, и упомянутый выше инструмент сбора аутентификации может затем использовать это статическое свойство для указания обработчика, который может использоваться для доступа к конечной точке конфигурации openid.

    public AuthenticationFixture()
    {
        //start the authentication service
        var authWebHostBuilder = new WebHostBuilder()
                .UseEnvironment("Testing")
                .UseStartup<Adv.Authentication.Api.Startup>()
                .ConfigureTestServices(s =>
                {

                    var userAccountWebServiceMock = new Mock<IUserAccountWebservice>();
                    userAccountWebServiceMock
                        .Setup(o => o.LogInAsync(It.IsAny<LogInCommand>()))
                        .Returns(Task.FromResult((ActionResult<LogInDto>)(new OkObjectResult(new LogInDto() { IsAuthenticated = true, UserId = 1 }))));

                    s.AddSingleton(userAccountWebServiceMock.Object);

                })
               .ConfigureAppConfiguration((builderContext, config) =>
               {
                   Configuration = config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true).AddEnvironmentVariables().Build();
               });

        var testServer = new TestServer(authWebHostBuilder);

        **Startup.BackChannelHandler = testServer.CreateHandler();**
        this.Client = testServer.CreateClient();

        GetAccessTokensAsync().Wait();
    }
person Theo Kand.    schedule 13.09.2018