add 'git credential' plumbing command
The credential API is in C, and not available to scripting languages. Expose the functionalities of the API by wrapping them into a new plumbing command "git credentials". In other words, replace the internal "test-credential" by an official Git command. Most documentation writen by: Jeff King <peff@peff.net> Signed-off-by: Pavel Volek <Pavel.Volek@ensimag.imag.fr> Signed-off-by: Kim Thuat Nguyen <Kim-Thuat.Nguyen@ensimag.imag.fr> Signed-off-by: Javier Roucher Iglesias <Javier.Roucher-Iglesias@ensimag.imag.fr> Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Javier Roucher Iglesias committed
Jun 24, 2012 at 13:39 UTC
e30b2feb1b50c2d14d32dc3e6e41f7b20a677ff2
8 files changed
+163
-52
.gitignore
+1
-1
@@ -31,6 +31,7 @@
31
/git-commit-tree
32
/git-config
33
/git-count-objects
34
+/git-credential
35
/git-credential-cache
36
/git-credential-cache--daemon
37
/git-credential-store
@@ -172,7 +173,6 @@
173
/gitweb/static/gitweb.js
174
/gitweb/static/gitweb.min.*
175
/test-chmtime
175
-/test-credential
176
/test-ctype
177
/test-date
178
/test-delta
Documentation/git-credential.txt
new
+136
@@ -0,0 +1,136 @@
1
+git-credential(1)
2
+=================
3
+
4
+NAME
5
+----
6
+git-credential - retrieve and store user credentials
7
+
8
+SYNOPSIS
9
+--------
10
+------------------
11
+git credential <fill|approve|reject>
12
+------------------
13
+
14
+DESCRIPTION
15
+-----------
16
+
17
+Git has an internal interface for storing and retrieving credentials
18
+from system-specific helpers, as well as prompting the user for
19
+usernames and passwords. The git-credential command exposes this
20
+interface to scripts which may want to retrieve, store, or prompt for
21
+credentials in the same manner as git. The design of this scriptable
22
+interface models the internal C API; see
23
+link:technical/api-credentials.txt[the git credential API] for more
24
+background on the concepts.
25
+
26
+git-credential takes an "action" option on the command-line (one of
27
+`fill`, `approve`, or `reject`) and reads a credential description
28
+on stdin (see <<IOFMT,INPUT/OUTPUT FORMAT>>).
29
+
30
+If the action is `fill`, git-credential will attempt to add "username"
31
+and "password" attributes to the description by reading config files,
32
+by contacting any configured credential helpers, or by prompting the
33
+user. The username and password attributes of the credential
34
+description are then printed to stdout together with the attributes
35
+already provided.
36
+
37
+If the action is `approve`, git-credential will send the description
38
+to any configured credential helpers, which may store the credential
39
+for later use.
40
+
41
+If the action is `reject`, git-credential will send the description to
42
+any configured credential helpers, which may erase any stored
43
+credential matching the description.
44
+
45
+If the action is `approve` or `reject`, no output should be emitted.
46
+
47
+TYPICAL USE OF GIT CREDENTIAL
48
+-----------------------------
49
+
50
+An application using git-credential will typically use `git
51
+credential` following these steps:
52
+
53
+ 1. Generate a credential description based on the context.
54
++
55
+For example, if we want a password for
56
+`https://example.com/foo.git`, we might generate the following
57
+credential description (don't forget the blank line at the end; it
58
+tells `git credential` that the application finished feeding all the
59
+infomation it has):
60
+
61
+ protocol=https
62
+ host=example.com
63
+ path=foo.git
64
+
65
+ 2. Ask git-credential to give us a username and password for this
66
+ description. This is done by running `git credential fill`,
67
+ feeding the description from step (1) to its standard input. The
68
+ credential will be produced on standard output, like:
69
+
70
+ username=bob
71
+ password=secr3t
72
++
73
+If the `git credential` knew about the password, this step may
74
+not have involved the user actually typing this password (the
75
+user may have typed a password to unlock the keychain instead,
76
+or no user interaction was done if the keychain was already
77
+unlocked) before it returned `password=secr3t`.
78
+
79
+ 3. Use the credential (e.g., access the URL with the username and
80
+ password from step (2)), and see if it's accepted.
81
+
82
+ 4. Report on the success or failure of the password. If the
83
+ credential allowed the operation to complete successfully, then
84
+ it can be marked with an "approve" action to tell `git
85
+ credential` to reuse it in its next invocation. If the credential
86
+ was rejected during the operation, use the "reject" action so
87
+ that `git credential` will ask for a new password in its next
88
+ invocation. In either case, `git credential` should be fed with
89
+ the credential description obtained from step (2) together with
90
+ the ones already provided in step (1).
91
+
92
+[[IOFMT]]
93
+INPUT/OUTPUT FORMAT
94
+-------------------
95
+
96
+`git credential` reads and/or writes (depending on the action used)
97
+credential information in its standard input/output. These information
98
+can correspond either to keys for which `git credential` will obtain
99
+the login/password information (e.g. host, protocol, path), or to the
100
+actual credential data to be obtained (login/password).
101
+
102
+The credential is split into a set of named attributes.
103
+Attributes are provided to the helper, one per line. Each attribute is
104
+specified by a key-value pair, separated by an `=` (equals) sign,
105
+followed by a newline. The key may contain any bytes except `=`,
106
+newline, or NUL. The value may contain any bytes except newline or NUL.
107
+In both cases, all bytes are treated as-is (i.e., there is no quoting,
108
+and one cannot transmit a value with newline or NUL in it). The list of
109
+attributes is terminated by a blank line or end-of-file.
110
+Git will send the following attributes (but may not send all of
111
+them for a given credential; for example, a `host` attribute makes no
112
+sense when dealing with a non-network protocol):
113
+
114
+`protocol`::
115
+
116
+ The protocol over which the credential will be used (e.g.,
117
+ `https`).
118
+
119
+`host`::
120
+
121
+ The remote hostname for a network credential.
122
+
123
+`path`::
124
+
125
+ The path with which the credential will be used. E.g., for
126
+ accessing a remote https repository, this will be the
127
+ repository's path on the server.
128
+
129
+`username`::
130
+
131
+ The credential's username, if we already have one (e.g., from a
132
+ URL, from the user, or from a previously run helper).
133
+
134
+`password`::
135
+
136
+ The credential's password, if we are asking it to be stored.
Documentation/technical/api-credentials.txt
+3
-36
@@ -241,42 +241,9 @@ appended to its command line, which is one of:
241
Remove a matching credential, if any, from the helper's storage.
242
243
The details of the credential will be provided on the helper's stdin
244
-stream. The credential is split into a set of named attributes.
245
-Attributes are provided to the helper, one per line. Each attribute is
246
-specified by a key-value pair, separated by an `=` (equals) sign,
247
-followed by a newline. The key may contain any bytes except `=`,
248
-newline, or NUL. The value may contain any bytes except newline or NUL.
249
-In both cases, all bytes are treated as-is (i.e., there is no quoting,
250
-and one cannot transmit a value with newline or NUL in it). The list of
251
-attributes is terminated by a blank line or end-of-file.
252
-
253
-Git will send the following attributes (but may not send all of
254
-them for a given credential; for example, a `host` attribute makes no
255
-sense when dealing with a non-network protocol):
256
-
257
-`protocol`::
258
-
259
- The protocol over which the credential will be used (e.g.,
260
- `https`).
261
-
262
-`host`::
263
-
264
- The remote hostname for a network credential.
265
-
266
-`path`::
267
-
268
- The path with which the credential will be used. E.g., for
269
- accessing a remote https repository, this will be the
270
- repository's path on the server.
271
-
272
-`username`::
273
-
274
- The credential's username, if we already have one (e.g., from a
275
- URL, from the user, or from a previously run helper).
276
-
277
-`password`::
278
-
279
- The credential's password, if we are asking it to be stored.
244
+stream. The exact format is the same as the input/output format of the
245
+`git credential` plumbing command (see the section `INPUT/OUTPUT
246
+FORMAT` in linkgit:git-credential[7] for a detailed specification).
247
248
For a `get` operation, the helper should produce a list of attributes
249
on stdout in the same format. A helper is free to produce a subset, or
Makefile
+1
-1
@@ -487,7 +487,6 @@ X =
487
PROGRAMS += $(patsubst %.o,git-%$X,$(PROGRAM_OBJS))
488
489
TEST_PROGRAMS_NEED_X += test-chmtime
490
-TEST_PROGRAMS_NEED_X += test-credential
490
TEST_PROGRAMS_NEED_X += test-ctype
491
TEST_PROGRAMS_NEED_X += test-date
492
TEST_PROGRAMS_NEED_X += test-delta
@@ -835,6 +834,7 @@ BUILTIN_OBJS += builtin/commit-tree.o
834
BUILTIN_OBJS += builtin/commit.o
835
BUILTIN_OBJS += builtin/config.o
836
BUILTIN_OBJS += builtin/count-objects.o
837
+BUILTIN_OBJS += builtin/credential.o
838
BUILTIN_OBJS += builtin/describe.o
839
BUILTIN_OBJS += builtin/diff-files.o
840
BUILTIN_OBJS += builtin/diff-index.o
builtin.h
+1
@@ -65,6 +65,7 @@ extern int cmd_commit(int argc, const char **argv, const char *prefix);
65
extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
66
extern int cmd_config(int argc, const char **argv, const char *prefix);
67
extern int cmd_count_objects(int argc, const char **argv, const char *prefix);
68
+extern int cmd_credential(int argc, const char **argv, const char *prefix);
69
extern int cmd_describe(int argc, const char **argv, const char *prefix);
70
extern int cmd_diff_files(int argc, const char **argv, const char *prefix);
71
extern int cmd_diff_index(int argc, const char **argv, const char *prefix);
builtin/credential.c
renamed
+8
-12
@@ -1,21 +1,18 @@
1
-#include "cache.h"
1
+#include "git-compat-util.h"
2
#include "credential.h"
3
-#include "string-list.h"
3
+#include "builtin.h"
4
5
static const char usage_msg[] =
6
-"test-credential <fill|approve|reject> [helper...]";
6
+ "git credential [fill|approve|reject]";
7
8
-int main(int argc, const char **argv)
8
+int cmd_credential(int argc, const char **argv, const char *prefix)
9
{
10
const char *op;
11
struct credential c = CREDENTIAL_INIT;
12
- int i;
12
13
op = argv[1];
14
if (!op)
15
usage(usage_msg);
17
- for (i = 2; i < argc; i++)
18
- string_list_append(&c.helpers, argv[i]);
16
17
if (credential_read(&c, stdin) < 0)
18
die("unable to read credential from stdin");
@@ -26,13 +23,12 @@ int main(int argc, const char **argv)
23
printf("username=%s\n", c.username);
24
if (c.password)
25
printf("password=%s\n", c.password);
29
- }
30
- else if (!strcmp(op, "approve"))
26
+ } else if (!strcmp(op, "approve")) {
27
credential_approve(&c);
32
- else if (!strcmp(op, "reject"))
28
+ } else if (!strcmp(op, "reject")) {
29
credential_reject(&c);
34
- else
30
+ } else {
31
usage(usage_msg);
36
-
32
+ }
33
return 0;
34
}
git.c
+1
@@ -351,6 +351,7 @@ static void handle_internal_command(int argc, const char **argv)
351
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
352
{ "config", cmd_config, RUN_SETUP_GENTLY },
353
{ "count-objects", cmd_count_objects, RUN_SETUP },
354
+ { "credential", cmd_credential, RUN_SETUP_GENTLY },
355
{ "describe", cmd_describe, RUN_SETUP },
356
{ "diff", cmd_diff },
357
{ "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE },
t/lib-credential.sh
+12
-2
@@ -4,10 +4,20 @@
4
# stdout and stderr should be provided on stdin,
5
# separated by "--".
6
check() {
7
+ credential_opts=
8
+ credential_cmd=$1
9
+ shift
10
+ for arg in "$@"; do
11
+ credential_opts="$credential_opts -c credential.helper='$arg'"
12
+ done
13
read_chunk >stdin &&
14
read_chunk >expect-stdout &&
15
read_chunk >expect-stderr &&
10
- test-credential "$@" <stdin >stdout 2>stderr &&
16
+ if ! eval "git $credential_opts credential $credential_cmd <stdin >stdout 2>stderr"; then
17
+ echo "git credential failed with code $?" &&
18
+ cat stderr &&
19
+ false
20
+ fi &&
21
test_cmp expect-stdout stdout &&
22
test_cmp expect-stderr stderr
23
}
@@ -41,7 +51,7 @@ reject() {
51
echo protocol=$2
52
echo host=$3
53
echo username=$4
44
- ) | test-credential reject $1
54
+ ) | git -c credential.helper=$1 credential reject
55
}
56
57
helper_test() {