如何将(Microsoft.AspNetCore.TestHost)TestServer与客户端证书一起使用

时间:2020-01-08 13:59:01

标签: c# ssl asp.net-core integration-testing asp.net-core-webapi

在.net core api中启用证书身份验证会导致TestServer在集成测试中始终返回403-Forbidden(尽管请求中使用了证书)。

我尝试更改TestClientProvider中的CertificateValidationService,但似乎证书验证在到达用户定义的身份验证逻辑之前失败。 该服务在Azure中部署时可以与客户端证书一起正常使用。

我错过了什么吗?有什么方法可以将TestServer与受客户端证书保护的API一起使用?

要复制

  1. 在.NET Core API中启用证书身份验证 https://docs.microsoft.com/en-us/aspnet/core/security/authentication/certauth?view=aspnetcore-3.1
// Startup.cs
    ...
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<CertificateValidationService>();
        services.AddAuthentication(
            CertificateAuthenticationDefaults.AuthenticationScheme).AddCertificate(options =>
        {
            ...
        });
        services.AddAuthorization();
        services.AddControllers();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
    {
        ...

        app.UseRouting();

        app.UseCertificateForwarding();
        app.UseAuthentication();
        app.UseAuthorization();
        ...

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
  1. 在您的api上使用“授权”属性
// WeatherForecastController.cs  (VS 2019 template)
    [ApiController]
    [Route("api/weather")]
    [Authorize]
    public class WeatherForecastController : ControllerBase
    {
    ...
    }
  1. 使用Microsoft.AspNetCore.TestHost编写集成测试
// IntegrationTests/ClientCertificateTests.cs
    [Fact]
    public async void GivenValidCertificate_PerformGet_ExpectSuccess()
    {
        X509Certificate2 validClientCertificate;
        using (var certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser))
        {
            certStore.Open(OpenFlags.ReadOnly);
            validClientCertificate = certStore.Certificates.Find(X509FindType.FindByTimeValid, DateTime.Now, true)[0];
        }

        using (var server = new TestClientProvider(ignoreCertificate: false).Server)
        {
            // Act
            var result = await server.SendAsync(context =>
            {
                context.Connection.ClientCertificate = validClientCertificate;
                context.Request.Method = "GET";
                context.Request.Path = "/api/weather";
            });

            // Assert
            Assert.Equal(200, result.Response.StatusCode);
        }
    }

1 个答案:

答案 0 :(得分:1)

根据https://github.com/dotnet/aspnetcore/issues/18177,我还必须将请求方案设置为对我有用的“ https”。

    var result = await server.SendAsync(context =>
    {
        context.Connection.ClientCertificate = validClientCertificate;
        context.Request.Method = "GET";
        context.Request.Scheme = "https";
        context.Request.Path = "/api/weather";
    });