Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WCF client behind corporate proxy authentication failure - (407) Proxy Authentication Required. #3311

Closed
mmohoney opened this issue Dec 4, 2018 · 10 comments
Assignees

Comments

@mmohoney
Copy link

mmohoney commented Dec 4, 2018

I'm running into an issue when calling an external WCF behind a corporate proxy. In full .Net framework the following was placed in the app.config file which allowed the call to succeed:

  <system.net>
    <defaultProxy enabled="true" useDefaultCredentials="true">
      <proxy bypassonlocal="true" proxyaddress="http://address:port" />
    </defaultProxy>
  </system.net>

In .Net Core I have tried several ways of setting the proxy including setting the ProxyAddress in the BasicHttpBinding. When doing this I receive the (407) Proxy Authentication Required response. I believe this is due to not being able to set the useDefaultCredentials="true" portion in the binding.

In full .Net framework if I set useDefaultCredentials="false" I also receive the exact error of (407) Proxy Authentication Required.

Is there a way to set this to use default credentials when using a proxy?

@mconnew
Copy link
Member

mconnew commented Dec 15, 2018

Be default WCF doesn't provide credentials to a proxy server for security reasons. You have to explicitly opt in to sending credentials. The relevant properties aren't available on BasicHttpBinding, instead you need to modify them on the HttpTransportBindingElement.

var httpBinding = new BasicHttpBinding();
// Set anything you need on the binding
var customBinding = new CustomBinding(httpBinding);
var htbe = customBinding.Element.Find<HttpTransportBindingElement>();
htbe.ProxyAddress = new Uri("http://address:port");
htbe.ProxyAuthenticationScheme = System.Net.AuthenticationSchemes.IntegratedWindowsAuthentication; // Or whatever authentication mechanism your proxy server uses
htbe.UseDefaultWebProxy = false;

This will then use whatever credentials you have set for that authentication scheme in your ChannelFactory.ClientCredentials instance. For example, using IntegratedWindowsAuthentication, it would use ClientCredentials.Windows to get the credentials.

@dmnk
Copy link

dmnk commented Dec 28, 2018

Thanks for the code snippet. if possible change Element to Elements

I've been doing something similar, but instead of generating a new binding i'd like to utilize a proxy class generated by Visual Studio 2019.

var b_custom = client.Endpoint.Binding as System.ServiceModel.Channels.CustomBinding;
            
if (b_custom != null)
{
   var htbe = b_custom.Elements.Find<HttpTransportBindingElement>();
   htbe.ProxyAddress =  new Uri(string.Format("http://{0}:{1}", address, port));
   htbe.ProxyAuthenticationScheme = System.Net.AuthenticationSchemes.Anonymous; // Or whatever authentication mechanism your proxy server uses
   htbe.UseDefaultWebProxy = false;
   return;
}

however on windows 10 / core 2.2 that throws the following exception:

InvalidOperationException: When using a non-null Proxy, the WindowsProxyUsePolicy property must be set to WindowsProxyUsePolicy.UseCustomProxy.

@mconnew
Copy link
Member

mconnew commented Jan 10, 2019

That error message comes from WinHttpHandler. WCF stopped using that class directly quite a while ago and we now only reference HttpClientHandler. As of .NET Core 2.1, the default implementation is no longer WinHttpHandler and instead uses the newer SocketsHttpHandler. I suspect you are using a really old release of WCF. Can you make sure you are using the latest versions of System.ServiceModel.*. There was a bug in an earlier version around setting the proxy values on WinHttpHandler and I suspect you are running into that issue.

@dmnk
Copy link

dmnk commented Jan 10, 2019

Thanks. I kind of expected that the required parts are installed and used in the up-to date version either by the .net core 2.2 installation or VS 2019.

After telling the package-manager to lift all System.ServiceModel's from 4.4.4 to 4.5.3 the Exception vanishes and the proxy is used as configured.

According to ConnectedService.json the WCF in charge was 15.0.21025.787

Thanks!

@fjdean
Copy link

fjdean commented May 1, 2019

Thanks. I kind of expected that the required parts are installed and used in the up-to date version either by the .net core 2.2 installation or VS 2019.

After telling the package-manager to lift all System.ServiceModel's from 4.4.4 to 4.5.3 the Exception vanishes and the proxy is used as configured.

According to ConnectedService.json the WCF in charge was 15.0.21025.787

Thanks!

