WCF Unsecured response in .NET 4.5 - c#

I'm working on client application to utilize SOAP web service. Added SOAP web services as Service reference. It connects to IBM server and server requires WS-Security basic authentification.
Called with default settings and got an error(no authentication header)
Modified code to look like so:
var service = new RealTimeOnlineClient();
service.ClientCredentials.UserName.UserName = "xxxxx";
service.ClientCredentials.UserName.Password = "yyyyy";
Now when I look at response in Fiddler - works properly (I get expected envelope from server), I get proper envelope back.
However, I get exception from WCF:
Security processor was unable to find a security header in the message. This might be because the message is an unsecured fault or because there is a binding mismatch between the communicating parties. This can occur if the service is configured for security and the client is not using security.
Quick search and bunch of answers here on SO points me to HotFix from Microsoft where they added new property EnableUnsecuredResponse. Problem is - I can't figure out WHERE to apply this property in my code OR in config. Adding to security tag in web.config doesn't work (errors out can't find property).
I understand hotfix came out for .NET 3.5 and most questions from 2009-2010. It should be in 4.5 already, correct? How do I apply this property to my code?

I had to add following code to alter value of "EnableUnsecureResponse"
var service = new RealTimeOnlineClient();
service.ClientCredentials.UserName.UserName = "xxxxx";
service.ClientCredentials.UserName.Password = "yyyyy";
var elements = service.Endpoint.Binding.CreateBindingElements();
elements.Find<SecurityBindingElement>().EnableUnsecuredResponse = true;
service.Endpoint.Binding = new CustomBinding(elements);

Related

How do i Set the System.ServiceModel.ClientBase<TChannel> to Ignore CERT Errors

I am moving an application that communicates with a WCF service from .net 4.8 to net5 i ran the utility SvcUtil.exe (importing a WDSL File) which generated the Reference.cs file which created the classes and object from the WSDL file. In net5 it is now using the System.ServiceModel.ClientBase class to interact with the WCF Service, where as in net48 it was using 'System.Web.Services.Protocols.SoapHttpClientProtocol'. Code compiles but there remains two problems that I'm experiencing right now that i cannot seem to find the answer for using the new 'System.ServiceModel.ClientBase' implementation generated by the SvcUtil.exe tool.
When the connection is trying to be established i am always getting the following Exception:
{"Could not establish trust relationship for the SSL/TLS secure channel with authority 'xxx.xxx.xxx.xxx'."} InnerException => {"The SSL connection could not be established, see inner exception."} InnerException => {"The remote certificate is invalid according to the validation procedure: RemoteCertificateNameMismatch, RemoteCertificateChainErrors"}
Also the in the net48 version i store the cookie in the cookie container like So:
Cookie cookie = new Cookie(cookieParts[0], cookieParts[1],
serviceUri.LocalPath, serviceUri.Host);
cookie.Expires = DateTime.Now.AddHours(1);
_xieServiceRef.CookieContainer = new CookieContainer();
_xieServiceRef.CookieContainer.Add(serviceUri, cookie);
My problem is that for one in net48 to tell the service to ignore all cert errors we execute the following code
ServicePointManager.ServerCertificateValidationCallback +=
(sender, cert, chain, sslPolicyErrors) => { return true; }
From anywhere in the app and we bypass those errors. But in net5 you have to approach it differently and the only example is given using the HttpClient class and you create the HttpClient with a defined HttpClientHandler callback as in the example below this will ignore the CERT errors just as the code above for net48.
var EndPoint = "https://192.168.0.1/api";
var httpClientHandler = new HttpClientHandler();
httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) =>
{
return true;
};
httpClient = new HttpClient(httpClientHandler) { BaseAddress = new Uri(EndPoint) };
In using the SvcUtil.exe generated code with the use of the ClientBase class as a means of interaction with the WCF Service, I cannot find methods or example similar to the above code to ignore the CERT errors. I also cannot find the Cookie Container for the ClientBase either. Do I need to skip using the generated code from SvcUtil.exe and switch to the HttpClient instead of the ClientBase. Or are there similar ways to store the generated cookie and ignore the CERT errors. We don't control the API we are calling and there is no REST version of the API and none coming soon so we are stuck working with what we have.
Any advice would be greatly appreciated and also thank you ahead of time
UPDATE
So i did some more research and digging and i have found that using the following code:
//Right Here we are creating the Service Object
XIEserviceClient _xieServiceRef = null;
_xieServiceRef = new XIEserviceClient();
_xieServiceRef.ChannelFactory.Credentials.ServiceCertificate.SslCertificateAuthentication = new X509ServiceCertificateAuthentication()
{
CertificateValidationMode = X509CertificateValidationMode.None,
RevocationMode = X509RevocationMode.NoCheck
};
_xieServiceRef.ChannelFactory.Credentials.UserName.UserName = CalderaConfiguration.SelectedOS4000ApiConnection.Username;
_xieServiceRef.ChannelFactory.Credentials.UserName.UserName = CalderaConfiguration.SelectedOS4000ApiConnection.Password;
We are now able to bypass the cert errors.
Now I'm just trying to I'm to figure out the whole cookie/authentication error, I now get the following Exception:
"The content type text/html of the response message does not match the content type of the binding (text/xml; charset=utf-8)
This i believe, according to Fiddler, appears to be an authentication issue because it appears that a login page is being returned from the service i believe this is the cookie issue I'm still looking into....
There are a few things to consider :
Do you have DNS and line-of-sight to the server?
Are you using the correct name from the certificate?
Is the certificate still valid?
Is a badly configured load balancer messing things up?
Does the new server machine have the clock set correctly (i.e. so that the UTC time is correct [ignore local time, it is largely irrelevent]) - this certainly matters for WCF, so may impact regular SOAP?
Is there a certificate trust chain issue? if you browse from the server to the soap service, can you get SSL?
Related to the above - has the certificate been installed to the correct location? (you may need a copy in Trusted Root Certification Authorities)
is the server's machine-level proxy set correctly? (which different to the user's proxy);see proxycfg for XP / 2003 (not sure about Vista etc)

