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

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.

Related

How can I disable the SSL Certificate check in the .NET Core http client?

I am trying to connect to a website via a proxy. This is happening in an AWS Lambda with .NET Core SDK using an http client. The call looks pretty much like this:
handler = new HttpClientHandler()
{
CookieContainer = cookieContainer,
Proxy = new WebProxy(
new Uri(Environment.GetEnvironmentVariable("proxyURL"))),
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator,
SslProtocols = SslProtocols.Tls12,
ClientCertificateOptions = ClientCertificateOption.Manual
};
using(var client = new HttpClient(handler))
{
var content = await client.GetAsync("https://my-website.com/");
}
I am not able to make the call to "https://my-website.com/". The call times out without an error message.
However I was able to access the website using Golang and resty in an AWS Lambda, skipping the TLS Check:
client := resty.New()
resp, err := client.
SetProxy(os.Getenv("proxyURL")).
SetRetryCount(3).SetTimeout(3*time.Second).SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}).
R().Get("https://my-website.com/")
My question is: how can I achieve the behaviour from my Golang Code in my .NET Core Code?
TL; DR: The problem lied not within certificate validation, but in a security group rule.
As Marc Gravell kindly pointed out, the DangerousAcceptAnyServerCertificateValidator already achieves the aim of ignoring certificate validation problems.
After deploying the same code in an EC2 instance in the same VPC and subnet I noticed, that the .NET Core code was making one more HTTP call than the Go code (Although I still do not understand why). The IP adress was not within the allowed IP range of outgoing traffic, thus blocking the request and causing a timeout of the HttpClient.

How to properly establish SSL connection from UWP App to WebAPI using HttpClient class?

I have an UWP application which communicates with server WebAPI. To do this I am using HttpClient class from Windows.Web.Http namespace. It does work fine if I use simple Http URL. Because of sending passwords and other sesitive data I would like to use SSL. But the problem appears when I am trying to use Https URL. Program still shows me an error which says that "The certificate authority is invalid or incorrect". I am new in certificates etc. so it does not tell me anything useful.
On some websites I found some semi-solution. Using HttpBaseProtocolFilter class I can set options to ignore some server certificate errors like this:
HttpBaseProtocolFilter filter = new HttpBaseProtocolFilter();
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted);
HttpClient client = new HttpClient(filter);
It works, but only on desktop. When I run my application on Mobile Emulator, the error shows up again. Also I do not really think that this is a good solution so I have searched for something else and just found this: https://pfelix.wordpress.com/2012/12/16/using-httpclient-with-ssltls/ . There are some informations about HttpClient and SSL, but as far as I understand it is about HttpClient from namespace System.Net.Http. I tried this solution for Windows Store App, but it have not worked too.
var client = new HttpClient(new HttpClientHandler
{
ClientCertificateOptions = ClientCertificateOption.Automatic
});
So here is my question: how can I set up this HttpClient (from Windows.Web.Http or System.Net.Http) to perform working SSL connection with my WebAPI? Maybe is there something to set by server side?
Edit: I am using IIS Express from Visual Studio 2015 because I do not really know how to add my WebAPI to full IIS and let it work. I also turn on SSL in WebAPI project Properties, which generated for me a Https URL (so I thought that it would also generate a properly certificate). If I try to navigate to the Http URL everything is fine on my Mozilla Firefox and IE. The error about untrusted certificate shows when I try my https://localhost:44301/ URL in both browsers.
You were close with the HttpClientHandler approach, but you want to trust the server certificate, not the client certificate (which doesn't exist in your example). Try this:
HttpClient client = new HttpClient(new HttpClientHandler {
ServerCertificateCustomValidationCallback = (a, b, c, d) => true });
This will cause ALL server certificates to be trusted so don't use it in production, but works great for accessing an https service on localhost from a UWP app during development.

How can I get more information about a fault in system.net.http?

I'm using HttpClient from System.Net.Http on nuget to make a request from a module (assembly) written in c#. This needs to work with a legacy application in Windows XP so we're using .Net Framework 4.0.
I can successfully send a https request to our server from my Windows 10 machine; however, when I test it from Windows XP in a VM, I get a fault. I can request websites like https://google.com but our https site causes a fault. On top of all this, the res.StackTrace is null! The Message I get from obj.Exception.InnerException is An error ocurred while sending the request. I can however get to our site in a browser in the VM without trouble. So why can't I get a StackTrace? Could this be some kind of ssl trust issue (our site has an ssl certificate from godaddy)?
var client = new HttpClient();
client.BaseAddress = new Uri(SERVER_BASE_URL); // https://...
// Works when BaseAddress="https://google.com" but not our https site
return client.GetAsync("/").ContinueWith(res =>
{
if (res.IsFaulted)
// res.StackTrace is empty >:(
MessageBox.Show("Faulted");
else
MessageBox.Show("Success");
});

WCF Unsecured response in .NET 4.5

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);

