{"thread":{"id":"57877","subject":"[RFC PATCH 3/3] Allow empty user name in HTTP authentication","startedAt":"2022-05-13T07:13:02Z","lastAt":"2022-05-14T01:51:38Z","messageCount":7,"participants":["simon.richter@hogyros.de","Junio C Hamano","brian m. carlson"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"455255","messageId":"20220513070416.37235-4-Simon.Richter@hogyros.de","threadId":"57877","inReplyTo":"20220513070416.37235-1-Simon.Richter@hogyros.de","subject":"[RFC PATCH 3/3] Allow empty user name in HTTP authentication","fromName":"","fromEmail":"simon.richter@hogyros.de","sentAt":"2022-05-13T07:04:16Z","receivedAt":"2022-05-13T07:13:02Z","isPatch":true,"sender":{"key":"simon.richter@hogyros.de","avatar":"https://gravatar.com/avatar/1192aa9fa5dd19ce258b12b044cc27111dd7cdb58d920dc2123a02a24f55b5c5?d=mp&s=160"},"body":"From: Simon Richter <Simon.Richter@hogyros.de>\n\nWhen using a Personal Access Token in Microsoft DevOps server, the username\ncan be empty, so users might expect that pressing return on an username\nprompt will work.\n---\n http.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/http.c b/http.c\nindex c5af90b1b8..dc71fb75ea 100644\n--- a/http.c\n+++ b/http.c\n@@ -433,7 +433,7 @@ static int curl_empty_auth_enabled(void)\n \n static void init_curl_http_auth(CURL *result)\n {\n-\tif (!http_auth.username || !*http_auth.username) {\n+\tif (!http_auth.username) {\n \t\tif (curl_empty_auth_enabled())\n \t\t\tcurl_easy_setopt(result, CURLOPT_USERPWD, \":\");\n \t\treturn;\n-- \n2.30.2\n\n"},{"id":"455256","messageId":"20220513070416.37235-2-Simon.Richter@hogyros.de","threadId":"57877","inReplyTo":"20220513070416.37235-1-Simon.Richter@hogyros.de","subject":"[PATCH 1/3] Rename proxy_authmethods -> authmethods","fromName":"","fromEmail":"simon.richter@hogyros.de","sentAt":"2022-05-13T07:04:14Z","receivedAt":"2022-05-13T07:13:05Z","isPatch":true,"sender":{"key":"simon.richter@hogyros.de","avatar":"https://gravatar.com/avatar/1192aa9fa5dd19ce258b12b044cc27111dd7cdb58d920dc2123a02a24f55b5c5?d=mp&s=160"},"body":"From: Simon Richter <Simon.Richter@hogyros.de>\n\nCurl also allows specifying a list of acceptable auth methods for the\nrequest itself, so this isn't specific to proxy authentication.\n\nSigned-off-by: Simon Richter <Simon.Richter@hogyros.de>\n---\n http.c | 10 +++++-----\n 1 file changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/http.c b/http.c\nindex 229da4d148..318dc5daea 100644\n--- a/http.c\n+++ b/http.c\n@@ -79,7 +79,7 @@ static int proxy_ssl_cert_password_required;\n static struct {\n \tconst char *name;\n \tlong curlauth_param;\n-} proxy_authmethods[] = {\n+} authmethods[] = {\n \t{ \"basic\", CURLAUTH_BASIC },\n \t{ \"digest\", CURLAUTH_DIGEST },\n \t{ \"negotiate\", CURLAUTH_GSSNEGOTIATE },\n@@ -470,14 +470,14 @@ static void init_curl_proxy_auth(CURL *result)\n \n \tif (http_proxy_authmethod) {\n \t\tint i;\n-\t\tfor (i = 0; i < ARRAY_SIZE(proxy_authmethods); i++) {\n-\t\t\tif (!strcmp(http_proxy_authmethod, proxy_authmethods[i].name)) {\n+\t\tfor (i = 0; i < ARRAY_SIZE(authmethods); i++) {\n+\t\t\tif (!strcmp(http_proxy_authmethod, authmethods[i].name)) {\n \t\t\t\tcurl_easy_setopt(result, CURLOPT_PROXYAUTH,\n-\t\t\t\t\t\tproxy_authmethods[i].curlauth_param);\n+\t\t\t\t\t\tauthmethods[i].curlauth_param);\n \t\t\t\tbreak;\n \t\t\t}\n \t\t}\n-\t\tif (i == ARRAY_SIZE(proxy_authmethods)) {\n+\t\tif (i == ARRAY_SIZE(authmethods)) {\n \t\t\twarning(\"unsupported proxy authentication method %s: using anyauth\",\n \t\t\t\t\thttp_proxy_authmethod);\n \t\t\tcurl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);\n-- \n2.30.2\n\n"},{"id":"455257","messageId":"20220513070416.37235-1-Simon.Richter@hogyros.de","threadId":"57877","inReplyTo":null,"subject":"[PATCH 0/3] Allow configuration of HTTP authentication method","fromName":"","fromEmail":"simon.richter@hogyros.de","sentAt":"2022-05-13T07:04:13Z","receivedAt":"2022-05-13T07:13:09Z","isPatch":true,"sender":{"key":"simon.richter@hogyros.de","avatar":"https://gravatar.com/avatar/1192aa9fa5dd19ce258b12b044cc27111dd7cdb58d920dc2123a02a24f55b5c5?d=mp&s=160"},"body":"From: Simon Richter <Simon.Richter@hogyros.de>\n\nHi,\n\nthis adds a configuration option to set the authentication method curl uses\nwhen authenticating to a server.\n\nThe method is always configured, not just when a username is set, to allow\nfailing early if the server does not support the selected method;\notherwise, this mechanism is orthogonal to the proxy authentication method\nhandling, and I've liberally copied code from there.\n\nThis introduces http.authmethod and remote.<name>.authmethod configuration\noptions and an environment variable GIT_HTTP_AUTHMETHOD, with ascending\nprecedence.\n\nThere are three patches in this series, one that just renames a constant\nlist of options as it is used outside the proxy configuration scope now,\none that contains the main patch, and one I'm unsure about (hence no\nSigned-Off-By yet) that allows empty user names during authentication.\n\nThe latter avoids surprises when people half-follow Microsoft's\ndocumentation, which suggests that users configure a custom header\ncontaining a hand-crafted Basic authentication string with an empty user\nname. This is not strictly required by the \"DevOps\" server, any string will\ndo here, but simply pressing return on the username prompt will otherwise\nfail to present the credentials at all, and give an error message\nindicating that the given token is invalid.\n\nI haven't investigated fully whether this is of any use outside the\ninteractive case, so the third patch is more of a request for comments.\n\nWith these changes, I can successfully authenticate to MS DevOps server\nover HTTP using a Personal Access Token, without using the custom header\nworkaround[1], which allows me to use git-lfs (which in turn doesn't work\nover ssh) from Jenkins with a limited token that is stored in the Jenkins\ncredential store, solving a problem for approximately tens of users[2].\n\n   Simon\n\n[1] https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows#use-a-pat\n\n[2] https://stackoverflow.com/q/64800010\n\nSimon Richter (3):\n  Rename proxy_authmethods -> authmethods\n  Add config option/env var to limit HTTP auth methods\n  Allow empty user name in HTTP authentication\n\n Documentation/config/http.txt   | 19 ++++++++++++++\n Documentation/config/remote.txt |  4 +++\n http.c                          | 45 ++++++++++++++++++++++++++++-----\n remote.c                        |  4 +++\n remote.h                        |  3 +++\n 5 files changed, 68 insertions(+), 7 deletions(-)\n\n-- \n2.30.2\n\n"},{"id":"455258","messageId":"20220513070416.37235-3-Simon.Richter@hogyros.de","threadId":"57877","inReplyTo":"20220513070416.37235-1-Simon.Richter@hogyros.de","subject":"[PATCH 2/3] Add config option/env var to limit HTTP auth methods","fromName":"","fromEmail":"simon.richter@hogyros.de","sentAt":"2022-05-13T07:04:15Z","receivedAt":"2022-05-13T07:13:14Z","isPatch":true,"sender":{"key":"simon.richter@hogyros.de","avatar":"https://gravatar.com/avatar/1192aa9fa5dd19ce258b12b044cc27111dd7cdb58d920dc2123a02a24f55b5c5?d=mp&s=160"},"body":"From: Simon Richter <Simon.Richter@hogyros.de>\n\nThis allows forcing an authentication mechanism when the available\ncredentials do not match the automatically selected \"best\" mechanism.\n\nFor example, MS DevOps server supports both NTLM and Basic authentication,\nbut the NTLM backend is connected to the user database only and does not\naccept Personal Access Tokens; curl however selects NTLM over Basic if both\nare available.\n\nSigned-off-by: Simon Richter <Simon.Richter@hogyros.de>\n---\n Documentation/config/http.txt   | 19 +++++++++++++++++++\n Documentation/config/remote.txt |  4 ++++\n http.c                          | 33 ++++++++++++++++++++++++++++++++-\n remote.c                        |  4 ++++\n remote.h                        |  3 +++\n 5 files changed, 62 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/config/http.txt b/Documentation/config/http.txt\nindex 7003661c0d..d9875afa4d 100644\n--- a/Documentation/config/http.txt\n+++ b/Documentation/config/http.txt\n@@ -1,3 +1,22 @@\n+http.authMethod::\n+\tSet the method with which to authenticate to the HTTP server, if\n+\trequired. This can be overridden on a per-remote basis; see\n+\t`remote.<name>.authMethod`. Both can be overridden by the\n+\t`GIT_HTTP_AUTHMETHOD` environment variable.  Possible values are:\n++\n+--\n+* `anyauth` - Automatically pick a suitable authentication method. It is\n+  assumed that the server answers an unauthenticated request with a 401\n+  status code and one or more WWW-Authenticate headers with supported\n+  authentication methods. This is the default.\n+* `basic` - HTTP Basic authentication\n+* `digest` - HTTP Digest authentication; this prevents the password from being\n+  transmitted to the server in clear text\n+* `negotiate` - GSS-Negotiate authentication (compare the --negotiate option\n+  of `curl(1)`)\n+* `ntlm` - NTLM authentication (compare the --ntlm option of `curl(1)`)\n+--\n+\n http.proxy::\n \tOverride the HTTP proxy, normally configured using the 'http_proxy',\n \t'https_proxy', and 'all_proxy' environment variables (see `curl(1)`). In\ndiff --git a/Documentation/config/remote.txt b/Documentation/config/remote.txt\nindex 0678b4bcfe..0f87234427 100644\n--- a/Documentation/config/remote.txt\n+++ b/Documentation/config/remote.txt\n@@ -10,6 +10,10 @@ remote.<name>.url::\n remote.<name>.pushurl::\n \tThe push URL of a remote repository.  See linkgit:git-push[1].\n \n+remote.<name>.authMethod::\n+\tFor http and https remotes, the method to use for\n+\tauthenticating against the server. See `http.authMethod`.\n+\n remote.<name>.proxy::\n \tFor remotes that require curl (http, https and ftp), the URL to\n \tthe proxy to use for that remote.  Set to the empty string to\ndiff --git a/http.c b/http.c\nindex 318dc5daea..c5af90b1b8 100644\n--- a/http.c\n+++ b/http.c\n@@ -108,6 +108,7 @@ static const char *curl_proxyuserpwd;\n static const char *curl_cookie_file;\n static int curl_save_cookies;\n struct credential http_auth = CREDENTIAL_INIT;\n+static const char *http_authmethod;\n static int http_proactive_auth;\n static const char *user_agent;\n static int curl_empty_auth = -1;\n@@ -356,6 +357,9 @@ static int http_options(const char *var, const char *value, void *cb)\n \tif (!strcmp(\"http.useragent\", var))\n \t\treturn git_config_string(&user_agent, var, value);\n \n+\tif (!strcmp(\"http.authmethod\", var))\n+\t\treturn git_config_string(&http_authmethod, var, value);\n+\n \tif (!strcmp(\"http.emptyauth\", var)) {\n \t\tif (value && !strcmp(\"auto\", value))\n \t\t\tcurl_empty_auth = -1;\n@@ -450,6 +454,27 @@ static void var_override(const char **var, char *value)\n \t}\n }\n \n+static void init_curl_http_auth_method(CURL *result)\n+{\n+\tvar_override(&http_authmethod, getenv(\"GIT_HTTP_AUTHMETHOD\"));\n+\n+\tif (http_authmethod) {\n+\t\tint i;\n+\t\tfor (i = 0; i < ARRAY_SIZE(authmethods); i++) {\n+\t\t\tif (!strcmp(http_authmethod, authmethods[i].name)) {\n+\t\t\t\thttp_auth_methods = authmethods[i].curlauth_param;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t\tif (i == ARRAY_SIZE(authmethods)) {\n+\t\t\twarning(\"unsupported authentication method %s: using anyauth\",\n+\t\t\t\t\thttp_authmethod);\n+\t\t\thttp_auth_methods = CURLAUTH_ANY;\n+\t\t}\n+\t}\n+\tcurl_easy_setopt(result, CURLOPT_HTTPAUTH, http_auth_methods);\n+}\n+\n static void set_proxyauth_name_password(CURL *result)\n {\n \t\tcurl_easy_setopt(result, CURLOPT_PROXYUSERNAME,\n@@ -786,7 +811,7 @@ static CURL *get_curl_handle(void)\n #endif\n \n \tcurl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);\n-\tcurl_easy_setopt(result, CURLOPT_HTTPAUTH, CURLAUTH_ANY);\n+\tinit_curl_http_auth_method(result);\n \n #ifdef CURLGSSAPI_DELEGATION_FLAG\n \tif (curl_deleg) {\n@@ -1040,6 +1065,9 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)\n \tif (remote && remote->http_proxy)\n \t\tcurl_http_proxy = xstrdup(remote->http_proxy);\n \n+\tif (remote)\n+\t\tvar_override(&http_authmethod, remote->http_authmethod);\n+\n \tif (remote)\n \t\tvar_override(&http_proxy_authmethod, remote->http_proxy_authmethod);\n \n@@ -1504,6 +1532,9 @@ static int handle_curl_result(struct slot_results *results)\n \t\t\tif (results->auth_avail) {\n \t\t\t\thttp_auth_methods &= results->auth_avail;\n \t\t\t\thttp_auth_methods_restricted = 1;\n+\t\t\t\t/* fail if no methods left */\n+\t\t\t\tif(http_auth_methods == 0)\n+\t\t\t\t\treturn HTTP_NOAUTH;\n \t\t\t}\n \t\t\treturn HTTP_REAUTH;\n \t\t}\ndiff --git a/remote.c b/remote.c\nindex 42a4e7106e..dca7b82c9f 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -155,6 +155,7 @@ static void remote_clear(struct remote *remote)\n \tFREE_AND_NULL(remote->pushurl);\n \tfree((char *)remote->receivepack);\n \tfree((char *)remote->uploadpack);\n+\tFREE_AND_NULL(remote->http_authmethod);\n \tFREE_AND_NULL(remote->http_proxy);\n \tFREE_AND_NULL(remote->http_proxy_authmethod);\n }\n@@ -461,6 +462,9 @@ static int handle_config(const char *key, const char *value, void *cb)\n \t\t\tremote->fetch_tags = -1;\n \t\telse if (!strcmp(value, \"--tags\"))\n \t\t\tremote->fetch_tags = 2;\n+\t} else if (!strcmp(subkey, \"authmethod\")) {\n+\t\treturn git_config_string((const char **)&remote->http_authmethod,\n+\t\t\t\t\t key, value);\n \t} else if (!strcmp(subkey, \"proxy\")) {\n \t\treturn git_config_string((const char **)&remote->http_proxy,\n \t\t\t\t\t key, value);\ndiff --git a/remote.h b/remote.h\nindex 4a1209ae2c..c063d30356 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -105,6 +105,9 @@ struct remote {\n \tconst char *receivepack;\n \tconst char *uploadpack;\n \n+\t/* The method for authenticating against the (HTTP) server */\n+\tchar *http_authmethod;\n+\n \t/* The proxy to use for curl (http, https, ftp, etc.) URLs. */\n \tchar *http_proxy;\n \n-- \n2.30.2\n\n"},{"id":"455273","messageId":"xmqq7d6p9pq0.fsf@gitster.g","threadId":"57877","inReplyTo":"20220513070416.37235-2-Simon.Richter@hogyros.de","subject":"Re: [PATCH 1/3] Rename proxy_authmethods -> authmethods","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-13T19:50:31Z","receivedAt":"2022-05-13T19:50:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Simon.Richter@hogyros.de writes:\n\n> From: Simon Richter <Simon.Richter@hogyros.de>\n>\n> Curl also allows specifying a list of acceptable auth methods for the\n> request itself, so this isn't specific to proxy authentication.\n\nWhile that is true, given that it is ONLY used to sanity check the\nhttp_proxy_authmethod variable and use CURLOPT_PROXYAUTH thing, the\nabove alone is not a good excuse to rename this array.\n\nI haven't read the later patches, but I would imagine that this is\nso that you'd create another consumer that is about authentication\nmethod that is not for the proxyauth.  And if that is the case, the\nproposed log message for this change should explicitly say so to\njustify this change.\n\n    We are about to reuse this table of authmethods to parse the\n    non-proxy authentication in a later step in this series.  Let's\n    rename it to just \"authmethod[]\".\n\nappended as the second paragraph after the above might be sufficient.\n\nTwo things that comes to mind:\n\n * In general, an array whose elements are accessed individually is\n   better named in singular, i.e. \"type thing[]\", not \"type\n   things[]\" (an exception is when the most prevalent use of the\n   array is to pass it as a whole to functions as a bag of things,\n   instead of accessing individual element).  This is because it is\n   more natural to see the zeroth thing to be spelled \"thing[0]\",\n   and not \"things[0]\".  If we are renaming this array anyway, it\n   may make sense to rename it to authmethod[].\n\n * If the reason why this rename is warranted is because there will\n   be another user of this table that maps a string name to its\n   corresponding CURLAUTH_* constant, it would probably make sense\n   to extract a helper function out of this loop to do just that,\n   something along the lines of ...\n\n   static int parse_authmethod(const char *name, long *auth_param)\n   {\n       int i;\n\n       for (i = 0; i < ARRAY_SIZE(authmethod); i++)\n           if (!strcmp(name, authmethod[i].name)) {\n\t\t*auth_param = authmethod[i].curlauth_param;\n                return i;\n           }\n       return -1;\n   }\n\n   Then the existing code can become\n\n   if (http_proxy_authmethod) {\n        long auth_param;\n\n\tif (parse_authmethod(http_proxy_authmethod, &auth_param) < 0) {\n\t    warning(\"unsupported ... %s: using anyauth\", http_proxy_authmethod);\n            auth_param = CURLAUTH_ANY;\n\t}\n\tcurl_easy_setopt(result, CURLOPT_PROXYAUTH, auth_param);\n   }\n\n   It is probably OK to do so in the same patch as renaming of the\n   table, but the focus of the step will then become \"factor out\n   parsing of authmethod from string to CURLAUTH_* constants\" and\n   the patch should be retitled accordingly.  Then you do not have\n   to justify the rename of the table based on the future plan.\n\n> Subject: Re: [PATCH 1/3] Rename proxy_authmethods -> authmethods\n\nThe title of a patch in this project follows certain convention.\ncf. Documentation/SubmittingPatches.\n\n    Subject: [PATCH 1/n] http: factor out parsing of authmethod\n\n    In order to support CURLOPT_PROXYAUTH, there is a code to parse\n    the name of an authentication method given as a string into one\n    of the CURLAUTH_* constant.  The next step of this series wants\n    to reuse the same parser to support CURLOPT_HTTPAUTH in a\n    similar way.\n\n    Factor out the loop into a separate helper function.  Since the\n    table of authentication methods no longer is only for proxy\n    authentication, drop \"proxy\" prefix from its name while we are\n    at it.\n\nor something like that, perhaps.\n\n> Signed-off-by: Simon Richter <Simon.Richter@hogyros.de>\n> ---\n>  http.c | 10 +++++-----\n>  1 file changed, 5 insertions(+), 5 deletions(-)\n>\n> diff --git a/http.c b/http.c\n> index 229da4d148..318dc5daea 100644\n> --- a/http.c\n> +++ b/http.c\n> @@ -79,7 +79,7 @@ static int proxy_ssl_cert_password_required;\n>  static struct {\n>  \tconst char *name;\n>  \tlong curlauth_param;\n> -} proxy_authmethods[] = {\n> +} authmethods[] = {\n>  \t{ \"basic\", CURLAUTH_BASIC },\n>  \t{ \"digest\", CURLAUTH_DIGEST },\n>  \t{ \"negotiate\", CURLAUTH_GSSNEGOTIATE },\n> @@ -470,14 +470,14 @@ static void init_curl_proxy_auth(CURL *result)\n>  \n>  \tif (http_proxy_authmethod) {\n>  \t\tint i;\n> -\t\tfor (i = 0; i < ARRAY_SIZE(proxy_authmethods); i++) {\n> -\t\t\tif (!strcmp(http_proxy_authmethod, proxy_authmethods[i].name)) {\n> +\t\tfor (i = 0; i < ARRAY_SIZE(authmethods); i++) {\n> +\t\t\tif (!strcmp(http_proxy_authmethod, authmethods[i].name)) {\n>  \t\t\t\tcurl_easy_setopt(result, CURLOPT_PROXYAUTH,\n> -\t\t\t\t\t\tproxy_authmethods[i].curlauth_param);\n> +\t\t\t\t\t\tauthmethods[i].curlauth_param);\n>  \t\t\t\tbreak;\n>  \t\t\t}\n>  \t\t}\n> -\t\tif (i == ARRAY_SIZE(proxy_authmethods)) {\n> +\t\tif (i == ARRAY_SIZE(authmethods)) {\n>  \t\t\twarning(\"unsupported proxy authentication method %s: using anyauth\",\n>  \t\t\t\t\thttp_proxy_authmethod);\n>  \t\t\tcurl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);\n"},{"id":"455275","messageId":"xmqqzgjl89i6.fsf@gitster.g","threadId":"57877","inReplyTo":"20220513070416.37235-3-Simon.Richter@hogyros.de","subject":"Re: [PATCH 2/3] Add config option/env var to limit HTTP auth methods","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-13T20:26:09Z","receivedAt":"2022-05-13T20:26:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Simon.Richter@hogyros.de writes:\n\n> +http.authMethod::\n> +\tSet the method with which to authenticate to the HTTP server, if\n> +\trequired. This can be overridden on a per-remote basis; see\n> +\t`remote.<name>.authMethod`. Both can be overridden by the\n> +\t`GIT_HTTP_AUTHMETHOD` environment variable.  Possible values are:\n> ++\n> +--\n> +* `anyauth` - Automatically pick a suitable authentication method. It is\n> +  assumed that the server answers an unauthenticated request with a 401\n> +  status code and one or more WWW-Authenticate headers with supported\n> +  authentication methods. This is the default.\n> +* `basic` - HTTP Basic authentication\n> +* `digest` - HTTP Digest authentication; this prevents the password from being\n> +  transmitted to the server in clear text\n> +* `negotiate` - GSS-Negotiate authentication (compare the --negotiate option\n> +  of `curl(1)`)\n> +* `ntlm` - NTLM authentication (compare the --ntlm option of `curl(1)`)\n> +--\n\nThe above makes sense.\n\nConfiguring this variable per URL, just like all other variables in\n\"http.*\" namespace, we should be able to use the \"http.<url>.*\"\nmechanism that the users are already familiar with.\n\n> diff --git a/Documentation/config/remote.txt b/Documentation/config/remote.txt\n> index 0678b4bcfe..0f87234427 100644\n> --- a/Documentation/config/remote.txt\n> +++ b/Documentation/config/remote.txt\n> @@ -10,6 +10,10 @@ remote.<name>.url::\n>  remote.<name>.pushurl::\n>  \tThe push URL of a remote repository.  See linkgit:git-push[1].\n>  \n> +remote.<name>.authMethod::\n> +\tFor http and https remotes, the method to use for\n> +\tauthenticating against the server. See `http.authMethod`.\n\nIOW, this looks out of place.\n"},{"id":"455280","messageId":"Yn7vCg6Rl7TYRw82@camp.crustytoothpaste.net","threadId":"57877","inReplyTo":"20220513070416.37235-4-Simon.Richter@hogyros.de","subject":"Re: [RFC PATCH 3/3] Allow empty user name in HTTP authentication","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2022-05-13T23:51:38Z","receivedAt":"2022-05-14T01:51:38Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"On 2022-05-13 at 07:04:16, Simon.Richter@hogyros.de wrote:\n> From: Simon Richter <Simon.Richter@hogyros.de>\n> \n> When using a Personal Access Token in Microsoft DevOps server, the username\n> can be empty, so users might expect that pressing return on an username\n> prompt will work.\n\nI don't think this is a good idea.  libcurl relies on CURLOPT_USERPWD\nbeing set to enable authentication, and before the appearance of\nhttp.emptyAuth, it was extremely common for Kerberos users to specify an\nempty username to get Git to authenticate properly.  I probably still\nhave some repositories on my system configured that way.\n\nI believe GitHub can also accept an empty username with a PAT, but it\ncan also accept a dummy (e.g., \"token\"), which I would hope Azure DevOps\ncan do as well.  In such a case, the documentation for Azure DevOps\nshould just be updated to tell people to specify something like \"token\"\nor their username.\n-- \nbrian m. carlson (he/him or they/them)\nToronto, Ontario, CA\n"}]}