git-lfs/lfs/ntlm.go
2015-10-05 10:05:32 -04:00

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)
}