httpClient.GetAsync 抛出异常;怀疑证书配置
httpClient.GetAsync throws exception; certificate configuration suspected
TL;DR version (somewhat)
我有两台服务器(X 和 Y)正在尝试通信,但未能成功通过 TLS1.2 执行此操作(TLS1.1 和 TLS1.0 均正常运行)。
我的服务器 X 无法从 localhost
获得响应。
抛出异常的调用就是这行代码
HttpResponseMessage response = await httpClient.GetAsync(address, cancel);
地址为 https://localhost/XXXXX/Identity/.well-known/jwks
,取消为 IsCancellationRequested = false
我注意到为 https://localhost/XXXXX/Identity/.well-known/jwks
提供的服务器证书是有效的,用 RSA256 签名,不在吊销列表中等等,一切看起来都不错,但是主题是 *.testing.corp,它与我尝试导航到的 URL 不匹配。当从服务器 X 上的 Chrome 导航到 https://localhost/XXXXX/Identity/.well-known/jwks
时,这会导致出现证书警告,但在手动单击它后,我得到了预期的结果。
所以我的想法是,如果我可以覆盖 HttpClient.GetAsync 的证书验证,我应该能够完成这项工作,所以我在我的客户端周围添加了以下代码:
var handler = new WebRequestHandler();
httpClient = new HttpClient(handler);
handler.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(dumbvalidationdeletemeishouldnotbeversioned);
public static bool dumbvalidationdeletemeishouldnotbeversioned(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors err)
{
return true;
}
有趣的是,这永远不会成功,当我进入 GetAsync
代码行时,一个步骤会抛出异常,而不会达到虚拟验证。
这是怎么回事?为什么这个方法会失败?
更多上下文:
编辑:相关的,X 正在利用身份服务器尝试进行身份验证。尝试访问 https://localhost/XXXXX/Identity/.well-known/jwks
时发生故障
我正在使用 IISCrypto 在这些机器上配置协议。 (在评论中采纳@Oleg 的建议并没有改变这种行为)。我通过单击 "Best Practices" 按钮然后取消选中 TLS1.0 和 TLS1.1 来配置它们,以便两个服务器看起来像这样:
编辑:添加一些堆栈跟踪信息
在我添加虚拟处理程序之前,这是抛出异常的堆栈跟踪:
System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send. ---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
--- End of inner exception stack trace ---
at System.Net.TlsStream.EndWrite(IAsyncResult asyncResult)
at System.Net.ConnectStream.WriteHeadersCallback(IAsyncResult ar)
--- End of inner exception stack trace ---
at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.Net.Http.HttpClientHandler.GetResponseCallback(IAsyncResult ar)
--- End of inner exception stack trace ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at XXXXXXXX.Authentication.Extensions.XXXXXXOpenIDConnectAuthentication.<ReadJWTKeys>d__8.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at XXXXXXX.Authentication.Extensions.XXXXXXOpenIDConnectAuthentication.<MessageRecieved>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Owin.Security.OpenIdConnect.OpenIdConnectAuthenticationHandler.<AuthenticateCoreAsync>d__1a.MoveNext()
添加虚拟处理程序后,异常完全为空 <-- 查看评论。异常是完全一样的,但是当我调试进程时,我的虚拟处理程序中的 return 语句从未被命中,所以 我的问题的症结变为 "What else is there to check?"
应该加上
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
(来自 System.Net
命名空间)在 调用
之前
await httpClient.GetAsync(address, cancel);
强制使用正确的协议。请参阅 the blog 以及 HttpClient
和 ServicePointManager.SecurityProtocol
的详细实验。
TL;DR version (somewhat)
我有两台服务器(X 和 Y)正在尝试通信,但未能成功通过 TLS1.2 执行此操作(TLS1.1 和 TLS1.0 均正常运行)。
我的服务器 X 无法从 localhost
获得响应。
抛出异常的调用就是这行代码
HttpResponseMessage response = await httpClient.GetAsync(address, cancel);
地址为 https://localhost/XXXXX/Identity/.well-known/jwks
,取消为 IsCancellationRequested = false
我注意到为 https://localhost/XXXXX/Identity/.well-known/jwks
提供的服务器证书是有效的,用 RSA256 签名,不在吊销列表中等等,一切看起来都不错,但是主题是 *.testing.corp,它与我尝试导航到的 URL 不匹配。当从服务器 X 上的 Chrome 导航到 https://localhost/XXXXX/Identity/.well-known/jwks
时,这会导致出现证书警告,但在手动单击它后,我得到了预期的结果。
所以我的想法是,如果我可以覆盖 HttpClient.GetAsync 的证书验证,我应该能够完成这项工作,所以我在我的客户端周围添加了以下代码:
var handler = new WebRequestHandler();
httpClient = new HttpClient(handler);
handler.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(dumbvalidationdeletemeishouldnotbeversioned);
public static bool dumbvalidationdeletemeishouldnotbeversioned(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors err)
{
return true;
}
有趣的是,这永远不会成功,当我进入 GetAsync
代码行时,一个步骤会抛出异常,而不会达到虚拟验证。
这是怎么回事?为什么这个方法会失败?
更多上下文:
编辑:相关的,X 正在利用身份服务器尝试进行身份验证。尝试访问 https://localhost/XXXXX/Identity/.well-known/jwks
我正在使用 IISCrypto 在这些机器上配置协议。 (在评论中采纳@Oleg 的建议并没有改变这种行为)。我通过单击 "Best Practices" 按钮然后取消选中 TLS1.0 和 TLS1.1 来配置它们,以便两个服务器看起来像这样:
编辑:添加一些堆栈跟踪信息
在我添加虚拟处理程序之前,这是抛出异常的堆栈跟踪:
System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send. ---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
--- End of inner exception stack trace ---
at System.Net.TlsStream.EndWrite(IAsyncResult asyncResult)
at System.Net.ConnectStream.WriteHeadersCallback(IAsyncResult ar)
--- End of inner exception stack trace ---
at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.Net.Http.HttpClientHandler.GetResponseCallback(IAsyncResult ar)
--- End of inner exception stack trace ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at XXXXXXXX.Authentication.Extensions.XXXXXXOpenIDConnectAuthentication.<ReadJWTKeys>d__8.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at XXXXXXX.Authentication.Extensions.XXXXXXOpenIDConnectAuthentication.<MessageRecieved>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Owin.Security.OpenIdConnect.OpenIdConnectAuthenticationHandler.<AuthenticateCoreAsync>d__1a.MoveNext()
添加虚拟处理程序后,异常完全为空 <-- 查看评论。异常是完全一样的,但是当我调试进程时,我的虚拟处理程序中的 return 语句从未被命中,所以 我的问题的症结变为 "What else is there to check?"
应该加上
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
(来自 System.Net
命名空间)在 调用
await httpClient.GetAsync(address, cancel);
强制使用正确的协议。请参阅 the blog 以及 HttpClient
和 ServicePointManager.SecurityProtocol
的详细实验。