What can be done to get SecurityProtocol working, I'm getting "The SSL connection could not be established"? - powershell

I'm building an ASP.NET Core 3.0 web application, that gets deployed using Octopus. This is all working just fine. We're going live soon, so I've been hardening the servers, by removing insecure protocols etc. using IISCrypto. Only one left is Tls 1.2.
Now all of a sudden I can't do a HttpWebRequest to my deployed web application from a .NET Core command line tool I have written for commissioning the application. I'm getting this error in the logs:
System.Net.WebException: The SSL connection could not be established, see inner exception. Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host..
---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
---> 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 (10054): An existing connection was forcibly closed by the remote host.
So I tried using some of the suggestions found on SO:
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
But this doesn't change anything. It's like this line gets ignored.
The code that fails:
HttpWebRequest http = (HttpWebRequest)WebRequest.Create(new Uri(url));
http.Accept = "application/json";
http.ContentType = "application/json";
http.Method = method;
if (String.IsNullOrWhiteSpace(token) == false) {
http.Headers.Add("Authorization", $"Bearer {token}");
}
if (String.IsNullOrWhiteSpace(data) == false) {
UTF8Encoding encoding = new UTF8Encoding();
Byte[] bytes = encoding.GetBytes(data);
Stream newStream = http.GetRequestStream();
newStream.Write(bytes, 0, bytes.Length);
newStream.Close();
}
try {
WebResponse response = http.GetResponse();
Stream stream = response.GetResponseStream();
StreamReader sr = new StreamReader(stream);
return sr.ReadToEnd();
}
catch (Exception ex) {
logger.Error(ex, $"{method} on {relativeUrl} failed");
Console.WriteLine(ex.Message);
}
Just to try something else, I did a small test from Powershell, and I ended up getting a similar error message. Then I added the security protocol line to the script, and it works:
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-WebRequest -UseBasicParsing https://mysite/app/authenticate -ContentType "application/json" -Method POST -Body (#{"emailAddress"="somemail#address"; "password"="somepassword"}|ConvertTo-Json)
Any ideas as to why this isn't working with .NET Core ?

This actually turned out to be "wrong server" issue. For some reason my request ended up on the wrong server, and this apparently is the reply/error you get, when you request something on a server that does not have the requested site hosted.

Related

Intermittent "error occurred while making the HTTP request"

error occurred while making the HTTP request
I have a c# client that calls a remote endpoint using a HttpClient. The client is hosted on a Windows Server.
The client will run fine for a long time and then I encounter a "error occurred while making the HTTP request".
We do use Trend Micro AntiVirus.
I run this client about every 5 minutes. It works very well when it starts but when the error happens it keeps happening. To resolve it I shut the service down, wait awhile and then restart it.
Here is my code snippet:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3;
System.Net.ServicePointManager.MaxServicePointIdleTime = 10000;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(URL);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.ConnectionClose = true;
HttpResponseMessage response = await client.PostAsync(URL, content);
}
Here is the error:
Exception: 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 established connection was aborted by the software in your host machine. ---> System.Net.Sockets.SocketException: An established connection was aborted by the software in your host machine
at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
Any help would be appreciated.
Thanks!

Reports endpoint returns System.Net.WebException: The underlying connection was closed

I am trying to retrieve the Usage (report) data from Microsoft Graph using PowerShell but I'm getting the following exception:
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.Socket.EndReceive(IAsyncResult asyncResult)
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)
It looks like server is terminating the connection abruptly.
Here are the commands that I am using through PowerShell
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
$headers = #{Authorization = 'Bearer ' + $AT.AccessToken; ContentType='application/json'}
$result=Invoke-RestMethod -Method GET -Uri "https://graph.microsoft.com/v1.0/reports/getOffice365ActiveUserDetail(period='D90')?$format=text/csv" -Headers $headers
This is happening intermittently, regardless of setting Tls12. I have analyzed the packets through Wireshark and it looks like TLS handshake was completed correctly.
Version: TLS 1.2 (0x0303)
Cipher Suite: TLS_RSA_WITH_AES_256_GCM_SHA384 (0x009d)
I also see that Change Cipher Spec was communicated by client and server.
TLSv1.2 Record Layer: Change Cipher Spec Protocol: Change Cipher Spec
It is important to note that I am able to get the Users and SubscribedSkus correctly, so I can't conclude that this is happening because of the TLS issues. It's only the /reports endpoint which is causing the problem.
Any insight will be helpful to address this problem.
Is it possible that Usage data is large and leads to connection termination?
This endpoint doesn't return the data directly, it returns a 302 redirect to a CSV file to download. You'll want to sepcifiy an OutFile to save the file to:
$uri = "https://graph.microsoft.com/v1.0/reports/getOffice365ActiveUserDetail(period='D90')?$format=text/csv"
Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -OutFile report.csv

Call to TLS 1.2 server with RestSharp works in console app, not in Xamarin Forms

