http transport: prompt for proxy credentials Teach the HTTP transport how to prompt for proxy credentials.
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 135 136 137 138 139 140
diff --git a/src/transports/http.c b/src/transports/http.c
index 57aa9f7..29924a0 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -37,6 +37,9 @@ static const char *receive_pack_service_url = "/git-receive-pack";
static const char *get_verb = "GET";
static const char *post_verb = "POST";
+#define SERVER_TYPE_REMOTE "remote"
+#define SERVER_TYPE_PROXY "proxy"
+
#define OWNING_SUBTRANSPORT(s) ((http_subtransport *)(s)->parent.subtransport)
#define PARSE_ERROR_GENERIC -1
@@ -97,6 +100,7 @@ typedef struct {
/* Authentication */
git_cred *cred;
git_cred *url_cred;
+ git_cred *proxy_cred;
git_vector auth_contexts;
} http_subtransport;
@@ -353,10 +357,19 @@ static int on_header_value(http_parser *parser, const char *str, size_t len)
return 0;
}
+GIT_INLINE(void) free_cred(git_cred **cred)
+{
+ if (*cred) {
+ git_cred_free(*cred);
+ (*cred) = NULL;
+ }
+}
+
static int on_auth_required(
git_cred **creds,
http_parser *parser,
const char *url,
+ const char *type,
git_cred_acquire_cb callback,
void *callback_payload,
const char *username,
@@ -367,17 +380,13 @@ static int on_auth_required(
int ret;
if (!allowed_types) {
- giterr_set(GITERR_NET, "remote did not prompt for authentication mechanisms");
+ giterr_set(GITERR_NET, "%s requested authentication but did not negotiate mechanisms", type);
t->parse_error = PARSE_ERROR_GENERIC;
return t->parse_error;
}
if (callback) {
- if (*creds) {
- (*creds)->free(*creds);
- *creds = NULL;
- }
-
+ free_cred(creds);
ret = callback(creds, url, username, allowed_types, callback_payload);
if (ret == GIT_PASSTHROUGH) {
@@ -390,7 +399,7 @@ static int on_auth_required(
assert(*creds);
if (!((*creds)->credtype & allowed_types)) {
- giterr_set(GITERR_NET, "credential provider returned an invalid cred type");
+ giterr_set(GITERR_NET, "%s credential provider returned an invalid cred type", type);
t->parse_error = PARSE_ERROR_GENERIC;
return t->parse_error;
}
@@ -401,7 +410,8 @@ static int on_auth_required(
}
}
- giterr_set(GITERR_NET, "authentication required but no callback set");
+ giterr_set(GITERR_NET, "%s authentication required but no callback set",
+ type);
t->parse_error = PARSE_ERROR_GENERIC;
return t->parse_error;
}
@@ -412,7 +422,7 @@ static int on_headers_complete(http_parser *parser)
http_subtransport *t = ctx->t;
http_stream *s = ctx->s;
git_buf buf = GIT_BUF_INIT;
- int allowed_www_auth_types = 0;
+ int allowed_proxy_auth_types = 0, allowed_www_auth_types = 0;
/* Both parse_header_name and parse_header_value are populated
* and ready for consumption. */
@@ -425,15 +435,29 @@ static int on_headers_complete(http_parser *parser)
* 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,
+ if (parse_authenticate_response(&t->proxy_authenticate, t,
+ &allowed_proxy_auth_types) < 0 ||
+ parse_authenticate_response(&t->www_authenticate, t,
&allowed_www_auth_types) < 0)
return t->parse_error = PARSE_ERROR_GENERIC;
+ /* Check for a proxy authentication failure. */
+ if (parser->status_code == 407 && get_verb == s->verb)
+ return on_auth_required(&t->proxy_cred,
+ parser,
+ t->proxy.url,
+ SERVER_TYPE_PROXY,
+ t->proxy.credentials,
+ t->proxy.payload,
+ t->proxy_data.user,
+ allowed_proxy_auth_types);
+
/* Check for an authentication failure. */
if (parser->status_code == 401 && get_verb == s->verb)
return on_auth_required(&t->cred,
parser,
t->owner->url,
+ SERVER_TYPE_REMOTE,
t->owner->cred_acquire_cb,
t->owner->cred_acquire_payload,
t->gitserver_data.user,
@@ -1131,15 +1155,9 @@ static int http_close(git_smart_subtransport *subtransport)
t->gitserver_stream = NULL;
}
- if (t->cred) {
- t->cred->free(t->cred);
- t->cred = NULL;
- }
-
- if (t->url_cred) {
- t->url_cred->free(t->url_cred);
- t->url_cred = NULL;
- }
+ free_cred(&t->cred);
+ free_cred(&t->url_cred);
+ free_cred(&t->proxy_cred);
git_vector_foreach(&t->auth_contexts, i, context) {
if (context->free)