Change WebService Endpoint from HTTP to HTTPS

I'm really new to .NET and I have come to a roadblock (I guess).
I have a project that needs changing one address for another service we use, this address changed from HTTP to HTTPS.
My question is, for this change, do I need to change the code of the method that invokes the request, so I load the certificate in there, or do I just change the endpoint config?
I've tried the endpoint config security binding from None to TransportWithMessageCredential, also loading the certificate to the machine repository, but I'm not sure how do I specify what certificate I want to send.
I guess you are using BasicHttpBinding right now, and need to change from a HTTP endpoint to a HTTPS endpoint that requires validation through X509 certificate. I'm assuming you're using C#.
If you're using any version of .NET Framework older than 4.5, you can do:
var binding = new BasicHttpBinding(BasicHttpsSecurityMode.Transport);
If you are using .NET Framework 4.5 or newer version, you can do like this:
var binding = new BasicHttpsBinding();
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
Assuming you've imported the WebService definition deriving from System.ServiceModel.ClientBase (like when you right-click the project in Visual Studio and choose Add > Service Reference), you can do something like this:
var address = new EndpointAddress(serviceUrl);
var wsClient = new ServiceReference1.YourServiceClient(binding, address);
// x509Cert is a variable of type 'X509Certificate2'.
wsClient.ClientCredentials.ClientCertificate.Certificate = x509Cert;
// Take a look at: https://stackoverflow.com/a/49303859/
wsClient.Open();
wsClient.CallTheService();
wsClient.Close();

SOAP authentication fails when running a c# app on a linux box

I'm trying to connect to a third-party SOAP service via a c# app. The following code works when running the app on a Windows machine:
var ws = new MyWebServiceClient();
ws.ClientCredentials.Windows.ClientCredential = new System.Net.NetworkCredential("myusername", "mypassword", "mydomain");
var response = ws.SomeEndpoint();
Element xmlResult = response.Result.SomeEndpoint;
...
But if I run the same code from Linux or Mac OS, it fails with:
The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Negotiate, NTLM'.
I have a python app that can consume that same SOAP service when running on any operating system without running into issues, so the problem isn't in my linux distribution/setup.
Has anyone seen a similar issue with .NET core or found a workaround?
I found this issue report that suggests that the earlier versions of .NET core had limitations/bugs that could cause behavior similar to what I'm seeing, but it claims that those issues were resolved after RC2.
Assuming that issue report is wrong and that the issue still remains in the Linux/Mac distribution of .NET core, does anyone know how I can get the CredentialCache workaround, suggested in that article, working with a SOAP client? I'm pretty new to .NET and super new to .NET soap clients, so I apologize if that's a naive question.
It seems that, for non-Windows, .NET core is failing to attempt NTLM after Negotiate fails. I know, from the python app, that NTLM works with this particular SOAP service. How can I force it to skip "Negotiate" and and go straight to NTLM? It seems that that is what the CredentialCache workaround, from the above article, is doing. I just can't figure out how to make that work with a SOAP service...
.Net Core SOAP client wih NTLM Authentication and CredentialCache
As described on MSDN and here,
BasicHttpBinding basicHttpBinding = new BasicHttpBinding();
basicHttpBinding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
basicHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;
EndpointAddress endpoint = new EndpointAddress("http://myservice");
var factory = new ChannelFactory<IMyService>(basicHttpBinding, endpoint);
CredentialCache myCredentialCache = new CredentialCache();
NetworkCredential myCreds = new NetworkCredential("username", "password", "domain");
myCredentialCache.Add("ContoscoMail", 45, "NTLM", myCreds);
factory.Credentials.Windows.ClientCredential =
myCredentialCache.GetCredential("ContosoMail", 45, "NTLM");
var client = factory.CreateChannel();
// ... use the webservice
Update: it's a bug fixed in 2.1
As already encountered here and fixed as a bug here, it should work with .net core 2.1 (not released and scheduled for Q1 2018).
So right now, you should try to use another type of authentication when connecting from Linux (look at RuntimeInformation.IsOSPlatform).
It is important to know how authentication works differently in Windows/Console app VS Web application.
Answers to your question to skip Negotiate (From Server): Go to IIS --> Go to site/application --> Select Authentication (Double Click on that)--> You will see options here --> Under Windows authentication (if this is enabled) then --> click on Provider in right side action pan.
Here you can move up down/remove "Negotiate" options.

