git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 2/2] credential: erase all matching credentials

From
M Hickford via GitGitGadget <gitgitgadget@gmail.com>
Date
Jun 14, 2023, 11:23 UTC
Message-ID
<fcdb579263f87dd089c50fc5799cf30b21f4d12c.1686741785.git.gitgitgadget@gmail.com>
In-Reply-To
<pull.1525.git.git.1686741785.gitgitgadget@gmail.com>
From: M Hickford <mirth.hickford@gmail.com>

Users expect that `echo "url=https://example.com" | git credential reject` or `echo "url=https://example.com\nusername=tim" | git credential reject` erase all matching credentials.

Fixes for credential-cache and credential-store.
Signed-off-by: M Hickford <mirth.hickford@gmail.com>
---
 Documentation/git-credential.txt   |  4 ++--
 Documentation/gitcredentials.txt   |  2 +-
 builtin/credential-cache--daemon.c | 15 ++++++++------
 builtin/credential-store.c         |  3 ++-
 t/lib-credential.sh                | 33 ++++++++++++++++++++++++++++++
 5 files changed, 47 insertions(+), 10 deletions(-)
diff --git a/Documentation/git-credential.txt b/Documentation/git-credential.txt
index 0e6d9e85ec7..04bfb918de6 100644
--- a/Documentation/git-credential.txt
+++ b/Documentation/git-credential.txt
@@ -38,8 +38,8 @@ to any configured credential helpers, which may store the credential
 for later use.
 
 If the action is `reject`, git-credential will send the description to
-any configured credential helpers, which may erase any stored
-credential matching the description.
+any configured credential helpers, which may erase stored credentials
+matching the description.
 
 If the action is `approve` or `reject`, no output should be emitted.
 
diff --git a/Documentation/gitcredentials.txt b/Documentation/gitcredentials.txt
index 100f045bb1a..65d652dc40e 100644
--- a/Documentation/gitcredentials.txt
+++ b/Documentation/gitcredentials.txt
@@ -260,7 +260,7 @@ appended to its command line, which is one of:
 
 `erase`::
 
-	Remove a matching credential, if any, from the helper's storage.
+	Remove matching credentials, if any, from the helper's storage.
 
 The details of the credential will be provided on the helper's stdin
 stream. The exact format is the same as the input/output format of the
diff --git a/builtin/credential-cache--daemon.c b/builtin/credential-cache--daemon.c
index 82f376d3351..5e3a766e42d 100644
--- a/builtin/credential-cache--daemon.c
+++ b/builtin/credential-cache--daemon.c
@@ -33,12 +33,12 @@ static void cache_credential(struct credential *c, int timeout)
 	e->expiration = time(NULL) + timeout;
 }
 
