GithubHelp home page GithubHelp logo

go-ntlmssp's Introduction

go-ntlmssp

Golang package that provides NTLM/Negotiate authentication over HTTP

GoDoc Build Status

Protocol details from https://msdn.microsoft.com/en-us/library/cc236621.aspx 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. For more information see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.

go-ntlmssp's People

Contributors

boumenot avatar catbuttes avatar davejohnston avatar justdan96 avatar lafriks avatar microsoft-github-policy-service[bot] avatar mszuyev avatar nqv avatar palumacil avatar paulmey avatar resousse avatar tirupatibg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-ntlmssp's Issues

Local account - HTTP 401

When attempting to authenticate using a local user against a domain-joined machine, a HTTP 401 response is returned. Setting the domain appears to have no affect (.\myuser , TEST\myuser etc.)

default negotiate flags aren't working for proxy server

Hi. I'm very new to using NTLM, so I'm sorry if my questions are misguided, but here's my situation:

I've been trying to use this package in combination with go-ntlm-proxy-auth to connect to an NTLM-authenticated proxy server (currently WinGate 9.4). What I'm seeing is that the proxy conversation (the part handled by go-ntlm-proxy-auth) works as expected, and the NTLM messages are well-formed, but WinGate always rejects the initial Negotiate message, saying that the flags are invalid (with no further explanation, unfortunately).

So I tried modifying the default flags in negotiate_message.go, and making them look more similar to what I saw when I connected to the server with other NTLM-enabled tools (e.g. the Windows version of curl). I found that it would only work if I added both negotiateFlagNTLMSSPNEGOTIATENTLM and negotiateFlagNTLMSSPNEGOTIATEALWAYSSIGN. Also, looking at NTLM implementations for other platforms (like Apache HTTPClient), it seems that it's pretty much universal to use those flags.

For now, I'm using a fork where I've added those flags, but I'm uncomfortable with my lack of understanding of all this. If it really is correct to send ALWAYSSIGN (which seems odd to me since it disables a security feature), then why hasn't this been a problem for any other users of this package? Maybe everyone else is authenticating direct requests instead of proxy connections?—but I can't think why that would make a difference.

Unfortunately the Microsoft docs about the protocol are somewhat vague as to which of the many optional flags should be used in any given situation. So I'd really appreciate any insights anyone might have.

Only the first Www-Authenticate header is checked

If the first Www-Authenticate header is not Basic, NTLM, or Negotiate then this will fail as the referenced code in the link below only gets the first Www-Authenticate header. This also means that if the server offers [Negotiate, NTLM] and the server's implementation of Negotiate only supports Kerberos (it will not fallback to NTLM), then this will fail since only Negotiate is attempted... even though NTLM is offered.

https://github.com/Azure/go-ntlmssp/blob/master/negotiator.go#L63

NTLM HTTP Auth doesn't work (wrong negotiation implementation)?

Hi, I think there are few issues with the negotiator. Here's roughly how I'm trying to use your library:

package main

import (
    "fmt"
    "github.com/paulmey/go-ntlmssp"
    "log"
    "net/http"
    "net/http/httputil"
)

func dumpResponse(r *http.Response, prefix string) {
    dump, err := httputil.DumpResponse(r, true)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s %s\n", prefix, string(dump))
}

func main() {
    someURL := "http://example.com/some/endpoint/behind/ntlm.aspx"
    c := &http.Client{
        Transport: ntlmssp.Negotiator{
            &http.Transport{},
        },
    }
    req, _ := http.NewRequest("GET", someURL, nil)
    req.SetBasicAuth("someuser", "somepass")
    res, err := c.Do(req)
    if err != nil {
        log.Fatal(err)
    }
    dumpResponse(res, "Page retrived after NTLM authentication:\n")
}

This code doesn't work. It panics with a nil pointer de-reference and after fixing that in negotiator.go, it doesn't correctly authenticate. After making the changes in this diff it works as expected. What do you think?

Negotiation fails when server Requires NTLMv2 session security

Negotiate fails when servers have strict checking enabled using the registry key NtlmMinServerSec.
The key can be found under HKLM\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0
If it is set to 0x00080000 or greater, the request will fail.

The issue appears to be that the negotiate header is not setting the relevant flag to indicate that this is supported.

https://www.ultimatewindowssecurity.com/wiki/page.aspx?spid=NSrpcservers
Require NTLMv2 session security. If the value of either this entry or the NtlmMinClientSec entry is 0x80000, then the connection will fail unless NTLMv2 session security is negotiated

