147 lines
3.1 KiB
Go
147 lines
3.1 KiB
Go
package lfs
|
|
|
|
import (
|
|
"io"
|
|
//"bufio"
|
|
//"net"
|
|
"net/http"
|
|
//"encoding/xml"
|
|
"encoding/base64"
|
|
"bytes"
|
|
"io/ioutil"
|
|
//"os"
|
|
"github.com/ThomsonReutersEikon/go-ntlm/ntlm"
|
|
"github.com/github/git-lfs/vendor/_nuts/github.com/rubyist/tracerx"
|
|
)
|
|
|
|
func (c *Configuration) NTLMSession() ntlm.ClientSession {
|
|
|
|
if c.ntlmSession != nil {
|
|
|
|
|
|
|
|
return c.ntlmSession
|
|
}
|
|
|
|
var session, _ = ntlm.CreateClientSession(ntlm.Version2, ntlm.ConnectionOrientedMode)
|
|
session.SetUserInfo("user","password","domain")
|
|
|
|
c.ntlmSession = session
|
|
|
|
return session
|
|
}
|
|
|
|
func DoNTLMRequest(request *http.Request) (*http.Response, *WrappedError) {
|
|
|
|
tracerx.Printf("DoNTLMRequest ENTER")
|
|
defer racerx.Printf("DoNTLMRequest LEAVE")
|
|
|
|
if !Config.NTLM() {
|
|
tracerx.Printf("DoNTLMRequest ntlm is not enabled")
|
|
|
|
return nil, Error("NTLM is not enabled")
|
|
}
|
|
|
|
res, err := InitHandShake(request)
|
|
|
|
//If the status is 401 then we need to re-authenticate, otherwise it was successful
|
|
if res.StatusCode == 401 {
|
|
challengeMessage := Negotiate(request, getNegotiateMessage())
|
|
|
|
res, err := Challenge(request, challengeMessage)
|
|
|
|
return res, err
|
|
}
|
|
|
|
return res, Error(err)
|
|
}
|
|
|
|
func InitHandShake(request *http.Request) (*http.Response, *WrappedError){
|
|
|
|
var response, err = Config.HttpClient().Do(request)
|
|
|
|
if err != nil {
|
|
return nil, Error(err)
|
|
}
|
|
|
|
io.Copy(ioutil.Discard, response.Body)
|
|
response.Body.Close()
|
|
|
|
return response, nil
|
|
}
|
|
|
|
func Negotiate(request *http.Request, message string) []byte{
|
|
|
|
request.Header.Add("Authorization", message)
|
|
var response, err = Config.HttpClient().Do(request)
|
|
|
|
if err != nil{
|
|
panic(err)
|
|
}
|
|
|
|
ret := ParseChallengeMessage(response)
|
|
|
|
io.Copy(ioutil.Discard, response.Body)
|
|
response.Body.Close()
|
|
|
|
return ret;
|
|
}
|
|
|
|
func Challenge(request *http.Request, challengeBytes []byte) (*http.Response, *WrappedError){
|
|
|
|
challenge, err := ntlm.ParseChallengeMessage(challengeBytes)
|
|
|
|
if err != nil {
|
|
return nil, Error(err)
|
|
}
|
|
|
|
Config.NTLMSession().ProcessChallengeMessage(challenge)
|
|
authenticate, err := Config.NTLMSession().GenerateAuthenticateMessage()
|
|
|
|
if err != nil {
|
|
return nil, Error(err)
|
|
}
|
|
|
|
authenticateMessage := string(Concat([]byte("NTLM "), []byte(base64.StdEncoding.EncodeToString(authenticate.Bytes()))))
|
|
|
|
request.Header.Add("Authorization", authenticateMessage)
|
|
response, err := Config.HttpClient().Do(request)
|
|
|
|
io.Copy(ioutil.Discard, response.Body)
|
|
response.Body.Close()
|
|
|
|
return response, nil
|
|
}
|
|
|
|
// get the bytes for the Type2 message
|
|
func ParseChallengeMessage(response *http.Response) []byte{
|
|
|
|
if headers, ok := response.Header["Www-Authenticate"]; ok{
|
|
|
|
//parse out the "NTLM " at the beginning of the resposne
|
|
challenge := headers[0][5:]
|
|
|
|
val, err := base64.StdEncoding.DecodeString(challenge)
|
|
|
|
if err != nil{
|
|
panic(err)
|
|
}
|
|
|
|
return []byte(val)
|
|
}
|
|
|
|
panic("www-Authenticate header is not present")
|
|
}
|
|
|
|
//Get Type 1 message
|
|
func getNegotiateMessage() string{
|
|
|
|
//var negotiate, _ = session.GenerateNegotiateMessage()
|
|
//return negotiate.Bytes
|
|
|
|
return "NTLM TlRMTVNTUAABAAAAB7IIogwADAAzAAAACwALACgAAAAKAAAoAAAAD1dJTExISS1NQUlOTk9SVEhBTUVSSUNB"
|
|
}
|
|
|
|
func Concat(ar ...[]byte) []byte {
|
|
return bytes.Join(ar, nil)
|
|
} |