From 33e376281740a92b4ffafb4f201b967d650462b7 Mon Sep 17 00:00:00 2001 From: Rafael Rivera Date: Thu, 4 Oct 2018 21:33:57 -0700 Subject: [PATCH] Update Azure/go-ntlmssp dep --- vendor/github.com/Azure/go-ntlmssp/README.md | 18 ++++++ .../github.com/Azure/go-ntlmssp/authheader.go | 4 ++ .../Azure/go-ntlmssp/negotiate_flags.go | 24 +++++--- .../Azure/go-ntlmssp/negotiate_message.go | 55 +++++++++++++++---- .../github.com/Azure/go-ntlmssp/negotiator.go | 46 ++++++++++++++-- vendor/github.com/Azure/go-ntlmssp/version.go | 20 +++++++ vendor/vendor.json | 5 +- 7 files changed, 145 insertions(+), 27 deletions(-) create mode 100644 vendor/github.com/Azure/go-ntlmssp/version.go diff --git a/vendor/github.com/Azure/go-ntlmssp/README.md b/vendor/github.com/Azure/go-ntlmssp/README.md index 91948c243..55cdcefab 100644 --- a/vendor/github.com/Azure/go-ntlmssp/README.md +++ b/vendor/github.com/Azure/go-ntlmssp/README.md @@ -9,3 +9,21 @@ Implementation hints from http://davenport.sourceforge.net/ntlm.html This package only implements authentication, no key exchange or encryption. It only supports Unicode (UTF16LE) encoding of protocol strings, no OEM encoding. This package implements NTLMv2. + +# Usage + +``` +url, user, password := "http://www.example.com/secrets", "robpike", "pw123" +client := &http.Client{ + Transport: ntlmssp.Negotiator{ + RoundTripper:&http.Transport{}, + }, +} + +req, _ := http.NewRequest("GET", url, nil) +req.SetBasicAuth(user, password) +res, _ := client.Do(req) +``` + +----- +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. diff --git a/vendor/github.com/Azure/go-ntlmssp/authheader.go b/vendor/github.com/Azure/go-ntlmssp/authheader.go index 4ca6f1b46..aac3f77d1 100644 --- a/vendor/github.com/Azure/go-ntlmssp/authheader.go +++ b/vendor/github.com/Azure/go-ntlmssp/authheader.go @@ -15,6 +15,10 @@ func (h authheader) IsNegotiate() bool { return strings.HasPrefix(string(h), "Negotiate") } +func (h authheader) IsNTLM() bool { + return strings.HasPrefix(string(h), "NTLM") +} + func (h authheader) GetData() ([]byte, error) { p := strings.Split(string(h), " ") if len(p) < 2 { diff --git a/vendor/github.com/Azure/go-ntlmssp/negotiate_flags.go b/vendor/github.com/Azure/go-ntlmssp/negotiate_flags.go index 6c3ce7b01..5905c023d 100644 --- a/vendor/github.com/Azure/go-ntlmssp/negotiate_flags.go +++ b/vendor/github.com/Azure/go-ntlmssp/negotiate_flags.go @@ -7,30 +7,38 @@ const ( /*B*/ negotiateFlagNTLMNEGOTIATEOEM = 1 << 1 /*C*/ negotiateFlagNTLMSSPREQUESTTARGET = 1 << 2 - /*D*/ negotiateFlagNTLMSSPNEGOTIATESIGN = 1 << 4 + /*D*/ + negotiateFlagNTLMSSPNEGOTIATESIGN = 1 << 4 /*E*/ negotiateFlagNTLMSSPNEGOTIATESEAL = 1 << 5 /*F*/ negotiateFlagNTLMSSPNEGOTIATEDATAGRAM = 1 << 6 /*G*/ negotiateFlagNTLMSSPNEGOTIATELMKEY = 1 << 7 - /*H*/ negotiateFlagNTLMSSPNEGOTIATENTLM = 1 << 9 + /*H*/ + negotiateFlagNTLMSSPNEGOTIATENTLM = 1 << 9 - /*J*/ negotiateFlagANONYMOUS = 1 << 11 + /*J*/ + negotiateFlagANONYMOUS = 1 << 11 /*K*/ negotiateFlagNTLMSSPNEGOTIATEOEMDOMAINSUPPLIED = 1 << 12 /*L*/ negotiateFlagNTLMSSPNEGOTIATEOEMWORKSTATIONSUPPLIED = 1 << 13 - /*M*/ negotiateFlagNTLMSSPNEGOTIATEALWAYSSIGN = 1 << 15 + /*M*/ + negotiateFlagNTLMSSPNEGOTIATEALWAYSSIGN = 1 << 15 /*N*/ negotiateFlagNTLMSSPTARGETTYPEDOMAIN = 1 << 16 /*O*/ negotiateFlagNTLMSSPTARGETTYPESERVER = 1 << 17 - /*P*/ negotiateFlagNTLMSSPNEGOTIATEEXTENDEDSESSIONSECURITY = 1 << 19 + /*P*/ + negotiateFlagNTLMSSPNEGOTIATEEXTENDEDSESSIONSECURITY = 1 << 19 /*Q*/ negotiateFlagNTLMSSPNEGOTIATEIDENTIFY = 1 << 20 - /*R*/ negotiateFlagNTLMSSPREQUESTNONNTSESSIONKEY = 1 << 22 + /*R*/ + negotiateFlagNTLMSSPREQUESTNONNTSESSIONKEY = 1 << 22 /*S*/ negotiateFlagNTLMSSPNEGOTIATETARGETINFO = 1 << 23 - /*T*/ negotiateFlagNTLMSSPNEGOTIATEVERSION = 1 << 25 + /*T*/ + negotiateFlagNTLMSSPNEGOTIATEVERSION = 1 << 25 - /*U*/ negotiateFlagNTLMSSPNEGOTIATE128 = 1 << 29 + /*U*/ + negotiateFlagNTLMSSPNEGOTIATE128 = 1 << 29 /*V*/ negotiateFlagNTLMSSPNEGOTIATEKEYEXCH = 1 << 30 /*W*/ negotiateFlagNTLMSSPNEGOTIATE56 = 1 << 31 ) diff --git a/vendor/github.com/Azure/go-ntlmssp/negotiate_message.go b/vendor/github.com/Azure/go-ntlmssp/negotiate_message.go index 97aa07e8f..e466a9861 100644 --- a/vendor/github.com/Azure/go-ntlmssp/negotiate_message.go +++ b/vendor/github.com/Azure/go-ntlmssp/negotiate_message.go @@ -3,29 +3,62 @@ package ntlmssp import ( "bytes" "encoding/binary" + "errors" + "strings" ) +const expMsgBodyLen = 40 + type negotiateMessageFields struct { messageHeader NegotiateFlags negotiateFlags + + Domain varField + Workstation varField + + Version } +var defaultFlags = negotiateFlagNTLMSSPNEGOTIATETARGETINFO | + negotiateFlagNTLMSSPNEGOTIATE56 | + negotiateFlagNTLMSSPNEGOTIATE128 | + negotiateFlagNTLMSSPNEGOTIATEUNICODE | + negotiateFlagNTLMSSPNEGOTIATEEXTENDEDSESSIONSECURITY + //NewNegotiateMessage creates a new NEGOTIATE message with the //flags that this package supports. -func NewNegotiateMessage() []byte { - m := negotiateMessageFields{ - messageHeader: newMessageHeader(1), +func NewNegotiateMessage(domainName, workstationName string) ([]byte, error) { + payloadOffset := expMsgBodyLen + flags := defaultFlags + + if domainName != "" { + flags |= negotiateFlagNTLMSSPNEGOTIATEOEMDOMAINSUPPLIED + } + + if workstationName != "" { + flags |= negotiateFlagNTLMSSPNEGOTIATEOEMWORKSTATIONSUPPLIED } - m.NegotiateFlags = negotiateFlagNTLMSSPREQUESTTARGET | - negotiateFlagNTLMSSPNEGOTIATENTLM | - negotiateFlagNTLMSSPNEGOTIATEALWAYSSIGN | - negotiateFlagNTLMSSPNEGOTIATEUNICODE + msg := negotiateMessageFields{ + messageHeader: newMessageHeader(1), + NegotiateFlags: flags, + Domain: newVarField(&payloadOffset, len(domainName)), + Workstation: newVarField(&payloadOffset, len(workstationName)), + Version: DefaultVersion(), + } b := bytes.Buffer{} - err := binary.Write(&b, binary.LittleEndian, &m) - if err != nil { - panic(err) + if err := binary.Write(&b, binary.LittleEndian, &msg); err != nil { + return nil, err + } + if b.Len() != expMsgBodyLen { + return nil, errors.New("incorrect body length") } - return b.Bytes() + + payload := strings.ToUpper(domainName + workstationName) + if _, err := b.WriteString(payload); err != nil { + return nil, err + } + + return b.Bytes(), nil } diff --git a/vendor/github.com/Azure/go-ntlmssp/negotiator.go b/vendor/github.com/Azure/go-ntlmssp/negotiator.go index fa39683e1..6e304544b 100644 --- a/vendor/github.com/Azure/go-ntlmssp/negotiator.go +++ b/vendor/github.com/Azure/go-ntlmssp/negotiator.go @@ -3,10 +3,24 @@ package ntlmssp import ( "bytes" "encoding/base64" + "io" "io/ioutil" "net/http" + "strings" ) +// GetDomain : parse domain name from based on slashes in the input +func GetDomain(user string) (string, string) { + domain := "" + + if strings.Contains(user, "\\") { + ucomponents := strings.SplitN(user, "\\", 2) + domain = ucomponents[0] + user = ucomponents[1] + } + return user, domain +} + //Negotiator is a http.Roundtripper decorator that automatically //converts basic authentication to NTLM/Negotiate authentication when appropriate. type Negotiator struct{ http.RoundTripper } @@ -47,9 +61,10 @@ func (l Negotiator) RoundTrip(req *http.Request) (res *http.Response, err error) } resauth := authheader(res.Header.Get("Www-Authenticate")) - if !resauth.IsNegotiate() { + if !resauth.IsNegotiate() && !resauth.IsNTLM() { // Unauthorized, Negotiate not requested, let's try with basic auth req.Header.Set("Authorization", string(reqauth)) + io.Copy(ioutil.Discard, res.Body) res.Body.Close() req.Body = ioutil.NopCloser(bytes.NewReader(body.Bytes())) @@ -63,8 +78,9 @@ func (l Negotiator) RoundTrip(req *http.Request) (res *http.Response, err error) resauth = authheader(res.Header.Get("Www-Authenticate")) } - if resauth.IsNegotiate() { + if resauth.IsNegotiate() || resauth.IsNTLM() { // 401 with request:Basic and response:Negotiate + io.Copy(ioutil.Discard, res.Body) res.Body.Close() // recycle credentials @@ -73,9 +89,21 @@ func (l Negotiator) RoundTrip(req *http.Request) (res *http.Response, err error) return nil, err } + // get domain from username + domain := "" + u, domain = GetDomain(u) + // send negotiate - negotiateMessage := NewNegotiateMessage() - req.Header.Set("Authorization", "Negotiate "+base64.StdEncoding.EncodeToString(negotiateMessage)) + negotiateMessage, err := NewNegotiateMessage(domain, "") + if err != nil { + return nil, err + } + if resauth.IsNTLM() { + req.Header.Set("Authorization", "NTLM "+base64.StdEncoding.EncodeToString(negotiateMessage)) + } else { + req.Header.Set("Authorization", "Negotiate "+base64.StdEncoding.EncodeToString(negotiateMessage)) + } + req.Body = ioutil.NopCloser(bytes.NewReader(body.Bytes())) res, err = rt.RoundTrip(req) @@ -89,10 +117,11 @@ func (l Negotiator) RoundTrip(req *http.Request) (res *http.Response, err error) if err != nil { return nil, err } - if !resauth.IsNegotiate() || len(challengeMessage) == 0 { + if !(resauth.IsNegotiate() || resauth.IsNTLM()) || len(challengeMessage) == 0 { // Negotiation failed, let client deal with response return res, nil } + io.Copy(ioutil.Discard, res.Body) res.Body.Close() // send authenticate @@ -100,7 +129,12 @@ func (l Negotiator) RoundTrip(req *http.Request) (res *http.Response, err error) if err != nil { return nil, err } - req.Header.Set("Authorization", "Negotiate "+base64.StdEncoding.EncodeToString(authenticateMessage)) + if resauth.IsNTLM() { + req.Header.Set("Authorization", "NTLM "+base64.StdEncoding.EncodeToString(authenticateMessage)) + } else { + req.Header.Set("Authorization", "Negotiate "+base64.StdEncoding.EncodeToString(authenticateMessage)) + } + req.Body = ioutil.NopCloser(bytes.NewReader(body.Bytes())) res, err = rt.RoundTrip(req) diff --git a/vendor/github.com/Azure/go-ntlmssp/version.go b/vendor/github.com/Azure/go-ntlmssp/version.go new file mode 100644 index 000000000..6d8489212 --- /dev/null +++ b/vendor/github.com/Azure/go-ntlmssp/version.go @@ -0,0 +1,20 @@ +package ntlmssp + +// Version is a struct representing https://msdn.microsoft.com/en-us/library/cc236654.aspx +type Version struct { + ProductMajorVersion uint8 + ProductMinorVersion uint8 + ProductBuild uint16 + _ [3]byte + NTLMRevisionCurrent uint8 +} + +// DefaultVersion returns a Version with "sensible" defaults (Windows 7) +func DefaultVersion() Version { + return Version{ + ProductMajorVersion: 6, + ProductMinorVersion: 1, + ProductBuild: 7601, + NTLMRevisionCurrent: 15, + } +} diff --git a/vendor/vendor.json b/vendor/vendor.json index 6ffa53a75..46f13a17a 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -117,9 +117,10 @@ "versionExact": "v10.12.0" }, { - "checksumSHA1": "TgrN0l/E16deTlLYNt8wf66urSU=", + "checksumSHA1": "4LNEtQCFSZ/NbHBdkB7XPrwO+kI=", "path": "github.com/Azure/go-ntlmssp", - "revision": "e0b63eb299a769ea4b04dadfe530f6074b277afb" + "revision": "4a21cbd618b459155f8b8ee7f4491cd54f5efa77", + "revisionTime": "2018-08-10T17:55:52Z" }, { "checksumSHA1": "++XyYR/ZfYoCxGn5vTlXzQZ9eo0=",