I am communicating with a server that uses mutual TLS v1.2. I have been able to make this request in a c# console application, but when I copy this exact code to Xamarin forms, my RestClient gives me an exception: "Connection reset by peer" after a few seconds.
The code:
var client = new RestClient("https://api-sandbox.rabobank.nl/openapi/sandbox/payments/account-information/ais/v3/accounts");
ServicePointManager.Expect100Continue = true;
ServicePointManager.DefaultConnectionLimit = 9999;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
client.ClientCertificates = new X509CertificateCollection() { certificate };
client.Proxy = new WebProxy();
var request = new RestRequest(Method.GET);
var response = client.Execute(request);
Console.WriteLine(response.StatusCode);
Console.WriteLine(response.Content);
I am unable to share my API keys and such, for obvious reasons. These are added through headers and are removed from the code snippet.
Things I have tried:
I checked if the projects are set to use TLS 1.2, both iOS and Android are.
I tried this in simulators and on real devices
I tried using this library, but whenever I try to add the certificate to the clientcertificate list of the handler, I get a NotImplementedException thrown.

ASP double hop request in kerberos delegation scenario

Please help!
I need my asp application to request remote systems with credentials of impersonated user. But always get 401 Unauthorized errors.
I made all configurations from here: https://support.microsoft.com/en-us/help/810572/how-to-configure-an-asp-net-application-for-a-delegation-scenario
Kerberos is configured and working in my app and my test remote app(i see kerberos tickets in fiddler). Delegation, spns and everything is configured.
Thats my code usnig System.Net.Http.httpclient:
HttpClientHandler handler = new HttpClientHandler()
{
UseDefaultCredentials = true,
PreAuthenticate = true
};
using (HttpClient client = new HttpClient(handler))
{
client.DefaultRequestHeaders.Accept.Clear();
var method = new HttpMethod("GET");
var request = new HttpRequestMessage(method, "http://testdelegationapp.avp.ru/");
var response = client.SendAsync(request).Result;
}
In fact http request is made by Apppool account (I get 401 error when restricting access to Apppool account in remote app IIS)
Here: How to get HttpClient to pass credentials along with the request?
is claimed that HttpClient cant pass security token to another thread, and its better to use synchronous methods of System.Net.WebClient
Code using webclient:
var wi = (WindowsIdentity)HttpContext.User.Identity;
var wic = wi.Impersonate();
try
{
string URI = "http://testdelegationapp.avp.ru/";
using (WebClient wc = new WebClient())
{
wc.UseDefaultCredentials = true;
string response = wc.DownloadString(URI);
}
}
finally
{
wic.Undo();
}
Result is even worse, the same 401 error, but in fiddler i can see that webclient using NTLM ticket to get to remote app!
Configuring of flowing tokens throw threads from here :Unable to authenticate to ASP.NET Web Api service with HttpClient
doesnt help either. SecurityContext.IsWindowsIdentityFlowSuppressed() is false.
WindowsIdentity.GetCurrent().Name and Thread.CurrentPrincipal.Identity.Name shows impersonated user as it should be.
All that time problem was in chrome browser, by default it prohobits kerberos delegation. You shoud add the following to registry:
Path: HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome ;
string: AuthNegotiateDelegateWhitelist ;
value: *.avp.ru
So, now my working configuration is
HttpClient for web requests.
ASP impersonation ON in IIS if you want to execute all your app under
delegated credentials. If you want method specific delegation, then use:
var wi = (WindowsIdentity)HttpContext.User.Identity;
var wic = wi.Impersonate();
wic.Undo();
HttpClient executes request in another thread , so in aspnet_config.config we need following changes:
<legacyImpersonationPolicy enabled="false"/>
<alwaysFlowImpersonationPolicy enabled="true"/>
You can find aspnet_config.config in:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet.config
C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet.config
C:\Windows\Microsoft.NET\Framework64\v2.0.50727\aspnet.config
C:\Windows\Microsoft.NET\Framework\v2.0.50727\aspnet.config

SrpingFramework Web Client RestTemplate ConnectionRefused exception

I have some code that is attempting to make a RestTemplate call to a REST API on another server:
String url = "http://$authUrl:$authPort/cdpe/users/current";
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add("Cookie", rdgLogin.getName() + "=" + rdgLogin.getValue());
requestHeaders.add("Cookie", jsessionId.getName() + "=" + jsessionId.getValue());
RestTemplate restTemplate = new RestTemplate();
HttpEntity requestEntity = new HttpEntity(null, requestHeaders);
ResponseEntity<String> resp = restTemplate.exchange(url, HttpMethod.GET, requestEntity, String.class);
The server is up and running on a different machine "restserver" on port 8080. I've verified that it's up and running and waiting for connections.
When the above code executes I get a ConnectionRefused exception. Connection refused http://restserver:8080/cdpe/users/current. Usually this means the url is wrong or the server is not running. However, I can perform a curl command with the same URL on the same machine:
curl http://restserver:8080/cdpe/users/current
And I can get a response. Which leads me to believe there is something wrong with my RestTemplate call. Also, I can execute the same code on the same machine as the restserver and it works correctly. Any idea what I'm doing wrong?
I'm an idiot. I had typoed the URL in the $authUrl portion of the code in such a way that it was really, really hard to detect. Developer fail.