{"thread":{"id":"18140","subject":"[PATCH] http authentication via prompts","startedAt":"2009-03-05T01:07:11Z","lastAt":"2009-03-06T22:52:13Z","messageCount":6,"participants":["Mike Gaffney","Junio C Hamano","Johannes Schindelin","Jeff King","Fredrik Skolmli"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"107018","messageId":"49AF25BF.5060706@gmail.com","threadId":"18140","inReplyTo":null,"subject":"[PATCH] http authentication via prompts","fromName":"Mike Gaffney","fromEmail":"mr.gaffo@gmail.com","sentAt":"2009-03-05T01:07:11Z","receivedAt":"2009-03-05T01:07:11Z","isPatch":true,"sender":{"key":"mr.gaffo@gmail.com","avatar":"https://gravatar.com/avatar/5af46a60cbd83f2ddb0c2cf4d02b91db42fd25e2ac568ff0d71f699d852ee79d?d=mp&s=160"},"body":"Currently git over http only works with a .netrc file which required that you store your password on the file system in plaintext. This commit adds to configuration options for http for a username and an optional password. If a http.username is set, then the .netrc file is ignored and the username is used instead. If a http.password is set, then that is used as well, otherwise the user is prompted for their password.\n\nWith the old .netrc working, this patch provides backwards compatibility while adding a more secure option for users whose http password may be sensitive (such as if its a domain controller password) and do not wish to have it on the filesystem.\n\nSigned-off-by: Mike Gaffney <mike@uberu.com>\n---\n Documentation/config.txt                           |    7 +++\n Documentation/howto/setup-git-server-over-http.txt |   38 ++++++++++++++++--\n http.c                                             |   41 ++++++++++++++++++-\n http.h                                             |    2 +\n 4 files changed, 81 insertions(+), 7 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex f5152c5..821bf48 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -920,6 +920,13 @@ help.autocorrect::\n \tvalue is 0 - the command will be just shown but not executed.\n \tThis is the default.\n \n+http.username, http.password:\n+    The username and password for http authentication. http.username is\n+    required, http.password is optional. If supplied, the .netrc file will\n+    be ignored. If a password is not supplied, git will prompt for it.\n+    Be careful when configuring a password as it will be stored in plain text\n+    on the filesystem.\n+\n http.proxy::\n \tOverride the HTTP proxy, normally configured using the 'http_proxy'\n \tenvironment variable (see linkgit:curl[1]).  This can be overridden\ndiff --git a/Documentation/howto/setup-git-server-over-http.txt b/Documentation/howto/setup-git-server-over-http.txt\nindex 622ee5c..462a9d4 100644\n--- a/Documentation/howto/setup-git-server-over-http.txt\n+++ b/Documentation/howto/setup-git-server-over-http.txt\n@@ -189,8 +189,19 @@ Make sure that you have HTTP support, i.e. your git was built with\n libcurl (version more recent than 7.10). The command 'git http-push' with\n no argument should display a usage message.\n \n-Then, add the following to your $HOME/.netrc (you can do without, but will be\n-asked to input your password a _lot_ of times):\n+There are 2 ways to authenticate with git http, netrc and via the git config.\n+The netrc option requires that you put the username and password for the connection\n+in $HOME/.netrc. The configuration method allows you to specify a username and\n+optionally a password. If the password is not supplied then git will prompt you\n+for the password. The downside to the netrc method is that you must have your\n+username and password in plaintext on the filesystem, albeit in a protected file.\n+If the username/password combo is a sensitive one, you may wish to use the\n+git config method. The downside of the config method is that you will be prompted\n+for your password every time you push or pull to the remote repository.\n+\n+Using netrc:\n+\n+Using your favourite ext editor, add the following to your $HOME/.netrc:\n \n     machine <servername>\n     login <username>\n@@ -204,7 +215,7 @@ instead of the server name.\n \n To check whether all is OK, do:\n \n-   curl --netrc --location -v http://<username>@<servername>/my-new-repo.git/HEAD\n+   curl --netrc --location -v http://<servername>/my-new-repo.git/HEAD\n \n ...this should give something like 'ref: refs/heads/master', which is\n the content of the file HEAD on the server.\n@@ -213,12 +224,31 @@ Now, add the remote in your existing repository which contains the project\n you want to export:\n \n    $ git-config remote.upload.url \\\n-       http://<username>@<servername>/my-new-repo.git/\n+       http://<servername>/my-new-repo.git/\n \n It is important to put the last '/'; Without it, the server will send\n a redirect which git-http-push does not (yet) understand, and git-http-push\n will repeat the request infinitely.\n \n+Using git config:\n+\n+curl --user <username>:<password> --location -v http://<servername>/my-new-repo.git/HEAD\n+\n+...this should give something like 'ref: refs/heads/master', which is\n+the content of the file HEAD on the server.\n+\n+Now, add the remote in your existing repository which contains the project\n+you want to export:\n+\n+   $ git-config remote.upload.url \\\n+       http://<servername>/my-new-repo.git/\n+\n+Also, add in your username with:\n+   $ git-config http.username <username>\n+\n+And optionally your password (you will be prompted for it if you do not):\n+   $ git-config http.password <password>\n+\n \n Step 4: make the initial push\n -----------------------------\ndiff --git a/http.c b/http.c\nindex ee58799..348b9fb 100644\n--- a/http.c\n+++ b/http.c\n@@ -26,6 +26,9 @@ static long curl_low_speed_time = -1;\n static int curl_ftp_no_epsv = 0;\n static const char *curl_http_proxy = NULL;\n \n+static const char *curl_http_username = NULL;\n+static const char *curl_http_password = NULL;\n+\n static struct curl_slist *pragma_header;\n \n static struct active_request_slot *active_queue_head = NULL;\n@@ -153,11 +156,45 @@ static int http_options(const char *var, const char *value, void *cb)\n \t\t\treturn git_config_string(&curl_http_proxy, var, value);\n \t\treturn 0;\n \t}\n+\tif (!strcmp(\"http.username\", var)) {\n+\t\tif (curl_http_username == NULL)\n+\t\t{\n+\t\t\treturn git_config_string(&curl_http_username, var, value);\n+\t\t}\n+\t\treturn 0;\n+\t}\n+\tif (!strcmp(\"http.password\", var)) {\n+\t\tif (curl_http_password == NULL)\n+\t\t{\n+\t\t\treturn git_config_string(&curl_http_password, var, value);\n+\t\t}\n+\t\treturn 0;\n+\t}\n \n \t/* Fall back on the default ones */\n \treturn git_default_config(var, value, cb);\n }\n \n+static void init_curl_http_auth(CURL* result){\n+#if LIBCURL_VERSION_NUM >= 0x070907\n+        struct strbuf userpass;\n+        strbuf_init(&userpass, 0);\n+        if (curl_http_username != NULL) {\n+                strbuf_addstr(&userpass, curl_http_username);\n+\t\tstrbuf_addstr(&userpass, \":\");\n+\t\tif (curl_http_password != NULL) {\n+\t\t\tstrbuf_addstr(&userpass, curl_http_password);\n+\t\t} else {\n+\t\t\tstrbuf_addstr(&userpass, getpass(\"Password: \"));\n+\t\t}\n+\t\tcurl_easy_setopt(result, CURLOPT_USERPWD, userpass.buf);\n+\t\tcurl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_IGNORED);\n+        } else {\n+\t\tcurl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);\n+        }\n+#endif\n+}\n+\n static CURL* get_curl_handle(void)\n {\n \tCURL* result = curl_easy_init();\n@@ -172,9 +209,7 @@ static CURL* get_curl_handle(void)\n \t\tcurl_easy_setopt(result, CURLOPT_SSL_VERIFYHOST, 2);\n \t}\n \n-#if LIBCURL_VERSION_NUM >= 0x070907\n-\tcurl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);\n-#endif\n+        init_curl_http_auth(result);\n \n \tif (ssl_cert != NULL)\n \t\tcurl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert);\ndiff --git a/http.h b/http.h\nindex 905b462..71320d1 100644\n--- a/http.h\n+++ b/http.h\n@@ -5,6 +5,8 @@\n \n #include <curl/curl.h>\n #include <curl/easy.h>\n+#include <termios.h>\n+#include <stdio.h>\n \n #include \"strbuf.h\"\n #include \"remote.h\"\n-- \n1.6.1.2\n"},{"id":"107024","messageId":"7vd4cw4e40.fsf@gitster.siamese.dyndns.org","threadId":"18140","inReplyTo":"49AF25BF.5060706@gmail.com","subject":"Re: [PATCH] http authentication via prompts","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-03-05T07:34:39Z","receivedAt":"2009-03-05T07:34:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Mike Gaffney <mr.gaffo@gmail.com> writes:\n\n> Currently git over http only works with a .netrc file which required that you store your password on the file system in plaintext. This commit adds to configuration options for http for a username and an optional password. If a http.username is set, then the .netrc file is ignored and the username is used instead. If a http.password is set, then that is used as well, otherwise the user is prompted for their password.\n>\n> With the old .netrc working, this patch provides backwards compatibility while adding a more secure option for users whose http password may be sensitive (such as if its a domain controller password) and do not wish to have it on the filesystem.\n\nPlease wrap lines to readable length, such as under 72 cols.\n\n> diff --git a/Documentation/config.txt b/Documentation/config.txt\n> index f5152c5..821bf48 100644\n> --- a/Documentation/config.txt\n> +++ b/Documentation/config.txt\n> @@ -920,6 +920,13 @@ help.autocorrect::\n>  \tvalue is 0 - the command will be just shown but not executed.\n>  \tThis is the default.\n>  \n> +http.username, http.password:\n> +    The username and password for http authentication. http.username is\n> +    required, http.password is optional. If supplied, the .netrc file will\n> +    be ignored. If a password is not supplied, git will prompt for it.\n> +    Be careful when configuring a password as it will be stored in plain text\n> +    on the filesystem.\n> +\n>  http.proxy::\n\nList item ends with double colons; two headline items that are described\nwith the same description are listed each on its own line.  I.e.\n\n\thttp.username::\n        http.password::\n        \tThe username and ...\n\n> diff --git a/Documentation/howto/setup-git-server-over-http.txt b/Documentation/howto/setup-git-server-over-http.txt\n> index 622ee5c..462a9d4 100644\n> --- a/Documentation/howto/setup-git-server-over-http.txt\n> +++ b/Documentation/howto/setup-git-server-over-http.txt\n> @@ -189,8 +189,19 @@ Make sure that you have HTTP support, i.e. your git was built with\n>  libcurl (version more recent than 7.10). The command 'git http-push' with\n>  no argument should display a usage message.\n>  \n> -Then, add the following to your $HOME/.netrc (you can do without, but will be\n> -asked to input your password a _lot_ of times):\n> +There are 2 ways to authenticate with git http, netrc and via the git config.\n> +The netrc option requires that you put the username and password for the connection\n> +in $HOME/.netrc. The configuration method allows you to specify a username and\n> +optionally a password. If the password is not supplied then git will prompt you\n> +for the password. The downside to the netrc method is that you must have your\n> +username and password in plaintext on the filesystem, albeit in a protected file.\n> +If the username/password combo is a sensitive one, you may wish to use the\n> +git config method. The downside of the config method is that you will be prompted\n> +for your password every time you push or pull to the remote repository.\n\nThe contents look readable, but each line is a bit too long.\n\n> @@ -204,7 +215,7 @@ instead of the server name.\n>  \n>  To check whether all is OK, do:\n>  \n> -   curl --netrc --location -v http://<username>@<servername>/my-new-repo.git/HEAD\n> +   curl --netrc --location -v http://<servername>/my-new-repo.git/HEAD\n\nWhy?\n\n> @@ -213,12 +224,31 @@ Now, add the remote in your existing repository which contains the project\n>  you want to export:\n>  \n>     $ git-config remote.upload.url \\\n> -       http://<username>@<servername>/my-new-repo.git/\n> +       http://<servername>/my-new-repo.git/\n\nWhy?\n\n> +Using git config:\n\nThe bulk of text before this does not have a subtitle like this.  Perhaps\nyou would want to add one?  The presense of this subtitle makes it clear\nthat you are going to talk about _another_ way, but for first time readers\nit is unclear how that other way is different and what its advantages are.\n\nPerhaps drop this subtitle, and instead give one short paragraph, e.g.\n\n    Instead of storing your password in plaintext $HOME/.netrc file, you\n    can store only the username in the configuration file and have the\n    program prompt for a password.  Here is how.\n\nAlternatively keep the subtitle and explain what the subsection is about\nin a similar way.\n\nBut I think this section raises a bigger usability and user perception\nissue.\n\nWhen \"http://user@host/rest\" URL is given to your \"git push/fetch\",\nwithout .netrc nor http.username configuration, we allow the curl library\nto prompt for a password, and because we do not reuse the password (and\nreinstantiate the curl handle), we end up asking the user million times.\n\nBut from the end user's point of view, that's all implementation detail.\nIt does not explain why \"http://user@host/rest\" acts in a silly way, and\n\"http://host/rest\" with http.username configuration doesn't.\n\nPerhaps you instead inspect the URL and see if you have the \"user\" part\n(without password), and then:\n\n (1) transform the URL to http://host/rest\" before giving it to libcurl;\n     and\n\n (2) use your CURLOPT_USERPWD logic with your own getpass() call in\n     init_curl_http_auth()?\n\nThat way you do not have (even though you could) to introduce a new\nconfiguration, nor have a new section in the documentation.  It will be a\nstraightforward fix of the \"will be asked ... a lot of times\" bug you\nremoved from the documentation, no?\n\n> diff --git a/http.c b/http.c\n> index ee58799..348b9fb 100644\n> --- a/http.c\n> +++ b/http.c\n> @@ -26,6 +26,9 @@ static long curl_low_speed_time = -1;\n>  static int curl_ftp_no_epsv = 0;\n>  static const char *curl_http_proxy = NULL;\n>  \n> +static const char *curl_http_username = NULL;\n> +static const char *curl_http_password = NULL;\n> +\n\nPlease do not introduce new initializations of static variables to 0 or\nNULL.  As a clean-up, before your patch, you can send in a patch to fix\nexisting such initializations.\n\n> +static void init_curl_http_auth(CURL* result){\n> +#if LIBCURL_VERSION_NUM >= 0x070907\n> +        struct strbuf userpass;\n> +        strbuf_init(&userpass, 0);\n> +        if (curl_http_username != NULL) {\n> +                strbuf_addstr(&userpass, curl_http_username);\n> +\t\tstrbuf_addstr(&userpass, \":\");\n> +\t\tif (curl_http_password != NULL) {\n> +\t\t\tstrbuf_addstr(&userpass, curl_http_password);\n> +\t\t} else {\n> +\t\t\tstrbuf_addstr(&userpass, getpass(\"Password: \"));\n> +\t\t}\n> +\t\tcurl_easy_setopt(result, CURLOPT_USERPWD, userpass.buf);\n> +\t\tcurl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_IGNORED);\n\nWhy NETRC_IGNORED?\n\nOn CURLOPT_NETRC, http://curl.haxx.se/libcurl/c/curl_easy_setopt.html says \n\n\tlibcurl uses a user name (and supplied or prompted password)\n\tsupplied with CURLOPT_USERPWD in preference to any of the options\n\tcontrolled by this parameter.\n\nDoes it not work as advertised?\n\nIn short, I think what you did in init_curl_http_auth() makes a lot of\nsense except for the NETRC_IGNORED bit, but:\n\n (1) I think http.password configuration has the exact same \"plaintext\n     password in a read-protected file\" issue as .netrc; it is\n     unnecessary.\n\n (2) http.username is used by your patch primarily as a way to trigger the\n     new logic to call getpass() and use CURLOPT_USERPWD.  It would be a\n     lot nicer to inspect the URL to notice that there is a username part\n     in it and triggering the same codepath.  That would be a genuine\n     improvement (and you can even claim it is a bugfix).  And if that\n     works, the new configuration variable does not add much value (except\n     that different people involved in the same project can use the same\n     URL but their own (username, password) pair to access it.\n"},{"id":"107055","messageId":"alpine.DEB.1.00.0903051149280.6524@intel-tinevez-2-302","threadId":"18140","inReplyTo":"49AF25BF.5060706@gmail.com","subject":"Re: [PATCH] http authentication via prompts","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2009-03-05T10:55:37Z","receivedAt":"2009-03-05T10:55:37Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nDisclaimer: if you are offended by constructive criticism, or likely to \nanswer with insults to the comments I offer, please stop reading this mail \nnow (and please do not answer my mail, either). :-)\n\nStill with me?  Good.  Nice to meet you.\n\nJust for the record: responding to a patch is my strongest way of saying \nthat I appreciate your work.\n\nOn Wed, 4 Mar 2009, Mike Gaffney wrote:\n\n> Currently git over http only works with a .netrc file which required \n> that you store your password on the file system in plaintext. This \n> commit adds to configuration options for http for a username and an \n> optional password. If a http.username is set, then the .netrc file is \n> ignored and the username is used instead. If a http.password is set, \n> then that is used as well, otherwise the user is prompted for their \n> password.\n\n>From the subject, I would have expected a way to type in the password \ninstead of storing it.  (Think getpass()... which would pose problems \nwith Windows support, of course.)\n\nFWIW by having it in .git/config (which is most likely more world-readable \nthan $HOME/.netrc ever will be) does not provide any security over .netrc.\n\nAnd I doubt that http.username is a good choice: what if you have multiple \nhttp:// URLs with different usernames/passwords?  So would it not make \nmore sense to make this remote.<name>.user and ...password?\n\nCiao,\nDscho\n"},{"id":"107071","messageId":"49AFEC91.10009@gmail.com","threadId":"18140","inReplyTo":"alpine.DEB.1.00.0903051149280.6524@intel-tinevez-2-302","subject":"Re: [PATCH] http authentication via prompts","fromName":"Mike Gaffney","fromEmail":"mr.gaffo@gmail.com","sentAt":"2009-03-05T15:15:29Z","receivedAt":"2009-03-05T15:15:29Z","isPatch":true,"sender":{"key":"mr.gaffo@gmail.com","avatar":"https://gravatar.com/avatar/5af46a60cbd83f2ddb0c2cf4d02b91db42fd25e2ac568ff0d71f699d852ee79d?d=mp&s=160"},"body":"My thought was that if you had a password you didn't care about you could put it in the config.\nIt does ask you for a password with getpass, It compiles under cygwin, I havent tried it under\nwindows. However the man page for getpass shows the source so coding up getpass directly isn't a\nbig deal.\n\nJunio, I'm new to this patch game and using Thunderbird. What's the best way\nto wrap the patch?\n\n-Mike\n\nJohannes Schindelin wrote:\n> Hi,\n> \n> Disclaimer: if you are offended by constructive criticism, or likely to \n> answer with insults to the comments I offer, please stop reading this mail \n> now (and please do not answer my mail, either). :-)\n> \n> Still with me?  Good.  Nice to meet you.\n> \n> Just for the record: responding to a patch is my strongest way of saying \n> that I appreciate your work.\n> \n> On Wed, 4 Mar 2009, Mike Gaffney wrote:\n> \n>> Currently git over http only works with a .netrc file which required \n>> that you store your password on the file system in plaintext. This \n>> commit adds to configuration options for http for a username and an \n>> optional password. If a http.username is set, then the .netrc file is \n>> ignored and the username is used instead. If a http.password is set, \n>> then that is used as well, otherwise the user is prompted for their \n>> password.\n> \n> From the subject, I would have expected a way to type in the password \n> instead of storing it.  (Think getpass()... which would pose problems \n> with Windows support, of course.)\n> \n> FWIW by having it in .git/config (which is most likely more world-readable \n> than $HOME/.netrc ever will be) does not provide any security over .netrc.\n> \n> And I doubt that http.username is a good choice: what if you have multiple \n> http:// URLs with different usernames/passwords?  So would it not make \n> more sense to make this remote.<name>.user and ...password?\n> \n> Ciao,\n> Dscho\n\n-- \n-Mike Gaffney (http://rdocul.us)\n"},{"id":"107078","messageId":"20090305163740.GC4213@coredump.intra.peff.net","threadId":"18140","inReplyTo":"49AFEC91.10009@gmail.com","subject":"Re: [PATCH] http authentication via prompts","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-03-05T16:37:40Z","receivedAt":"2009-03-05T16:37:40Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Mar 05, 2009 at 09:15:29AM -0600, Mike Gaffney wrote:\n\n> My thought was that if you had a password you didn't care about you\n> could put it in the config.  It does ask you for a password with\n> getpass, It compiles under cygwin, I havent tried it under windows.\n\nI think part of the confusion is that your patch does two things, which\nmeans it is probably more sensible as two separate patches:\n\n  1. support http.username and http.password in the git config instead\n     of the .netrc\n\n  2. support getpass() if http.password (or .netrc password) is not\n     available\n\n-Peff\n"},{"id":"107251","messageId":"20090306225213.GH5204@frsk.net","threadId":"18140","inReplyTo":"49AFEC91.10009@gmail.com","subject":"Re: [PATCH] http authentication via prompts","fromName":"Fredrik Skolmli","fromEmail":"fredrik@frsk.net","sentAt":"2009-03-06T22:52:13Z","receivedAt":"2009-03-06T22:52:13Z","isPatch":true,"sender":{"key":"fredrik@frsk.net","avatar":"https://avatars.githubusercontent.com/u/40261?v=4"},"body":"On Thu, Mar 05, 2009 at 09:15:29AM -0600, Mike Gaffney wrote:\n\nHi.\n \n> Junio, I'm new to this patch game and using Thunderbird. What's the best way\n> to wrap the patch?\n\nI'm not Junio, but I'll give answering a shot anyway. ;-)\n\nSee Documentation/SubmittingPatches, line 374-456.\n\n-- \nFredrik Skolmli\n"}]}