ajd
ajd

Reputation: 1022

Using Git on Windows, behind an HTTP proxy, without storing proxy password on disk

I'm using Git on Windows, on a corporate network where I'm behind an HTTP proxy with Basic authentication. Outbound SSH doesn't work, so I have to use HTTPS through the proxy.

I'm aware of how to use git config http.proxy to configure the settings as http://[username]:[password]@[proxy]:[port].

However, particularly as this is a shared machine, I'd rather not store my password in my .gitconfig. Additionally, changing my .gitconfig using the git config command leaves my password in my bash history, so even if I remember to clear my .gitconfig at the end of the session, I'll almost certainly forget to clear my history as well.

I've tried setting http.proxy without a password, in the vain hope that I'd get a prompt asking me for my password when I try to push/pull, but I only get a 407 Proxy Authentication Required. All the information I've found online seems to either ignore the issues with having the password saved in plaintext in .gitconfig, or deals with NTLM proxies.

I'm quite happy to type my proxy details every time I need to connect - the best solution I can see at the moment is writing a wrapper script that will prompt for my password and set that as an environment variable when calling git proper. Is this a decent solution, and are there any security implications to setting an environment variable for a single call in a script? Preferably, are there any built-in settings or existing tools that I can use for this?

Upvotes: 56

Views: 109209

Answers (6)

VonC
VonC

Reputation: 1324337

Git 2.46 should offer an alternative to the HTTP proxy server I mentioned in my 2014-2020 answer:

With Git 2.46 (Q3 2024), batch 2, the credential helper protocol, together with the HTTP layer, have been enhanced to support authentication schemes different from username & password pair, like Bearer and NTLM.

See commit ffff4ac, commit 40220f4, commit 30c0a30, commit ac4c7cb, commit 37417b7, commit bd590bd, commit 36f7d86, commit 8470c94, commit ad9bb6d, commit 5af5cc6, commit 2ae6dc6, commit ca9ccbf, commit 6a6d6fb, commit d01c76f, commit 90765ea, commit 7046f1d (17 Apr 2024) by brian m. carlson (bk2204).
(Merged by Junio C Hamano -- gitster -- in commit c5c9acf, 08 May 2024)

credential: add an authtype field

Signed-off-by: brian m. carlson

When Git makes an HTTP request, it can negotiate the type of authentication to use with the server provided the authentication scheme is one of a few well-known types (Basic, Digest, NTLM, or Negotiate).
However, some servers wish to use other types of authentication, such as the Bearer type from OAuth2.
Since libcurl doesn't natively support this type, it isn't possible to use it, and the user is forced to specify the Authorization header using the http.extraheader setting.

However, storing a plaintext token in the repository configuration is not very secure, especially if a repository can be shared by multiple parties.
We already have support for many types of secure credential storage by using credential helpers, so let's teach credential helpers how to produce credentials for an arbitrary scheme.

If the credential helper specifies an authtype field, then it specifies an authentication scheme (e.g., Bearer) and the password field specifies the raw authentication token, with any encoding already specified.
We reuse the password field for this because some credential helpers store the metadata without encryption even though the password is encrypted, and we'd like to avoid insecure storage if an older version of the credential helper gets ahold of the data.

The username is not used in this case, but it is still preserved for the purpose of finding the right credential if the user has multiple accounts.

If the authtype field is not specified, then the password behaves as normal and it is passed along with the username to libcurl.

Documentation:

docs: indicate new credential protocol fields

Signed-off-by: brian m. carlson

Now that we have new fields (authtype and credential), let's document them for users and credential helper implementers.

Indicate specifically what common values of authtype are and what values are allowed.
Note that, while common, digest and NTLM authentication are insecure because they require unsalted, uniterated password hashes to be stored.

Tell users that they can continue to use a username and password even if the new capability is supported.

git credential now includes in its man page:

authtype

This indicates that the authentication scheme in question should be used. Common values for HTTP and HTTPS include basic, bearer, and digest, although the latter is insecure and should not be used. If credential is used, this may be set to an arbitrary string suitable for the protocol in question (usually HTTP).

This value should not be sent unless the appropriate capability (see below) is provided on input.

credential

The pre-encoded credential, suitable for the protocol in question (usually HTTP). If this key is sent, authtype is mandatory, and username and password are not used. For HTTP, Git concatenates the authtype value and this value with a single space to determine the Authorization header.

This value should not be sent unless the appropriate capability (see below) is provided on input.

ephemeral

This boolean value indicates, if true, that the value in the credential field should not be saved by the credential helper because its usefulness is limited in time. For example, an HTTP Digest credential value is computed using a nonce and reusing it will not result in successful authentication. This may also be used for situations with short duration (e.g., 24-hour) credentials. The default value is false.

The credential helper will still be invoked with store or erase so that it can determine whether the operation was successful.

This value should not be sent unless the appropriate capability (see below) is provided on input.

git credential now includes in its man page:

capability[]

This signals that the caller supports the capability in question. This can be used to provide better, more specific data as part of the protocol.

The only capability currently supported is authtype, which indicates that the authtype, credential, and ephemeral values are understood. It is not obligatory to use these values in such a case, but they should not be provided without this capability.

Callers of git credential and credential helpers should emit the capabilities they support unconditionally, and Git will gracefully handle passing them on.

Unrecognised attributes and capabilities are silently discarded.

With:

credential: add support for multistage credential rounds

Signed-off-by: brian m. carlson

