Connect over company proxy with user name

585 Views Asked by At

I am trying to connect to external IP address but I am behind company firewall, so I need to connect over the proxy.

I run a test with curl:

curl -v https://IP_ADDRESS_OF_EXTERNAL_CLIENT:6125 -x http://MyComparyProxyAddress.com:8080 -U MYUSERNAME:MYPASSWORD

but I am failing to replicate aforementioned cUrl command in C#:

private static Socket CreateTunnelThruProxy(string destIP, int destPort)
        {
            string destUriWithPort = $"{destIP}:{destPort}";
            UriBuilder uriBuilder = new UriBuilder(destUriWithPort);
            Uri destUri = uriBuilder.Uri;

            var proxy = new WebProxy("http://MyComparyProxyAddress.com", 8080);
            proxy.UseDefaultCredentials = false;
            proxy.Credentials = new NetworkCredential("MYUSERNAME", "MYPASSWORD");
            WebRequest.DefaultWebProxy = proxy;

            IWebProxy webProxy = WebRequest.DefaultWebProxy;

            try
            {
                if (webProxy.IsBypassed(destUri))
                    return null;
            }
            catch (PlatformNotSupportedException)
            {
                // .NET Core doesn't support IWebProxy.IsBypassed
                // (because .NET Core doesn't have access to Windows-specific services, of course)
                return null;
            }

            Uri proxyUri = webProxy.GetProxy(destUri);
            if (proxyUri == null)
                return null;

            IPAddress[] proxyEntry = Dns.GetHostAddresses(proxyUri.Host);
            int iPort = proxyUri.Port;
            IPAddress address = proxyEntry.First(a => a.AddressFamily == AddressFamily.InterNetwork);
            IPEndPoint proxyEndPoint = new IPEndPoint(address, iPort);
            Socket socketThruProxy = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socketThruProxy.Connect(proxyEndPoint);

            string proxyMsg = $"CONNECT {destIP}:{destPort} HTTP/1.1 \n\n";
            byte[] buffer = Encoding.ASCII.GetBytes(proxyMsg);
            byte[] buffer12 = new byte[50000];
            socketThruProxy.Send(buffer, buffer.Length, 0);
            int msg = socketThruProxy.Receive(buffer12, 50000, 0);
            string data;
            data = Encoding.ASCII.GetString(buffer12);
            int index = data.IndexOf("200");

            if (index < 0)
                throw new ApplicationException(
                    $"Connection failed to {destUriWithPort} through proxy server {proxyUri.ToString()}.");

            return socketThruProxy;
        }

I keep getting following information from my company proxy:

HTTP/1.1 407 Proxy Authentication Required
Proxy-Authenticate: NEGOTIATE
Proxy-Authenticate: NTLM
Proxy-Authenticate: BASIC realm="ztb"
Cache-Control: no-cache
Pragma: no-cache
Content-Type: text/html; charset=utf-8
Proxy-Connection: close
Connection: close
Content-Length: 797

<HTML><HEAD>
<TITLE>Access Denied</TITLE>
</HEAD>
<BODY>
<body bgcolor="#FFFFEA">
<blockquote>
<TABLE border=0 cellPadding=1 width="80%">
<TR><TD>
<FONT face="Verdana">
<big>Access Denied (authentication_failed)</big>
<BR>
<BR>
</FONT>
</TD></TR>
<TR><TD>
<FONT face="Verdana">
Your credentials could not be authenticated: "Credentials are missing.". You will not be permitted access until your credentials can be verified.
</FONT>
</TD></TR>
<TR><TD>
<FONT face="Verdana">
This is typically caused by an incorrect username and/or password, but could also be caused by network problems.
</FONT>
</TD></TR>
<TR><TD>
<FONT face="Verdana" SIZE=2>
<BR>
For assistance, contact your Tech Desk . PXFFM25
</FONT>
</TD></TR>
</TABLE>
</blockquote>
</FONT>
</BODY></HTML>

I can clearly see that webProxy object contains credentials set by me, the same credentials that are working with cUrl.

Also I am getting the same error when trying simply calling:

IWebProxy webProxy = WebRequest.GetSystemWebProxy();

instead of setting credentials manually, as per code snippet above. So it looks like my credentials are not taken into account....

Any ideas ?

5

There are 5 best solutions below

0
Jack On BEST ANSWER

This can be accomplished in the following way:

 if (IsProxyProvided(settings))
            {
                IPAddress[] proxyEntry = Dns.GetHostAddresses(settings.ProxyHost);
                IPAddress address = proxyEntry.First(a => a.AddressFamily == AddressFamily.InterNetwork);
                IPEndPoint proxyEndPoint = new IPEndPoint(address, settings.ProxyPort);
                socket.Connect(proxyEndPoint);

                if (AreProxyCredntialsProvided(settings))
                {
                    var basicAuthBase64 = Convert.ToBase64String(
                        Encoding.GetEncoding("ISO-8859-1").GetBytes($"{settings.ProxyUserName}:{settings.ProxyUserNamePassword}"));
                    var proxyMessage = $"Proxy-Authorization: {string.Format("Basic {0}", basicAuthBase64)} \r\n";
                    var keepAlive = "Connection: keep-alive\r\n";
                    var request = $"CONNECT {endpoint.Address}:{endpoint.Port} HTTP/1.1 \r\n" + proxyMessage + keepAlive + "\r\n";
                    byte[] buffer = Encoding.ASCII.GetBytes(request);
                    socket.Send(buffer, buffer.Length, 0);
                }
            }

Thanks to Victor Victor Stone who had similar issue here

2
MHassan On

I tried this scenario before and it works with me by creating a custom proxy class that inherits IWebProxy

public class MyProxy : IWebProxy
    {
        public ICredentials Credentials
        {
            get { return new NetworkCredential("your username","your password"); }
            set { }
        }

        public Uri GetProxy(Uri destination)
        {
            return new Uri("http://MyComparyProxyAddress.com:8080");
        }

        public bool IsBypassed(Uri host)
        {
            return false;
        }
    } 

and in the app configuration file add this part inside the configuration node

  <system.net>
    <defaultProxy enabled="true" useDefaultCredentials="false">
      <module type="yournamespace.MyProxy, your assembly name" />
    </defaultProxy>
  </system.net>
0
Jon On

I'd add this as a comment if it would let me, but does adding the domain help? In the past when I've authenticated, I've had to make sure the domain is correct. Per Network Credential docs

There is a constructor that takes the domain or you can set it as a property.

0
ycrumeyrolle On

Do not try to remediate this issue within you code. Use a local proxy like https://github.com/genotrance/px for providing your user credentials to the enterprise proxy. Otherwise you will found one day a developer password within your source control.

0
iSR5 On

I've had this issue with one of my projects, the company uses a firewall (to be exact Barracuda's firewall). I've tried to set WebProxy and also set the machine proxy with no luck.

Here is how I solved it :

I've asked the security team to whitelist the IPs along with the ports that would be used for the service. so any outgoing or incoming connections won't be blocked. Then, from the application, I've set the proxy in web.config like this :

<system.net>
    <defaultProxy>
        <proxy usesystemdefault="False" proxyaddress="http://proxy_ip" bypassonlocal="False" />
    </defaultProxy>
</system.net>

Also, the same proxy is set on the server that the application is running on.

This made things work as expected.

After a week or so, the service stopped suddenly. When I checked the connection with Fiddler it showed me that the API were redirected to another server (different IP), which the firewall blocks it. So, I asked the security team to whitelist it as well, and the service was back to live again.