This solved it for me. I was also receiving the exception "When using a non-null Proxy, the WindowsProxyUsePolicy property must be set to WindowsProxyUsePolicy.UseCustomProxy.", which then disappeared once I updated all System.ServiceModel libs. Cheers!

@jonathanmoffatt
Copy link

jonathanmoffatt commented Jun 12, 2019

I'm also getting the 407 issue. I'm not experienced with WCF so I'm probably doing something stupid, but when I try to use the fix from @mconnew the 407 error then changes to this one:

The 'IntegratedWindowsAuthentication' authentication scheme has been specified for the proxy on the HTTP factory. However, the factory only supports specification of exactly one authentication scheme. Valid authentication schemes are Digest, Negotiate, NTLM, Basic, or Anonymous.

This is my code :

            var oneMinute = new TimeSpan(0, 1, 0);

            var binding = new BasicHttpBinding();

            binding.Name = "DEEWR_Customer_OUTBinding";
            binding.AllowCookies = false;
            binding.SendTimeout = oneMinute;
            binding.ReceiveTimeout = new TimeSpan(0, 10, 0);
            binding.OpenTimeout = oneMinute;
            binding.CloseTimeout = oneMinute;
            binding.MaxBufferPoolSize = 2147483647;
            binding.MaxReceivedMessageSize = 2147483647;
            binding.TextEncoding = Encoding.UTF8;
            binding.TransferMode = TransferMode.Buffered;
            binding.BypassProxyOnLocal = false;
            binding.UseDefaultWebProxy = false;

            binding.ReaderQuotas.MaxDepth = 32;
            binding.ReaderQuotas.MaxStringContentLength = 5242880;
            binding.ReaderQuotas.MaxArrayLength = 16384;
            binding.ReaderQuotas.MaxBytesPerRead = 4096;
            binding.ReaderQuotas.MaxNameTableCharCount = 16384;

            binding.Security.Mode = BasicHttpSecurityMode.Transport;
            binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;

            var customBinding = new CustomBinding(binding);
            var htbe = customBinding.Elements.Find<HttpTransportBindingElement>();
            htbe.ProxyAddress = new Uri("http://proxy.dmz.ige:8080");
            htbe.ProxyAuthenticationScheme = System.Net.AuthenticationSchemes.IntegratedWindowsAuthentication;
            htbe.BypassProxyOnLocal = false;
            htbe.UseDefaultWebProxy = false;

            var endpointAddress = new EndpointAddress(EndpointUrl);

            var factory = new ChannelFactory<DEEWR_Customer_OUT>(customBinding, endpointAddress);
            factory.Credentials.ClientCertificate.SetCertificate(
                StoreLocation.LocalMachine,
                StoreName.My,
                X509FindType.FindBySubjectName,
                CertificateName);
            DEEWR_Customer_OUT serviceProxy = factory.CreateChannel();

Any suggestions for what I might be doing wrong?

@mconnew
Copy link
Member

mconnew commented Jun 12, 2019

Can you please provide the stack trace of the exception?

@jonathanmoffatt
Copy link

Looks like IntegratedWindowsAuthentication isn't supported. It's a flag that includes Negotiate and Ntlm so I've changed mine to use Ntlm instead - which has worked insomuch as it's moved me on to a different error, sigh.

Thanks for responding!

@mconnew
Copy link
Member

mconnew commented Jun 13, 2019

As you've already worked out, IntegratedWindowsAuthentication has a value of 6, Negotiate has a value of 2 and Ntlm has a value of 4. This means that IntegratedWindowsAuthentication isn't an authentication scheme in it's own right, it's a convenience value to mean Negotiate | Ntlm. We can't accept two different schemes being specified which is why IntegratedWindowsAuthentication isn't supported. The description for Negotiate is:

Negotiates with the client to determine the authentication scheme. If both client and server support Kerberos, it is used; otherwise, NTLM is used.

The only time when this won't work is when integrated Windows authentication isn't enabled on the proxy server but NTLM is. In which case specifying NTLM is needed. Otherwise Negotiate should generally work for you.

@mumby0168
Copy link

@mconnew hi seen your comment earlier up in the feed. I am having the same issue with wanting to provide a NetworkCredential object to a WCF generated service. This is made up of the domain, username & password as strings provided by config, how should I setup my binding and construct my service seem to have tried every which way and had no luck any help would be greatly appreciated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants