summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2018-07-25 18:27:33 +0100
committerEdward Thomson <ethomson@edwardthomson.com>2018-07-25 18:27:33 +0100
commit37a4d007e8fcc9b7846ed90baddc7fd7263276c5 (patch)
tree19e9d0ab3fa6dcb316a65a8ffdaf820e337dac6a
parent45a78977f034c4f9a3558c6c140899c07f47c2f8 (diff)
downloadlibgit2-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.h6
-rw-r--r--src/transports/http.c55
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");