Skip to content
This repository was archived by the owner on Jul 9, 2023. It is now read-only.
This repository was archived by the owner on Jul 9, 2023. It is now read-only.

Support NTLM/Kerberos upstream proxy authentication #944

Open
@SamuelePilleri

Description

@SamuelePilleri

I'm trying to create a local proxy service based on the WindowsService example to overcome limitations in my company.

Every PC is set up with a PAC URL that contains what proxy to use for each destination. This is what a correct request to the outside world looks like:

$ curl --proxy {upstreamproxy}:8080 --proxy-ntlm --proxy-user ":" --verbose https://ipinfo.io
* Trying {omitted}:8080...
* Connected to {upstreamproxy} ({omitted}) port 8080 (#0)
* allocate connect buffer
> CONNECT ipinfo.io:443 HTTP/1.1
> Host: ipinfo.io:443
> Proxy-Authorization: NTLM {omitted}
> User-Agent: curl/7.83.1
> Proxy-Connection: Keep-Alive
>
< HTTP/1.1 407 authenticationrequired
< Date: Wed, 04 Jan 2023 10:36:50 GMT
< Content-Type: text/html
< Cache-Control: no-cache
< Content-Length: 0
< X-Frame-Options: deny
< Proxy-Connection: Keep-Alive
< Proxy-Authenticate: NTLM {omitted}
<
> CONNECT ipinfo.io:443 HTTP/1.1
> Host: ipinfo.io:443
> Proxy-Authorization: NTLM {omitted}
> User-Agent: curl/7.83.1
> Proxy-Connection: Keep-Alive
>
< HTTP/1.0 200 Connection established
<
> GET / HTTP/1.1
> Host: ipinfo.io
> User-Agent: curl/7.83.1
> Accept: */*
>
< HTTP/1.1 200 OK
< {ipinfo.io response headers, omitted}

Based on the example provided, this is what I've written:

protected override void OnStart(string[] args)
{
	proxyServerInstance = new(userTrustRootCertificate: false) {
		CheckCertificateRevocation = X509RevocationMode.NoCheck,
		ConnectionTimeOutSeconds = 30,
		Enable100ContinueBehaviour = true,
		EnableConnectionPool = true,
		EnableTcpServerConnectionPrefetch = true,
		EnableWinAuth = true,
		ForwardToUpstreamGateway = true,
		MaxCachedConnections = 2,
		ReuseSocket = true,
		TcpTimeWaitSeconds = 30,
		EnableHttp2 = true,
		NoDelay = true,
		ThreadPoolWorkerThread = Environment.ProcessorCount,
		ExceptionFunc = ProxyException,
	};
	
	proxyServerInstance.CertificateManager.SaveFakeCertificates = false;

	var explicitEndPointV4 = new ExplicitProxyEndPoint(IPAddress.Loopback, ListeningPort, false);
	proxyServerInstance.AddEndPoint(explicitEndPointV4);

	var explicitEndPointV6 = new ExplicitProxyEndPoint(IPAddress.IPv6Loopback, ListeningPort, false);
	proxyServerInstance.AddEndPoint(explicitEndPointV6);

	proxyServerInstance.Start();

	#if DEBUG
	Console.WriteLine($"Service Listening on port {ListeningPort}");
	#else
	ProxyServiceEventLog.WriteEntry($"Service Listening on port {ListeningPort}", EventLogEntryType.Information);
	#endif
}

However the exception Upstream proxy failed to create a secure tunnel is raised.

throw new Exception("Upstream proxy failed to create a secure tunnel");

Looking at the code it may depend on how Windows authentication is handled.

// check for windows authentication
if (args.EnableWinAuth)
{
if (response.StatusCode == (int)HttpStatusCode.Unauthorized)
await Handle401UnAuthorized(args);
else
WinAuthEndPoint.AuthenticatedResponse(args.HttpClient.Data);
}

I guess the problem here is the upstream proxy replying with 407 rather then 401, but I have limited debugging capabilities (work PC) and it's hard to investigate further.

Can someone please help me troubleshoot this? I'm using .NET Core 6 (can't install full Visual Studio) and Titanium 3.2.0.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions