add support for HTTPS proxy URL

This commit is contained in:
Eli Bishop
2019-07-02 13:23:03 -07:00
parent 93e5be72ed
commit 88448ca6e9
2 changed files with 136 additions and 90 deletions

View File

@@ -1,11 +1,33 @@
# go-ntlm-proxy-auth
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![GoDoc](https://godoc.org/github.com/Codehardt/go-ntlm-proxy-auth?status.svg)](https://godoc.org/github.com/Codehardt/go-ntlm-proxy-auth)
[![GoDoc](https://godoc.org/github.com/launchdarkly/go-ntlm-proxy-auth?status.svg)](https://godoc.org/github.com/launchdarkly/go-ntlm-proxy-auth)
With this package, you can connect to http/https servers protected by an NTLM proxy in Golang.
## Example
This is a fork of https://github.com/Codehardt/go-ntlm-proxy-auth which adds support for HTTPS proxy URLs.
## Example: NewNTLMProxyDialContext
```golang
// create a dialer
dialer := &net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}
// wrap dial context with NTLM
ntlmDialContext := newNTLMProxyDialContext(dialer, proxyURL, "user", "password", "domain", nil)
// create a http(s) client
client := &http.Client{
Transport: &http.Transport{
Proxy: nil, // !!! IMPORTANT, do not set proxy here !!!
DialContext: ntlmDialContext,
},
}
```
## Example: WrapDialContext (deprecated - does not support HTTPS proxy URL)
```golang
// create a dialer
@@ -21,9 +43,7 @@ ntlmDialContext := ntlm.WrapDialContext(dialer.DialContext, "proxyAddr", "user",
client := &http.Client{
Transport: &http.Transport{
Proxy: nil, // !!! IMPORTANT, do not set proxy here !!!
Dial: dialer.Dial,
DialContext: ntlmDialContext,
// TLSClientConfig: ...
},
}
```

32
ntlm.go
View File

@@ -3,6 +3,7 @@ package ntlm
import (
"bufio"
"context"
"crypto/tls"
"encoding/base64"
"errors"
"fmt"
@@ -23,10 +24,36 @@ import (
// dialContext := (&net.Dialer{KeepAlive: 30*time.Second, Timeout: 30*time.Second}).DialContext
type DialContext func(ctx context.Context, network, addr string) (net.Conn, error)
// WrapDialContext wraps a DialContext with an NTLM Authentication to a proxy.
// NewNTLMProxyDialContext provides a DialContext function that includes transparent NTLM proxy authentication.
// Unlike WrapDialContext, it describes the proxy location with a full URL, whose scheme can be HTTP or HTTPS.
func NewNTLMProxyDialContext(dialer *net.Dialer, proxyURL url.URL, proxyUsername, proxyPassword, proxyDomain string, tlsConfig *tls.Config) DialContext {
if dialer == nil {
dialer = &net.Dialer{}
}
return func(ctx context.Context, network, addr string) (net.Conn, error) {
dialProxy := func() (net.Conn, error) {
debugf("ntlm> Will connect to proxy at " + proxyURL.Host)
if proxyURL.Scheme == "https" {
return tls.DialWithDialer(dialer, "tcp", proxyURL.Host, tlsConfig)
}
return dialer.DialContext(ctx, network, proxyURL.Host)
}
return dialAndNegotiate(addr, proxyUsername, proxyPassword, proxyDomain, dialProxy)
}
}
// WrapDialContext wraps a DialContext with an NTLM Authentication to a proxy. Note that this does not support
// using HTTPS to connect to the proxy; use NewNTLMProxyDialContext if that is required.
func WrapDialContext(dialContext DialContext, proxyAddress, proxyUsername, proxyPassword, proxyDomain string) DialContext {
return func(ctx context.Context, network, addr string) (net.Conn, error) {
conn, err := dialContext(ctx, network, proxyAddress)
return dialAndNegotiate(addr, proxyUsername, proxyPassword, proxyDomain, func() (net.Conn, error) {
return dialContext(ctx, network, proxyAddress)
})
}
}
func dialAndNegotiate(addr, proxyUsername, proxyPassword, proxyDomain string, baseDial func() (net.Conn, error)) (net.Conn, error) {
conn, err := baseDial()
if err != nil {
debugf("ntlm> Could not call dial context with proxy: %s", err)
return conn, err
@@ -112,4 +139,3 @@ func WrapDialContext(dialContext DialContext, proxyAddress, proxyUsername, proxy
debugf("ntlm> Successfully injected NTLM to connection")
return conn, nil
}
}