Skip to content

Commit 2ca91d1

Browse files
committed
Merge branch 'mh/credential-oauth-refresh-token'
The credential subsystem learns to help OAuth framework. * mh/credential-oauth-refresh-token: credential: new attribute oauth_refresh_token
2 parents c05615e + a5c7656 commit 2ca91d1

File tree

7 files changed

+65
-0
lines changed

7 files changed

+65
-0
lines changed

Documentation/git-credential.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,12 @@ Git understands the following attributes:
156156
When reading credentials from helpers, `git credential fill` ignores expired
157157
passwords. Represented as Unix time UTC, seconds since 1970.
158158

159+
`oauth_refresh_token`::
160+
161+
An OAuth refresh token may accompany a password that is an OAuth access
162+
token. Helpers must treat this attribute as confidential like the password
163+
attribute. Git itself has no special behaviour for this attribute.
164+
159165
`url`::
160166

161167
When this special attribute is read by `git credential`, the

builtin/credential-cache--daemon.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ static void serve_one_client(FILE *in, FILE *out)
134134
if (e->item.password_expiry_utc != TIME_MAX)
135135
fprintf(out, "password_expiry_utc=%"PRItime"\n",
136136
e->item.password_expiry_utc);
137+
if (e->item.oauth_refresh_token)
138+
fprintf(out, "oauth_refresh_token=%s\n",
139+
e->item.oauth_refresh_token);
137140
}
138141
}
139142
else if (!strcmp(action.buf, "exit")) {

credential.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ void credential_clear(struct credential *c)
2525
free(c->path);
2626
free(c->username);
2727
free(c->password);
28+
free(c->oauth_refresh_token);
2829
string_list_clear(&c->helpers, 0);
2930
strvec_clear(&c->wwwauth_headers);
3031

@@ -246,6 +247,9 @@ int credential_read(struct credential *c, FILE *fp)
246247
c->password_expiry_utc = parse_timestamp(value, NULL, 10);
247248
if (c->password_expiry_utc == 0 || errno == ERANGE)
248249
c->password_expiry_utc = TIME_MAX;
250+
} else if (!strcmp(key, "oauth_refresh_token")) {
251+
free(c->oauth_refresh_token);
252+
c->oauth_refresh_token = xstrdup(value);
249253
} else if (!strcmp(key, "url")) {
250254
credential_from_url(c, value);
251255
} else if (!strcmp(key, "quit")) {
@@ -281,6 +285,7 @@ void credential_write(const struct credential *c, FILE *fp)
281285
credential_write_item(fp, "path", c->path, 0);
282286
credential_write_item(fp, "username", c->username, 0);
283287
credential_write_item(fp, "password", c->password, 0);
288+
credential_write_item(fp, "oauth_refresh_token", c->oauth_refresh_token, 0);
284289
if (c->password_expiry_utc != TIME_MAX) {
285290
char *s = xstrfmt("%"PRItime, c->password_expiry_utc);
286291
credential_write_item(fp, "password_expiry_utc", s, 0);
@@ -406,6 +411,7 @@ void credential_reject(struct credential *c)
406411

407412
FREE_AND_NULL(c->username);
408413
FREE_AND_NULL(c->password);
414+
FREE_AND_NULL(c->oauth_refresh_token);
409415
c->password_expiry_utc = TIME_MAX;
410416
c->approved = 0;
411417
}

credential.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ struct credential {
141141
char *protocol;
142142
char *host;
143143
char *path;
144+
char *oauth_refresh_token;
144145
timestamp_t password_expiry_utc;
145146
};
146147

t/lib-credential.sh

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ helper_test_clean() {
4343
reject $1 https example.com store-user
4444
reject $1 https example.com user1
4545
reject $1 https example.com user2
46+
reject $1 https example.com user4
4647
reject $1 http path.tld user
4748
reject $1 https timeout.tld user
4849
reject $1 https sso.tld
@@ -327,6 +328,35 @@ helper_test_timeout() {
327328
'
328329
}
329330

331+
helper_test_oauth_refresh_token() {
332+
HELPER=$1
333+
334+
test_expect_success "helper ($HELPER) stores oauth_refresh_token" '
335+
check approve $HELPER <<-\EOF
336+
protocol=https
337+
host=example.com
338+
username=user4
339+
password=pass
340+
oauth_refresh_token=xyzzy
341+
EOF
342+
'
343+
344+
test_expect_success "helper ($HELPER) gets oauth_refresh_token" '
345+
check fill $HELPER <<-\EOF
346+
protocol=https
347+
host=example.com
348+
username=user4
349+
--
350+
protocol=https
351+
host=example.com
352+
username=user4
353+
password=pass
354+
oauth_refresh_token=xyzzy
355+
--
356+
EOF
357+
'
358+
}
359+
330360
write_script askpass <<\EOF
331361
echo >&2 askpass: $*
332362
what=$(echo $1 | cut -d" " -f1 | tr A-Z a-z | tr -cd a-z)

t/t0300-credentials.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,24 @@ test_expect_success 'credential_approve stores password expiry' '
214214
EOF
215215
'
216216

217+
test_expect_success 'credential_approve stores oauth refresh token' '
218+
check approve useless <<-\EOF
219+
protocol=http
220+
host=example.com
221+
username=foo
222+
password=bar
223+
oauth_refresh_token=xyzzy
224+
--
225+
--
226+
useless: store
227+
useless: protocol=http
228+
useless: host=example.com
229+
useless: username=foo
230+
useless: password=bar
231+
useless: oauth_refresh_token=xyzzy
232+
EOF
233+
'
234+
217235
test_expect_success 'do not bother storing password-less credential' '
218236
check approve useless <<-\EOF
219237
protocol=http

t/t0301-credential-cache.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ test_atexit 'git credential-cache exit'
2929

3030
# test that the daemon works with no special setup
3131
helper_test cache
32+
helper_test_oauth_refresh_token cache
3233

3334
test_expect_success 'socket defaults to ~/.cache/git/credential/socket' '
3435
test_when_finished "

0 commit comments

Comments
 (0)