From 22f10a0e9cdf8ddefcc5a61660cde290969b1522 Mon Sep 17 00:00:00 2001 From: Sam Uong Date: Fri, 25 Apr 2025 21:04:55 +1000 Subject: [PATCH 1/3] Try using github.com/ThomsonReutersEikon/go-ntlm (via omniboost's copy) --- authenticator.go | 26 +++++++++++++++++++++----- go.mod | 3 +++ go.sum | 2 ++ 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/authenticator.go b/authenticator.go index cd7369a..60a090e 100644 --- a/authenticator.go +++ b/authenticator.go @@ -1,4 +1,4 @@ -// Copyright 2019, 2021, 2024 The Alpaca Authors +// Copyright 2019, 2021, 2024, 2025 The Alpaca Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ import ( "os" "strings" + "github.com/ThomsonReutersEikon/go-ntlm/ntlm" "github.com/samuong/go-ntlmssp" ) @@ -34,6 +35,10 @@ type authenticator struct { func (a authenticator) do(req *http.Request, rt http.RoundTripper) (*http.Response, error) { hostname, _ := os.Hostname() // in case of error, just use the zero value ("") as hostname + // XXX: github.com/ThomsonReutersEikon/go-ntlm doesn't seem to have a + // way to generate a negotiate message (or even a hardcoded one in the + // library?). Use the one from github.com/Azure/go-ntlmssp, and hope + // that it works ¯\_(ツ)_/¯ negotiate, err := ntlmssp.NewNegotiateMessage(a.domain, hostname) if err != nil { log.Printf("Error creating NTLM Type 1 (Negotiate) message: %v", err) @@ -49,20 +54,31 @@ func (a authenticator) do(req *http.Request, rt http.RoundTripper) (*http.Respon return resp, nil } resp.Body.Close() - challenge, err := base64.StdEncoding.DecodeString( + challengeBytes, err := base64.StdEncoding.DecodeString( strings.TrimPrefix(resp.Header.Get("Proxy-Authenticate"), "NTLM ")) if err != nil { log.Printf("Error decoding NTLM Type 2 (Challenge) message: %v", err) return nil, err } - authenticate, err := ntlmssp.ProcessChallengeWithHash( - challenge, a.domain, a.username, a.hash) + challenge, err := ntlm.ParseChallengeMessage(challengeBytes) + if err != nil { + log.Printf("Error parsing NTLM Type 2 (Challenge) message: %v", err) + return nil, err + } + session, err := ntlm.CreateClientSession(ntlm.Version2, ntlm.ConnectionlessMode) + //session.SetUserInfo(a.username, os.Getenv("ALPACA_PASSWORD"), a.domain) + session.SetUserInfo(a.username, "guest", a.domain) + if err := session.ProcessChallengeMessage(challenge); err != nil { + log.Printf("Error processing NTLM Type 2 (Challenge) message: %v", err) + return nil, err + } + authenticate, err := session.GenerateAuthenticateMessage() if err != nil { log.Printf("Error processing NTLM Type 2 (Challenge) message: %v", err) return nil, err } req.Header.Set("Proxy-Authorization", - "NTLM "+base64.StdEncoding.EncodeToString(authenticate)) + "NTLM "+base64.StdEncoding.EncodeToString(authenticate.Bytes())) return rt.RoundTrip(req) } diff --git a/go.mod b/go.mod index 09b11da..4a7a40f 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( ) require ( + github.com/ThomsonReutersEikon/go-ntlm v0.0.0-00010101000000-000000000000 github.com/alessio/shellescape v1.4.1 // indirect github.com/danieljoos/wincred v1.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect @@ -26,3 +27,5 @@ require ( gopkg.in/sourcemap.v1 v1.0.5 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) + +replace github.com/ThomsonReutersEikon/go-ntlm => github.com/omniboost/ThomsonReutersEikon-go-ntlm v0.0.0-20200629081634-2b904c46aa41 diff --git a/go.sum b/go.sum index 9e3d582..a01f41e 100644 --- a/go.sum +++ b/go.sum @@ -10,6 +10,8 @@ github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs= github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw= +github.com/omniboost/ThomsonReutersEikon-go-ntlm v0.0.0-20200629081634-2b904c46aa41 h1:g5MhOh7x3/HJ4hjx1U8UuCqbmlTwAdkNe5tPL/17q3g= +github.com/omniboost/ThomsonReutersEikon-go-ntlm v0.0.0-20200629081634-2b904c46aa41/go.mod h1:1GjY7cBv+3oSiN701BVraCLtLPchBiGIB6t7hnMowSA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/robertkrimen/otto v0.4.0 h1:/c0GRrK1XDPcgIasAsnlpBT5DelIeB9U/Z/JCQsgr7E= From 47d3a492d3151df293082f30ba2f84378738686c Mon Sep 17 00:00:00 2001 From: Sam Uong Date: Fri, 25 Apr 2025 21:06:44 +1000 Subject: [PATCH 2/3] Remove hard-coded password --- authenticator.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/authenticator.go b/authenticator.go index 60a090e..da53c3e 100644 --- a/authenticator.go +++ b/authenticator.go @@ -66,8 +66,7 @@ func (a authenticator) do(req *http.Request, rt http.RoundTripper) (*http.Respon return nil, err } session, err := ntlm.CreateClientSession(ntlm.Version2, ntlm.ConnectionlessMode) - //session.SetUserInfo(a.username, os.Getenv("ALPACA_PASSWORD"), a.domain) - session.SetUserInfo(a.username, "guest", a.domain) + session.SetUserInfo(a.username, os.Getenv("ALPACA_PASSWORD"), a.domain) if err := session.ProcessChallengeMessage(challenge); err != nil { log.Printf("Error processing NTLM Type 2 (Challenge) message: %v", err) return nil, err From 0250bf0567a37df2d1f2bc08c85938b792af0fc9 Mon Sep 17 00:00:00 2001 From: Sam Uong Date: Fri, 25 Apr 2025 21:08:22 +1000 Subject: [PATCH 3/3] Add error check --- authenticator.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/authenticator.go b/authenticator.go index da53c3e..6f4854b 100644 --- a/authenticator.go +++ b/authenticator.go @@ -66,6 +66,10 @@ func (a authenticator) do(req *http.Request, rt http.RoundTripper) (*http.Respon return nil, err } session, err := ntlm.CreateClientSession(ntlm.Version2, ntlm.ConnectionlessMode) + if err != nil { + log.Printf("Error creating NTLM client session: %v", err) + return nil, err + } session.SetUserInfo(a.username, os.Getenv("ALPACA_PASSWORD"), a.domain) if err := session.ProcessChallengeMessage(challenge); err != nil { log.Printf("Error processing NTLM Type 2 (Challenge) message: %v", err)