How to use proxy like browser OR CredentialCache.DefaultCredentials different between XP and 7

I am able to fix a problem with a client where they cannot authenticate through a proxy doing the following:
var proxy = WebRequest.GetSystemWebProxy();
proxy.Credentials = CredentialCache.DefaultNetworkCredentials;
service.Proxy = proxy;
This works fine for Windows XP, however on Windows 7 I get a 407 (proxy not authenticated exception). Does anybody know what the difference is, and more importantly, what I need to do to get this to work on both OS?
UPDATE
I am having the users check the following:
In the registry editor, can you go to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon and let me know what the value is for CachedLogonsCount. f
In the Start box, type in Group Policy and an option to Edit Group Policy should pop up, click on it. Then go to Computer Configuration\Administrative Templates\System\User Profiles\Delete cached copies of roaming profiles and let me know if it is configured, and if so, to what is it set?
UPDATE FOR BOUNTY
So, I added the bounty. I can take a solution from here, or just an alternate means to getting through a proxy on Windows 7...
Another Update
I am not sure if this is useful or not, but we are also doing the following:
service.PreAuthenticate = true;
service.Url = "myurl";
service.Credentials = new NetworkCredential(txt_UserName.Text, txt_Password.Text);
My temporary solution
This is not really a solution, but works for now. I am using the app.config and setting the proxy to be default, with a ByPassList so that the proxy is not even used. This is only doable since the proxy does not have a strong firewall currently. For other clients, I need to get the above to work
This piece of code works for me on XP, Win7 and 2008
var webProxy = new WebProxy(WebRequest.DefaultWebProxy.GetProxy(new Uri({TheURLoftheService})));
webProxy.Credentials = CredentialCache.DefaultCredentials;
webProxy.UseDefaultCredentials = true;
service.Proxy = webProxy;
actually looks like they "fixed" it in Win7 :) Can you confirm that both client and server are specifying http 1.1
Now let's discuss as to why the browser works in this scenario. IE
uses WinINet under the hood rather than WinHTTP. If we look at the
network traces we see that IE sends HTTP/1.1, but the proxy replies
with HTTP/1.0. IE still accepts this behavior, because in the internet
scenario there are countless number of clients and servers which still
use HTTP/1.0.
WinHTTP strictly requires HTTP/1.1 compliance for keeping the
connection alive and HTTP Keep-Alives are not supported in HTTP/1.0
protocol. HTTP Keep-Alive feature was introduced in the HTTP/1.1
protocol as per RFC 2616. The server or the proxy which expects the
keep-alive should also implement the protocol correctly. WinHTTP on
Windows 7, Windows 2008 R2 are strict in terms of security wrto
protocol compliance. The ideal solution is to change the server/proxy
to use the right protocol and be RFC compliant.
http://blogs.msdn.com/b/httpcontext/archive/2012/02/21/changes-in-winhttp-on-windows-7-and-onwards-wrto-http-1-0.aspx
Will this work?
I am using this to set proxy, so far we did not encounter an error on all windows platform
Uri address = new Uri("http://your-webservice-address");
//Get User current network credential
ICredentials credentials = CredentialCache.DefaultCredentials;
NetworkCredential credential = credentials.GetCredential(address, "Basic");
//Get HttpWebRequest
HttpWebRequest request = WebRequest.Create(address) as HttpWebRequest;
//Network Credential should be included on the request to avoid network issues when requesting to the web servic
request.Proxy = WebRequest.DefaultWebProxy;
request.Credentials = new NetworkCredential(credential.UserName, credential.Password, credential.Domain);
It's hard to say based on the code you've given. I'd suspect that it's either your IE settings or your proxy variables.
Check http://social.msdn.microsoft.com/Forums/en/netfxnetcom/thread/61b71194-1758-4c7b-89fe-91be7363db13 it may help.

Categories