WCF REST Consuming error

I keep getting the following error when trying to consume a webservice:
The HTTP request is unauthorized with client authentication scheme 'Basic'. The authentication header received from the server was 'Basic Realm'.
The webservice is REST written with WCF. The authentication is basic over https.
Any help fixing the error would be apreciated.
Here is the code I tried:
WebHttpBinding webBinding = new WebHttpBinding();
webBinding.Security.Mode = WebHttpSecurityMode.Transport;
webBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
ChannelFactory<ServiceReferences.BTService.FLDT_WholesaleService> factory = new ChannelFactory<ServiceReferences.BTService.FLDT_WholesaleService>(webBinding,
new EndpointAddress(
"https://wholesale.fluidata.co.uk/FLDT_BT_wholesale/Service.svc"));
factory.Endpoint.Behaviors.Add(new WebHttpBehavior());
factory.Credentials.UserName.UserName = "username";
factory.Credentials.UserName.Password = "password";
ServiceReferences.BTService.FLDT_WholesaleService proxy = factory.CreateChannel();
proxy.AvailabilityCheck("123");
As long as you expose RESTful service you may attempt to use Fiddler - http://www.fiddler2.com/fiddler2/ and/or normal HttpRequest/HttpResponse. Did you try anything like that?
Mr. Franek's answer is useful - you WILL be using Fiddler in working with WCF, period. I can add a little bit...what is happening here is that you've specified "Basic" as your authentication scheme as a client. The server is saying "I only allow 'Basic Realm'" as the authentication scheme. What is 'realm'? Basically a credential namespace:
Realm for HTTP basic authentication
Here's another helpful link: Authentication in WinHTTP
I can't find a property or method overload that carries Realm...I would probably try to construct the Authenticate-WWW header manually.
That would go something like this:
request.Headers.Add("WWW-Authenticate", string.Format("basic realm=\"{0}\", realm));
"realm" would be the value of whatever the server is expecting, e.g., "www.targetsite.com".

Using WCF service in MonoTouch with Authentication

I am using a WCF service client generated by slsvcutil form Silverlight toolkit version 4. I've also tried version 3 with the same problems. When I use a client instance running on http with no user credentials it runs without problems. But I need to switch to https for productive servers and send user credentials that are hardcoded for my application. I use the following code for that:
var binding = new BasicHttpBinding (BasicHttpSecurityMode.TransportCredentialOnly);
var endpoint = new EndpointAddress (AppSettings.FlareEndPoint);
_service = new TopicAnalystAPIClient(binding, endpoint);
_service.ClientCredentials.UserName.UserName = "xxx";
_service.ClientCredentials.UserName.Password = "xxx";
When I call a method on that service pointing to http with no authentication it works. When I use the this code against http/https with the credential I get "There was an error on processing web request: Status code 401(Unauthorized): Unauthorized" exception. I've checked that the credentials are correct, I am able to open the service reference in my browser. I've also tried several combinations of http/https and SecurityMode value. I've also tried it on four different servers always with the same result.
What can be the problem?
A lot of permutations are possible. BasicHttpSecurityMode.TransportCredentialOnly should be usable without SSL [1] using HTTP itself. This means the server will send one (or more) authentication method(s) to the client (e.g. basic, digest, ntlm) and Mono (including MonoTouch) should be providing support for the most of them.
It is possible that the linker (if used) removes one of them. In that case you could try building and testing without linking (or skip linking of System.Net.dll).
It's also possible that the authentication method that the serve insist on is not supported. You could find which one is used by running a network trace (e.g. wireshark) or, maybe, it will show up in more details in the server log (along with the 401 error).
[1] http://msdn.microsoft.com/en-us/library/system.servicemodel.basichttpsecuritymode%28v=vs.95%29.aspx

Categories