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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
diff --git a/src/transports/http.c b/src/transports/http.c
index 7df139b..6f46094 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -346,13 +346,63 @@ static int on_header_value(http_parser *parser, const char *str, size_t len)
return 0;
}
+static int on_auth_required(http_parser *parser, int allowed_types)
+{
+ parser_context *ctx = (parser_context *) parser->data;
+ http_subtransport *t = ctx->t;
+ int ret;
+
+ if (!allowed_types) {
+ giterr_set(GITERR_NET, "remote did not prompt for authentication mechanisms");
+ t->parse_error = PARSE_ERROR_GENERIC;
+ return t->parse_error;
+ }
+
+ if (t->owner->cred_acquire_cb) {
+ if (t->cred) {
+ t->cred->free(t->cred);
+ t->cred = NULL;
+ }
+
+ ret = t->owner->cred_acquire_cb(&t->cred,
+ t->owner->url,
+ t->gitserver_data.user,
+ allowed_types,
+ t->owner->cred_acquire_payload);
+
+ if (ret == GIT_PASSTHROUGH) {
+ /* treat GIT_PASSTHROUGH as if callback isn't set */
+ } else if (ret < 0) {
+ t->error = ret;
+ t->parse_error = PARSE_ERROR_EXT;
+ return t->parse_error;
+ } else {
+ assert(t->cred);
+
+ if (!(t->cred->credtype & allowed_types)) {
+ giterr_set(GITERR_NET, "credential provider returned an invalid cred type");
+ t->parse_error = PARSE_ERROR_GENERIC;
+ return t->parse_error;
+ }
+
+ /* Successfully acquired a credential. */
+ t->parse_error = PARSE_ERROR_REPLAY;
+ return 0;
+ }
+ }
+
+ giterr_set(GITERR_NET, "authentication required but no callback set");
+ t->parse_error = PARSE_ERROR_GENERIC;
+ return t->parse_error;
+}
+
static int on_headers_complete(http_parser *parser)
{
parser_context *ctx = (parser_context *) parser->data;
http_subtransport *t = ctx->t;
http_stream *s = ctx->s;
git_buf buf = GIT_BUF_INIT;
- int error = 0, no_callback = 0, allowed_auth_types = 0;
+ int allowed_www_auth_types = 0;
/* Both parse_header_name and parse_header_value are populated
* and ready for consumption. */
@@ -360,57 +410,18 @@ static int on_headers_complete(http_parser *parser)
if (on_header_ready(t) < 0)
return t->parse_error = PARSE_ERROR_GENERIC;
- /* Capture authentication headers which may be a 401 (authentication
- * is not complete) or a 200 (simply informing us that auth *is*
- * complete.)
+ /*
+ * Capture authentication headers for the proxy or final endpoint,
+ * these may be 407/401 (authentication is not complete) or a 200
+ * (informing us that auth has completed).
*/
if (parse_authenticate_response(&t->www_authenticate, t,
- &allowed_auth_types) < 0)
+ &allowed_www_auth_types) < 0)
return t->parse_error = PARSE_ERROR_GENERIC;
/* Check for an authentication failure. */
- if (parser->status_code == 401 && get_verb == s->verb) {
- if (!t->owner->cred_acquire_cb) {
- no_callback = 1;
- } else {
- if (allowed_auth_types) {
- if (t->cred) {
- t->cred->free(t->cred);
- t->cred = NULL;
- }
-
- error = t->owner->cred_acquire_cb(&t->cred,
- t->owner->url,
- t->gitserver_data.user,
- allowed_auth_types,
- t->owner->cred_acquire_payload);
-
- /* treat GIT_PASSTHROUGH as if callback isn't set */
- if (error == GIT_PASSTHROUGH) {
- no_callback = 1;
- } else if (error < 0) {
- t->error = error;
- return t->parse_error = PARSE_ERROR_EXT;
- } else {
- assert(t->cred);
-
- if (!(t->cred->credtype & allowed_auth_types)) {
- giterr_set(GITERR_NET, "credentials callback returned an invalid cred type");
- return t->parse_error = PARSE_ERROR_GENERIC;
- }
-
- /* Successfully acquired a credential. */
- t->parse_error = PARSE_ERROR_REPLAY;
- return 0;
- }
- }
- }
-
- if (no_callback) {
- giterr_set(GITERR_NET, "authentication required but no callback set");
- return t->parse_error = PARSE_ERROR_GENERIC;
- }
- }
+ if (parser->status_code == 401 && get_verb == s->verb)
+ return on_auth_required(parser, allowed_www_auth_types);
/* Check for a redirect.
* Right now we only permit a redirect to the same hostname. */