aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/git-credential.txt28
-rw-r--r--credential.c20
-rw-r--r--credential.h7
-rwxr-xr-xt/t0300-credentials.sh28
4 files changed, 71 insertions, 12 deletions
diff --git a/Documentation/git-credential.txt b/Documentation/git-credential.txt
index 230ac4c2c3..f63a8e0458 100644
--- a/Documentation/git-credential.txt
+++ b/Documentation/git-credential.txt
@@ -211,6 +211,15 @@ can determine whether the operation was successful.
This value should not be sent unless the appropriate capability (see below) is
provided on input.
+`state[]`::
+ This value provides an opaque state that will be passed back to this helper
+ if it is called again. Each different credential helper may specify this
+ once. The value should include a prefix unique to the credential helper and
+ should ignore values that don't match its prefix.
++
+This value should not be sent unless the appropriate capability (see below) is
+provided on input.
+
`wwwauth[]`::
When an HTTP response is received by Git that includes one or more
@@ -223,18 +232,19 @@ they appear in the HTTP response. This attribute is 'one-way' from Git
to pass additional information to credential helpers.
`capability[]`::
- This signals that the caller supports the capability in question.
- This can be used to provide better, more specific data as part of the
+ This signals that Git, or the helper, as appropriate, supports the capability
+ in question. This can be used to provide better, more specific data as part
+ of the protocol. A `capability[]` directive must precede any value depending
+ on it and these directives _should_ be the first item announced in the
protocol.
+
-The only capability currently supported is `authtype`, which indicates that the
-`authtype`, `credential`, and `ephemeral` values are understood. It is not
-obligatory to use these values in such a case, but they should not be provided
-without this capability.
+There are two currently supported capabilities. The first is `authtype`, which
+indicates that the `authtype`, `credential`, and `ephemeral` values are
+understood. The second is `state`, which indicates that the `state[]` and
+`continue` values are understood.
+
-Callers of `git credential` and credential helpers should emit the
-capabilities they support unconditionally, and Git will gracefully
-handle passing them on.
+It is not obligatory to use the additional features just because the capability
+is supported, but they should not be provided without the capability.
Unrecognised attributes and capabilities are silently discarded.
diff --git a/credential.c b/credential.c
index 3531d74346..48826fb5a2 100644
--- a/credential.c
+++ b/credential.c
@@ -30,6 +30,7 @@ void credential_clear(struct credential *c)
free(c->authtype);
string_list_clear(&c->helpers, 0);
strvec_clear(&c->wwwauth_headers);
+ strvec_clear(&c->state_headers);
credential_init(c);
}
@@ -293,8 +294,13 @@ int credential_read(struct credential *c, FILE *fp,
c->ephemeral = !!git_config_bool("ephemeral", value);
} else if (!strcmp(key, "wwwauth[]")) {
strvec_push(&c->wwwauth_headers, value);
- } else if (!strcmp(key, "capability[]") && !strcmp(value, "authtype")) {
- credential_set_capability(&c->capa_authtype, op_type);
+ } else if (!strcmp(key, "state[]")) {
+ strvec_push(&c->state_headers, value);
+ } else if (!strcmp(key, "capability[]")) {
+ if (!strcmp(value, "authtype"))
+ credential_set_capability(&c->capa_authtype, op_type);
+ else if (!strcmp(value, "state"))
+ credential_set_capability(&c->capa_state, op_type);
} else if (!strcmp(key, "password_expiry_utc")) {
errno = 0;
c->password_expiry_utc = parse_timestamp(value, NULL, 10);
@@ -337,8 +343,12 @@ static void credential_write_item(FILE *fp, const char *key, const char *value,
void credential_write(const struct credential *c, FILE *fp,
enum credential_op_type op_type)
{
- if (credential_has_capability(&c->capa_authtype, op_type)) {
+ if (credential_has_capability(&c->capa_authtype, op_type))
credential_write_item(fp, "capability[]", "authtype", 0);
+ if (credential_has_capability(&c->capa_state, op_type))
+ credential_write_item(fp, "capability[]", "state", 0);
+
+ if (credential_has_capability(&c->capa_authtype, op_type)) {
credential_write_item(fp, "authtype", c->authtype, 0);
credential_write_item(fp, "credential", c->credential, 0);
if (c->ephemeral)
@@ -357,6 +367,10 @@ void credential_write(const struct credential *c, FILE *fp,
}
for (size_t i = 0; i < c->wwwauth_headers.nr; i++)
credential_write_item(fp, "wwwauth[]", c->wwwauth_headers.v[i], 0);
+ if (credential_has_capability(&c->capa_state, op_type)) {
+ for (size_t i = 0; i < c->state_headers.nr; i++)
+ credential_write_item(fp, "state[]", c->state_headers.v[i], 0);
+ }
}
static int run_credential_helper(struct credential *c,
diff --git a/credential.h b/credential.h
index da2a4802b7..c307300d12 100644
--- a/credential.h
+++ b/credential.h
@@ -145,6 +145,11 @@ struct credential {
struct strvec wwwauth_headers;
/**
+ * A `strvec` of state headers from credential helpers.
+ */
+ struct strvec state_headers;
+
+ /**
* Internal use only. Keeps track of if we previously matched against a
* WWW-Authenticate header line in order to re-fold future continuation
* lines into one value.
@@ -159,6 +164,7 @@ struct credential {
username_from_proto:1;
struct credential_capability capa_authtype;
+ struct credential_capability capa_state;
char *username;
char *password;
@@ -180,6 +186,7 @@ struct credential {
.helpers = STRING_LIST_INIT_DUP, \
.password_expiry_utc = TIME_MAX, \
.wwwauth_headers = STRVEC_INIT, \
+ .state_headers = STRVEC_INIT, \
}
/* Initialize a credential structure, setting all fields to empty. */
diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh
index eceb6bbfbe..432f029d48 100755
--- a/t/t0300-credentials.sh
+++ b/t/t0300-credentials.sh
@@ -46,9 +46,12 @@ test_expect_success 'setup helper scripts' '
credential=$1; shift
. ./dump
echo capability[]=authtype
+ echo capability[]=state
test -z "${capability##*authtype*}" || exit 0
test -z "$authtype" || echo authtype=$authtype
test -z "$credential" || echo credential=$credential
+ test -z "${capability##*state*}" || exit 0
+ echo state[]=verbatim-cred:foo
EOF
write_script git-credential-verbatim-ephemeral <<-\EOF &&
@@ -129,6 +132,28 @@ test_expect_success 'credential_fill invokes helper with ephemeral credential' '
verbatim-ephemeral: host=example.com
EOF
'
+test_expect_success 'credential_fill invokes helper with credential and state' '
+ check fill "verbatim-cred Bearer token" <<-\EOF
+ capability[]=authtype
+ capability[]=state
+ protocol=http
+ host=example.com
+ --
+ capability[]=authtype
+ capability[]=state
+ authtype=Bearer
+ credential=token
+ protocol=http
+ host=example.com
+ state[]=verbatim-cred:foo
+ --
+ verbatim-cred: get
+ verbatim-cred: capability[]=authtype
+ verbatim-cred: capability[]=state
+ verbatim-cred: protocol=http
+ verbatim-cred: host=example.com
+ EOF
+'
test_expect_success 'credential_fill invokes multiple helpers' '
check fill useless "verbatim foo bar" <<-\EOF
@@ -152,6 +177,7 @@ test_expect_success 'credential_fill invokes multiple helpers' '
test_expect_success 'credential_fill response does not get capabilities when helpers are incapable' '
check fill useless "verbatim foo bar" <<-\EOF
capability[]=authtype
+ capability[]=state
protocol=http
host=example.com
--
@@ -162,10 +188,12 @@ test_expect_success 'credential_fill response does not get capabilities when hel
--
useless: get
useless: capability[]=authtype
+ useless: capability[]=state
useless: protocol=http
useless: host=example.com
verbatim: get
verbatim: capability[]=authtype
+ verbatim: capability[]=state
verbatim: protocol=http
verbatim: host=example.com
EOF