Skip to content

Commit 32cb56c

Browse files
committed
http transport: refactor credential handling
Factor credential handling into its own function. Additionally, add safety checks to ensure that we are in a valid state - that we have received a valid challenge from the server and that we have configuration to respond to that challenge.
1 parent e6e399a commit 32cb56c

File tree

1 file changed

+58
-47
lines changed

1 file changed

+58
-47
lines changed

src/transports/http.c

Lines changed: 58 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -346,71 +346,82 @@ static int on_header_value(http_parser *parser, const char *str, size_t len)
346346
return 0;
347347
}
348348

349+
static int on_auth_required(http_parser *parser, int allowed_types)
350+
{
351+
parser_context *ctx = (parser_context *) parser->data;
352+
http_subtransport *t = ctx->t;
353+
int ret;
354+
355+
if (!allowed_types) {
356+
giterr_set(GITERR_NET, "remote did not prompt for authentication mechanisms");
357+
t->parse_error = PARSE_ERROR_GENERIC;
358+
return t->parse_error;
359+
}
360+
361+
if (t->owner->cred_acquire_cb) {
362+
if (t->cred) {
363+
t->cred->free(t->cred);
364+
t->cred = NULL;
365+
}
366+
367+
ret = t->owner->cred_acquire_cb(&t->cred,
368+
t->owner->url,
369+
t->gitserver_data.user,
370+
allowed_types,
371+
t->owner->cred_acquire_payload);
372+
373+
if (ret == GIT_PASSTHROUGH) {
374+
/* treat GIT_PASSTHROUGH as if callback isn't set */
375+
} else if (ret < 0) {
376+
t->error = ret;
377+
t->parse_error = PARSE_ERROR_EXT;
378+
return t->parse_error;
379+
} else {
380+
assert(t->cred);
381+
382+
if (!(t->cred->credtype & allowed_types)) {
383+
giterr_set(GITERR_NET, "credential provider returned an invalid cred type");
384+
t->parse_error = PARSE_ERROR_GENERIC;
385+
return t->parse_error;
386+
}
387+
388+
/* Successfully acquired a credential. */
389+
t->parse_error = PARSE_ERROR_REPLAY;
390+
return 0;
391+
}
392+
}
393+
394+
giterr_set(GITERR_NET, "authentication required but no callback set");
395+
t->parse_error = PARSE_ERROR_GENERIC;
396+
return t->parse_error;
397+
}
398+
349399
static int on_headers_complete(http_parser *parser)
350400
{
351401
parser_context *ctx = (parser_context *) parser->data;
352402
http_subtransport *t = ctx->t;
353403
http_stream *s = ctx->s;
354404
git_buf buf = GIT_BUF_INIT;
355-
int error = 0, no_callback = 0, allowed_auth_types = 0;
405+
int allowed_www_auth_types = 0;
356406

357407
/* Both parse_header_name and parse_header_value are populated
358408
* and ready for consumption. */
359409
if (VALUE == t->last_cb)
360410
if (on_header_ready(t) < 0)
361411
return t->parse_error = PARSE_ERROR_GENERIC;
362412

363-
/* Capture authentication headers which may be a 401 (authentication
364-
* is not complete) or a 200 (simply informing us that auth *is*
365-
* complete.)
413+
/*
414+
* Capture authentication headers for the proxy or final endpoint,
415+
* these may be 407/401 (authentication is not complete) or a 200
416+
* (informing us that auth has completed).
366417
*/
367418
if (parse_authenticate_response(&t->www_authenticate, t,
368-
&allowed_auth_types) < 0)
419+
&allowed_www_auth_types) < 0)
369420
return t->parse_error = PARSE_ERROR_GENERIC;
370421

371422
/* Check for an authentication failure. */
372-
if (parser->status_code == 401 && get_verb == s->verb) {
373-
if (!t->owner->cred_acquire_cb) {
374-
no_callback = 1;
375-
} else {
376-
if (allowed_auth_types) {
377-
if (t->cred) {
378-
t->cred->free(t->cred);
379-
t->cred = NULL;
380-
}
381-
382-
error = t->owner->cred_acquire_cb(&t->cred,
383-
t->owner->url,
384-
t->gitserver_data.user,
385-
allowed_auth_types,
386-
t->owner->cred_acquire_payload);
387-
388-
/* treat GIT_PASSTHROUGH as if callback isn't set */
389-
if (error == GIT_PASSTHROUGH) {
390-
no_callback = 1;
391-
} else if (error < 0) {
392-
t->error = error;
393-
return t->parse_error = PARSE_ERROR_EXT;
394-
} else {
395-
assert(t->cred);
396-
397-
if (!(t->cred->credtype & allowed_auth_types)) {
398-
giterr_set(GITERR_NET, "credentials callback returned an invalid cred type");
399-
return t->parse_error = PARSE_ERROR_GENERIC;
400-
}
401-
402-
/* Successfully acquired a credential. */
403-
t->parse_error = PARSE_ERROR_REPLAY;
404-
return 0;
405-
}
406-
}
407-
}
408-
409-
if (no_callback) {
410-
giterr_set(GITERR_NET, "authentication required but no callback set");
411-
return t->parse_error = PARSE_ERROR_GENERIC;
412-
}
413-
}
423+
if (parser->status_code == 401 && get_verb == s->verb)
424+
return on_auth_required(parser, allowed_www_auth_types);
414425

415426
/* Check for a redirect.
416427
* Right now we only permit a redirect to the same hostname. */

0 commit comments

Comments
 (0)