Over HTTP, NTLM and Kerberos require two rounds of authentication on the client side.
It's possible that there are custom authentication schemes that also implement this same approach.
Since these are tricky schemes to implement and the HTTP library in use may not always handle them gracefully on all systems, it would be helpful to allow the credential helper to implement them instead for increased portability and robustness.

To allow this to happen, add a boolean flag, continue, that indicates that instead of failing when we get a 401, we should retry another round of authentication.
However, this necessitates some changes in our current credential code so that we can make this work.

Limit the number of iterations of reauthentication we do to 3. This means that if there's a problem, we'll terminate with an error message instead of retrying indefinitely and not informing the user (and possibly conducting a DoS on the server).

git credential now includes in its man page:

continue

This is a boolean value, which, if enabled, indicates that this authentication is a non-final part of a multistage authentication step. This is common in protocols such as NTLM and Kerberos, where two rounds of client authentication are required, and setting this flag allows the credential helper to implement the multistage authentication step. This flag should only be sent if a further stage is required; that is, if another round of authentication is expected.

This value should not be sent unless the appropriate capability (see below) is provided on input. This attribute is 'one-way' from a credential helper to pass information to Git (or other programs invoking git credential).

You can check with:

credential: add method for querying capabilities

Signed-off-by: brian m. carlson

Right now, there's no specific way to determine whether a credential helper or git credential(man) itself supports a given set of capabilities.
It would be helpful to have such a way, so let's let credential helpers and git credential take an argument, "capability", which has it list the capabilities and a version number on standard output.

Specifically choose a format that is slightly different from regular credential output and assume that no capabilities are supported if a non-zero exit status occurs or the data deviates from the format.
It is common for users to write small shell scripts as the argument to credential.helper, which will almost never be designed to emit capabilities.
We want callers to gracefully handle this case by assuming that they are not capable of extended support because that is almost certainly the case, and specifying the error behavior up front does this and preserves backwards compatibility in a graceful way.

git credential now includes in its man page:

 git credential' (fill|approve|reject|capability)

If the action is capability, git-credential will announce any capabilities it supports to standard output.

git credential now includes in its man page:

CAPABILITY INPUT/OUTPUT FORMAT

For git credential capability, the format is slightly different. First, a version 0 announcement is made to indicate the current version of the protocol, and then each capability is announced with a line like capability authtype. Credential helpers may also implement this format, again with the capability argument. Additional lines may be added in the future; callers should ignore lines which they don't understand.

Because this is a new part of the credential helper protocol, older versions of Git, as well as some credential helpers, may not support it. If a non-zero exit status is received, or if the first line doesn't start with the word version and a space, callers should assume that no capabilities are supported.

The intention of this format is to differentiate it from the credential output in an unambiguous way. It is possible to use very simple credential helpers (e.g., inline shell scripts) which always produce identical output. Using a distinct format allows users to continue to use this syntax without having to worry about correctly implementing capability advertisements or accidentally confusing callers querying for capabilities.

Upvotes: 0

iowatiger08
iowatiger08

Reputation: 1962

I know this is an old post but thought I should add a note. In Windows 10, I did the above command in git bash as "git config --global https.proxy http://[userid]:[passwordWithSpclChars]@url:port" ... but since my credential has special characters, I had to then edit the config file C:\USERS<userid>.gitconfig to URL encode the special characters in my credential. Then I was able to proceed with git fetch from origin.

Upvotes: 0

VonC
VonC

Reputation: 1324337

Instead of using git setting, you can also use environment variable (that you can set just for your session), as described in this answer:

set http_proxy=http://username:password@proxydomain:port
set https_proxy=http://username:password@proxydomain:port
set no_proxy=localhost,.my.company 

So your wrapper script could, instead of modifying the .gitconfig (and leaving your password in plain text) set environment variables on demand, just for your current session.

As noted by Welgriv, this is unsafe since environmental variables can be accessed by any program in user mode.


These days (2020, 5+ years later), I prefer:

set http_proxy=http://127.0.0.1:3128
set https_proxy=http://127.0.0.1:3128

With 127.0.0.1:3128 being the default URL for a genotrance/px, a small HTTP proxy server, which will automatically authenticate through an NTLM proxy.
No password or even user to set.

Upvotes: 44

0xA0
0xA0

Reputation: 739

since git 2.8.0

git config --global http.proxy http://[user]@proxyhost:port
git config --global credential.helper wincred

Upvotes: 71

Rahul Shukla
Rahul Shukla

Reputation: 21

If you are behind Proxy server, follow this.

Make sure port 9418 is excluded from your firewall rules.Ask network administrator

Unset Proxy if it is already set:

  • git config --global --unset http.proxy
  • git config --global --unset https.proxy

Set the proper Proxy:

Common Errors:

  • 502: URL/IP is unreachable from your network.
  • 407: Proxy authentication Denied.
  • 80 : Proxy has not been set properly.

Upvotes: -3

DomTomCat
DomTomCat

Reputation: 8569

VonC's answer doesn't always solve the problem. I don't know why, but it may depend on the proxy server - or maybe it's some other issue alltogether?

It may help to replace the git:// protocol of the repository with http://.

Note: As in VonC's answer, you'll have to setup the http(s)_proxy environment variables first:

set http_proxy=http://username:password@proxydomain:port
set https_proxy=http://username:password@proxydomain:port

For example, clone marble's stable git would usually be cloned like this (from the marble documentation):

git clone -b Applications/15.12 git://anongit.kde.org/marble ~/marble/sources

In windows' cmd (assuming http_proxy has been set), you may then have to use http[s]:// instead:

git clone -b Applications/15.12 http://anongit.kde.org/marble ~/marble/sources

Upvotes: 3

Related Questions