diff options
author | Edward Thomson <ethomson@edwardthomson.com> | 2018-07-25 18:27:33 +0100 |
---|---|---|
committer | Edward Thomson <ethomson@edwardthomson.com> | 2018-07-25 18:27:33 +0100 |
commit | 37a4d007e8fcc9b7846ed90baddc7fd7263276c5 (patch) | |
tree | 19e9d0ab3fa6dcb316a65a8ffdaf820e337dac6a | |
parent | 45a78977f034c4f9a3558c6c140899c07f47c2f8 (diff) | |
download | libgit2-37a4d007e8fcc9b7846ed90baddc7fd7263276c5.tar.gz |
http: only provide "preauth" for certain mechs
When a user specifies a username and password before being prompted
(through the callback), we similarly want to provide those to the remote
server immediately, without it returning a 401. This saves a
round-trip.
However, only certain mechanisms support this behavior - for example,
Basic. As we add other mechanisms that support username/password
credentials, we want to ensure that we do not try to preauthenticate
with them, since they require negotiation. If we are given a username
and password, force the use of Basic.
-rw-r--r-- | src/transports/auth.h | 6 | ||||
-rw-r--r-- | src/transports/http.c | 55 |
2 files changed, 47 insertions, 14 deletions
diff --git a/src/transports/auth.h b/src/transports/auth.h index 3b8b29eb9..38c1b0f88 100644 --- a/src/transports/auth.h +++ b/src/transports/auth.h @@ -47,6 +47,12 @@ typedef struct { /** Credential types this scheme supports */ git_credtype_t credtypes; + /** + * If this scheme supports "preauthentication" (sending credentials + * on the first request, before a challenge from the server). + */ + unsigned int preauth; + /** Function to initialize an authentication context */ int (*init_context)( git_http_auth_context **out, diff --git a/src/transports/http.c b/src/transports/http.c index ea3e57a49..c1a502a1d 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -24,8 +24,8 @@ #include "streams/curl.h" git_http_auth_scheme auth_schemes[] = { - { GIT_AUTHTYPE_NEGOTIATE, "Negotiate", GIT_CREDTYPE_DEFAULT, git_http_auth_negotiate }, - { GIT_AUTHTYPE_BASIC, "Basic", GIT_CREDTYPE_USERPASS_PLAINTEXT, git_http_auth_basic }, + { GIT_AUTHTYPE_NEGOTIATE, "Negotiate", GIT_CREDTYPE_DEFAULT, 0, git_http_auth_negotiate }, + { GIT_AUTHTYPE_BASIC, "Basic", GIT_CREDTYPE_USERPASS_PLAINTEXT, 1, git_http_auth_basic }, }; static const char *upload_pack_service = "upload-pack"; @@ -104,6 +104,12 @@ typedef struct { size_t *bytes_read; } parser_context; +static bool preauth_match(git_http_auth_scheme *scheme, void *data) +{ + unsigned int credtype = *(unsigned int *)data; + return scheme->preauth && !!(scheme->credtypes & credtype); +} + static bool credtype_match(git_http_auth_scheme *scheme, void *data) { unsigned int credtype = *(unsigned int *)data; @@ -166,24 +172,45 @@ static int auth_context_match( return 0; } -static int apply_credentials(git_buf *buf, http_subtransport *t) +static int apply_preauthentication(git_buf *buf, http_subtransport *t) { - git_cred *cred = t->cred; git_http_auth_context *context; + unsigned int credtype; - /* Apply the credentials given to us in the URL */ - if (!cred && t->connection_data.user && t->connection_data.pass) { - if (!t->url_cred && - git_cred_userpass_plaintext_new(&t->url_cred, - t->connection_data.user, t->connection_data.pass) < 0) - return -1; + if (!t->connection_data.user || !t->connection_data.pass) + return 0; - cred = t->url_cred; - } + if (!t->url_cred && + git_cred_userpass_plaintext_new(&t->url_cred, + t->connection_data.user, t->connection_data.pass) < 0) + return -1; - if (!cred) + if (!t->url_cred) + return 0; + + credtype = t->url_cred->credtype; + + if (auth_context_match(&context, t, preauth_match, &credtype) < 0) + return -1; + else if (!context) return 0; + return context->next_token(buf, context, t->url_cred); +} + +static int apply_authentication(git_buf *buf, http_subtransport *t) +{ + git_http_auth_context *context; + git_cred *cred = t->cred; + + /* + * We've not asked the caller for credentials but they've pre- + * provided us with some (in the URL for example) so let's try them. + */ + + if (!cred) + return apply_preauthentication(buf, t); + /* Get or create a context for the best scheme for this cred type */ if (auth_context_match(&context, t, credtype_match, &cred->credtype) < 0) return -1; @@ -224,7 +251,7 @@ static int gen_request( } /* Apply credentials to the request */ - if (apply_credentials(buf, t) < 0) + if (apply_authentication(buf, t) < 0) return -1; git_buf_puts(buf, "\r\n"); |