]> git.ipfire.org Git - thirdparty/git.git/commitdiff
credential-cache: implement authtype capability
authorbrian m. carlson <sandals@crustytoothpaste.net>
Wed, 17 Apr 2024 00:02:39 +0000 (00:02 +0000)
committerJunio C Hamano <gitster@pobox.com>
Wed, 17 Apr 2024 05:39:08 +0000 (22:39 -0700)
Now that we have full support in Git for the authtype capability, let's
add support to the cache credential helper.

When parsing data, we always set the initial capabilities because we're
the helper, and we need both the initial and helper capabilities to be
set in order to have the helper capabilities take effect.

When emitting data, always emit the supported capability and make sure
we emit items only if we have them and they're supported by the caller.
Since we may no longer have a username or password, be sure to emit
those conditionally as well so we don't segfault on a NULL pointer.
Similarly, when comparing credentials, consider both the password and
credential fields when we're matching passwords.

Adjust the partial credential detection code so that we can store
credentials missing a username or password as long as they have an
authtype and credential.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/credential-cache--daemon.c
credential.c
credential.h
t/t0301-credential-cache.sh

index ccbcf99ac1966655bb8216d9ca56721f30e8f9fa..6ffedcd17c2db9b8583d295d408fd5ab06af1404 100644 (file)
@@ -115,6 +115,8 @@ static int read_request(FILE *fh, struct credential *c,
                return error("client sent bogus timeout line: %s", item.buf);
        *timeout = atoi(p);
 
+       credential_set_all_capabilities(c, CREDENTIAL_OP_INITIAL);
+
        if (credential_read(c, fh, CREDENTIAL_OP_HELPER) < 0)
                return -1;
        return 0;
@@ -131,8 +133,18 @@ static void serve_one_client(FILE *in, FILE *out)
        else if (!strcmp(action.buf, "get")) {
                struct credential_cache_entry *e = lookup_credential(&c);
                if (e) {
-                       fprintf(out, "username=%s\n", e->item.username);
-                       fprintf(out, "password=%s\n", e->item.password);
+                       e->item.capa_authtype.request_initial = 1;
+                       e->item.capa_authtype.request_helper = 1;
+
+                       fprintf(out, "capability[]=authtype\n");
+                       if (e->item.username)
+                               fprintf(out, "username=%s\n", e->item.username);
+                       if (e->item.password)
+                               fprintf(out, "password=%s\n", e->item.password);
+                       if (credential_has_capability(&c.capa_authtype, CREDENTIAL_OP_HELPER) && e->item.authtype)
+                               fprintf(out, "authtype=%s\n", e->item.authtype);
+                       if (credential_has_capability(&c.capa_authtype, CREDENTIAL_OP_HELPER) && e->item.credential)
+                               fprintf(out, "credential=%s\n", e->item.credential);
                        if (e->item.password_expiry_utc != TIME_MAX)
                                fprintf(out, "password_expiry_utc=%"PRItime"\n",
                                        e->item.password_expiry_utc);
@@ -157,8 +169,10 @@ static void serve_one_client(FILE *in, FILE *out)
        else if (!strcmp(action.buf, "store")) {
                if (timeout < 0)
                        warning("cache client didn't specify a timeout");
-               else if (!c.username || !c.password)
+               else if ((!c.username || !c.password) && (!c.authtype && !c.credential))
                        warning("cache client gave us a partial credential");
+               else if (c.ephemeral)
+                       warning("not storing ephemeral credential");
                else {
                        remove_credential(&c, 0);
                        cache_credential(&c, timeout);
index 98b040cf11a0c569901265c197d07dc326d8b9d4..ffaf31499e3af8e06578fd2417b1314dbfc7494f 100644 (file)
@@ -80,7 +80,8 @@ int credential_match(const struct credential *want,
               CHECK(host) &&
               CHECK(path) &&
               CHECK(username) &&
-              (!match_password || CHECK(password));
+              (!match_password || CHECK(password)) &&
+              (!match_password || CHECK(credential));
 #undef CHECK
 }
 
@@ -248,8 +249,8 @@ static void credential_getpass(struct credential *c)
                                                 PROMPT_ASKPASS);
 }
 
-static int credential_has_capability(const struct credential_capability *capa,
-                                    enum credential_op_type op_type)
+int credential_has_capability(const struct credential_capability *capa,
+                             enum credential_op_type op_type)
 {
        /*
         * We're checking here if each previous step indicated that we had the
index 19163fc6a07db08b533e4565c8fcf68390adc036..f8df10937c8457c3911c5c8a7350d7de0a0bb68c 100644 (file)
@@ -263,6 +263,12 @@ void credential_clear_secrets(struct credential *c);
  */
 void credential_next_state(struct credential *c);
 
+/**
+ * Return true if the capability is enabled for an operation of op_type.
+ */
+int credential_has_capability(const struct credential_capability *capa,
+                             enum credential_op_type op_type);
+
 int credential_read(struct credential *, FILE *,
                    enum credential_op_type);
 void credential_write(const struct credential *, FILE *,
index 8300faadea9a76f19e3d2c82f5ff600f38bfe18f..3897353d5569013daeb117519384b03c99b56d75 100755 (executable)
@@ -31,6 +31,7 @@ test_atexit 'git credential-cache exit'
 helper_test cache
 helper_test_password_expiry_utc cache
 helper_test_oauth_refresh_token cache
+helper_test_authtype cache
 
 test_expect_success 'socket defaults to ~/.cache/git/credential/socket' '
        test_when_finished "