Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.kernel.org/pub/scm/git/git.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/config/fetch.txt14
-rw-r--r--remote.c48
-rwxr-xr-xt/t5516-fetch-push.sh32
-rwxr-xr-xt/t5601-clone.sh23
4 files changed, 117 insertions, 0 deletions
diff --git a/Documentation/config/fetch.txt b/Documentation/config/fetch.txt
index cd65d236b4..0db7fe85bb 100644
--- a/Documentation/config/fetch.txt
+++ b/Documentation/config/fetch.txt
@@ -96,3 +96,17 @@ fetch.writeCommitGraph::
merge and the write may take longer. Having an updated commit-graph
file helps performance of many Git commands, including `git merge-base`,
`git push -f`, and `git log --graph`. Defaults to false.
+
+fetch.credentialsInUrl::
+ A URL can contain plaintext credentials in the form
+ `<protocol>://<user>:<password>@<domain>/<path>`. Using such URLs
+ is not recommended as it exposes the password in multiple ways,
+ including Git storing the URL as plaintext in the repository config.
+ The `fetch.credentialsInUrl` option provides instruction for how Git
+ should react to seeing such a URL, with these values:
++
+* `allow` (default): Git will proceed with its activity without warning.
+* `warn`: Git will write a warning message to `stderr` when parsing a URL
+ with a plaintext credential.
+* `die`: Git will write a failure message to `stderr` when parsing a URL
+ with a plaintext credential.
diff --git a/remote.c b/remote.c
index 404e1e0a0d..5824b08eb5 100644
--- a/remote.c
+++ b/remote.c
@@ -1,6 +1,7 @@
#include "cache.h"
#include "config.h"
#include "remote.h"
+#include "urlmatch.h"
#include "refs.h"
#include "refspec.h"
#include "object-store.h"
@@ -617,6 +618,50 @@ const char *remote_ref_for_branch(struct branch *branch, int for_push)
return NULL;
}
+static void validate_remote_url(struct remote *remote)
+{
+ int i;
+ const char *value;
+ struct strbuf redacted = STRBUF_INIT;
+ int warn_not_die;
+
+ if (git_config_get_string_tmp("fetch.credentialsinurl", &value))
+ return;
+
+ if (!strcmp("warn", value))
+ warn_not_die = 1;
+ else if (!strcmp("die", value))
+ warn_not_die = 0;
+ else if (!strcmp("allow", value))
+ return;
+ else
+ die(_("unrecognized value fetch.credentialsInURL: '%s'"), value);
+
+ for (i = 0; i < remote->url_nr; i++) {
+ struct url_info url_info = { 0 };
+
+ if (!url_normalize(remote->url[i], &url_info) ||
+ !url_info.passwd_off)
+ goto loop_cleanup;
+
+ strbuf_reset(&redacted);
+ strbuf_add(&redacted, url_info.url, url_info.passwd_off);
+ strbuf_addstr(&redacted, "<redacted>");
+ strbuf_addstr(&redacted,
+ url_info.url + url_info.passwd_off + url_info.passwd_len);
+
+ if (warn_not_die)
+ warning(_("URL '%s' uses plaintext credentials"), redacted.buf);
+ else
+ die(_("URL '%s' uses plaintext credentials"), redacted.buf);
+
+loop_cleanup:
+ free(url_info.url);
+ }
+
+ strbuf_release(&redacted);
+}
+
static struct remote *
remotes_remote_get_1(struct remote_state *remote_state, const char *name,
const char *(*get_default)(struct remote_state *,
@@ -642,6 +687,9 @@ remotes_remote_get_1(struct remote_state *remote_state, const char *name,
add_url_alias(remote_state, ret, name);
if (!valid_remote(ret))
return NULL;
+
+ validate_remote_url(ret);
+
return ret;
}
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index e99c31f8c3..dedca106a7 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -12,6 +12,7 @@ This test checks the following functionality:
* --porcelain output format
* hiderefs
* reflogs
+* URL validation
'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
@@ -1833,4 +1834,35 @@ test_expect_success 'refuse to push a hidden ref, and make sure do not pollute t
test_dir_is_empty testrepo/.git/objects/pack
'
+test_expect_success 'fetch warns or fails when using username:password' '
+ message="URL '\''https://username:<redacted>@localhost/'\'' uses plaintext credentials" &&
+ test_must_fail git -c fetch.credentialsInUrl=allow fetch https://username:password@localhost 2>err &&
+ ! grep "$message" err &&
+
+ test_must_fail git -c fetch.credentialsInUrl=warn fetch https://username:password@localhost 2>err &&
+ grep "warning: $message" err >warnings &&
+ test_line_count = 3 warnings &&
+
+ test_must_fail git -c fetch.credentialsInUrl=die fetch https://username:password@localhost 2>err &&
+ grep "fatal: $message" err >warnings &&
+ test_line_count = 1 warnings &&
+
+ test_must_fail git -c fetch.credentialsInUrl=die fetch https://username:@localhost 2>err &&
+ grep "fatal: $message" err >warnings &&
+ test_line_count = 1 warnings
+'
+
+
+test_expect_success 'push warns or fails when using username:password' '
+ message="URL '\''https://username:<redacted>@localhost/'\'' uses plaintext credentials" &&
+ test_must_fail git -c fetch.credentialsInUrl=allow push https://username:password@localhost 2>err &&
+ ! grep "$message" err &&
+
+ test_must_fail git -c fetch.credentialsInUrl=warn push https://username:password@localhost 2>err &&
+ grep "warning: $message" err >warnings &&
+ test_must_fail git -c fetch.credentialsInUrl=die push https://username:password@localhost 2>err &&
+ grep "fatal: $message" err >warnings &&
+ test_line_count = 1 warnings
+'
+
test_done
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 4a61f2c901..d2f046b4b9 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -71,6 +71,29 @@ test_expect_success 'clone respects GIT_WORK_TREE' '
'
+test_expect_success 'clone warns or fails when using username:password' '
+ message="URL '\''https://username:<redacted>@localhost/'\'' uses plaintext credentials" &&
+ test_must_fail git -c fetch.credentialsInUrl=allow clone https://username:password@localhost attempt1 2>err &&
+ ! grep "$message" err &&
+
+ test_must_fail git -c fetch.credentialsInUrl=warn clone https://username:password@localhost attempt2 2>err &&
+ grep "warning: $message" err >warnings &&
+ test_line_count = 2 warnings &&
+
+ test_must_fail git -c fetch.credentialsInUrl=die clone https://username:password@localhost attempt3 2>err &&
+ grep "fatal: $message" err >warnings &&
+ test_line_count = 1 warnings &&
+
+ test_must_fail git -c fetch.credentialsInUrl=die clone https://username:@localhost attempt3 2>err &&
+ grep "fatal: $message" err >warnings &&
+ test_line_count = 1 warnings
+'
+
+test_expect_success 'clone does not detect username:password when it is https://username@domain:port/' '
+ test_must_fail git -c fetch.credentialsInUrl=warn clone https://username@localhost:8080 attempt3 2>err &&
+ ! grep "uses plaintext credentials" err
+'
+
test_expect_success 'clone from hooks' '
test_create_repo r0 &&