Merge branch 'bc/credential-scheme-enhancement'
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. * bc/credential-scheme-enhancement: credential: add method for querying capabilities credential-cache: implement authtype capability t: add credential tests for authtype credential: add support for multistage credential rounds t5563: refactor for multi-stage authentication docs: set a limit on credential line length credential: enable state capability credential: add an argument to keep state http: add support for authtype and credential docs: indicate new credential protocol fields credential: add a field called "ephemeral" credential: gate new fields on capability credential: add a field for pre-encoded credentials http: use new headers for each object request remote-curl: reset headers on new request credential: add an authtype field
This commit is contained in:
129
http.c
129
http.c
@ -128,7 +128,6 @@ static unsigned long empty_auth_useless =
|
||||
| CURLAUTH_DIGEST;
|
||||
|
||||
static struct curl_slist *pragma_header;
|
||||
static struct curl_slist *no_pragma_header;
|
||||
static struct string_list extra_http_headers = STRING_LIST_INIT_DUP;
|
||||
|
||||
static struct curl_slist *host_resolutions;
|
||||
@ -299,6 +298,11 @@ size_t fwrite_null(char *ptr UNUSED, size_t eltsize UNUSED, size_t nmemb,
|
||||
return nmemb;
|
||||
}
|
||||
|
||||
static struct curl_slist *object_request_headers(void)
|
||||
{
|
||||
return curl_slist_append(http_copy_default_headers(), "Pragma:");
|
||||
}
|
||||
|
||||
static void closedown_active_slot(struct active_request_slot *slot)
|
||||
{
|
||||
active_requests--;
|
||||
@ -557,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);
|
||||
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 */
|
||||
@ -582,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);
|
||||
if (!proxy_auth.password && !proxy_auth.credential)
|
||||
credential_fill(&proxy_auth, 1);
|
||||
set_proxyauth_name_password(result);
|
||||
}
|
||||
|
||||
@ -626,7 +651,7 @@ static int has_cert_password(void)
|
||||
cert_auth.host = xstrdup("");
|
||||
cert_auth.username = xstrdup("");
|
||||
cert_auth.path = xstrdup(ssl_cert);
|
||||
credential_fill(&cert_auth);
|
||||
credential_fill(&cert_auth, 0);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -641,7 +666,7 @@ static int has_proxy_cert_password(void)
|
||||
proxy_cert_auth.host = xstrdup("");
|
||||
proxy_cert_auth.username = xstrdup("");
|
||||
proxy_cert_auth.path = xstrdup(http_proxy_ssl_cert);
|
||||
credential_fill(&proxy_cert_auth);
|
||||
credential_fill(&proxy_cert_auth, 0);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -1275,8 +1300,6 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
|
||||
|
||||
pragma_header = curl_slist_append(http_copy_default_headers(),
|
||||
"Pragma: no-cache");
|
||||
no_pragma_header = curl_slist_append(http_copy_default_headers(),
|
||||
"Pragma:");
|
||||
|
||||
{
|
||||
char *http_max_requests = getenv("GIT_HTTP_MAX_REQUESTS");
|
||||
@ -1360,9 +1383,6 @@ void http_cleanup(void)
|
||||
curl_slist_free_all(pragma_header);
|
||||
pragma_header = NULL;
|
||||
|
||||
curl_slist_free_all(no_pragma_header);
|
||||
no_pragma_header = NULL;
|
||||
|
||||
curl_slist_free_all(host_resolutions);
|
||||
host_resolutions = NULL;
|
||||
|
||||
@ -1470,7 +1490,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;
|
||||
@ -1759,7 +1779,12 @@ 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)) {
|
||||
if (http_auth.multistage) {
|
||||
credential_clear_secrets(&http_auth);
|
||||
return HTTP_REAUTH;
|
||||
}
|
||||
credential_reject(&http_auth);
|
||||
return HTTP_NOAUTH;
|
||||
} else {
|
||||
@ -2067,11 +2092,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, "");
|
||||
@ -2153,6 +2182,7 @@ static int http_request_reauth(const char *url,
|
||||
void *result, int target,
|
||||
struct http_get_options *options)
|
||||
{
|
||||
int i = 3;
|
||||
int ret = http_request(url, result, target, options);
|
||||
|
||||
if (ret != HTTP_OK && ret != HTTP_REAUTH)
|
||||
@ -2166,35 +2196,35 @@ static int http_request_reauth(const char *url,
|
||||
}
|
||||
}
|
||||
|
||||
if (ret != HTTP_REAUTH)
|
||||
return ret;
|
||||
while (ret == HTTP_REAUTH && --i) {
|
||||
/*
|
||||
* The previous request may have put cruft into our output stream; we
|
||||
* should clear it out before making our next request.
|
||||
*/
|
||||
switch (target) {
|
||||
case HTTP_REQUEST_STRBUF:
|
||||
strbuf_reset(result);
|
||||
break;
|
||||
case HTTP_REQUEST_FILE:
|
||||
if (fflush(result)) {
|
||||
error_errno("unable to flush a file");
|
||||
return HTTP_START_FAILED;
|
||||
}
|
||||
rewind(result);
|
||||
if (ftruncate(fileno(result), 0) < 0) {
|
||||
error_errno("unable to truncate a file");
|
||||
return HTTP_START_FAILED;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BUG("Unknown http_request target");
|
||||
}
|
||||
|
||||
/*
|
||||
* The previous request may have put cruft into our output stream; we
|
||||
* should clear it out before making our next request.
|
||||
*/
|
||||
switch (target) {
|
||||
case HTTP_REQUEST_STRBUF:
|
||||
strbuf_reset(result);
|
||||
break;
|
||||
case HTTP_REQUEST_FILE:
|
||||
if (fflush(result)) {
|
||||
error_errno("unable to flush a file");
|
||||
return HTTP_START_FAILED;
|
||||
}
|
||||
rewind(result);
|
||||
if (ftruncate(fileno(result), 0) < 0) {
|
||||
error_errno("unable to truncate a file");
|
||||
return HTTP_START_FAILED;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BUG("Unknown http_request target");
|
||||
credential_fill(&http_auth, 1);
|
||||
|
||||
ret = http_request(url, result, target, options);
|
||||
}
|
||||
|
||||
credential_fill(&http_auth);
|
||||
|
||||
return http_request(url, result, target, options);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int http_get_strbuf(const char *url,
|
||||
@ -2371,6 +2401,7 @@ void release_http_pack_request(struct http_pack_request *preq)
|
||||
}
|
||||
preq->slot = NULL;
|
||||
strbuf_release(&preq->tmpfile);
|
||||
curl_slist_free_all(preq->headers);
|
||||
free(preq->url);
|
||||
free(preq);
|
||||
}
|
||||
@ -2455,11 +2486,11 @@ struct http_pack_request *new_direct_http_pack_request(
|
||||
}
|
||||
|
||||
preq->slot = get_active_slot();
|
||||
preq->headers = object_request_headers();
|
||||
curl_easy_setopt(preq->slot->curl, CURLOPT_WRITEDATA, preq->packfile);
|
||||
curl_easy_setopt(preq->slot->curl, CURLOPT_WRITEFUNCTION, fwrite);
|
||||
curl_easy_setopt(preq->slot->curl, CURLOPT_URL, preq->url);
|
||||
curl_easy_setopt(preq->slot->curl, CURLOPT_HTTPHEADER,
|
||||
no_pragma_header);
|
||||
curl_easy_setopt(preq->slot->curl, CURLOPT_HTTPHEADER, preq->headers);
|
||||
|
||||
/*
|
||||
* If there is data present from a previous transfer attempt,
|
||||
@ -2625,13 +2656,14 @@ struct http_object_request *new_http_object_request(const char *base_url,
|
||||
}
|
||||
|
||||
freq->slot = get_active_slot();
|
||||
freq->headers = object_request_headers();
|
||||
|
||||
curl_easy_setopt(freq->slot->curl, CURLOPT_WRITEDATA, freq);
|
||||
curl_easy_setopt(freq->slot->curl, CURLOPT_FAILONERROR, 0);
|
||||
curl_easy_setopt(freq->slot->curl, CURLOPT_WRITEFUNCTION, fwrite_sha1_file);
|
||||
curl_easy_setopt(freq->slot->curl, CURLOPT_ERRORBUFFER, freq->errorstr);
|
||||
curl_easy_setopt(freq->slot->curl, CURLOPT_URL, freq->url);
|
||||
curl_easy_setopt(freq->slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);
|
||||
curl_easy_setopt(freq->slot->curl, CURLOPT_HTTPHEADER, freq->headers);
|
||||
|
||||
/*
|
||||
* If we have successfully processed data from a previous fetch
|
||||
@ -2719,5 +2751,6 @@ void release_http_object_request(struct http_object_request *freq)
|
||||
release_active_slot(freq->slot);
|
||||
freq->slot = NULL;
|
||||
}
|
||||
curl_slist_free_all(freq->headers);
|
||||
strbuf_release(&freq->tmpfile);
|
||||
}
|
||||
|
Reference in New Issue
Block a user