WCF over HTTPS in Monotouch? - wcf

I am trying to call a wcf service over https and have followed the suggested setup from here. It works fine over http, but I get a RemoteCertificateNameMismatch error over https which I am handling with this (as suggested) -
System.Net.ServicePointManager.ServerCertificateValidationCallback +=
(se, cert, chain, sslerror) => { return true; };
I later get a 415 unsupported media type error which I can't figure out. I have a win .net test client that is able to call the service and receive results, but from monotouch I can't get it to work. Has anyone been able to do this successfully and wouldn't mind pasting an example?
Any help is much appreciated!

HTTP error codes comes from the server side. Of course the client configuration may play a role into this.
If possible switch to HTTP and compare sessions (e.g. using wireshark) between your Windows's and MonoTouch clients. Doing so in HTTPS may tell you a few things but that's less likely to be helpful.
Also check for similars 415 errors affecting other (non-MonoTouch) projects. Since the error comes the server the information they provide might help you find what's going on.

Related

WCF - certificate not configured properly with HTTP.SYS in the HTTPS case. Works with Charles proxy running

This seems to be a common error (there are other posts with similar issues) - however, I have gone through all those posts and MSDN articles ( https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/working-with-certificates ).
Scenario: Trying to access a service with an HTTPS end point.
Setting the client certificate in code (certificate is loading correctly).
As for the Server cert, I have tried both the options below:
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.PeerOrChainTrust;
I have imported the server certificate to Personal as well as machine store (Trusted Root certificate authorities / certificates).
The weird thing is the call is going through when I use Charles Proxy as the SSL proxy.
Other settings:
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Ssl3;
ServicePointManager.ServerCertificateValidationCallback +=
(se, cert, chain, sslerror) =>
{
//Console.WriteLine(cert.GetCertHashString());
if (cert.GetCertHashString() == "[actual hash here]")
return true;
else
return false;
};
The above Hash check works fine when Charles proxy is running. Without the proxy running, the callback does not even get called.
Any feedback is appreciated.
(It may be worthwhile to note that a Java client using Apache CXF library works fine - against the same service.)
Update:
For completeness, the original error also had this text:
This could be due to the fact that the server certificate is not configured properly with HTTP.SYS in the HTTPS case. This could also be caused by a mismatch of the security binding between the client and the server.
OK, after days(& nights) of head banging, the following are my musings / findings (& of course the solution !):
There is "SSL" and then there is SSLv2, SSLv3, TLSv1.0, TLSv1.1, TLS1.2 & TLSv1.3 (draft as of now).
It is critical that the server and client are able to negotiate & pick one of these versions to successfully communicate.
The HTTP.SYS error seems to be a result of the client not being able to negotiate with the server on the appropriate version. When going through Charles proxy, it was clear that both Charles and the service we were trying to hit, were using TLSV1.1.
In my case, I was using wsHTTPBinding & though I tried setting the System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls; and other combinations, I could never get the HTTP.SYS error to go away. It would seem that the server and the client could never pick a version that they could agree on.
I did try using other bindings such as basicHttpBinding (with TransportWithMessageCredential) as well as basicHttpsBinding, but to no avail. What's more with some minor tweaks in the binding elements (through config & code) in each case, I ended with exactly the same binding configuration in all 3 cases (basicHttp/basichHttps/wsHttp bindings)! In essence, while there are these out-of-the-box bindings, they probably work for the most simple of scenarios. What's more, there is probably no need for so many of these pre-packaged bindings, especially as they seem to be using mostly the same binding elements.
I did remember reading that using a custom binding is better in many cases - but I imagined that by customizing a wsHttpBinding I would be achieving the same thing. Looks not - as there are some hard-coded properties (e.g.: default SSL protocols) in this binding that seem difficult to get around. I did take a look at the source code of wsHttpBinding and its base class, but could not find the exact hard coded location (but there are references to "default" protocols in the System.ServiceModel code).
In the end a "CustomBinding" worked for me, configured like so:
Custom Binding configuration
- Sorry for including this as an image - as the formatting on SO was playing up.
The idea is to use httpsTransport with requireClientCertificate, security with authenticationMode="CertificateOverTransport" & includeTimestamp="true" (our service required Timestamp) and the relevant messageSecurityVersion - in our case it was:
WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10.
The above configurations automatically signed the Timestamp as well.
On top of this we had to include the username / password credentials. Simply setting the client.ClientCredentials.UserName.UserName & client.ClientCredentials.UserName.Password did not result in these credentials included in the Security header. The logic was to add the username "token" as well, like so:
//Get the current binding
System.ServiceModel.Channels.Binding binding = client.Endpoint.Binding;
//Get the binding elements
BindingElementCollection elements = binding.CreateBindingElements();
//Locate the Security binding element
SecurityBindingElement security = elements.Find<SecurityBindingElement>();
//This should not be null - as we are using Certificate authentication anyway
if (security != null)
{
UserNameSecurityTokenParameters uTokenParams = new UserNameSecurityTokenParameters();
uTokenParams.InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient;
security.EndpointSupportingTokenParameters.SignedEncrypted.Add(uTokenParams);
}
client.Endpoint.Binding = new CustomBinding(elements.ToArray());
With all this setup, I was able to finally hit the Service and actually get the result - well, almost ! - as the result does not include a Timestamp, which WCF is throwing up as an exception. That is another problem to solve though.
Hopefully readers find this useful.
Update:
Now the Timestamp issue is also "sorted". The thing is the response lacked any security header, not just the timestamp. Thankfully there was a straightforward way to notify WCF to ignore unsecure responses, by simply marking an attribute on the security element: enableUnsecuredResponse="true". Obviously this is not desirable, but as we do not have any control on the service, this is the best we can do at the moment.