According to the spec (https://msdn.microsoft.com/en-us/library/cc236621.aspx) in 2.2.2.5 NEGOTIATE

P (1 bit): If set, requests usage of the NTLM v2 session security. NTLM v2 session security is a
misnomer because it is not NTLM v2. It is NTLM v1 using the extended session security that is also
in NTLM v2. NTLMSSP_NEGOTIATE_LM_KEY and
NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY are mutually exclusive. If both
NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY and NTLMSSP_NEGOTIATE_LM_KEY are
requested, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY alone MUST be returned to the
client. NTLM v2 authentication session key generation MUST be supported by both the client and
the DC in order to be used, and extended session security signing and sealing requires support
from the client and the server in order to be used.<25> An alternate name for this field is
NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY

Test failure

Trying to build commit 754e693 on Fedora Rawhide I'm getting:

+ go-rpm-integration check -i github.com/Azure/go-ntlmssp -b /home/orion/fedora/golang-github-azure-ntlmssp/go-ntlmssp-754e69321358ada85ce213a4ec971d3e4d1bfdf7/_build/bin -s /home/orion/fedora/golang-github-azure-ntlmssp/go-ntlmssp-754e69321358ada85ce213a4ec971d3e4d1bfdf7/_build -V 0-0.10.20230516git754e693.fc39 -C 754e69321358ada85ce213a4ec971d3e4d1bfdf7 -p /home/orion/BUILDROOT/golang-github-azure-ntlmssp-0-0.10.20230516git754e693.fc39.x86_64 -g /usr/share/gocode -r '.*example.*'
Testing    in: /home/orion/fedora/golang-github-azure-ntlmssp/go-ntlmssp-754e69321358ada85ce213a4ec971d3e4d1bfdf7/_build/src
         PATH: /home/orion/fedora/golang-github-azure-ntlmssp/go-ntlmssp-754e69321358ada85ce213a4ec971d3e4d1bfdf7/_build/bin:/home/orion/.local/bin:/home/orion/bin:/usr/lib64/ccache:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/usr/sbin:/opt/local/rsi/idl/bin
       GOPATH: /home/orion/fedora/golang-github-azure-ntlmssp/go-ntlmssp-754e69321358ada85ce213a4ec971d3e4d1bfdf7/_build:/usr/share/gocode
  GO111MODULE: off
      command: go test -buildmode pie -compiler gc -ldflags " -X github.com/Azure/go-ntlmssp/version.commit=754e69321358ada85ce213a4ec971d3e4d1bfdf7 -X github.com/Azure/go-ntlmssp/version=0 -extldflags '-Wl,-z,relro -Wl,--as-needed  -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1  -Wl,--build-id=sha1 -specs=/usr/lib/rpm/redhat/redhat-package-notes  '"
      testing: github.com/Azure/go-ntlmssp
github.com/Azure/go-ntlmssp
# github.com/Azure/go-ntlmssp [github.com/Azure/go-ntlmssp.test]
./nlmp_test.go:52:21: assignment mismatch: 2 variables but GetDomain returns 3 values
FAIL    github.com/Azure/go-ntlmssp [build failed]

Looks like nlmp_test.go hasn't been updated to handle the 3 return values.

ntlmssp.Negotiator is storing the entire body in memory and causing out of memory errors

I had a bug report in rclone which was complaining about huge memory use.

I tracked it down from the log to this

github.com/Azure/go-ntlmssp.Negotiator.RoundTrip({{0x27ff220?, 0xc0006ce230?}}, 0xc0009d6000)
	github.com/Azure/[email protected]/negotiator.go:52 +0x2bd fp=0xc0007aac68 sp=0xc0007aa990 pc=0x191645d
github.com/Azure/go-ntlmssp.(*Negotiator).RoundTrip(0xc0007aad48?, 0x418f48?)
	<autogenerated>:1 +0x31 fp=0xc0007aac90 sp=0xc0007aac68 pc=0x1918a31

Which points to this bit of code

go-ntlmssp/negotiator.go

Lines 49 to 59 in 754e693

// Save request body
body := bytes.Buffer{}
if req.Body != nil {
_, err = body.ReadFrom(req.Body)
if err != nil {
return nil, err
}
req.Body.Close()
req.Body = ioutil.NopCloser(bytes.NewReader(body.Bytes()))
}

Where we see, yes this does load the entire body into memory.

The user is complaining about out of memory errors when trying to upload a very large file (10GB).

This might be an error we are making in the rclone code - I didn't write this bit of code so maybe we are using the library wrong, but loading a 10GB body into memory is a bit unfriendly!

Here is the rclone code if anyone wants to take a look

https://github.com/rclone/rclone/blob/1ebbc74f1d62457aea660b9e4378cc085c0dd25e/backend/webdav/webdav.go#L462

Negotiate vs NTLM

Hi,

Not reporting an issue but seeking clarification. I see that there is no difference between the processing of challenge / response when Authorization header is Negotiate or NTLM. Isn't Negotiate header intended for use Kerberose if available and if not available fallback to NTLM ? Is my understanding correct ? If yes, is Negotiate implementation on the road map ? Thanks for any inputs.

Hardcoded workstation name

As for now the workstation name for the ntlm negotiation is hard coded in authenticate_message.go to workstation := toUnicode("go-ntlmssp"). It is not possible to set it manually. This can lead to problems with logs of intrusion detection systems, since they can log the client as the workstation name, what can lead to confusion. Therefore, it would be desirable to have the possibility to set the workstation name by oneself.

Error 401 with concurrent requests

When I tried to use this library with concurrent api calls, I sometimes get an error 401.

url, user, password := "http://www.example.com/secrets", "robpike", "pw123"
client := &http.Client{
  Transport: ntlmssp.Negotiator{
    RoundTripper:&http.Transport{},
  },
}
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
  wg.Add(1)
  go func() {
    defer wg.Done()
    req, _ := http.NewRequest("GET", url, nil)
    req.SetBasicAuth(user, password)
    res, _ := client.Do(req)
    fmt.Println(resp.StatusCode)
  }()
}
wg.Wait()

