HttpWebRequest with client certificate fails - xamarin.ios

I am using Visual Studio Mac (latest version) and need to fetch data from an IIs server (vaersion 10) with a GET request and by passing a client certificate.
Unfortunately the IIs answers with an RST packet and shows the error:
The I/O operation has been aborted becourse of either a thread exit or an application request.
I know apple uses ATS (I am using iOS 10.3.3).
I guess this has something to do with the client certificate and IIS not accepting it.
Can someone point me to a differnt mono api where I can append the client cert to a GET request?
My code so far is as follows (with request.GetResponse() waiting until timeout...):
X509Certificate2Collection certificates = new X509Certificate2Collection (certificate);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.uriString);
request.ClientCertificates = certificates;
request.Method = "GET";
request.ContentType = "application/json";
request.Accept = "application/json";
request.UserAgent = UserAgentString;
request.KeepAlive = false;
request.ProtocolVersion = HttpVersion.Version11;
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse ())
{
this.webResponse = response;
stream = response.GetResponseStream ();
}

Related

Two way SSL X509 Certificate location for secure service request in .Net Core MVC - Azure Services Hosted application

I've being working with x509 certificates in order to make secure requests to some data services. They require Two way SSL auth, so I've converted my "Sandbox" certificate (.crt) w/ my Private Key to a Password protected .p12 file.
Here's the first question: Where should I place this .p12 file so that it's readable by my application after deploying to Azure (Using DevOps) but still stored securely? Can I use an my Azure Key Vault?
The second issue is that in my Dev environment I haven't been able to establish the SSL binding after making the request (With a .p12 absolute path):
Here's the code I'm using:
void GetATMs()
{
string requestURL = "https://sandbox.api.visa.com/globalatmlocator/v1/localatms/atmsinquiry";
string userId = "MyUserId";
string password = "MyPassword";
string p12certificatePath = "C:\\Code\\projects\\project\\\\Clients\\PaymentGateways\\Visa\\Certs\\TC_keyAndCertBundle.p12";
string p12certificatePassword = "CertPassword";
string postData = #"{""wsRequestHeaderV2"": { ""requestTs"": ""2018-11-06T03:16:18.000Z"", ""applicationId"": ""VATMLOC"", ""requestMessageId"": ""ICE01-001"", ""userId"": ""CDISIUserID"", ""userBid"": ""10000108"", ""correlationId"": ""909420141104053819418"" }, ""requestData"": { ""culture"": ""en-US"", ""distance"": ""20"", ""distanceUnit"": ""mi"", ""metaDataOptions"": 0, ""location"": { ""address"": null, ""placeName"": ""700 Arch St, Pittsburgh, PA 15212"", ""geocodes"": null }, ""options"": { ""range"": { ""start"": 10, ""count"": 20 }, ""sort"": { ""primary"": ""city"", ""direction"": ""asc"" }, ""operationName"": ""or"", ""findFilters"": [ { ""filterName"": ""OPER_HRS"", ""filterValue"": ""C"" } ], ""useFirstAmbiguous"": true } } }";
HttpWebRequest request = WebRequest.Create(requestURL) as HttpWebRequest;
request.Method = "POST";
// Add headers
string authString = userId + ":" + password;
var authStringBytes = System.Text.Encoding.UTF8.GetBytes(authString);
string authHeaderString = Convert.ToBase64String(authStringBytes);
request.Headers["Authorization"] = "Basic " + authHeaderString;
// Add certificate
var certificate = new X509Certificate2(p12certificatePath, p12certificatePassword);
request.ClientCertificates.Add(certificate);
request.Accept = "application/json";
var data = Encoding.ASCII.GetBytes(postData);
request.ContentLength = data.Length;
// Get the request stream.
Stream dataStream = request.GetRequestStream();
// Write the data to the request stream.
dataStream.Write(data, 0, data.Length);
// Close the Stream object.
dataStream.Close();
// Get the response.
WebResponse response = request.GetResponse();
// Display the status.
Console.WriteLine(((HttpWebResponse)response).StatusDescription);
// Get the stream containing content returned by the server.
dataStream = response.GetResponseStream();
// Open the stream using a StreamReader for easy access.
StreamReader reader = new StreamReader(dataStream);
// Read the content.
string responseFromServer = reader.ReadToEnd();
// Display the content.
Console.WriteLine(responseFromServer);
// Clean up the streams.
reader.Close();
dataStream.Close();
response.Close();
What am I missing here?
It fails the following way:
An unhandled exception occurred while processing the request.
Win32Exception: The credentials supplied to the package were not recognized
System.Net.SSPIWrapper.AcquireCredentialsHandle(SSPIInterface secModule, string package, CredentialUse intent, SCHANNEL_CRED scc)
HttpRequestException: The SSL connection could not be established, see inner exception.
System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
WebException: The SSL connection could not be established, see inner exception. The credentials supplied to the package were not recognized
System.Net.HttpWebRequest.GetResponse()
We have a Wildcard SSL for our domain. Are they different? Can it be registered in the Visa dashboard and used for make secure request as it is signed by a trusted CA authority?
Well, yes. As per, #dagope Recommendation, I've uploaded my certificate to key-management on Azure and access it through the SDK. This is also a best practice for key/certificate management on Azure.

Socket handle leak happening on Azure Web App

I have been stuck in one issue. I am getting error of "Unable to connect to the remote server. An attempt was made to access a socket in a way forbidden by its access permissions".
After searching on web and taking help of azure support, I came to know that if Web App reaches outbound connection limit of azure web app instance, it refuses connections or kill extra connections. Here is the image of open socket handles
My application calls third party WebAPI and wcf service. I have written code to close connections after making call to APIs. but it doesn't work for me. I did following code to call Web API.
var request = (HttpWebRequest)WebRequest.Create("www.xyz.com");
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.KeepAlive = false;
request.Headers.Add("Authorization", "Handshake");
byte[] bodyData;
bodyData = Encoding.UTF8.GetBytes(input_data);
request.ContentLength = bodyData.Length;
request.GetRequestStream().Write(bodyData, 0, bodyData.Length);
request.GetRequestStream().Flush();
request.GetRequestStream().Close();
using (var response = request.GetResponse())
{
using (var reader = new StreamReader(response.GetResponseStream(),
Encoding.UTF8))
{
string output_data = reader.ReadToEnd();
}
response.Close();
}
Could anyone guide me how to get rid on this issue?

HTTP :connect timeout and read timeout for URLStreamHandler with SAAJ working for windows but not working on linux sytem

I'm a beginner when it comes to HTTP connections.
Currently i'm working with SAAJ api to have my soap based client, where to handle timeouts i ended up using URLStreamHandler for HTTP connection properties with the endpoints.
Problem is that this timeout works for my windows based system, however it isn't working for the Linux server it is going to go live on.
below is the code for fetching endpoint with set properties. It is a HTTP POST connection.
URL endpoint = new URL (null, url, new URLStreamHandler () {
protected URLConnection openConnection (URL url) throws IOException {
// The url is the parent of this stream handler, so must create clone
URL clone = new URL (url.toString ());
HttpURLConnection connection = (HttpURLConnection) clone.openConnection();
connection.setRequestProperty("Content-Type",
"text/xml");
connection.setRequestProperty("Accept",
"application/soap+xml, text/*");
// If we cast to HttpURLConnection, we can set redirects
// connection.setInstanceFollowRedirects (false);
connection.setDoOutput(true);
connection.setConnectTimeout(3 * 1000);
connection.setReadTimeout(3 * 1000);
return connection;
for the SAAJ API part, below is the implementation, pretty basic one
SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory
.newInstance();
soapConnection = soapConnectionFactory.createConnection();
is = new ByteArrayInputStream(command.getBytes());
SOAPMessage request = MessageFactory.newInstance(
SOAPConstants.SOAP_1_1_PROTOCOL).createMessage(
new MimeHeaders(), is);
MimeHeaders headers = request.getMimeHeaders();
headers.addHeader("Content-Type", "text/xml");
request.saveChanges();
ByteArrayOutputStream out = new ByteArrayOutputStream();
request.writeTo(out);
soapResponse = soapConnection.call(request, endpoint);
Is it that system properties would affect connect or read timeout. If so please let me know what could cause this behavior.

Windows Azure Cloud App - Could not create SSL/TLS secure channel

I am trying to pull JSON from a customer's website, but I get this error.
The code works my local machine.
For other sites, both on my local machine and on the server, the code works.
The site is https://www.vapedepot.ca/wc-api/v1
Does he have a special SSL cert where I need to change my code? Here is my code:
string GetJson(string url)
{
string resultData = string.Empty;
HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url);
myHttpWebRequest.Accept = "application/json";
myHttpWebRequest.Timeout = 6000;
//myHttpWebRequest.ContentType = "application/x-www-form-urlencoded";
string userP = m_UserName + ":" + m_Password;
byte[] authBytes = Encoding.UTF8.GetBytes(userP).ToArray();
myHttpWebRequest.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(authBytes));
WebResponse httpResponse = myHttpWebRequest.GetResponse();
Stream responseStream = httpResponse.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
resultData = reader.ReadToEnd();
responseStream.Close();
httpResponse.Close();
return resultData;
}
He is using CloudFlare and the SSL uses ecdsa.
I had the same issue. I swapped to using RestSharp to make my secure web requests and it resolved my issue.

Creating Azure Traffic Manager through REST API - unexpected behaviour

I created Traffic Manager throught its REST API using 2011-10-01 MS verion.
Resources I followed -
Create Profile -
http://msdn.microsoft.com/en-us/library/windowsazure/hh758254.aspx
Create Definition -
http://msdn.microsoft.com/en-us/library/windowsazure/hh758257.aspx
Traffic Manager got created successfully. All happies.
But after 30mins of time, traffic manager is going to INACTIVE status and all its endpoints are GONE. It shows there are no endpoints associated with it.
I am not sure what is happening around. Is it Azure problem? or is it REST API problem? or is it my way of creating Traffic manager problem.
PS - I followed this sample for making REST API calls - http://msdn.microsoft.com/en-us/library/windowsazure/gg651127.aspx
Any help would be highly appreciated.
UPDATE1
Parameters
SubscriptionID - a Valid GUID from publishsettings
Certificate - I cross checked a valid certificate present in the local cert store
endpoint1 domain name - JASH13.CLOUDAPP.NET
endpoint2 domain name - JASH23.CLOUDAPP.NET
There is no error at REST API calls level. Everything worked seamlessly.
Profile Creation -
// X.509 certificate variables.
X509Store certStore = null;
X509Certificate2Collection certCollection = null;
X509Certificate2 certificate = null;
// Request and response variables.
HttpWebRequest httpWebRequest = null;
HttpWebResponse httpWebResponse = null;
// Stream variables.
Stream responseStream = null;
StreamReader reader = null;
// URI variable.
Uri requestUri = null;
// The thumbprint for the certificate. This certificate would have been
// previously added as a management certificate within the Windows Azure management portal.
string thumbPrint = CertificateThumbprint;
// Open the certificate store for the current user.
certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
certStore.Open(OpenFlags.ReadOnly);
// Find the certificate with the specified thumbprint.
certCollection = certStore.Certificates.Find(
X509FindType.FindByThumbprint,
thumbPrint,
false);
// Close the certificate store.
certStore.Close();
// Check to see if a matching certificate was found.
if (0 == certCollection.Count)
{
throw new Exception("No certificate found containing thumbprint " + thumbPrint);
}
// A matching certificate was found.
certificate = certCollection[0];
// Create the request.
requestUri = new Uri("https://management.core.windows.net/"
+ SubscriptionId
+ "/services/WATM/profiles");
httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(requestUri);
// Add the certificate to the request.
httpWebRequest.ClientCertificates.Add(certificate);
httpWebRequest.Method = "POST";
httpWebRequest.Headers.Add("x-ms-version", "2011-10-01");
string str = #"<Profile xmlns=""http://schemas.microsoft.com/windowsazure""><DomainName>" + ProfileDomain + "</DomainName><Name>" + ProfileName + "</Name></Profile>";
byte[] bodyStart = System.Text.Encoding.UTF8.GetBytes(str.ToString());
Stream dataStream = httpWebRequest.GetRequestStream();
dataStream.Write(bodyStart, 0, str.ToString().Length);
// Make the call using the web request.
httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
// Parse the web response.
responseStream = httpWebResponse.GetResponseStream();
reader = new StreamReader(responseStream);
// Close the resources no longer needed.
httpWebResponse.Close();
responseStream.Close();
reader.Close();
Definition Creation-
// X.509 certificate variables.
X509Store certStore = null;
X509Certificate2Collection certCollection = null;
X509Certificate2 certificate = null;
// Request and response variables.
HttpWebRequest httpWebRequest = null;
HttpWebResponse httpWebResponse = null;
// Stream variables.
Stream responseStream = null;
StreamReader reader = null;
// URI variable.
Uri requestUri = null;
// The thumbprint for the certificate. This certificate would have been
// previously added as a management certificate within the Windows Azure management portal.
string thumbPrint = CertificateThumbprint;
// Open the certificate store for the current user.
certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
certStore.Open(OpenFlags.ReadOnly);
// Find the certificate with the specified thumbprint.
certCollection = certStore.Certificates.Find(
X509FindType.FindByThumbprint,
thumbPrint,
false);
// Close the certificate store.
certStore.Close();
// Check to see if a matching certificate was found.
if (0 == certCollection.Count)
{
throw new Exception("No certificate found containing thumbprint " + thumbPrint);
}
// A matching certificate was found.
certificate = certCollection[0];
// Create the request.
requestUri = new Uri("https://management.core.windows.net/"
+ SubscriptionId
+ "/services/WATM/profiles/" + ProfileName + "/definitions");
httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(requestUri);
// Add the certificate to the request.
httpWebRequest.ClientCertificates.Add(certificate);
httpWebRequest.Method = "POST";
httpWebRequest.Headers.Add("x-ms-version", "2011-10-01");
string str = #"<Definition xmlns=""http://schemas.microsoft.com/windowsazure""><DnsOptions><TimeToLiveInSeconds>300</TimeToLiveInSeconds></DnsOptions><Monitors><Monitor><IntervalInSeconds>30</IntervalInSeconds><TimeoutInSeconds>10</TimeoutInSeconds><ToleratedNumberOfFailures>3</ToleratedNumberOfFailures><Protocol>HTTP</Protocol><Port>80</Port><HttpOptions><Verb>GET</Verb><RelativePath>/</RelativePath><ExpectedStatusCode>200</ExpectedStatusCode></HttpOptions></Monitor></Monitors><Policy><LoadBalancingMethod>RoundRobin</LoadBalancingMethod><Endpoints><Endpoint><DomainName>" + PrimaryService + "</DomainName><Status>Enabled</Status></Endpoint><Endpoint><DomainName>" + SecondaryService + "</DomainName><Status>Enabled</Status></Endpoint></Endpoints></Policy></Definition>";
byte[] bodyStart = System.Text.Encoding.UTF8.GetBytes(str.ToString());
Stream dataStream = httpWebRequest.GetRequestStream();
dataStream.Write(bodyStart, 0, str.ToString().Length);
// Make the call using the web request.
httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
// Parse the web response.
responseStream = httpWebResponse.GetResponseStream();
reader = new StreamReader(responseStream);
// Close the resources no longer needed.
httpWebResponse.Close();
responseStream.Close();
reader.Close();
UPDATE2
Once the TM went into Inactive State, I checked the profile definition using REST API. In there I was not able to find any endpoints. They are missing.
<Definitions xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Definition>
<DnsOptions>
<TimeToLiveInSeconds>300</TimeToLiveInSeconds>
</DnsOptions>
<Status>Enabled</Status>
<Version>1</Version>
<Monitors>
<Monitor>
<IntervalInSeconds>30</IntervalInSeconds>
<TimeoutInSeconds>10</TimeoutInSeconds>
<ToleratedNumberOfFailures>3</ToleratedNumberOfFailures>
<Protocol>HTTP</Protocol>
<Port>80</Port>
<HttpOptions>
<Verb>GET</Verb>
<RelativePath>/</RelativePath>
<ExpectedStatusCode>200</ExpectedStatusCode>
</HttpOptions>
</Monitor>
</Monitors>
<Policy>
<LoadBalancingMethod>Performance</LoadBalancingMethod>
<Endpoints/>
<MonitorStatus>Inactive</MonitorStatus>
</Policy>
</Definition>
</Definitions>
UPDATE3
This sporadic behavior is ONLY happening with the specific cloud services and TM profile/definitiona. When I create new set of cloud services and TM profile, then everything seems to be working fine. I tested this multiple times. So the only problem is with following parameters.
endpoint1 domain name - JASH13.CLOUDAPP.NET
endpoint2 domain name -JASH23.CLOUDAPP.NET
TM Domain - ramitm.trafficmanager.net
TM profilename - ramitm
This seems like some DNS Problems for very fast REST API Operations. I was not able to get the crux of the problem, but this is how I solved it.
Previously I was getting this problem for this patter - Create -> Delete -> Re-Create
Now I made it this way - Create -> Delete -> Delay -> Re-Create
I think by introducing delay component, I am giving enough time for Azure to settle down all the DNS and infrastructure and there by update them. So after introducing delay, I was not experiencing the problem. Delay can be 5 - 10 mins.

Resources