Possible proxy issue with WSO2 API Manager

Whenever I try to add the following endpoint, "http://ws.cdyne.com/phoneverify/phoneverify.asmx", during the Managed API setup process and press the Test button I get an error on the server. ERROR - APIProviderHostObject Error occurred while connecting to backend : "stackOverflow preventing me from showing this link", reason: Connect to ws.cdyne.com:80 timed out
When I try this exact same process on a machine outside of our proxy it works fine. I have gone into the axis2.xml file and added proxy information and even went as far as installing cntlm and setting the proxy to localhost - same error.
I can browse to the above link just fine on this machine.
My environment is Windows 10.
I assume you talk about clicking the Test button when providing Backend Endpoint in API publisher.
The way that Test button works at the moment (as far as I understand) is that it invokes HTTP HEAD method on the endpoint provided (because according to RFC 2616, "This method is often used for testing hypertext links for validity, accessibility, and recent modification.")
Then it checks response. If response is valid or 405 (method not allowed), then the URL is marked as Valid.
Thus sometimes, if backend is not properly following RFC, you might get otherwise working URLs declared as Invalid during the test because of that improper HEAD response evaluation. Obviously, this is just a check for your convenience and you can ignore the check if you know the endpoint works for the methods and resources you need it to work.
So my advice would be to try ignoring the Test and just finishing setting up and publishing the API.
P.S. I am checking it on WSO2 API Cloud but behavior is identical to downloadable API Manager.

WSO2 API Manager is not responding to a request that returns zip file (application/octet-stream)

