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
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.
free(c->authtype);
string_list_clear(&c->helpers, 0);
strvec_clear(&c->wwwauth_headers);
+ strvec_clear(&c->state_headers);
credential_init(c);
}
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);
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)
}
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,
*/
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
username_from_proto:1;
struct credential_capability capa_authtype;
+ struct credential_capability capa_state;
char *username;
char *password;
.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. */
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 &&
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
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
--
--
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