Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@ public HttpClientHandler_ServerCertificates_Test(ITestOutputHelper output) : bas

// This enables customizing ServerCertificateCustomValidationCallback in WinHttpHandler variants:
protected bool AllowAllCertificates { get; set; } = true;
protected new HttpClientHandler CreateHttpClientHandler() => CreateHttpClientHandler(
protected new HttpClientHandler CreateHttpClientHandler() => CreateHttpClientHandler(allowTlsResume: true);
protected new HttpClientHandler CreateHttpClientHandler(bool allowTlsResume) => CreateHttpClientHandler(
useVersion: UseVersion,
allowAllCertificates: UseVersion >= HttpVersion20.Value && AllowAllCertificates);
allowAllCertificates: UseVersion >= HttpVersion20.Value && AllowAllCertificates,
allowTlsResume: allowTlsResume);
protected override HttpClient CreateHttpClient() => CreateHttpClient(CreateHttpClientHandler());

[Fact]
Expand Down Expand Up @@ -143,7 +145,7 @@ public static IEnumerable<object[]> UseCallback_ValidCertificate_ExpectedValuesD
[MemberData(nameof(UseCallback_ValidCertificate_ExpectedValuesDuringCallback_Urls))]
public async Task UseCallback_ValidCertificate_ExpectedValuesDuringCallback(Configuration.Http.RemoteServer remoteServer, Uri url, bool checkRevocation)
{
HttpClientHandler handler = CreateHttpClientHandler();
HttpClientHandler handler = CreateHttpClientHandler(allowTlsResume: false);
using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer, handler))
{
bool callbackCalled = false;
Expand Down Expand Up @@ -186,7 +188,7 @@ public async Task UseCallback_ValidCertificate_ExpectedValuesDuringCallback(Conf
[Fact]
public async Task UseCallback_CallbackReturnsFailure_ThrowsException()
{
HttpClientHandler handler = CreateHttpClientHandler();
HttpClientHandler handler = CreateHttpClientHandler(allowTlsResume: false);
using (HttpClient client = CreateHttpClient(handler))
{
handler.ServerCertificateCustomValidationCallback = delegate { return false; };
Expand All @@ -198,7 +200,7 @@ public async Task UseCallback_CallbackReturnsFailure_ThrowsException()
[Fact]
public async Task UseCallback_CallbackThrowsException_ExceptionPropagatesAsBaseException()
{
HttpClientHandler handler = CreateHttpClientHandler();
HttpClientHandler handler = CreateHttpClientHandler(allowTlsResume: false);
using (HttpClient client = CreateHttpClient(handler))
{
var e = new DivideByZeroException();
Expand All @@ -221,7 +223,8 @@ public async Task UseCallback_CallbackThrowsException_ExceptionPropagatesAsBaseE
[MemberData(nameof(CertificateValidationServers))]
public async Task NoCallback_BadCertificate_ThrowsException(string url)
{
using (HttpClient client = CreateHttpClient())
using (HttpClientHandler handler = CreateHttpClientHandler(allowTlsResume: false))
using (HttpClient client = CreateHttpClient(handler))
{
await Assert.ThrowsAsync<HttpRequestException>(() => client.GetAsync(url));
}
Expand All @@ -245,7 +248,7 @@ public async Task NoCallback_RevokedCertificate_NoRevocationChecking_Succeeds()
[Fact]
public async Task NoCallback_RevokedCertificate_RevocationChecking_Fails()
{
HttpClientHandler handler = CreateHttpClientHandler();
HttpClientHandler handler = CreateHttpClientHandler(allowTlsResume: false);
handler.CheckCertificateRevocationList = true;
using (HttpClient client = CreateHttpClient(handler))
{
Expand All @@ -261,7 +264,7 @@ public async Task NoCallback_RevokedCertificate_RevocationChecking_Fails()

private async Task UseCallback_BadCertificate_ExpectedPolicyErrors_Helper(string url, string useHttp2String, SslPolicyErrors expectedErrors)
{
HttpClientHandler handler = CreateHttpClientHandler(useHttp2String);
HttpClientHandler handler = CreateHttpClientHandler(useHttp2String, allowTlsResume: false);
using (HttpClient client = CreateHttpClient(handler, useHttp2String))
{
bool callbackCalled = false;
Expand Down Expand Up @@ -318,18 +321,20 @@ public async Task UseCallback_BadCertificate_ExpectedPolicyErrors(string url, Ss
}
}

[Fact]
public async Task UseCallback_SelfSignedCertificate_ExpectedPolicyErrors()
[Theory]
[InlineData(1)]
[InlineData(3)]
public async Task UseCallback_SelfSignedCertificate_ExpectedPolicyErrors(int requestCount)
{
using (HttpClientHandler handler = CreateHttpClientHandler())
using (HttpClientHandler handler = CreateHttpClientHandler(allowTlsResume: false))
using (HttpClient client = CreateHttpClient(handler))
{
bool callbackCalled = false;
X509Certificate2 certificate = TestHelper.CreateServerSelfSignedCertificate();
int callbackCount = 0;
using X509Certificate2 certificate = TestHelper.CreateServerSelfSignedCertificate();

handler.ServerCertificateCustomValidationCallback = (request, cert, chain, errors) =>
{
callbackCalled = true;
callbackCount++;
Assert.NotNull(request);
Assert.NotNull(cert);
Assert.NotNull(chain);
Expand All @@ -341,12 +346,23 @@ public async Task UseCallback_SelfSignedCertificate_ExpectedPolicyErrors()

await LoopbackServer.CreateServerAsync(async (server, url) =>
{
await TestHelper.WhenAllCompletedOrAnyFailed(
server.AcceptConnectionSendResponseAndCloseAsync(),
client.GetAsync($"https://{certificate.GetNameInfo(X509NameType.SimpleName, false)}:{url.Port}/"));
for (int i = 0; i < requestCount; i++)
{
#if NETFRAMEWORK
// The loopback authentication overload disposes its certificate after each handshake.
options.Certificate = new X509Certificate2(certificate);
#endif
Task<HttpResponseMessage> responseTask = client.GetAsync($"https://{certificate.GetNameInfo(X509NameType.SimpleName, false)}:{url.Port}/");
await TestHelper.WhenAllCompletedOrAnyFailed(
server.AcceptConnectionSendResponseAndCloseAsync(),
responseTask);
using HttpResponseMessage response = await responseTask;
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal(i + 1, callbackCount);
}
}, options);

Assert.True(callbackCalled);
Assert.Equal(requestCount, callbackCount);
}
}

Expand Down Expand Up @@ -411,7 +427,8 @@ await RemoteExecutor.Invoke(async (useVersionString, allowAllCertificatesString)
var version = Version.Parse(useVersionString);
using HttpClientHandler handler = CreateHttpClientHandler(
useVersion: version,
allowAllCertificates: version >= HttpVersion20.Value && bool.Parse(allowAllCertificatesString));
allowAllCertificates: version >= HttpVersion20.Value && bool.Parse(allowAllCertificatesString),
allowTlsResume: false);
using HttpClient client = CreateHttpClient(handler, useVersionString);

await Assert.ThrowsAsync<HttpRequestException>(() => client.GetAsync(Url));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public static IEnumerable<object[]> GetAsync_AllowedSSLVersion_Succeeds_MemberDa
public async Task GetAsync_AllowedSSLVersion_Succeeds(SslProtocols acceptedProtocol, bool requestOnlyThisProtocol)
{
int count = 0;
using (HttpClientHandler handler = CreateHttpClientHandler())
using (HttpClientHandler handler = CreateHttpClientHandler(allowTlsResume: false))
using (HttpClient client = CreateHttpClient(handler))
{
handler.ServerCertificateCustomValidationCallback =
Expand Down
2 changes: 2 additions & 0 deletions src/libraries/Common/tests/System/Net/Http/LoopbackServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,7 @@ public static string GetConnectionCloseResponse(HttpStatusCode statusCode = Http

public class Options : GenericLoopbackOptions
{
public bool AllowTlsResume { get; set; } = true;
public bool WebSocketEndpoint { get; set; } = false;
public Func<Stream, Stream> StreamWrapper { get; set; }
public string Username { get; set; }
Expand Down Expand Up @@ -483,6 +484,7 @@ public static async Task<Connection> CreateAsync(SocketWrapper socket, Stream st
#if !NETFRAMEWORK
SslServerAuthenticationOptions sslOptions = new SslServerAuthenticationOptions()
{
AllowTlsResume = httpOptions.AllowTlsResume,
EnabledSslProtocols = httpOptions.SslProtocols,
ServerCertificateContext = httpOptions.CertificateContext ?? SslStreamCertificateContext.Create(Configuration.Certificates.GetServerCertificate(), null),
ClientCertificateRequired = true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ public abstract partial class HttpClientHandlerTestBase : FileCleanupTestBase
{
protected static bool IsWinHttpHandler => true;

protected static WinHttpClientHandler CreateHttpClientHandler(Version useVersion = null, bool allowAllCertificates = true)
// WinHTTP owns TLS and does not expose SslStream's resumption setting.
protected static WinHttpClientHandler CreateHttpClientHandler(Version useVersion = null, bool allowAllCertificates = true, bool allowTlsResume = true)
{
useVersion ??= HttpVersion.Version11;

Expand All @@ -26,8 +27,11 @@ protected static WinHttpClientHandler CreateHttpClientHandler(Version useVersion

protected WinHttpClientHandler CreateHttpClientHandler() => CreateHttpClientHandler(UseVersion);

protected static WinHttpClientHandler CreateHttpClientHandler(string useVersionString) =>
CreateHttpClientHandler(Version.Parse(useVersionString));
protected WinHttpClientHandler CreateHttpClientHandler(bool allowTlsResume) =>
CreateHttpClientHandler(UseVersion, allowTlsResume: allowTlsResume);

protected static WinHttpClientHandler CreateHttpClientHandler(string useVersionString, bool allowTlsResume = true) =>
CreateHttpClientHandler(Version.Parse(useVersionString), allowTlsResume: allowTlsResume);

protected static HttpRequestMessage CreateRequest(HttpMethod method, Uri uri, Version version, bool exactVersion = false) =>
new HttpRequestMessage(method, uri)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,7 @@ public async Task ServerCertificateCustomValidationCallback_Succeeds()
HttpRequestMessage? callbackRequest = null;
int invocationCount = 0;

var httpClientHandler = CreateHttpClientHandler();
var httpClientHandler = CreateHttpClientHandler(allowTlsResume: false);
httpClientHandler.ServerCertificateCustomValidationCallback = (request, _, _, _) =>
{
callbackRequest = request;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public static bool IsHttp3Supported
}
}

protected static HttpClientHandler CreateHttpClientHandler(Version useVersion = null, bool allowAllCertificates = true)
protected static HttpClientHandler CreateHttpClientHandler(Version useVersion = null, bool allowAllCertificates = true, bool allowTlsResume = true)
{
useVersion ??= HttpVersion.Version11;

Expand All @@ -58,6 +58,13 @@ protected static HttpClientHandler CreateHttpClientHandler(Version useVersion =
handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;
}

// Native mobile handlers do not use SslStream or expose its resumption setting.
if (!allowTlsResume && PlatformDetection.IsNotBrowser && PlatformDetection.IsNotWasi &&
GetUnderlyingSocketsHttpHandler(handler) is SocketsHttpHandler socketsHandler)
{
socketsHandler.SslOptions.AllowTlsResume = false;
}

return handler;
}

Expand All @@ -71,8 +78,11 @@ protected static Http3LoopbackServer CreateHttp3LoopbackServer(Http3Options opti

protected HttpClientHandler CreateHttpClientHandler() => CreateHttpClientHandler(UseVersion);

protected static HttpClientHandler CreateHttpClientHandler(string useVersionString) =>
CreateHttpClientHandler(Version.Parse(useVersionString));
protected HttpClientHandler CreateHttpClientHandler(bool allowTlsResume) =>
CreateHttpClientHandler(UseVersion, allowTlsResume: allowTlsResume);

protected static HttpClientHandler CreateHttpClientHandler(string useVersionString, bool allowTlsResume = true) =>
CreateHttpClientHandler(Version.Parse(useVersionString), allowTlsResume: allowTlsResume);

protected static SocketsHttpHandler GetUnderlyingSocketsHttpHandler(HttpClientHandler handler)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,28 @@ await server.AcceptConnectionAsync(async connection =>
public sealed class SocketsHttpHandler_HttpClientHandler_ServerCertificates_Test : HttpClientHandler_ServerCertificates_Test
{
public SocketsHttpHandler_HttpClientHandler_ServerCertificates_Test(ITestOutputHelper output) : base(output) { }

[Theory]
[InlineData(true)]
[InlineData(false)]
[PlatformSpecific(TestPlatforms.Windows | TestPlatforms.Linux | TestPlatforms.OSX)]
public void CreateHttpClientHandler_AllowTlsResume_ConfiguresSslOptions(bool allowTlsResume)
{
using HttpClientHandler defaultHandler = CreateHttpClientHandler();
Assert.True(GetUnderlyingSocketsHttpHandler(defaultHandler).SslOptions.AllowTlsResume);

using HttpClientHandler instanceHandler = CreateHttpClientHandler(allowTlsResume: allowTlsResume);
Assert.Equal(allowTlsResume, GetUnderlyingSocketsHttpHandler(instanceHandler).SslOptions.AllowTlsResume);
Assert.Null(instanceHandler.ServerCertificateCustomValidationCallback);

using HttpClientHandler versionHandler = CreateHttpClientHandler(UseVersion, allowAllCertificates: false, allowTlsResume: allowTlsResume);
Assert.Equal(allowTlsResume, GetUnderlyingSocketsHttpHandler(versionHandler).SslOptions.AllowTlsResume);
Assert.Null(versionHandler.ServerCertificateCustomValidationCallback);

using HttpClientHandler stringHandler = CreateHttpClientHandler(UseVersion.ToString(), allowTlsResume: allowTlsResume);
Assert.Equal(allowTlsResume, GetUnderlyingSocketsHttpHandler(stringHandler).SslOptions.AllowTlsResume);
Assert.NotNull(stringHandler.ServerCertificateCustomValidationCallback);
}
}

[SkipOnPlatform(TestPlatforms.Browser, "ResponseDrainTimeout is not supported on Browser")]
Expand Down Expand Up @@ -6233,7 +6255,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(

policy.ExtraStore.AddRange(_certificateSetup.ServerChain);
policy.CustomTrustStore.Add(_certificateSetup.ServerChain[^1]);
socketsHandler.SslOptions = new SslClientAuthenticationOptions() { CertificateChainPolicy = policy };
socketsHandler.SslOptions = new SslClientAuthenticationOptions() { CertificateChainPolicy = policy, AllowTlsResume = false };
using HttpClient client = CreateHttpClient(handler);
client.DefaultVersionPolicy = HttpVersionPolicy.RequestVersionExact;
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, uri) { Version = UseVersion, VersionPolicy = HttpVersionPolicy.RequestVersionExact };
Expand Down Expand Up @@ -6266,7 +6288,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(

policy.ExtraStore.AddRange(_certificateSetup.ServerChain);
policy.CustomTrustStore.Add(_certificateSetup.ServerChain[^1]);
socketsHandler.SslOptions = new SslClientAuthenticationOptions() { CertificateChainPolicy = policy };
socketsHandler.SslOptions = new SslClientAuthenticationOptions() { CertificateChainPolicy = policy, AllowTlsResume = false };
using HttpClient client = CreateHttpClient(handler);
client.DefaultVersionPolicy = HttpVersionPolicy.RequestVersionExact;
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, uri) { Version = UseVersion, VersionPolicy = HttpVersionPolicy.RequestVersionExact };
Expand Down Expand Up @@ -6305,7 +6327,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(

policy.ExtraStore.AddRange(_certificateSetup.ServerChain);
policy.CustomTrustStore.Add(_certificateSetup.ServerChain[^1]);
socketsHandler.SslOptions = new SslClientAuthenticationOptions() { CertificateChainPolicy = policy };
socketsHandler.SslOptions = new SslClientAuthenticationOptions() { CertificateChainPolicy = policy, AllowTlsResume = false };

using HttpClient client = CreateHttpClient(handler);
client.DefaultVersionPolicy = HttpVersionPolicy.RequestVersionExact;
Expand Down
Loading
Loading