{"thread":{"id":"30738","subject":"[PATCH/RFC] credentials helpers+remote helpers","startedAt":"2012-06-07T14:35:43Z","lastAt":"2012-06-07T19:22:30Z","messageCount":3,"participants":["javier.roucher-iglesias@ensimag.imag.fr","Matthieu Moy","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"193070","messageId":"1339079743-31068-1-git-send-email-Javier.Roucher-Iglesias@ensimag.imag.fr","threadId":"30738","inReplyTo":null,"subject":"[PATCH/RFC] credentials helpers+remote helpers","fromName":"","fromEmail":"javier.roucher-iglesias@ensimag.imag.fr","sentAt":"2012-06-07T14:35:43Z","receivedAt":"2012-06-07T14:35:43Z","isPatch":true,"sender":{"key":"javier.roucher-iglesias@ensimag.imag.fr","avatar":null},"body":"From: Javier Roucher <jroucher@gmail.com>\n\n\nAdd \"git credential\" plumbing command\n\nThe credential API is in C, and not available to scripting languages.\nExpose the functionalities of the API by wrapping them into a new\nplumbing command \"git credentials\".\n\nSigned-off-by: Pavel Volek <Pavel.Volek@ensimag.imag.fr>\nSigned-off-by: NGUYEN Kim Thuat <Kim-Thuat.Nguyen@ensimag.imag.fr>\nSigned-off-by: ROUCHER IGLESIAS Javier <roucherj@ensimag.imag.fr>\nSigned-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>\n---\n .gitignore                       |  1 +\n Documentation/git-credential.txt | 70 ++++++++++++++++++++++++++++++++++++++++\n Makefile                         |  1 +\n builtin.h                        |  1 +\n builtin/credential.c             | 40 +++++++++++++++++++++++\n git.c                            |  1 +\n 6 files changed, 114 insertions(+)\n create mode 100644 Documentation/git-credential.txt\n create mode 100644 builtin/credential.c\n\ndiff --git a/.gitignore b/.gitignore\nindex bf66648..7d1d86e 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -31,6 +31,7 @@\n /git-commit-tree\n /git-config\n /git-count-objects\n+/git-credential\n /git-credential-cache\n /git-credential-cache--daemon\n /git-credential-store\ndiff --git a/Documentation/git-credential.txt b/Documentation/git-credential.txt\nnew file mode 100644\nindex 0000000..a6e1d0a\n--- /dev/null\n+++ b/Documentation/git-credential.txt\n@@ -0,0 +1,70 @@\n+git-credential(7)\n+=================\n+\n+NAME\n+----\n+git-credential - Providing and storing user credentials to git\n+\n+SYNOPSIS\n+--------\n+------------------\n+git credential [fill|approve|reject]\n+\n+------------------\n+\n+DESCRIPTION\n+-----------\n+\n+Git-credential permits to save username, password, host, path and protocol.\n+When you invoke git-credential, you can ask for a password, using the command\n+'git credential fill'.\n+Providing them by STDIN: \n+\n+\t\tusername=admin\\n \n+\t\tprotocol=[http|https]\\n\n+\t\thost=localhost\\n\n+\t\tpath=/dir\\n\\n\n+\n+-If git-credential system, have the password already stored\n+git-credential will answer by STDOUT:\n+\t\n+\t\tusername=admin\\n\n+\t\tpassword=*****\\n\n+\n+-If it is not stored, git-credential will ask you to enter \n+the password:\n+\t\t\n+\t\t> Password for '[http|https]admin@localhost':\n+\n+Then if password is correct, you can store using command\n+'git crendential approve' providing the structure, by STDIN.\n+\n+\t\tusername=admin\\n \n+\t\tpassword=*****\\n\n+\t\tprotocol=[http|https]\\n\n+\t\thost=localhost\\n\n+\t\tpath=/dir\\n\\n\n+\n+If the password is refused, you can delete using command\n+'git credential reject' providing the same structure.\n+\n+\n+REQUESTING CREDENTIALS\n+----------------------\n+\n+1. The 'git credential fill' makes the structure:\n+\t\tusername=foo\n+\t\tpassword=****\n+\t\tprotocol=[http|https]\n+\t\tlocalhost=url\n+\t\tpath=/direction\n+\n+   with this structure it will be able to save your\n+   credentials, and if the credential is allready stored,\n+   it will fill the password.\n+\n+2. Then 'git credential approve' to store them.\n+\n+3. Otherwise, if the credential is not correct you can do\n+  'git credential reject' to delete the credential.\n+-------------------------------------------\ndiff --git a/Makefile b/Makefile\nindex 4592f1f..3f53da8 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -827,6 +827,7 @@ BUILTIN_OBJS += builtin/commit-tree.o\n BUILTIN_OBJS += builtin/commit.o\n BUILTIN_OBJS += builtin/config.o\n BUILTIN_OBJS += builtin/count-objects.o\n+BUILTIN_OBJS += builtin/credential.o\n BUILTIN_OBJS += builtin/describe.o\n BUILTIN_OBJS += builtin/diff-files.o\n BUILTIN_OBJS += builtin/diff-index.o\ndiff --git a/builtin.h b/builtin.h\nindex 338f540..48feddc 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -66,6 +66,7 @@ extern int cmd_commit(int argc, const char **argv, const char *prefix);\n extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);\n extern int cmd_config(int argc, const char **argv, const char *prefix);\n extern int cmd_count_objects(int argc, const char **argv, const char *prefix);\n+extern int cmd_credential(int argc, const char **argv, const char *prefix);\n extern int cmd_describe(int argc, const char **argv, const char *prefix);\n extern int cmd_diff_files(int argc, const char **argv, const char *prefix);\n extern int cmd_diff_index(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/credential.c b/builtin/credential.c\nnew file mode 100644\nindex 0000000..89f976b\n--- /dev/null\n+++ b/builtin/credential.c\n@@ -0,0 +1,40 @@\n+#include <stdio.h>\n+#include \"cache.h\"\n+#include \"credential.h\"\n+#include \"string-list.h\"\n+\n+static const char usage_msg[] =\n+\"credential <fill|approve|reject> [helper...]\";\n+\n+void cmd_credential (int argc, char **argv, const char *prefix){\n+\tconst char *op;\n+\tstruct credential c = CREDENTIAL_INIT;\n+\tint i;\n+\n+\top = argv[1];\n+\tif (!op)\n+\t\tusage(usage_msg);\n+\n+\tfor (i = 2; i < argc; i++)\n+\t\tstring_list_append(&c.helpers, argv[i]);\n+\n+\tif (credential_read(&c, stdin) < 0)\n+\t\tdie(\"unable to read credential from stdin\");\n+\n+\tif (!strcmp(op, \"fill\")) {\n+\t\tcredential_fill(&c);\n+\t\tif (c.username)\n+\t\t\tprintf(\"username=%s\\n\", c.username);\n+\t\tif (c.password)\n+\t\t\tprintf(\"password=%s\\n\", c.password);\n+\t}\n+\telse if (!strcmp(op, \"approve\")) {\n+\t\tcredential_approve(&c);\n+\t}\n+\telse if (!strcmp(op, \"reject\")) {\n+\t\tcredential_reject(&c);\n+\t}\n+\telse\n+\t\tusage(usage_msg);\n+}\n+\ndiff --git a/git.c b/git.c\nindex d232de9..211f01f 100644\n--- a/git.c\n+++ b/git.c\n@@ -353,6 +353,7 @@ static void handle_internal_command(int argc, const char **argv)\n \t\t{ \"commit-tree\", cmd_commit_tree, RUN_SETUP },\n \t\t{ \"config\", cmd_config, RUN_SETUP_GENTLY },\n \t\t{ \"count-objects\", cmd_count_objects, RUN_SETUP },\n+\t\t{ \"credential\", cmd_credential, RUN_SETUP },\n \t\t{ \"describe\", cmd_describe, RUN_SETUP },\n \t\t{ \"diff\", cmd_diff },\n \t\t{ \"diff-files\", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE },\n-- \n1.7.11.rc0.5.ge0c9cc0.dirty\n"},{"id":"193082","messageId":"vpqvcj32ggt.fsf@bauges.imag.fr","threadId":"30738","inReplyTo":"1339079743-31068-1-git-send-email-Javier.Roucher-Iglesias@ensimag.imag.fr","subject":"Re: [PATCH/RFC] credentials helpers+remote helpers","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2012-06-07T17:13:06Z","receivedAt":"2012-06-07T17:13:06Z","isPatch":true,"sender":{"key":"matthieu.moy@grenoble-inp.fr","avatar":"https://gravatar.com/avatar/72c8a2705971a25dfaff23cece15130d405685845d911aedd5667ace277f3fc5?d=mp&s=160"},"body":"> Subject: Re: [PATCH/RFC] credentials helpers+remote helpers\n\nThis is not a good title. The one you have below (which I suggested\noff-list) should be the first line of the patch.\n\nJavier.Roucher-Iglesias@ensimag.imag.fr writes:\n\n> Add \"git credential\" plumbing command\n\n(I mean this one)\n\n>  .gitignore                       |  1 +\n>  Documentation/git-credential.txt | 70 ++++++++++++++++++++++++++++++++++++++++\n>  Makefile                         |  1 +\n>  builtin.h                        |  1 +\n>  builtin/credential.c             | 40 +++++++++++++++++++++++\n>  git.c                            |  1 +\n\nNo tests?\n\nSince this new command is essentially a copy-paste of test-credential.c,\nit would indeed make sense to replace test-credential calls in the\nscripts by calls to this \"git credential\" command.\n\n> index 0000000..a6e1d0a\n> --- /dev/null\n> +++ b/Documentation/git-credential.txt\n\nThis file is not valid asciidoc. Please, run \"make doc\" and see if the\ngenerated HTML is right. Currently, it says\n\n    SUBDIR ../\nmake[1]: `GIT-VERSION-FILE' is up to date.\n    ASCIIDOC git-credential.html\nasciidoc: ERROR: git-credential.txt: line 69: [blockdef-listing] missing closing delimiter\nmake: *** [git-credential.html] Error 1\n\n(didn't I already mention it off-list?)\n> +------------------\n> +git credential [fill|approve|reject]\n> +\n> +------------------\n[...]\n> +static const char usage_msg[] =\n> +\"credential <fill|approve|reject> [helper...]\";\n\nWhich one is right?\n\nI already suggested several times that you get rid of this \"helper\"\nargument (inherited from test-credential), or that you give it a better\nAPI (e.g. --helper HELPER, but not positional argument). If this\nargument is usefull, then keep it but it should be documented properly.\n\n> +Git-credential permits to save username, password, host, path and protocol.\n> +When you invoke git-credential, you can ask for a password, using the command\n> +'git credential fill'.\n\nWho is \"you\" here? This \"you\" is the developer writing a script using\n\"git credential\", while this one :\n\n> +-If it is not stored, git-credential will ask you to enter \n> +the password:\n> +\t\t\n> +\t\t> Password for '[http|https]admin@localhost':\n\n... is the user of the script. Please be more precise, e.g. \"a script\ncan ask ...\", \"the user will be prompted for a password\".\n\n> +Then if password is correct, you can store using command\n\nif _the_ password ... you can store _it_ using ...\n\n> +If the password is refused, you can delete using command\n\ndelete _it_\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"193101","messageId":"7vr4trexl5.fsf@alter.siamese.dyndns.org","threadId":"30738","inReplyTo":"1339079743-31068-1-git-send-email-Javier.Roucher-Iglesias@ensimag.imag.fr","subject":"Re: [PATCH/RFC] credentials helpers+remote helpers","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-07T19:22:30Z","receivedAt":"2012-06-07T19:22:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Javier.Roucher-Iglesias@ensimag.imag.fr writes:\n\n> From: Javier Roucher <jroucher@gmail.com>\n>\n>\n> Add \"git credential\" plumbing command\n>\n> The credential API is in C, and not available to scripting languages.\n> Expose the functionalities of the API by wrapping them into a new\n> plumbing command \"git credentials\".\n>\n> Signed-off-by: Pavel Volek <Pavel.Volek@ensimag.imag.fr>\n> Signed-off-by: NGUYEN Kim Thuat <Kim-Thuat.Nguyen@ensimag.imag.fr>\n> Signed-off-by: ROUCHER IGLESIAS Javier <roucherj@ensimag.imag.fr>\n> Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>\n\nIn addition to all good comments already given by Matthieu,...\n\n> diff --git a/Documentation/git-credential.txt b/Documentation/git-credential.txt\n> new file mode 100644\n> index 0000000..a6e1d0a\n> --- /dev/null\n> +++ b/Documentation/git-credential.txt\n> @@ -0,0 +1,70 @@\n> +git-credential(7)\n> +=================\n> +\n> +NAME\n> +----\n> +git-credential - Providing and storing user credentials to git\n\nThis sounds as if we are storing passwords \"in git\", which is not\nexactly the point of the credential API, no?\n\n> +SYNOPSIS\n> +--------\n> +------------------\n> +git credential [fill|approve|reject]\n> +\n> +------------------\n> +\n> +DESCRIPTION\n> +-----------\n> +\n> +Git-credential permits to save username, password, host, path and protocol.\n> +When you invoke git-credential, you can ask for a password, using the command\n> +'git credential fill'.\n> +Providing them by STDIN: \n> +\n> +\t\tusername=admin\\n \n> +\t\tprotocol=[http|https]\\n\n> +\t\thost=localhost\\n\n> +\t\tpath=/dir\\n\\n\n\nIt's a bit strange way to convey that the user feeds record\nseparated by a blank line, and each column in a record is terminated\nwith a newline.\n\nHow about saying that more explicitly?  E.g. \"when taking data from\nthe standard input, the program treats each line as a separate data\nitem, and the end of series of data item is signalled by a blank\nline\" or something?\n\n> +-If git-credential system, have the password already stored\n> +git-credential will answer by STDOUT:\n> +\t\n> +\t\tusername=admin\\n\n> +\t\tpassword=*****\\n\n\nDoes the reading side get any clue that there is no more output,\nlike you gave yourself on the input side (i.e. it can and should\nread until it sees a blank line)?\n\nShouldn't it?\n\n> +-If it is not stored, git-credential will ask you to enter \n> +the password:\n> +\t\t\n> +\t\t> Password for '[http|https]admin@localhost':\n> +\n> +Then if password is correct, you can store using command\n> +'git crendential approve' providing the structure, by STDIN.\n> +\n> +\t\tusername=admin\\n \n> +\t\tpassword=*****\\n\n> +\t\tprotocol=[http|https]\\n\n> +\t\thost=localhost\\n\n> +\t\tpath=/dir\\n\\n\n> +\n> +If the password is refused, you can delete using command\n> +'git credential reject' providing the same structure.\n\nIt is unclear who decides \"correct\" vs \"refused\" here.\n\nPerhaps it would help to describe the purpose of the script that\nuses this command first.  My understanding is that there are three\nactors: the end user, the script that uses \"git credential\" and an\nexternal system that wants to authenticate the user.\n\n    _\n   / \\        +------------------+      +-----------------+\n  | U |       |                  |      |                 |\n   \\ /        | Script that uses |      | External system |\n  --+--  <==> | \"git credential\" | <==> |                 | \n    ^         +------------------+      +-----------------+\n   / \\                 ^\n                       |\n                       v\n                credential API\n\nAnd the \"Script\" is trying to respond to the external system with\ncredential material on behalf of the user.  For that, if the script\nknows the username, it can give the <user,proto,host,path> tuple to\n\"git credential\", and if \"git credential\" knows the password, it\nwill be given to the script. If it does not, it may ask the user and\nobtain it before giving it back to the script.\n\nIs that what is going on?\n\nAssuming it is, after that happens, the script gives the credential\ninformation to the external system. The external system may or may\nnot accept that credential, and that is what decides \"correct\" vs\n\"refused\".\n\nAfter that, the script tells the \"git credential\" the result; giving\n\"reject\" to it to purge the credential information that it already\nknows the external system will reject, for example.\n"}]}