http: add support for authtype and credential
Now that we have the credential helper code set up to handle arbitrary authentications schemes, let's add support for this in the HTTP code, where we really want to use it. If we're using this new functionality, don't set a username and password, and instead set a header wherever we'd normally do so, including for proxy authentication. Since we can now handle this case, ask the credential helper to enable the appropriate capabilities. Finally, if we're using the authtype value, set "Expect: 100-continue". Any type of authentication that requires multiple rounds (such as NTLM or Kerberos) requires a 100 Continue (if we're larger than http.postBuffer) because otherwise we send the pack data before we're authenticated, the push gets a 401 response, and we can't rewind the stream. We don't know for certain what other custom schemes might require this, the HTTP/1.1 standard has required handling this since 1999, the broken HTTP server for which we disabled this (Google's) is now fixed and has been for some time, and libcurl has a 1-second fallback in case the HTTP server is still broken. In addition, it is not unreasonable to require compliance with a 25-year old standard to use new Git features. For all of these reasons, do so here. Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
committed by
Junio C Hamano
parent
5af5cc68aa
commit
ad9bb6dfe6
48
http.c
48
http.c
@ -561,18 +561,34 @@ static int curl_empty_auth_enabled(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct curl_slist *http_append_auth_header(const struct credential *c,
|
||||
struct curl_slist *headers)
|
||||
{
|
||||
if (c->authtype && c->credential) {
|
||||
struct strbuf auth = STRBUF_INIT;
|
||||
strbuf_addf(&auth, "Authorization: %s %s",
|
||||
c->authtype, c->credential);
|
||||
headers = curl_slist_append(headers, auth.buf);
|
||||
strbuf_release(&auth);
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
static void init_curl_http_auth(CURL *result)
|
||||
{
|
||||
if (!http_auth.username || !*http_auth.username) {
|
||||
if ((!http_auth.username || !*http_auth.username) &&
|
||||
(!http_auth.credential || !*http_auth.credential)) {
|
||||
if (curl_empty_auth_enabled())
|
||||
curl_easy_setopt(result, CURLOPT_USERPWD, ":");
|
||||
return;
|
||||
}
|
||||
|
||||
credential_fill(&http_auth, 0);
|
||||
credential_fill(&http_auth, 1);
|
||||
|
||||
curl_easy_setopt(result, CURLOPT_USERNAME, http_auth.username);
|
||||
curl_easy_setopt(result, CURLOPT_PASSWORD, http_auth.password);
|
||||
if (http_auth.password) {
|
||||
curl_easy_setopt(result, CURLOPT_USERNAME, http_auth.username);
|
||||
curl_easy_setopt(result, CURLOPT_PASSWORD, http_auth.password);
|
||||
}
|
||||
}
|
||||
|
||||
/* *var must be free-able */
|
||||
@ -586,17 +602,22 @@ static void var_override(const char **var, char *value)
|
||||
|
||||
static void set_proxyauth_name_password(CURL *result)
|
||||
{
|
||||
if (proxy_auth.password) {
|
||||
curl_easy_setopt(result, CURLOPT_PROXYUSERNAME,
|
||||
proxy_auth.username);
|
||||
curl_easy_setopt(result, CURLOPT_PROXYPASSWORD,
|
||||
proxy_auth.password);
|
||||
} else if (proxy_auth.authtype && proxy_auth.credential) {
|
||||
curl_easy_setopt(result, CURLOPT_PROXYHEADER,
|
||||
http_append_auth_header(&proxy_auth, NULL));
|
||||
}
|
||||
}
|
||||
|
||||
static void init_curl_proxy_auth(CURL *result)
|
||||
{
|
||||
if (proxy_auth.username) {
|
||||
if (!proxy_auth.password)
|
||||
credential_fill(&proxy_auth, 0);
|
||||
if (!proxy_auth.password && !proxy_auth.credential)
|
||||
credential_fill(&proxy_auth, 1);
|
||||
set_proxyauth_name_password(result);
|
||||
}
|
||||
|
||||
@ -1468,7 +1489,7 @@ struct active_request_slot *get_active_slot(void)
|
||||
|
||||
curl_easy_setopt(slot->curl, CURLOPT_IPRESOLVE, git_curl_ipresolve);
|
||||
curl_easy_setopt(slot->curl, CURLOPT_HTTPAUTH, http_auth_methods);
|
||||
if (http_auth.password || curl_empty_auth_enabled())
|
||||
if (http_auth.password || http_auth.credential || curl_empty_auth_enabled())
|
||||
init_curl_http_auth(slot->curl);
|
||||
|
||||
return slot;
|
||||
@ -1757,7 +1778,8 @@ static int handle_curl_result(struct slot_results *results)
|
||||
} else if (missing_target(results))
|
||||
return HTTP_MISSING_TARGET;
|
||||
else if (results->http_code == 401) {
|
||||
if (http_auth.username && http_auth.password) {
|
||||
if ((http_auth.username && http_auth.password) ||\
|
||||
(http_auth.authtype && http_auth.credential)) {
|
||||
credential_reject(&http_auth);
|
||||
return HTTP_NOAUTH;
|
||||
} else {
|
||||
@ -2065,11 +2087,15 @@ static int http_request(const char *url,
|
||||
/* Add additional headers here */
|
||||
if (options && options->extra_headers) {
|
||||
const struct string_list_item *item;
|
||||
for_each_string_list_item(item, options->extra_headers) {
|
||||
headers = curl_slist_append(headers, item->string);
|
||||
if (options && options->extra_headers) {
|
||||
for_each_string_list_item(item, options->extra_headers) {
|
||||
headers = curl_slist_append(headers, item->string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
headers = http_append_auth_header(&http_auth, headers);
|
||||
|
||||
curl_easy_setopt(slot->curl, CURLOPT_URL, url);
|
||||
curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, headers);
|
||||
curl_easy_setopt(slot->curl, CURLOPT_ENCODING, "");
|
||||
@ -2190,7 +2216,7 @@ static int http_request_reauth(const char *url,
|
||||
BUG("Unknown http_request target");
|
||||
}
|
||||
|
||||
credential_fill(&http_auth, 0);
|
||||
credential_fill(&http_auth, 1);
|
||||
|
||||
return http_request(url, result, target, options);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user