Using WSO2 API Manager 1.3.1. Trying to use the API Manager to proxy to a REST service. I have set up the service in API Mgr and can successfully post and get responses, typically json, though some are text.
However, when I try to GET a resource that returns binary content (a zip "file", content-type:application/octet-stream), the API Manager does not seem to respond and I can see an error in the console window (i'm running wso2server.bat in console):
[2013-07-03 11:52:05,048] WARN - SourceHandler Connection time out
while writing the response: 173.21.1.22:1268->173.21.1.22:8280
I have an HTTPModule on my internal service and it seems to be responding with the appropriate content (I can see the GET and response data logged). I can also call to the internal service directly and get a response, so that end of things seems OK. But going through the API Manager seems to fail.
I found information on enabling other content-types:
WSO2 API Manager - Publishing API with non-XML response
http://wso2.com/library/articles/binary-relay-efficient-way-pass-both-xml-non-xml-content-through-apache-synapse
Using that information I tried to enable the application/octet-stream for messageFormatter and messageBuilder using the binary relay and it did not help (or seem to make a difference). I have even disabled all other content-types and use the binary relay for all content-types and it does not help.
Currently, I'm running with just the following in both axis2.xml and axis2_client.xml (in their appropriate sections):
<messageBuilder contentType=".*" class="org.wso2.carbon.relay.BinaryRelayBuilder"/
<messageFormatter contentType=".*" class="org.wso2.carbon.relay.ExpandingMessageFormatter"/>
I still get my json and text responses, but WSO2 times out getting the zip content. I saw the JIRA referenced in axis2.xml about enabling the ".*" relay, but as the other requests seem to work, I'm not sure it's an issue for me. I did try adding
'format="rest"' to the API definition, but it seemed to break all operations even the ones that worked prior so I've pulled it back out.
Any ideas on what is happening or how to dig in and debug this will help. Thanks!
After working with this for much too long, it turns out that my WSO2 configuration was correct, using the Message Relay and BinaryRelayBuilder, etc. While my REST service could reply immediately, I was setting a HTTP header that I assume WSO2 does not like, because when i removed it WSO2 would reply at an expected rate (instantly).
I was setting the header:
Transfer-Encoding: binary
When I removed that header from my service reply, then WSO2 operated as expected. I don't know if that's a "bug" in WSO2 or if I was implementing incorrectly, but I do have what seems like a "workaround" by omitting that header from my service response.

WCF REST StarterKit HttpClient: Timeout from HttpClient when going remote - works fine locally or via local proxy

I'm getting repeated Microsoft.Http.HttpStageProcessingException timeout exceptions while trying to use the REST Starter kit's HttpClient. This has been working fine when used locally, but is failing when going remote.
The client is a c# process that runs as a windows service and uses HttpClient for making REST calls to our Java app server running in Tomcat6. When I started troubleshooting this, I came across a similar post on MSDN's forums: http://social.msdn.microsoft.com/Forums/en/wcf/thread/88487549-ce45-49d3-95e4-7ed413cbcfbc
Unfortunately, I can't isolate it to simply a Content-Length problem.
If anyone has any suggestions on how to solve this problem, I would greatly appreciate it - even if it means using HttpWebRequest directly. I understand HttpClient uses HttpWebRequest under the hood, but perhaps it's making some assumptions.
Found the solution. It turns out that the default number of outbound http connections when using the HttpClient seems to be 2. After I used the ServicePointManager static singleton to set the DefaultConnectionLimit for my client AppDomain to 10, everything worked fine.
Now, this is a little concerning, however - because I'm used to writing multi-threaded apps and using the new .NET 4 Tasks - so I really don't like having hard limits on outbound connections. Can anyone provide any links that provide details on how the low-level .NET Http handling works and what knobs control what settings?
Thanks again for the help,
Bob
NEVERMIND - found it myself, should have googled first - this MSDN blog on the Http Client protocol provides a good description of what's going on under-the-hood:
httpclient protocol blog
If it works locally or remotely via Fiddler then it is a problem with HTTP proxy. Your current configuration is not using proxy but Fiddler by default uses proxy configured for IE.
Get the same problem and solution is to Dispose method on response (maybe method named Close may be more clear) else response still occupy the socket and you have to increase the DefaultConnectionLimit to open new socket for each new request untill max limit reach (dirty and slow).
So the solution was:
HttpResponseMessage resp = this.HttpClient.Delete(uri);//or verb get/post/put
try {
//.... do what you need with response
}
finally {
resp.Dispose(); //free the socket for a new request
}

I need a simple web server with a console

My problem is I am adding an Ajax client to an existing RPC web service. i have a PHP client that talks to it, a java jibx.POX client that talks to it, a pure java http client that i wrote that talks to it, everything. but when i try to put my jquery ajax client im working on at it, the server sees the connection, but doesn't receive any data. same on the response, the service sends its error response xml and the ajax client says nothing came back.
what i need to debug this is a simple web server. i want something that is a stand alone program. where i can enter a port number and a start button. point my ajax interface to it, and it displays in a text area all the information possible on the request. then i can point one of my other interfaces to the same port and compare the two and hopefully figure out why 4 interfaces work and 1 doesn't.
does that exist out there somewhere? maybe in one of your arsenals somewhere.
OOPS, never mind, i found one. TCPMon, its a java system a friend of mine emailed me a while ago. does exactly this.
thanks