2016-12-16 22:03:20 +00:00
|
|
|
package lfsapi
|
|
|
|
|
2016-12-16 22:43:05 +00:00
|
|
|
import (
|
2021-09-01 19:41:10 +00:00
|
|
|
"github.com/git-lfs/git-lfs/v3/creds"
|
|
|
|
"github.com/git-lfs/git-lfs/v3/errors"
|
|
|
|
"github.com/git-lfs/git-lfs/v3/lfshttp"
|
|
|
|
"github.com/git-lfs/git-lfs/v3/ssh"
|
2021-12-14 16:05:42 +00:00
|
|
|
"github.com/git-lfs/git-lfs/v3/tr"
|
2021-05-07 16:56:15 +00:00
|
|
|
"github.com/rubyist/tracerx"
|
2016-12-16 22:43:05 +00:00
|
|
|
)
|
2016-12-16 22:03:20 +00:00
|
|
|
|
|
|
|
type Client struct {
|
2016-12-19 21:38:06 +00:00
|
|
|
Endpoints EndpointFinder
|
2018-09-19 15:05:48 +00:00
|
|
|
Credentials creds.CredentialHelper
|
2016-12-20 17:02:25 +00:00
|
|
|
|
2018-09-19 15:05:48 +00:00
|
|
|
credContext *creds.CredentialHelperContext
|
2018-06-28 18:01:29 +00:00
|
|
|
|
2021-03-17 18:09:17 +00:00
|
|
|
client *lfshttp.Client
|
|
|
|
context lfshttp.Context
|
Fall back from Negotiate to Basic
The Negotiate authentication scheme can support multiple different types
of authentication. The two most popular are NTLM and Kerberos. When we
supported NTLM, we'd first try Kerberos, and if it failed, fall back to
NTLM.
However, we no longer support NTLM, but some people still have server
configuration that uses NTLM via Negotiate. For these people,
authentication may be broken. Let's fall back to Basic in such a case
by keeping track of which authentication mechanisms we've tried,
keeping only the supported mechanisms if we got a response, and
stripping out failing mechanisms, falling back to Basic.
To help with servers that support both Negotiate and Basic, we
specifically consider SPNEGO (Negotiate) errors as authentication
errors. This is because if the server supports Kerberos but the client
does not have a ticket, then we'll get an error trying to read the
client's tickets, which will manifest in this way.
2022-01-13 20:10:58 +00:00
|
|
|
access []creds.AccessMode
|
2016-12-16 22:03:20 +00:00
|
|
|
}
|
|
|
|
|
2018-09-06 21:42:41 +00:00
|
|
|
func NewClient(ctx lfshttp.Context) (*Client, error) {
|
2017-10-25 21:33:20 +00:00
|
|
|
if ctx == nil {
|
2018-09-06 21:42:41 +00:00
|
|
|
ctx = lfshttp.NewContext(nil, nil, nil)
|
2016-12-20 17:29:26 +00:00
|
|
|
}
|
|
|
|
|
2017-10-25 22:05:08 +00:00
|
|
|
gitEnv := ctx.GitEnv()
|
|
|
|
osEnv := ctx.OSEnv()
|
2016-12-19 22:05:35 +00:00
|
|
|
|
2018-09-06 21:42:41 +00:00
|
|
|
httpClient, err := lfshttp.NewClient(ctx)
|
|
|
|
if err != nil {
|
2021-12-14 16:05:42 +00:00
|
|
|
return nil, errors.Wrap(err, tr.Tr.Get("error creating http client"))
|
2017-03-24 17:37:23 +00:00
|
|
|
}
|
2017-03-23 19:48:52 +00:00
|
|
|
|
2016-12-20 17:45:22 +00:00
|
|
|
c := &Client{
|
2018-09-19 14:05:24 +00:00
|
|
|
Endpoints: NewEndpointFinder(ctx),
|
|
|
|
client: httpClient,
|
2021-03-17 18:09:17 +00:00
|
|
|
context: ctx,
|
2018-09-19 15:05:48 +00:00
|
|
|
credContext: creds.NewCredentialHelperContext(gitEnv, osEnv),
|
Fall back from Negotiate to Basic
The Negotiate authentication scheme can support multiple different types
of authentication. The two most popular are NTLM and Kerberos. When we
supported NTLM, we'd first try Kerberos, and if it failed, fall back to
NTLM.
However, we no longer support NTLM, but some people still have server
configuration that uses NTLM via Negotiate. For these people,
authentication may be broken. Let's fall back to Basic in such a case
by keeping track of which authentication mechanisms we've tried,
keeping only the supported mechanisms if we got a response, and
stripping out failing mechanisms, falling back to Basic.
To help with servers that support both Negotiate and Basic, we
specifically consider SPNEGO (Negotiate) errors as authentication
errors. This is because if the server supports Kerberos but the client
does not have a ticket, then we'll get an error trying to read the
client's tickets, which will manifest in this way.
2022-01-13 20:10:58 +00:00
|
|
|
access: creds.AllAccessModes(),
|
2016-12-20 17:45:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return c, nil
|
2016-12-19 22:05:35 +00:00
|
|
|
}
|
2021-03-17 18:09:17 +00:00
|
|
|
|
|
|
|
func (c *Client) Context() lfshttp.Context {
|
|
|
|
return c.context
|
|
|
|
}
|
2021-05-07 16:56:15 +00:00
|
|
|
|
|
|
|
// SSHTransfer returns either an suitable transfer object or nil if the
|
|
|
|
// server is not using an SSH remote or the git-lfs-transfer style of SSH
|
|
|
|
// remote.
|
|
|
|
func (c *Client) SSHTransfer(operation, remote string) *ssh.SSHTransfer {
|
2021-05-14 17:43:57 +00:00
|
|
|
if len(operation) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
2021-05-07 16:56:15 +00:00
|
|
|
endpoint := c.Endpoints.Endpoint(operation, remote)
|
2021-05-14 17:43:57 +00:00
|
|
|
if len(endpoint.SSHMetadata.UserAndHost) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
ctx := c.Context()
|
|
|
|
tracerx.Printf("attempting pure SSH protocol connection")
|
|
|
|
sshTransfer, err := ssh.NewSSHTransfer(ctx.OSEnv(), ctx.GitEnv(), &endpoint.SSHMetadata, operation)
|
|
|
|
if err != nil {
|
|
|
|
tracerx.Printf("pure SSH protocol connection failed: %s", err)
|
|
|
|
return nil
|
2021-05-07 16:56:15 +00:00
|
|
|
}
|
2021-05-14 17:43:57 +00:00
|
|
|
return sshTransfer
|
2021-05-07 16:56:15 +00:00
|
|
|
}
|