CalAnonSync/src/calanonsync/vendor/github.com/vadimi/go-http-ntlm/ntlmtransport.go

104 lines
2.5 KiB
Go

package httpntlm
import (
"crypto/tls"
"errors"
"io"
"io/ioutil"
"net"
"net/http"
"strings"
"time"
"github.com/ThomsonReutersEikon/go-ntlm/ntlm"
)
// NtlmTransport is implementation of http.RoundTripper interface
type NtlmTransport struct {
TLSClientConfig *tls.Config
Domain string
User string
Password string
}
// RoundTrip method send http request and tries to perform NTLM authentication
func (t NtlmTransport) RoundTrip(req *http.Request) (res *http.Response, err error) {
// first send NTLM Negotiate header
r, _ := http.NewRequest("GET", req.URL.String(), strings.NewReader(""))
r.Header.Add("Authorization", "NTLM "+encBase64(negotiate()))
client := http.Client{Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
TLSClientConfig: t.TLSClientConfig,
}}
resp, err := client.Do(r)
if err != nil {
return nil, err
}
if err == nil && resp.StatusCode == http.StatusUnauthorized {
// it's necessary to reuse the same http connection
// in order to do that it's required to read Body and close it
_, err = io.Copy(ioutil.Discard, resp.Body)
if err != nil {
return nil, err
}
err = resp.Body.Close()
if err != nil {
return nil, err
}
// retrieve Www-Authenticate header from response
ntlmChallengeHeader := resp.Header.Get("WWW-Authenticate")
if ntlmChallengeHeader == "" {
return nil, errors.New("Wrong WWW-Authenticate header")
}
ntlmChallengeString := strings.Replace(ntlmChallengeHeader, "NTLM ", "", -1)
challengeBytes, err := decBase64(ntlmChallengeString)
if err != nil {
return nil, err
}
session, err := ntlm.CreateClientSession(ntlm.Version2, ntlm.ConnectionlessMode)
if err != nil {
return nil, err
}
session.SetUserInfo(t.User, t.Password, t.Domain)
// parse NTLM challenge
challenge, err := ntlm.ParseChallengeMessage(challengeBytes)
if err != nil {
return nil, err
}
err = session.ProcessChallengeMessage(challenge)
if err != nil {
return nil, err
}
// authenticate user
authenticate, err := session.GenerateAuthenticateMessage()
if err != nil {
return nil, err
}
// set NTLM Authorization header
req.Header.Set("Authorization", "NTLM "+encBase64(authenticate.Bytes()))
resp, err = client.Do(req)
}
return resp, err
}