Skip to content

Commit 6c26da8

Browse files
hickfordgitster
authored andcommitted
credential: erase all matching credentials
`credential reject` sends the erase action to each helper, but the exact behaviour of erase isn't specified in documentation or tests. Some helpers (such as credential-store and credential-libsecret) delete all matching credentials, others (such as credential-cache) delete at most one matching credential. Test that helpers erase all matching credentials. This behaviour is easiest to reason about. 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. Fix credential-cache. Signed-off-by: M Hickford <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent aeb21ce commit 6c26da8

File tree

4 files changed

+44
-8
lines changed

4 files changed

+44
-8
lines changed

Documentation/git-credential.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ for later use.
3939

4040
If the action is `reject`, git-credential will send the description to
4141
any configured credential helpers, which may erase any stored
42-
credential matching the description.
42+
credentials matching the description.
4343

4444
If the action is `approve` or `reject`, no output should be emitted.
4545

Documentation/gitcredentials.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ appended to its command line, which is one of:
260260

261261
`erase`::
262262

263-
Remove a matching credential, if any, from the helper's storage.
263+
Remove matching credentials, if any, from the helper's storage.
264264

265265
The details of the credential will be provided on the helper's stdin
266266
stream. The exact format is the same as the input/output format of the

builtin/credential-cache--daemon.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ static void cache_credential(struct credential *c, int timeout)
3333
e->expiration = time(NULL) + timeout;
3434
}
3535

36-
static struct credential_cache_entry *lookup_credential(const struct credential *c, int match_password)
36+
static struct credential_cache_entry *lookup_credential(const struct credential *c)
3737
{
3838
int i;
3939
for (i = 0; i < entries_nr; i++) {
4040
struct credential *e = &entries[i].item;
41-
if (credential_match(c, e, match_password))
41+
if (credential_match(c, e, 0))
4242
return &entries[i];
4343
}
4444
return NULL;
@@ -48,9 +48,12 @@ static void remove_credential(const struct credential *c, int match_password)
4848
{
4949
struct credential_cache_entry *e;
5050

51-
e = lookup_credential(c, match_password);
52-
if (e)
53-
e->expiration = 0;
51+
int i;
52+
for (i = 0; i < entries_nr; i++) {
53+
e = &entries[i];
54+
if (credential_match(c, &e->item, match_password))
55+
e->expiration = 0;
56+
}
5457
}
5558

5659
static timestamp_t check_expirations(void)
@@ -127,7 +130,7 @@ static void serve_one_client(FILE *in, FILE *out)
127130
if (read_request(in, &c, &action, &timeout) < 0)
128131
/* ignore error */ ;
129132
else if (!strcmp(action.buf, "get")) {
130-
struct credential_cache_entry *e = lookup_credential(&c, 0);
133+
struct credential_cache_entry *e = lookup_credential(&c);
131134
if (e) {
132135
fprintf(out, "username=%s\n", e->item.username);
133136
fprintf(out, "password=%s\n", e->item.password);

t/lib-credential.sh

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ helper_test_clean() {
4646
reject $1 https example.com user4
4747
reject $1 https example.com user-distinct-pass
4848
reject $1 https example.com user-overwrite
49+
reject $1 https example.com user-erase1
50+
reject $1 https example.com user-erase2
4951
reject $1 http path.tld user
5052
reject $1 https timeout.tld user
5153
reject $1 https sso.tld
@@ -342,6 +344,37 @@ helper_test() {
342344
EOF
343345
'
344346

347+
test_expect_success "helper ($HELPER) erases all matching credentials" '
348+
check approve $HELPER <<-\EOF &&
349+
protocol=https
350+
host=example.com
351+
username=user-erase1
352+
password=pass1
353+
EOF
354+
check approve $HELPER <<-\EOF &&
355+
protocol=https
356+
host=example.com
357+
username=user-erase2
358+
password=pass1
359+
EOF
360+
check reject $HELPER <<-\EOF &&
361+
protocol=https
362+
host=example.com
363+
EOF
364+
check fill $HELPER <<-\EOF
365+
protocol=https
366+
host=example.com
367+
--
368+
protocol=https
369+
host=example.com
370+
username=askpass-username
371+
password=askpass-password
372+
--
373+
askpass: Username for '\''https://example.com'\'':
374+
askpass: Password for '\''https://[email protected]'\'':
375+
EOF
376+
'
377+
345378
: ${GIT_TEST_LONG_CRED_BUFFER:=1024}
346379
# 23 bytes accounts for "wwwauth[]=basic realm=" plus NUL
347380
LONG_VALUE_LEN=$((GIT_TEST_LONG_CRED_BUFFER - 23))

0 commit comments

Comments
 (0)