Does Go have some way of using DefaultNetworkCredentials with a proxy when making an HTTP request?

655 views Asked by At

I'm writing a simple Go utility that makes some POST requests to the internet, but I need to go through a proxy and use NTLM without knowing the user's credentials. I've seen CSharp code like below:

wc = new CookieWebClient();
wc.UseDefaultCredentials = true;
wc.Proxy = WebRequest.DefaultWebProxy;
wc.Proxy.Credentials = CredentialCache.DefaultNetworkCredentials;

In Go I've managed to determine the system proxy with what feels like a hack:

import (
    "net/http"
    "net/url"
    "strings"

    "golang.org/x/sys/windows/registry"
)

func getSystemProxy() func(req *http.Request) (*url.URL, error) {
    var e error
    var k registry.Key
    var proxy *url.URL
    var v string

    // Open the "Internet Settings" registry key
    k, e = registry.OpenKey(
        registry.CURRENT_USER,
        strings.Join(
            []string{
                "Software",
                "Microsoft",
                "Windows",
                "CurrentVersion",
                "Internet Settings",
            },
            "\\",
        ),
        registry.QUERY_VALUE,
    )
    if e != nil {
        return http.ProxyFromEnvironment
    }
    defer k.Close()

    // Read the "ProxyServer" value
    v, _, e = k.GetStringValue("ProxyServer")
    if (e != nil) || (v == "") {
        return http.ProxyFromEnvironment
    }

    // Get the http= portion and fix it up
    v = strings.Split(v, ";")[0]
    v = strings.Replace(v, "=", "://", 1)

    // Parse url
    if proxy, e = url.Parse(v); e != nil {
        return http.ProxyFromEnvironment
    }

    return http.ProxyURL(proxy)
}

I've been unable to find a Go equivalent to CSharp's https://learn.microsoft.com/en-us/dotnet/api/system.net.credentialcache.defaultnetworkcredentials?view=netcore-3.1. I have found https://github.com/Azure/go-ntlmssp but that requires me to hard-code the user's credentials, which I do not have, and I would need to compile a new binary for each user, which I do not want to do. I'm looking for a 0 config solution. I would prefer this to be as dynamic as possible. If CSharp can do it, why can't Go?

Any help would be greatly appreciated!

1

There are 1 answers

0
mjwhitta On BEST ANSWER

I've been told I can use WinHTTP or WinInet to achieve this. I will play with the golang.org/x/sys/windows package and call the procedures from the DLLs. Alternatively, I've been told I could use github.com/go-ole/go-ole and use WinHTTP via COM objects like in this other SO question: Windows system credentials in Go HTTP NTLM requests.

Update: I ultimately decided to settle on WinInet and I created my own package (gitlab.com/mjwhitta/win/wininet) which contains an http.Client which can be used to make GET and POST requests. See the README for an example of how to use it. I will probably expand on it in the future should I have the need. Pull requests are welcome.

Last update: Boy do I feel stupid. WinInet doesn't look to do NTLM for you... so I ported it to WinHttp (gitlab.com/mjwhitta/win/winhttp).