|
|
@@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core;
|
|
|
using Microsoft.AspNetCore.Server.Kestrel.Https;
|
|
|
using Microsoft.AspNetCore.Testing;
|
|
|
using Microsoft.Extensions.Hosting;
|
|
|
+using Microsoft.Extensions.Logging;
|
|
|
using Xunit;
|
|
|
|
|
|
namespace Interop.FunctionalTests.Http3
|
|
|
@@ -149,11 +150,13 @@ namespace Interop.FunctionalTests.Http3
|
|
|
}
|
|
|
|
|
|
[ConditionalTheory]
|
|
|
- [InlineData(ClientCertificateMode.RequireCertificate)]
|
|
|
- [InlineData(ClientCertificateMode.AllowCertificate)]
|
|
|
+ [InlineData(ClientCertificateMode.RequireCertificate, false)]
|
|
|
+ [InlineData(ClientCertificateMode.RequireCertificate, true)]
|
|
|
+ [InlineData(ClientCertificateMode.AllowCertificate, false)]
|
|
|
+ [InlineData(ClientCertificateMode.AllowCertificate, true)]
|
|
|
[MsQuicSupported]
|
|
|
[OSSkipCondition(OperatingSystems.MacOSX | OperatingSystems.Linux, SkipReason = "https://github.com/dotnet/aspnetcore/issues/35800")]
|
|
|
- public async Task ClientCertificate_AllowOrRequire_Available_Invalid_Refused(ClientCertificateMode mode)
|
|
|
+ public async Task ClientCertificate_AllowOrRequire_Available_Invalid_Refused(ClientCertificateMode mode, bool serverAllowInvalid)
|
|
|
{
|
|
|
var builder = CreateHostBuilder(async context =>
|
|
|
{
|
|
|
@@ -168,7 +171,11 @@ namespace Interop.FunctionalTests.Http3
|
|
|
{
|
|
|
httpsOptions.ServerCertificate = TestResources.GetTestCertificate();
|
|
|
httpsOptions.ClientCertificateMode = mode;
|
|
|
- // httpsOptions.AllowAnyClientCertificate(); // The self-signed cert is invalid. Let it fail the default checks.
|
|
|
+
|
|
|
+ if (serverAllowInvalid)
|
|
|
+ {
|
|
|
+ httpsOptions.AllowAnyClientCertificate(); // The self-signed cert is invalid. Let it fail the default checks.
|
|
|
+ }
|
|
|
});
|
|
|
});
|
|
|
});
|
|
|
@@ -182,12 +189,22 @@ namespace Interop.FunctionalTests.Http3
|
|
|
request.Version = HttpVersion.Version30;
|
|
|
request.VersionPolicy = HttpVersionPolicy.RequestVersionExact;
|
|
|
|
|
|
- var ex = await Assert.ThrowsAsync<HttpRequestException>(() => client.SendAsync(request, CancellationToken.None).DefaultTimeout());
|
|
|
- // This poor error is likely a symptom of https://github.com/dotnet/runtime/issues/57246
|
|
|
- // QuicListener returns the connection before (or in spite of) the cert validation failing.
|
|
|
- // There's a race where the stream could be accepted before the connection is aborted.
|
|
|
- var qex = Assert.IsType<QuicOperationAbortedException>(ex.InnerException);
|
|
|
- Assert.Equal("Operation aborted.", qex.Message);
|
|
|
+ var sendTask = client.SendAsync(request, CancellationToken.None);
|
|
|
+
|
|
|
+ if (!serverAllowInvalid)
|
|
|
+ {
|
|
|
+ // In .NET 6 there is a race condition between throwing HttpRequestException and QuicException.
|
|
|
+ // Unable to test the exact error.
|
|
|
+ var ex = await Assert.ThrowsAnyAsync<Exception>(() => sendTask).DefaultTimeout();
|
|
|
+ Logger.LogInformation(ex, "SendAsync successfully threw error.");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // Because we can't verify the exact error reason, check that the cert is the cause be successfully
|
|
|
+ // making a call when invalid certs are allowed.
|
|
|
+ var response = await sendTask.DefaultTimeout();
|
|
|
+ response.EnsureSuccessStatusCode();
|
|
|
+ }
|
|
|
|
|
|
await host.StopAsync().DefaultTimeout();
|
|
|
}
|