Merge pull request #4815 from bk2204/negotiate-fallback
Fall back from Negotiate to Basic
This commit is contained in:
commit
4a3701b555
@ -31,3 +31,12 @@ func (a *Access) Mode() AccessMode {
|
||||
func (a *Access) URL() string {
|
||||
return a.url
|
||||
}
|
||||
|
||||
// AllAccessModes returns all access modes in the order they should be tried.
|
||||
func AllAccessModes() []AccessMode {
|
||||
return []AccessMode{
|
||||
NoneAccess,
|
||||
NegotiateAccess,
|
||||
BasicAccess,
|
||||
}
|
||||
}
|
||||
|
@ -68,9 +68,11 @@ func (c *Client) doWithAuth(remote string, access creds.Access, req *http.Reques
|
||||
res, err := c.doWithCreds(req, credWrapper, access, via)
|
||||
if err != nil {
|
||||
if errors.IsAuthError(err) {
|
||||
newAccess := access.Upgrade(getAuthAccess(res))
|
||||
newMode, newModes := getAuthAccess(res, access.Mode(), c.access)
|
||||
newAccess := access.Upgrade(newMode)
|
||||
if newAccess.Mode() != access.Mode() {
|
||||
c.Endpoints.SetAccess(newAccess)
|
||||
c.access = newModes
|
||||
}
|
||||
|
||||
if credWrapper.Creds != nil {
|
||||
@ -312,20 +314,34 @@ var (
|
||||
authenticateHeaders = []string{"Lfs-Authenticate", "Www-Authenticate"}
|
||||
)
|
||||
|
||||
func getAuthAccess(res *http.Response) creds.AccessMode {
|
||||
for _, headerName := range authenticateHeaders {
|
||||
for _, auth := range res.Header[headerName] {
|
||||
pieces := strings.SplitN(strings.ToLower(auth), " ", 2)
|
||||
if len(pieces) == 0 {
|
||||
continue
|
||||
}
|
||||
func getAuthAccess(res *http.Response, access creds.AccessMode, modes []creds.AccessMode) (creds.AccessMode, []creds.AccessMode) {
|
||||
newModes := make([]creds.AccessMode, 0, len(modes))
|
||||
for _, mode := range modes {
|
||||
if access != mode {
|
||||
newModes = append(newModes, mode)
|
||||
}
|
||||
}
|
||||
if res != nil {
|
||||
supportedModes := make(map[creds.AccessMode]struct{})
|
||||
for _, headerName := range authenticateHeaders {
|
||||
for _, auth := range res.Header[headerName] {
|
||||
pieces := strings.SplitN(strings.ToLower(auth), " ", 2)
|
||||
if len(pieces) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
switch creds.AccessMode(pieces[0]) {
|
||||
case creds.NegotiateAccess:
|
||||
return creds.AccessMode(pieces[0])
|
||||
switch creds.AccessMode(pieces[0]) {
|
||||
case creds.BasicAccess, creds.NegotiateAccess:
|
||||
supportedModes[creds.AccessMode(pieces[0])] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, mode := range newModes {
|
||||
if _, ok := supportedModes[mode]; ok {
|
||||
return mode, newModes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return creds.BasicAccess
|
||||
return creds.BasicAccess, newModes
|
||||
}
|
||||
|
@ -39,11 +39,23 @@ func TestAuthenticateHeaderAccess(t *testing.T) {
|
||||
res := &http.Response{Header: make(http.Header)}
|
||||
res.Header.Set(key, value)
|
||||
t.Logf("%s: %s", key, value)
|
||||
assert.Equal(t, expected, getAuthAccess(res))
|
||||
result, _ := getAuthAccess(res, creds.NoneAccess, creds.AllAccessModes())
|
||||
assert.Equal(t, expected, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDualAccessModes(t *testing.T) {
|
||||
res := &http.Response{Header: make(http.Header)}
|
||||
res.Header["Www-Authenticate"] = []string{"Negotiate 123", "Basic 456"}
|
||||
access, next := getAuthAccess(res, creds.NoneAccess, creds.AllAccessModes())
|
||||
assert.Equal(t, creds.NegotiateAccess, access)
|
||||
access, next = getAuthAccess(res, access, next)
|
||||
assert.Equal(t, creds.BasicAccess, access)
|
||||
access, _ = getAuthAccess(res, access, next)
|
||||
assert.Equal(t, creds.BasicAccess, access)
|
||||
}
|
||||
|
||||
func TestDoWithAuthApprove(t *testing.T) {
|
||||
var called uint32
|
||||
|
||||
|
@ -17,6 +17,7 @@ type Client struct {
|
||||
|
||||
client *lfshttp.Client
|
||||
context lfshttp.Context
|
||||
access []creds.AccessMode
|
||||
}
|
||||
|
||||
func NewClient(ctx lfshttp.Context) (*Client, error) {
|
||||
@ -37,6 +38,7 @@ func NewClient(ctx lfshttp.Context) (*Client, error) {
|
||||
client: httpClient,
|
||||
context: ctx,
|
||||
credContext: creds.NewCredentialHelperContext(gitEnv, osEnv),
|
||||
access: creds.AllAccessModes(),
|
||||
}
|
||||
|
||||
return c, nil
|
||||
|
@ -3,6 +3,7 @@ package lfshttp
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
goerrors "errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
@ -301,6 +302,11 @@ func (c *Client) DoWithRedirect(cli *http.Client, req *http.Request, remote stri
|
||||
|
||||
if err != nil {
|
||||
c.traceResponse(req, tracedReq, nil)
|
||||
// SPNEGO (Negotiate) errors are authentication errors.
|
||||
var spnegoErr *spnego.Error
|
||||
if goerrors.As(err, &spnegoErr) {
|
||||
return nil, nil, errors.NewAuthError(err)
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user