-static struct credential_cache_entry *lookup_credential(const struct credential *c, int match_password)
+static struct credential_cache_entry *lookup_credential(const struct credential *c)
 {
 	int i;
 	for (i = 0; i < entries_nr; i++) {
 		struct credential *e = &entries[i].item;
-		if (credential_match(c, e, match_password))
+		if (credential_match(c, e, 0))
 			return &entries[i];
 	}
 	return NULL;
@@ -48,9 +48,12 @@ static void remove_credential(const struct credential *c)
 {
 	struct credential_cache_entry *e;
 
-	e = lookup_credential(c, c->password != NULL);
-	if (e)
-		e->expiration = 0;
+	int i;
+	for (i = 0; i < entries_nr; i++) {
+		e = &entries[i];
+		if (credential_match(c, &e->item, c->password != NULL))
+			e->expiration = 0;
+	}
 }
 
 static timestamp_t check_expirations(void)
@@ -127,7 +130,7 @@ static void serve_one_client(FILE *in, FILE *out)
 	if (read_request(in, &c, &action, &timeout) < 0)
 		/* ignore error */ ;
 	else if (!strcmp(action.buf, "get")) {
-		struct credential_cache_entry *e = lookup_credential(&c, 0);
+		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);
diff --git a/builtin/credential-store.c b/builtin/credential-store.c
index e0ae028b1c3..85b147e460f 100644
--- a/builtin/credential-store.c
+++ b/builtin/credential-store.c
@@ -36,7 +36,8 @@ static int parse_credential_file(const char *fn,
 			found_credential = 1;
 			if (match_cb) {
 				match_cb(&entry);
-				break;
+				if (strcmp(op, "erase"))
+					break;
 			}
 		}
 		else if (other_cb)
diff --git a/t/lib-credential.sh b/t/lib-credential.sh
index f7e4e29c5e1..3f4100b6ce2 100644
--- a/t/lib-credential.sh
+++ b/t/lib-credential.sh
@@ -45,6 +45,8 @@ helper_test_clean() {
 	reject $1 https example.com user2
 	reject $1 https example.com user4
 	reject $1 https example.com user5
+	reject $1 https example.com user6
+	reject $1 https example.com user7
 	reject $1 http path.tld user
 	reject $1 https timeout.tld user
 	reject $1 https sso.tld
@@ -298,6 +300,37 @@ helper_test() {
 		EOF
 	'
 
+	test_expect_success "helper ($HELPER) erases all matching credentials" '
+		check approve $HELPER <<-\EOF &&
+		protocol=https
+		host=example.com
+		username=user6
+		password=pass1
+		EOF
+		check approve $HELPER <<-\EOF &&
+		protocol=https
+		host=example.com
+		username=user7
+		password=pass1
+		EOF
+		check reject $HELPER <<-\EOF &&
+		protocol=https
+		host=example.com
+		EOF
+		check fill $HELPER <<-\EOF
+		protocol=https
+		host=example.com
+		--
+		protocol=https
+		host=example.com
+		username=askpass-username
+		password=askpass-password
+		--
+		askpass: Username for '\''https://example.com'\'':
+		askpass: Password for '\''https://askpass-username@example.com'\'':
+		EOF
+	'
+
 	: ${GIT_TEST_LONG_CRED_BUFFER:=1024}
 	# 23 bytes accounts for "wwwauth[]=basic realm=" plus NUL
 	LONG_VALUE_LEN=$((GIT_TEST_LONG_CRED_BUFFER - 23))
-- 
gitgitgadget
Previous: M Hickford via GitGitGadgetNext: Junio C Hamano
Message 3 of 26 in “credential: improvements to erase in helpers”
  1. 0/2 credential: improvements to erase in helpersM Hickford via GitGitGadget, Jun 14, 2023
  2. 1/2 credential: avoid erasing distinct passwordM Hickford via GitGitGadget, Jun 14, 2023
  3. 2/2 credential: erase all matching credentialsM Hickford via GitGitGadget, Jun 14, 2023
  4. Junio C HamanoJun 14, 2023
  5. M HickfordJun 14, 2023
  6. 0/2 credential: improvements to erase in helpersM Hickford via GitGitGadget, Jun 14, 2023
  7. 1/2 credential: avoid erasing distinct passwordM Hickford via GitGitGadget, Jun 14, 2023
  8. Jeff KingJun 14, 2023
  9. M HickfordJun 15, 2023
  10. 2/2 credential: erase all matching credentialsM Hickford via GitGitGadget, Jun 14, 2023
  11. Jeff KingJun 14, 2023
  12. M HickfordJun 15, 2023
  13. Junio C HamanoJun 14, 2023
  14. Jeff KingJun 14, 2023
  15. 0/2 credential: improvements to erase in helpersM Hickford via GitGitGadget, Jun 15, 2023
  16. 1/2 credential: avoid erasing distinct passwordM Hickford via GitGitGadget, Jun 15, 2023
  17. Jeff KingJun 15, 2023
  18. 2/2 credential: erase all matching credentialsM Hickford via GitGitGadget, Jun 15, 2023
  19. Jeff KingJun 15, 2023
  20. 0/2 credential: improvements to erase in helpersM Hickford via GitGitGadget, Jun 15, 2023
  21. 1/2 credential: avoid erasing distinct passwordM Hickford via GitGitGadget, Jun 15, 2023
  22. 2/2 credential: erase all matching credentialsM Hickford via GitGitGadget, Jun 15, 2023
  23. Junio C HamanoJun 15, 2023
  24. Jeff KingJun 15, 2023
  25. Junio C HamanoJun 15, 2023
  26. Junio C HamanoJun 16, 2023

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.