If I make sure that the client only uses 1 active connection, I don't get any error. So I'm guessing this is a bug, right?

client := &http.Client{
  Transport: ntlmssp.Negotiator{
    RoundTripper:&http.Transport{
      MaxConnsPerHost: 1,  // limit connections
    },
  },
}

Example please

Hello,

It would be nice to see an example of how this library needs to be used. I will place a pull request to add one to the README, but any extra notes you can add would help a lot of people too. Thanks for the good library!

Dan

Negotiator violates the http.RoundTripper interface contract.

From http.RoundTripper documentation:

type RoundTripper interface {
// RoundTrip executes a single HTTP transaction, returning
// a Response for the provided Request.
//
// RoundTrip should not attempt to interpret the response. In
// particular, RoundTrip must return err == nil if it obtained
// a response, regardless of the response's HTTP status code.
// A non-nil err should be reserved for failure to obtain a
// response. Similarly, RoundTrip should not attempt to
// handle higher-level protocol details such as redirects,
// authentication, or cookies.
//
// RoundTrip should not modify the request, except for
// consuming and closing the Request's Body.
RoundTrip(*Request) (*Response, error)
}

Support nil Body

http.RoundTripper allows nil Body for http.Request (i.e. for GET requests) but Negotiator panics:

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x20 pc=0x122339]

goroutine 1 [running]:
bytes.(*Buffer).ReadFrom(0xc8200536c8, 0x0, 0x0, 0x0, 0x0, 0x0)
        /usr/local/go/src/bytes/buffer.go:173 +0x239
github.com/Azure/go-ntlmssp.Negotiator.RoundTrip(0x1364488, 0xc8200a4090, 0xc8200c2000, 0x0, 0x0, 0x0)
        /path/to/go/src/github.com/Azure/go-ntlmssp/negotiator.go:18 +0xb7
github.com/Azure/go-ntlmssp.(*Negotiator).RoundTrip(0xc820078ca0, 0xc8200c2000, 0x2, 0x0, 0x0)

Authenticate using default credentials from SSPI

Hi all,

I'm trying to call an NTLM-authenticated HTTP service in Go. I'm running on a Windows host and the process's default user credentials accessible via SSPI have access to this service.

I see that the usage examples for this package showcase providing explicit credentials (via the SetBasicAuth method) - I'd like to avoid this so that my service (possibly running as a GMSA) does not need to consume credentials from an insecure source or marshal credentials around otherwise.

I see that alexbrainman/sspi provides some methods to call SSPI, but I'm not sure how to chain these two packages together if that's even possible.

Can someone provide some guidance on how to make this work?

When Www-Authenticate doesn't advertise Basic Auth Basic Auth should never be used

In negotiator.go when the Www-Authenticate header does not advertise Basic Auth Basic Auth is still tried when neither party want it.

I'm happy to put something in for this as it would be trivial.

I think Basic Auth should only ever be tried whenever it is advertised in this header as being acceptable as when it isn't advertised it will just be another request to a server which doesn't support it anyway so it's just delaying the inevitable.

Authentication fails with 401

Authentication fails while using package for NTLM authentication. But the strange thing here is authentication do passes sometimes after many requests. Say for example after 5 or 10 requests, that means authentication happens at random trials.
Is there anything to be changed from client end

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.