mirror of
https://github.com/git/git.git
synced 2024-11-24 10:26:17 +08:00
http: use credential API to handle proxy authentication
Currently, the only way to pass proxy credentials to curl is by including them in the proxy URL. Usually, this means they will end up on disk unencrypted, one way or another (by inclusion in ~/.gitconfig, shell profile or history). Since proxy authentication often uses a domain user, credentials can be security sensitive; therefore, a safer way of passing credentials is desirable. If the configured proxy contains a username but not a password, query the credential API for one. Also, make sure we approve/reject proxy credentials properly. For consistency reasons, add parsing of http_proxy/https_proxy/all_proxy environment variables, which would otherwise be evaluated as a fallback by curl. Without this, we would have different semantics for git configuration and environment variables. Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Eric Sunshine <sunshine@sunshineco.com> Helped-by: Elia Pinto <gitter.spiros@gmail.com> Signed-off-by: Knut Franke <k.franke@science-computing.de> Signed-off-by: Elia Pinto <gitter.spiros@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
ef976395e2
commit
372370f167
@ -1596,9 +1596,13 @@ help.htmlPath::
|
|||||||
|
|
||||||
http.proxy::
|
http.proxy::
|
||||||
Override the HTTP proxy, normally configured using the 'http_proxy',
|
Override the HTTP proxy, normally configured using the 'http_proxy',
|
||||||
'https_proxy', and 'all_proxy' environment variables (see
|
'https_proxy', and 'all_proxy' environment variables (see `curl(1)`). In
|
||||||
`curl(1)`). This can be overridden on a per-remote basis; see
|
addition to the syntax understood by curl, it is possible to specify a
|
||||||
remote.<name>.proxy
|
proxy string with a user name but no password, in which case git will
|
||||||
|
attempt to acquire one in the same way it does for other credentials. See
|
||||||
|
linkgit:gitcredentials[7] for more information. The syntax thus is
|
||||||
|
'[protocol://][user[:password]@]proxyhost[:port]'. This can be overridden
|
||||||
|
on a per-remote basis; see remote.<name>.proxy
|
||||||
|
|
||||||
http.proxyAuthMethod::
|
http.proxyAuthMethod::
|
||||||
Set the method with which to authenticate against the HTTP proxy. This
|
Set the method with which to authenticate against the HTTP proxy. This
|
||||||
|
77
http.c
77
http.c
@ -80,6 +80,8 @@ static struct {
|
|||||||
* here, too
|
* here, too
|
||||||
*/
|
*/
|
||||||
};
|
};
|
||||||
|
static struct credential proxy_auth = CREDENTIAL_INIT;
|
||||||
|
static const char *curl_proxyuserpwd;
|
||||||
static const char *curl_cookie_file;
|
static const char *curl_cookie_file;
|
||||||
static int curl_save_cookies;
|
static int curl_save_cookies;
|
||||||
struct credential http_auth = CREDENTIAL_INIT;
|
struct credential http_auth = CREDENTIAL_INIT;
|
||||||
@ -177,6 +179,9 @@ static void finish_active_slot(struct active_request_slot *slot)
|
|||||||
#else
|
#else
|
||||||
slot->results->auth_avail = 0;
|
slot->results->auth_avail = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CONNECTCODE,
|
||||||
|
&slot->results->http_connectcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Run callback if appropriate */
|
/* Run callback if appropriate */
|
||||||
@ -334,8 +339,32 @@ static void var_override(const char **var, char *value)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void set_proxyauth_name_password(CURL *result)
|
||||||
|
{
|
||||||
|
#if LIBCURL_VERSION_NUM >= 0x071301
|
||||||
|
curl_easy_setopt(result, CURLOPT_PROXYUSERNAME,
|
||||||
|
proxy_auth.username);
|
||||||
|
curl_easy_setopt(result, CURLOPT_PROXYPASSWORD,
|
||||||
|
proxy_auth.password);
|
||||||
|
#else
|
||||||
|
struct strbuf s = STRBUF_INIT;
|
||||||
|
|
||||||
|
strbuf_addstr_urlencode(&s, proxy_auth.username, 1);
|
||||||
|
strbuf_addch(&s, ':');
|
||||||
|
strbuf_addstr_urlencode(&s, proxy_auth.password, 1);
|
||||||
|
curl_proxyuserpwd = strbuf_detach(&s, NULL);
|
||||||
|
curl_easy_setopt(result, CURLOPT_PROXYUSERPWD, curl_proxyuserpwd);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static void init_curl_proxy_auth(CURL *result)
|
static void init_curl_proxy_auth(CURL *result)
|
||||||
{
|
{
|
||||||
|
if (proxy_auth.username) {
|
||||||
|
if (!proxy_auth.password)
|
||||||
|
credential_fill(&proxy_auth);
|
||||||
|
set_proxyauth_name_password(result);
|
||||||
|
}
|
||||||
|
|
||||||
var_override(&http_proxy_authmethod, getenv("GIT_HTTP_PROXY_AUTHMETHOD"));
|
var_override(&http_proxy_authmethod, getenv("GIT_HTTP_PROXY_AUTHMETHOD"));
|
||||||
|
|
||||||
#if LIBCURL_VERSION_NUM >= 0x070a07 /* CURLOPT_PROXYAUTH and CURLAUTH_ANY */
|
#if LIBCURL_VERSION_NUM >= 0x070a07 /* CURLOPT_PROXYAUTH and CURLAUTH_ANY */
|
||||||
@ -517,6 +546,31 @@ static CURL *get_curl_handle(void)
|
|||||||
curl_easy_setopt(result, CURLOPT_USE_SSL, CURLUSESSL_TRY);
|
curl_easy_setopt(result, CURLOPT_USE_SSL, CURLUSESSL_TRY);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CURL also examines these variables as a fallback; but we need to query
|
||||||
|
* them here in order to decide whether to prompt for missing password (cf.
|
||||||
|
* init_curl_proxy_auth()).
|
||||||
|
*
|
||||||
|
* Unlike many other common environment variables, these are historically
|
||||||
|
* lowercase only. It appears that CURL did not know this and implemented
|
||||||
|
* only uppercase variants, which was later corrected to take both - with
|
||||||
|
* the exception of http_proxy, which is lowercase only also in CURL. As
|
||||||
|
* the lowercase versions are the historical quasi-standard, they take
|
||||||
|
* precedence here, as in CURL.
|
||||||
|
*/
|
||||||
|
if (!curl_http_proxy) {
|
||||||
|
if (!strcmp(http_auth.protocol, "https")) {
|
||||||
|
var_override(&curl_http_proxy, getenv("HTTPS_PROXY"));
|
||||||
|
var_override(&curl_http_proxy, getenv("https_proxy"));
|
||||||
|
} else {
|
||||||
|
var_override(&curl_http_proxy, getenv("http_proxy"));
|
||||||
|
}
|
||||||
|
if (!curl_http_proxy) {
|
||||||
|
var_override(&curl_http_proxy, getenv("ALL_PROXY"));
|
||||||
|
var_override(&curl_http_proxy, getenv("all_proxy"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (curl_http_proxy) {
|
if (curl_http_proxy) {
|
||||||
curl_easy_setopt(result, CURLOPT_PROXY, curl_http_proxy);
|
curl_easy_setopt(result, CURLOPT_PROXY, curl_http_proxy);
|
||||||
#if LIBCURL_VERSION_NUM >= 0x071800
|
#if LIBCURL_VERSION_NUM >= 0x071800
|
||||||
@ -530,6 +584,16 @@ static CURL *get_curl_handle(void)
|
|||||||
curl_easy_setopt(result,
|
curl_easy_setopt(result,
|
||||||
CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
|
CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
|
||||||
#endif
|
#endif
|
||||||
|
if (strstr(curl_http_proxy, "://"))
|
||||||
|
credential_from_url(&proxy_auth, curl_http_proxy);
|
||||||
|
else {
|
||||||
|
struct strbuf url = STRBUF_INIT;
|
||||||
|
strbuf_addf(&url, "http://%s", curl_http_proxy);
|
||||||
|
credential_from_url(&proxy_auth, url.buf);
|
||||||
|
strbuf_release(&url);
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_easy_setopt(result, CURLOPT_PROXY, proxy_auth.host);
|
||||||
}
|
}
|
||||||
init_curl_proxy_auth(result);
|
init_curl_proxy_auth(result);
|
||||||
|
|
||||||
@ -673,6 +737,15 @@ void http_cleanup(void)
|
|||||||
curl_http_proxy = NULL;
|
curl_http_proxy = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (proxy_auth.password) {
|
||||||
|
memset(proxy_auth.password, 0, strlen(proxy_auth.password));
|
||||||
|
free(proxy_auth.password);
|
||||||
|
proxy_auth.password = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free((void *)curl_proxyuserpwd);
|
||||||
|
curl_proxyuserpwd = NULL;
|
||||||
|
|
||||||
free((void *)http_proxy_authmethod);
|
free((void *)http_proxy_authmethod);
|
||||||
http_proxy_authmethod = NULL;
|
http_proxy_authmethod = NULL;
|
||||||
|
|
||||||
@ -1005,6 +1078,8 @@ static int handle_curl_result(struct slot_results *results)
|
|||||||
|
|
||||||
if (results->curl_result == CURLE_OK) {
|
if (results->curl_result == CURLE_OK) {
|
||||||
credential_approve(&http_auth);
|
credential_approve(&http_auth);
|
||||||
|
if (proxy_auth.password)
|
||||||
|
credential_approve(&proxy_auth);
|
||||||
return HTTP_OK;
|
return HTTP_OK;
|
||||||
} else if (missing_target(results))
|
} else if (missing_target(results))
|
||||||
return HTTP_MISSING_TARGET;
|
return HTTP_MISSING_TARGET;
|
||||||
@ -1019,6 +1094,8 @@ static int handle_curl_result(struct slot_results *results)
|
|||||||
return HTTP_REAUTH;
|
return HTTP_REAUTH;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (results->http_connectcode == 407)
|
||||||
|
credential_reject(&proxy_auth);
|
||||||
#if LIBCURL_VERSION_NUM >= 0x070c00
|
#if LIBCURL_VERSION_NUM >= 0x070c00
|
||||||
if (!curl_errorstr[0])
|
if (!curl_errorstr[0])
|
||||||
strlcpy(curl_errorstr,
|
strlcpy(curl_errorstr,
|
||||||
|
Loading…
Reference in New Issue
Block a user