2009-02-25 08:32:09 +00:00
|
|
|
#!/bin/sh
|
|
|
|
|
2009-10-31 00:47:47 +00:00
|
|
|
test_description='test dumb fetching over http via static file'
|
2020-11-18 23:44:34 +00:00
|
|
|
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
|
tests: mark tests relying on the current default for `init.defaultBranch`
In addition to the manual adjustment to let the `linux-gcc` CI job run
the test suite with `master` and then with `main`, this patch makes sure
that GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME is set in all test scripts
that currently rely on the initial branch name being `master by default.
To determine which test scripts to mark up, the first step was to
force-set the default branch name to `master` in
- all test scripts that contain the keyword `master`,
- t4211, which expects `t/t4211/history.export` with a hard-coded ref to
initialize the default branch,
- t5560 because it sources `t/t556x_common` which uses `master`,
- t8002 and t8012 because both source `t/annotate-tests.sh` which also
uses `master`)
This trick was performed by this command:
$ sed -i '/^ *\. \.\/\(test-lib\|lib-\(bash\|cvs\|git-svn\)\|gitweb-lib\)\.sh$/i\
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master\
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\
' $(git grep -l master t/t[0-9]*.sh) \
t/t4211*.sh t/t5560*.sh t/t8002*.sh t/t8012*.sh
After that, careful, manual inspection revealed that some of the test
scripts containing the needle `master` do not actually rely on a
specific default branch name: either they mention `master` only in a
comment, or they initialize that branch specificially, or they do not
actually refer to the current default branch. Therefore, the
aforementioned modification was undone in those test scripts thusly:
$ git checkout HEAD -- \
t/t0027-auto-crlf.sh t/t0060-path-utils.sh \
t/t1011-read-tree-sparse-checkout.sh \
t/t1305-config-include.sh t/t1309-early-config.sh \
t/t1402-check-ref-format.sh t/t1450-fsck.sh \
t/t2024-checkout-dwim.sh \
t/t2106-update-index-assume-unchanged.sh \
t/t3040-subprojects-basic.sh t/t3301-notes.sh \
t/t3308-notes-merge.sh t/t3423-rebase-reword.sh \
t/t3436-rebase-more-options.sh \
t/t4015-diff-whitespace.sh t/t4257-am-interactive.sh \
t/t5323-pack-redundant.sh t/t5401-update-hooks.sh \
t/t5511-refspec.sh t/t5526-fetch-submodules.sh \
t/t5529-push-errors.sh t/t5530-upload-pack-error.sh \
t/t5548-push-porcelain.sh \
t/t5552-skipping-fetch-negotiator.sh \
t/t5572-pull-submodule.sh t/t5608-clone-2gb.sh \
t/t5614-clone-submodules-shallow.sh \
t/t7508-status.sh t/t7606-merge-custom.sh \
t/t9302-fast-import-unpack-limit.sh
We excluded one set of test scripts in these commands, though: the range
of `git p4` tests. The reason? `git p4` stores the (foreign) remote
branch in the branch called `p4/master`, which is obviously not the
default branch. Manual analysis revealed that only five of these tests
actually require a specific default branch name to pass; They were
modified thusly:
$ sed -i '/^ *\. \.\/lib-git-p4\.sh$/i\
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master\
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\
' t/t980[0167]*.sh t/t9811*.sh
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-11-18 23:44:19 +00:00
|
|
|
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
|
|
|
|
|
2009-02-25 08:32:09 +00:00
|
|
|
. ./test-lib.sh
|
2021-12-22 10:59:42 +00:00
|
|
|
|
|
|
|
if test_have_prereq !REFFILES
|
|
|
|
then
|
|
|
|
skip_all='skipping test; dumb HTTP protocol not supported with reftable.'
|
|
|
|
test_done
|
|
|
|
fi
|
|
|
|
|
2011-10-17 19:55:47 +00:00
|
|
|
. "$TEST_DIRECTORY"/lib-httpd.sh
|
2009-02-25 08:32:09 +00:00
|
|
|
start_httpd
|
|
|
|
|
|
|
|
test_expect_success 'setup repository' '
|
2013-01-16 02:05:06 +00:00
|
|
|
git config push.default matching &&
|
2012-04-10 09:53:39 +00:00
|
|
|
echo content1 >file &&
|
2009-02-25 08:32:09 +00:00
|
|
|
git add file &&
|
2015-03-20 10:07:15 +00:00
|
|
|
git commit -m one &&
|
2012-04-10 09:53:39 +00:00
|
|
|
echo content2 >file &&
|
|
|
|
git add file &&
|
|
|
|
git commit -m two
|
2009-02-25 08:32:09 +00:00
|
|
|
'
|
|
|
|
|
2012-04-10 09:53:39 +00:00
|
|
|
test_expect_success 'create http-accessible bare repository with loose objects' '
|
2012-10-08 08:08:01 +00:00
|
|
|
cp -R .git "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
|
2009-02-25 08:32:09 +00:00
|
|
|
(cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
|
2012-04-10 09:53:39 +00:00
|
|
|
git config core.bare true &&
|
|
|
|
mkdir -p hooks &&
|
2017-04-18 23:17:55 +00:00
|
|
|
write_script "hooks/post-update" <<-\EOF &&
|
|
|
|
exec git update-server-info
|
|
|
|
EOF
|
2012-04-10 09:53:39 +00:00
|
|
|
hooks/post-update
|
2009-02-25 08:32:09 +00:00
|
|
|
) &&
|
|
|
|
git remote add public "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
|
2020-11-18 23:44:34 +00:00
|
|
|
git push public main:main
|
2009-02-25 08:32:09 +00:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'clone http repository' '
|
2010-11-25 08:21:03 +00:00
|
|
|
git clone $HTTPD_URL/dumb/repo.git clone-tmpl &&
|
|
|
|
cp -R clone-tmpl clone &&
|
2009-02-25 08:32:09 +00:00
|
|
|
test_cmp file clone/file
|
|
|
|
'
|
|
|
|
|
2017-02-14 20:36:19 +00:00
|
|
|
test_expect_success 'list refs from outside any repository' '
|
|
|
|
cat >expect <<-EOF &&
|
2020-11-18 23:44:34 +00:00
|
|
|
$(git rev-parse main) HEAD
|
|
|
|
$(git rev-parse main) refs/heads/main
|
2017-02-14 20:36:19 +00:00
|
|
|
EOF
|
|
|
|
nongit git ls-remote "$HTTPD_URL/dumb/repo.git" >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
2011-07-18 07:49:12 +00:00
|
|
|
test_expect_success 'create password-protected repository' '
|
2012-08-27 13:23:37 +00:00
|
|
|
mkdir -p "$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/" &&
|
2011-07-18 07:49:12 +00:00
|
|
|
cp -Rf "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
|
2012-08-27 13:23:37 +00:00
|
|
|
"$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/repo.git"
|
2011-07-18 07:49:12 +00:00
|
|
|
'
|
|
|
|
|
2020-06-19 17:55:51 +00:00
|
|
|
test_expect_success 'create empty remote repository' '
|
|
|
|
git init --bare "$HTTPD_DOCUMENT_ROOT_PATH/empty.git" &&
|
|
|
|
(cd "$HTTPD_DOCUMENT_ROOT_PATH/empty.git" &&
|
|
|
|
mkdir -p hooks &&
|
|
|
|
write_script "hooks/post-update" <<-\EOF &&
|
|
|
|
exec git update-server-info
|
|
|
|
EOF
|
|
|
|
hooks/post-update
|
|
|
|
)
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'empty dumb HTTP repository has default hash algorithm' '
|
|
|
|
test_when_finished "rm -fr clone-empty" &&
|
|
|
|
git clone $HTTPD_URL/dumb/empty.git clone-empty &&
|
|
|
|
git -C clone-empty rev-parse --show-object-format >empty-format &&
|
|
|
|
test "$(cat empty-format)" = "$(test_oid algo)"
|
|
|
|
'
|
|
|
|
|
2012-08-27 13:24:31 +00:00
|
|
|
setup_askpass_helper
|
http: use credential API to get passwords
This patch converts the http code to use the new credential
API, both for http authentication as well as for getting
certificate passwords.
Most of the code change is simply variable naming (the
passwords are now contained inside the credential struct)
or deletion of obsolete code (the credential code handles
URL parsing and prompting for us).
The behavior should be the same, with one exception: the
credential code will prompt with a description based on the
credential components. Therefore, the old prompt of:
Username for 'example.com':
Password for 'example.com':
now looks like:
Username for 'https://example.com/repo.git':
Password for 'https://user@example.com/repo.git':
Note that we include more information in each line,
specifically:
1. We now include the protocol. While more noisy, this is
an important part of knowing what you are accessing
(especially if you care about http vs https).
2. We include the username in the password prompt. This is
not a big deal when you have just been prompted for it,
but the username may also come from the remote's URL
(and after future patches, from configuration or
credential helpers). In that case, it's a nice
reminder of the user for which you're giving the
password.
3. We include the path component of the URL. In many
cases, the user won't care about this and it's simply
noise (i.e., they'll use the same credential for a
whole site). However, that is part of a larger
question, which is whether path components should be
part of credential context, both for prompting and for
lookup by storage helpers. That issue will be addressed
as a whole in a future patch.
Similarly, for unlocking certificates, we used to say:
Certificate Password for 'example.com':
and we now say:
Password for 'cert:///path/to/certificate':
Showing the path to the client certificate makes more sense,
as that is what you are unlocking, not "example.com".
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-12-10 10:31:21 +00:00
|
|
|
|
2011-07-18 07:49:12 +00:00
|
|
|
test_expect_success 'cloning password-protected repository can fail' '
|
2012-08-27 13:24:31 +00:00
|
|
|
set_askpass wrong &&
|
2012-08-27 13:23:37 +00:00
|
|
|
test_must_fail git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-fail &&
|
http: use credential API to get passwords
This patch converts the http code to use the new credential
API, both for http authentication as well as for getting
certificate passwords.
Most of the code change is simply variable naming (the
passwords are now contained inside the credential struct)
or deletion of obsolete code (the credential code handles
URL parsing and prompting for us).
The behavior should be the same, with one exception: the
credential code will prompt with a description based on the
credential components. Therefore, the old prompt of:
Username for 'example.com':
Password for 'example.com':
now looks like:
Username for 'https://example.com/repo.git':
Password for 'https://user@example.com/repo.git':
Note that we include more information in each line,
specifically:
1. We now include the protocol. While more noisy, this is
an important part of knowing what you are accessing
(especially if you care about http vs https).
2. We include the username in the password prompt. This is
not a big deal when you have just been prompted for it,
but the username may also come from the remote's URL
(and after future patches, from configuration or
credential helpers). In that case, it's a nice
reminder of the user for which you're giving the
password.
3. We include the path component of the URL. In many
cases, the user won't care about this and it's simply
noise (i.e., they'll use the same credential for a
whole site). However, that is part of a larger
question, which is whether path components should be
part of credential context, both for prompting and for
lookup by storage helpers. That issue will be addressed
as a whole in a future patch.
Similarly, for unlocking certificates, we used to say:
Certificate Password for 'example.com':
and we now say:
Password for 'cert:///path/to/certificate':
Showing the path to the client certificate makes more sense,
as that is what you are unlocking, not "example.com".
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-12-10 10:31:21 +00:00
|
|
|
expect_askpass both wrong
|
2011-07-18 07:49:12 +00:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'http auth can use user/pass in URL' '
|
2012-08-27 13:24:31 +00:00
|
|
|
set_askpass wrong &&
|
2012-08-27 13:23:37 +00:00
|
|
|
git clone "$HTTPD_URL_USER_PASS/auth/dumb/repo.git" clone-auth-none &&
|
http: use credential API to get passwords
This patch converts the http code to use the new credential
API, both for http authentication as well as for getting
certificate passwords.
Most of the code change is simply variable naming (the
passwords are now contained inside the credential struct)
or deletion of obsolete code (the credential code handles
URL parsing and prompting for us).
The behavior should be the same, with one exception: the
credential code will prompt with a description based on the
credential components. Therefore, the old prompt of:
Username for 'example.com':
Password for 'example.com':
now looks like:
Username for 'https://example.com/repo.git':
Password for 'https://user@example.com/repo.git':
Note that we include more information in each line,
specifically:
1. We now include the protocol. While more noisy, this is
an important part of knowing what you are accessing
(especially if you care about http vs https).
2. We include the username in the password prompt. This is
not a big deal when you have just been prompted for it,
but the username may also come from the remote's URL
(and after future patches, from configuration or
credential helpers). In that case, it's a nice
reminder of the user for which you're giving the
password.
3. We include the path component of the URL. In many
cases, the user won't care about this and it's simply
noise (i.e., they'll use the same credential for a
whole site). However, that is part of a larger
question, which is whether path components should be
part of credential context, both for prompting and for
lookup by storage helpers. That issue will be addressed
as a whole in a future patch.
Similarly, for unlocking certificates, we used to say:
Certificate Password for 'example.com':
and we now say:
Password for 'cert:///path/to/certificate':
Showing the path to the client certificate makes more sense,
as that is what you are unlocking, not "example.com".
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-12-10 10:31:21 +00:00
|
|
|
expect_askpass none
|
2011-07-18 07:49:12 +00:00
|
|
|
'
|
|
|
|
|
2012-04-10 09:53:40 +00:00
|
|
|
test_expect_success 'http auth can use just user in URL' '
|
2014-01-02 07:38:35 +00:00
|
|
|
set_askpass wrong pass@host &&
|
2012-08-27 13:23:37 +00:00
|
|
|
git clone "$HTTPD_URL_USER/auth/dumb/repo.git" clone-auth-pass &&
|
http: use credential API to get passwords
This patch converts the http code to use the new credential
API, both for http authentication as well as for getting
certificate passwords.
Most of the code change is simply variable naming (the
passwords are now contained inside the credential struct)
or deletion of obsolete code (the credential code handles
URL parsing and prompting for us).
The behavior should be the same, with one exception: the
credential code will prompt with a description based on the
credential components. Therefore, the old prompt of:
Username for 'example.com':
Password for 'example.com':
now looks like:
Username for 'https://example.com/repo.git':
Password for 'https://user@example.com/repo.git':
Note that we include more information in each line,
specifically:
1. We now include the protocol. While more noisy, this is
an important part of knowing what you are accessing
(especially if you care about http vs https).
2. We include the username in the password prompt. This is
not a big deal when you have just been prompted for it,
but the username may also come from the remote's URL
(and after future patches, from configuration or
credential helpers). In that case, it's a nice
reminder of the user for which you're giving the
password.
3. We include the path component of the URL. In many
cases, the user won't care about this and it's simply
noise (i.e., they'll use the same credential for a
whole site). However, that is part of a larger
question, which is whether path components should be
part of credential context, both for prompting and for
lookup by storage helpers. That issue will be addressed
as a whole in a future patch.
Similarly, for unlocking certificates, we used to say:
Certificate Password for 'example.com':
and we now say:
Password for 'cert:///path/to/certificate':
Showing the path to the client certificate makes more sense,
as that is what you are unlocking, not "example.com".
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-12-10 10:31:21 +00:00
|
|
|
expect_askpass pass user@host
|
2011-07-18 07:49:12 +00:00
|
|
|
'
|
|
|
|
|
2012-04-10 09:53:40 +00:00
|
|
|
test_expect_success 'http auth can request both user and pass' '
|
2014-01-02 07:38:35 +00:00
|
|
|
set_askpass user@host pass@host &&
|
2012-08-27 13:23:37 +00:00
|
|
|
git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-both &&
|
http: use credential API to get passwords
This patch converts the http code to use the new credential
API, both for http authentication as well as for getting
certificate passwords.
Most of the code change is simply variable naming (the
passwords are now contained inside the credential struct)
or deletion of obsolete code (the credential code handles
URL parsing and prompting for us).
The behavior should be the same, with one exception: the
credential code will prompt with a description based on the
credential components. Therefore, the old prompt of:
Username for 'example.com':
Password for 'example.com':
now looks like:
Username for 'https://example.com/repo.git':
Password for 'https://user@example.com/repo.git':
Note that we include more information in each line,
specifically:
1. We now include the protocol. While more noisy, this is
an important part of knowing what you are accessing
(especially if you care about http vs https).
2. We include the username in the password prompt. This is
not a big deal when you have just been prompted for it,
but the username may also come from the remote's URL
(and after future patches, from configuration or
credential helpers). In that case, it's a nice
reminder of the user for which you're giving the
password.
3. We include the path component of the URL. In many
cases, the user won't care about this and it's simply
noise (i.e., they'll use the same credential for a
whole site). However, that is part of a larger
question, which is whether path components should be
part of credential context, both for prompting and for
lookup by storage helpers. That issue will be addressed
as a whole in a future patch.
Similarly, for unlocking certificates, we used to say:
Certificate Password for 'example.com':
and we now say:
Password for 'cert:///path/to/certificate':
Showing the path to the client certificate makes more sense,
as that is what you are unlocking, not "example.com".
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-12-10 10:31:21 +00:00
|
|
|
expect_askpass both user@host
|
2010-11-14 01:51:14 +00:00
|
|
|
'
|
|
|
|
|
2012-04-10 09:53:40 +00:00
|
|
|
test_expect_success 'http auth respects credential helper config' '
|
2011-12-10 10:31:24 +00:00
|
|
|
test_config_global credential.helper "!f() {
|
|
|
|
cat >/dev/null
|
|
|
|
echo username=user@host
|
2014-01-02 07:38:35 +00:00
|
|
|
echo password=pass@host
|
2011-12-10 10:31:24 +00:00
|
|
|
}; f" &&
|
2012-08-27 13:24:31 +00:00
|
|
|
set_askpass wrong &&
|
2012-08-27 13:23:37 +00:00
|
|
|
git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-helper &&
|
2011-12-10 10:31:24 +00:00
|
|
|
expect_askpass none
|
|
|
|
'
|
|
|
|
|
2012-04-10 09:53:40 +00:00
|
|
|
test_expect_success 'http auth can get username from config' '
|
2011-12-10 10:31:30 +00:00
|
|
|
test_config_global "credential.$HTTPD_URL.username" user@host &&
|
2014-01-02 07:38:35 +00:00
|
|
|
set_askpass wrong pass@host &&
|
2012-08-27 13:23:37 +00:00
|
|
|
git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-user &&
|
2011-12-10 10:31:30 +00:00
|
|
|
expect_askpass pass user@host
|
|
|
|
'
|
|
|
|
|
2012-04-10 09:53:40 +00:00
|
|
|
test_expect_success 'configured username does not override URL' '
|
2011-12-10 10:31:30 +00:00
|
|
|
test_config_global "credential.$HTTPD_URL.username" wrong &&
|
2014-01-02 07:38:35 +00:00
|
|
|
set_askpass wrong pass@host &&
|
2012-08-27 13:23:37 +00:00
|
|
|
git clone "$HTTPD_URL_USER/auth/dumb/repo.git" clone-auth-user2 &&
|
2011-12-10 10:31:30 +00:00
|
|
|
expect_askpass pass user@host
|
|
|
|
'
|
|
|
|
|
2016-04-28 13:37:04 +00:00
|
|
|
test_expect_success 'set up repo with http submodules' '
|
2016-02-29 22:58:35 +00:00
|
|
|
git init super &&
|
|
|
|
set_askpass user@host pass@host &&
|
|
|
|
(
|
|
|
|
cd super &&
|
|
|
|
git submodule add "$HTTPD_URL/auth/dumb/repo.git" sub &&
|
|
|
|
git commit -m "add submodule"
|
2016-04-28 13:37:04 +00:00
|
|
|
)
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'cmdline credential config passes to submodule via clone' '
|
2016-02-29 22:58:35 +00:00
|
|
|
set_askpass wrong pass@host &&
|
|
|
|
test_must_fail git clone --recursive super super-clone &&
|
|
|
|
rm -rf super-clone &&
|
2016-04-28 13:37:04 +00:00
|
|
|
|
2016-02-29 22:58:35 +00:00
|
|
|
set_askpass wrong pass@host &&
|
2016-04-28 13:36:37 +00:00
|
|
|
git -c "credential.$HTTPD_URL.username=user@host" \
|
2016-02-29 22:58:35 +00:00
|
|
|
clone --recursive super super-clone &&
|
2016-04-28 13:39:15 +00:00
|
|
|
expect_askpass pass user@host
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'cmdline credential config passes submodule via fetch' '
|
|
|
|
set_askpass wrong pass@host &&
|
|
|
|
test_must_fail git -C super-clone fetch --recurse-submodules &&
|
|
|
|
|
|
|
|
set_askpass wrong pass@host &&
|
|
|
|
git -C super-clone \
|
|
|
|
-c "credential.$HTTPD_URL.username=user@host" \
|
|
|
|
fetch --recurse-submodules &&
|
2016-02-29 22:58:35 +00:00
|
|
|
expect_askpass pass user@host
|
|
|
|
'
|
|
|
|
|
2016-04-28 13:37:44 +00:00
|
|
|
test_expect_success 'cmdline credential config passes submodule update' '
|
|
|
|
# advance the submodule HEAD so that a fetch is required
|
|
|
|
git commit --allow-empty -m foo &&
|
|
|
|
git push "$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/repo.git" HEAD &&
|
|
|
|
sha1=$(git rev-parse HEAD) &&
|
|
|
|
git -C super-clone update-index --cacheinfo 160000,$sha1,sub &&
|
|
|
|
|
|
|
|
set_askpass wrong pass@host &&
|
|
|
|
test_must_fail git -C super-clone submodule update &&
|
|
|
|
|
|
|
|
set_askpass wrong pass@host &&
|
|
|
|
git -C super-clone \
|
|
|
|
-c "credential.$HTTPD_URL.username=user@host" \
|
|
|
|
submodule update &&
|
|
|
|
expect_askpass pass user@host
|
|
|
|
'
|
|
|
|
|
2009-02-25 08:32:09 +00:00
|
|
|
test_expect_success 'fetch changes via http' '
|
|
|
|
echo content >>file &&
|
|
|
|
git commit -a -m two &&
|
2010-11-25 08:21:02 +00:00
|
|
|
git push public &&
|
2009-02-25 08:32:09 +00:00
|
|
|
(cd clone && git pull) &&
|
|
|
|
test_cmp file clone/file
|
|
|
|
'
|
|
|
|
|
2010-11-25 08:21:03 +00:00
|
|
|
test_expect_success 'fetch changes via manual http-fetch' '
|
|
|
|
cp -R clone-tmpl clone2 &&
|
|
|
|
|
|
|
|
HEAD=$(git rev-parse --verify HEAD) &&
|
|
|
|
(cd clone2 &&
|
2020-11-18 23:44:34 +00:00
|
|
|
git http-fetch -a -w heads/main-new $HEAD $(git config remote.origin.url) &&
|
|
|
|
git checkout main-new &&
|
2010-11-25 08:21:03 +00:00
|
|
|
test $HEAD = $(git rev-parse --verify HEAD)) &&
|
|
|
|
test_cmp file clone2/file
|
|
|
|
'
|
|
|
|
|
2018-04-22 18:12:49 +00:00
|
|
|
test_expect_success 'manual http-fetch without -a works just as well' '
|
|
|
|
cp -R clone-tmpl clone3 &&
|
|
|
|
|
|
|
|
HEAD=$(git rev-parse --verify HEAD) &&
|
|
|
|
(cd clone3 &&
|
2020-11-18 23:44:34 +00:00
|
|
|
git http-fetch -w heads/main-new $HEAD $(git config remote.origin.url) &&
|
|
|
|
git checkout main-new &&
|
2018-04-22 18:12:49 +00:00
|
|
|
test $HEAD = $(git rev-parse --verify HEAD)) &&
|
|
|
|
test_cmp file clone3/file
|
|
|
|
'
|
|
|
|
|
2009-02-27 19:10:06 +00:00
|
|
|
test_expect_success 'http remote detects correct HEAD' '
|
2020-11-18 23:44:34 +00:00
|
|
|
git push public main:other &&
|
2009-02-27 19:10:06 +00:00
|
|
|
(cd clone &&
|
|
|
|
git remote set-head origin -d &&
|
|
|
|
git remote set-head origin -a &&
|
|
|
|
git symbolic-ref refs/remotes/origin/HEAD > output &&
|
2020-11-18 23:44:34 +00:00
|
|
|
echo refs/remotes/origin/main > expect &&
|
2009-02-27 19:10:06 +00:00
|
|
|
test_cmp expect output
|
|
|
|
)
|
|
|
|
'
|
|
|
|
|
2009-06-06 08:43:32 +00:00
|
|
|
test_expect_success 'fetch packed objects' '
|
|
|
|
cp -R "$HTTPD_DOCUMENT_ROOT_PATH"/repo.git "$HTTPD_DOCUMENT_ROOT_PATH"/repo_pack.git &&
|
2010-04-17 20:07:35 +00:00
|
|
|
(cd "$HTTPD_DOCUMENT_ROOT_PATH"/repo_pack.git &&
|
2012-01-04 15:55:34 +00:00
|
|
|
git --bare repack -a -d
|
2010-04-17 20:07:35 +00:00
|
|
|
) &&
|
2009-10-31 00:47:46 +00:00
|
|
|
git clone $HTTPD_URL/dumb/repo_pack.git
|
2009-06-06 08:43:32 +00:00
|
|
|
'
|
|
|
|
|
2020-06-10 20:57:18 +00:00
|
|
|
test_expect_success 'http-fetch --packfile' '
|
|
|
|
# Arbitrary hash. Use rev-parse so that we get one of the correct
|
|
|
|
# length.
|
|
|
|
ARBITRARY=$(git -C "$HTTPD_DOCUMENT_ROOT_PATH"/repo_pack.git rev-parse HEAD) &&
|
|
|
|
|
|
|
|
git init packfileclient &&
|
|
|
|
p=$(cd "$HTTPD_DOCUMENT_ROOT_PATH"/repo_pack.git && ls objects/pack/pack-*.pack) &&
|
2021-02-22 19:20:07 +00:00
|
|
|
git -C packfileclient http-fetch --packfile=$ARBITRARY \
|
|
|
|
--index-pack-arg=index-pack --index-pack-arg=--stdin \
|
|
|
|
--index-pack-arg=--keep \
|
|
|
|
"$HTTPD_URL"/dumb/repo_pack.git/$p >out &&
|
2020-06-10 20:57:18 +00:00
|
|
|
|
|
|
|
grep "^keep.[0-9a-f]\{16,\}$" out &&
|
|
|
|
cut -c6- out >packhash &&
|
|
|
|
|
|
|
|
# Ensure that the expected files are generated
|
|
|
|
test -e "packfileclient/.git/objects/pack/pack-$(cat packhash).pack" &&
|
|
|
|
test -e "packfileclient/.git/objects/pack/pack-$(cat packhash).idx" &&
|
|
|
|
test -e "packfileclient/.git/objects/pack/pack-$(cat packhash).keep" &&
|
|
|
|
|
|
|
|
# Ensure that it has the HEAD of repo_pack, at least
|
|
|
|
HASH=$(git -C "$HTTPD_DOCUMENT_ROOT_PATH"/repo_pack.git rev-parse HEAD) &&
|
|
|
|
git -C packfileclient cat-file -e "$HASH"
|
|
|
|
'
|
|
|
|
|
2010-04-19 14:23:09 +00:00
|
|
|
test_expect_success 'fetch notices corrupt pack' '
|
|
|
|
cp -R "$HTTPD_DOCUMENT_ROOT_PATH"/repo_pack.git "$HTTPD_DOCUMENT_ROOT_PATH"/repo_bad1.git &&
|
|
|
|
(cd "$HTTPD_DOCUMENT_ROOT_PATH"/repo_bad1.git &&
|
2016-01-04 09:10:47 +00:00
|
|
|
p=$(ls objects/pack/pack-*.pack) &&
|
2010-04-19 14:23:09 +00:00
|
|
|
chmod u+w $p &&
|
|
|
|
printf %0256d 0 | dd of=$p bs=256 count=1 seek=1 conv=notrunc
|
|
|
|
) &&
|
|
|
|
mkdir repo_bad1.git &&
|
|
|
|
(cd repo_bad1.git &&
|
|
|
|
git --bare init &&
|
|
|
|
test_must_fail git --bare fetch $HTTPD_URL/dumb/repo_bad1.git &&
|
2016-01-04 09:10:47 +00:00
|
|
|
test 0 = $(ls objects/pack/pack-*.pack | wc -l)
|
2010-04-19 14:23:09 +00:00
|
|
|
)
|
|
|
|
'
|
|
|
|
|
2020-06-10 20:57:18 +00:00
|
|
|
test_expect_success 'http-fetch --packfile with corrupt pack' '
|
|
|
|
rm -rf packfileclient &&
|
|
|
|
git init packfileclient &&
|
|
|
|
p=$(cd "$HTTPD_DOCUMENT_ROOT_PATH"/repo_bad1.git && ls objects/pack/pack-*.pack) &&
|
|
|
|
test_must_fail git -C packfileclient http-fetch --packfile \
|
|
|
|
"$HTTPD_URL"/dumb/repo_bad1.git/$p
|
|
|
|
'
|
|
|
|
|
2010-04-19 14:23:10 +00:00
|
|
|
test_expect_success 'fetch notices corrupt idx' '
|
|
|
|
cp -R "$HTTPD_DOCUMENT_ROOT_PATH"/repo_pack.git "$HTTPD_DOCUMENT_ROOT_PATH"/repo_bad2.git &&
|
|
|
|
(cd "$HTTPD_DOCUMENT_ROOT_PATH"/repo_bad2.git &&
|
2016-01-04 09:10:47 +00:00
|
|
|
p=$(ls objects/pack/pack-*.idx) &&
|
2010-04-19 14:23:10 +00:00
|
|
|
chmod u+w $p &&
|
|
|
|
printf %0256d 0 | dd of=$p bs=256 count=1 seek=1 conv=notrunc
|
|
|
|
) &&
|
|
|
|
mkdir repo_bad2.git &&
|
|
|
|
(cd repo_bad2.git &&
|
|
|
|
git --bare init &&
|
|
|
|
test_must_fail git --bare fetch $HTTPD_URL/dumb/repo_bad2.git &&
|
2016-01-04 09:10:47 +00:00
|
|
|
test 0 = $(ls objects/pack | wc -l)
|
2010-04-19 14:23:10 +00:00
|
|
|
)
|
|
|
|
'
|
|
|
|
|
dumb-http: do not pass NULL path to parse_pack_index
Once upon a time, dumb http always fetched .idx files
directly into their final location, and then checked their
validity with parse_pack_index. This was refactored in
commit 750ef42 (http-fetch: Use temporary files for
pack-*.idx until verified, 2010-04-19), which uses the
following logic:
1. If we have the idx already in place, see if it's
valid (using parse_pack_index). If so, use it.
2. Otherwise, fetch the .idx to a tempfile, check
that, and if so move it into place.
3. Either way, fetch the pack itself if necessary.
However, it got step 1 wrong. We pass a NULL path parameter
to parse_pack_index, so an existing .idx file always looks
broken. Worse, we do not treat this broken .idx as an
opportunity to re-fetch, but instead return an error,
ignoring the pack entirely. This can lead to a dumb-http
fetch failing to retrieve the necessary objects.
This doesn't come up much in practice, because it must be a
packfile that we found out about (and whose .idx we stored)
during an earlier dumb-http fetch, but whose packfile we
_didn't_ fetch. I.e., we did a partial clone of a
repository, didn't need some packfiles, and now a followup
fetch needs them.
Discovery and tests by Charles Bailey <charles@hashpling.org>.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-01-27 20:02:27 +00:00
|
|
|
test_expect_success 'fetch can handle previously-fetched .idx files' '
|
|
|
|
git checkout --orphan branch1 &&
|
|
|
|
echo base >file &&
|
|
|
|
git add file &&
|
|
|
|
git commit -m base &&
|
|
|
|
git --bare init "$HTTPD_DOCUMENT_ROOT_PATH"/repo_packed_branches.git &&
|
|
|
|
git push "$HTTPD_DOCUMENT_ROOT_PATH"/repo_packed_branches.git branch1 &&
|
|
|
|
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH"/repo_packed_branches.git repack -d &&
|
|
|
|
git checkout -b branch2 branch1 &&
|
|
|
|
echo b2 >>file &&
|
|
|
|
git commit -a -m b2 &&
|
|
|
|
git push "$HTTPD_DOCUMENT_ROOT_PATH"/repo_packed_branches.git branch2 &&
|
|
|
|
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH"/repo_packed_branches.git repack -d &&
|
|
|
|
git --bare init clone_packed_branches.git &&
|
|
|
|
git --git-dir=clone_packed_branches.git fetch "$HTTPD_URL"/dumb/repo_packed_branches.git branch1:branch1 &&
|
|
|
|
git --git-dir=clone_packed_branches.git fetch "$HTTPD_URL"/dumb/repo_packed_branches.git branch2:branch2
|
|
|
|
'
|
|
|
|
|
2009-10-31 00:47:47 +00:00
|
|
|
test_expect_success 'did not use upload-pack service' '
|
2020-03-26 08:27:51 +00:00
|
|
|
! grep "/git-upload-pack" "$HTTPD_ROOT_PATH/access.log"
|
2009-10-31 00:47:47 +00:00
|
|
|
'
|
|
|
|
|
2014-05-22 09:29:03 +00:00
|
|
|
test_expect_success 'git client shows text/plain errors' '
|
|
|
|
test_must_fail git clone "$HTTPD_URL/error/text" 2>stderr &&
|
|
|
|
grep "this is the error message" stderr
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'git client does not show html errors' '
|
|
|
|
test_must_fail git clone "$HTTPD_URL/error/html" 2>stderr &&
|
|
|
|
! grep "this is the error message" stderr
|
|
|
|
'
|
|
|
|
|
2014-05-22 09:29:47 +00:00
|
|
|
test_expect_success 'git client shows text/plain with a charset' '
|
|
|
|
test_must_fail git clone "$HTTPD_URL/error/charset" 2>stderr &&
|
|
|
|
grep "this is the error message" stderr
|
|
|
|
'
|
|
|
|
|
2014-05-22 09:30:29 +00:00
|
|
|
test_expect_success 'http error messages are reencoded' '
|
|
|
|
test_must_fail git clone "$HTTPD_URL/error/utf16" 2>stderr &&
|
|
|
|
grep "this is the error message" stderr
|
|
|
|
'
|
|
|
|
|
2014-06-17 22:11:53 +00:00
|
|
|
test_expect_success 'reencoding is robust to whitespace oddities' '
|
|
|
|
test_must_fail git clone "$HTTPD_URL/error/odd-spacing" 2>stderr &&
|
|
|
|
grep "this is the error message" stderr
|
|
|
|
'
|
|
|
|
|
2015-01-28 12:04:37 +00:00
|
|
|
check_language () {
|
|
|
|
case "$2" in
|
|
|
|
'')
|
|
|
|
>expect
|
|
|
|
;;
|
|
|
|
?*)
|
2016-09-05 19:19:40 +00:00
|
|
|
echo "=> Send header: Accept-Language: $1" >expect
|
2015-01-28 12:04:37 +00:00
|
|
|
;;
|
|
|
|
esac &&
|
2016-09-05 19:19:40 +00:00
|
|
|
GIT_TRACE_CURL=true \
|
2015-01-28 12:04:37 +00:00
|
|
|
LANGUAGE=$2 \
|
|
|
|
git ls-remote "$HTTPD_URL/dumb/repo.git" >output 2>&1 &&
|
|
|
|
tr -d '\015' <output |
|
|
|
|
sort -u |
|
2016-09-05 19:19:40 +00:00
|
|
|
sed -ne '/^=> Send header: Accept-Language:/ p' >actual &&
|
2015-01-28 12:04:37 +00:00
|
|
|
test_cmp expect actual
|
|
|
|
}
|
|
|
|
|
|
|
|
test_expect_success 'git client sends Accept-Language based on LANGUAGE' '
|
|
|
|
check_language "ko-KR, *;q=0.9" ko_KR.UTF-8'
|
|
|
|
|
|
|
|
test_expect_success 'git client sends Accept-Language correctly with unordinary LANGUAGE' '
|
|
|
|
check_language "ko-KR, *;q=0.9" "ko_KR:" &&
|
|
|
|
check_language "ko-KR, en-US;q=0.9, *;q=0.8" "ko_KR::en_US" &&
|
|
|
|
check_language "ko-KR, *;q=0.9" ":::ko_KR" &&
|
|
|
|
check_language "ko-KR, en-US;q=0.9, *;q=0.8" "ko_KR!!:en_US" &&
|
|
|
|
check_language "ko-KR, ja-JP;q=0.9, *;q=0.8" "ko_KR en_US:ja_JP"'
|
|
|
|
|
|
|
|
test_expect_success 'git client sends Accept-Language with many preferred languages' '
|
|
|
|
check_language "ko-KR, en-US;q=0.9, fr-CA;q=0.8, de;q=0.7, sr;q=0.6, \
|
|
|
|
ja;q=0.5, zh;q=0.4, sv;q=0.3, pt;q=0.2, *;q=0.1" \
|
|
|
|
ko_KR.EUC-KR:en_US.UTF-8:fr_CA:de.UTF-8@euro:sr@latin:ja:zh:sv:pt &&
|
|
|
|
check_language "ko-KR, en-US;q=0.99, fr-CA;q=0.98, de;q=0.97, sr;q=0.96, \
|
|
|
|
ja;q=0.95, zh;q=0.94, sv;q=0.93, pt;q=0.92, nb;q=0.91, *;q=0.90" \
|
|
|
|
ko_KR.EUC-KR:en_US.UTF-8:fr_CA:de.UTF-8@euro:sr@latin:ja:zh:sv:pt:nb
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'git client does not send an empty Accept-Language' '
|
2016-09-05 19:19:40 +00:00
|
|
|
GIT_TRACE_CURL=true LANGUAGE= git ls-remote "$HTTPD_URL/dumb/repo.git" 2>stderr &&
|
|
|
|
! grep "^=> Send header: Accept-Language:" stderr
|
2015-01-28 12:04:37 +00:00
|
|
|
'
|
|
|
|
|
2016-09-07 20:06:42 +00:00
|
|
|
test_expect_success 'remote-http complains cleanly about malformed urls' '
|
credential: treat URL without scheme as invalid
libcurl permits making requests without a URL scheme specified. In
this case, it guesses the URL from the hostname, so I can run
git ls-remote http::ftp.example.com/path/to/repo
and it would make an FTP request.
Any user intentionally using such a URL is likely to have made a typo.
Unfortunately, credential_from_url is not able to determine the host and
protocol in order to determine appropriate credentials to send, and
until "credential: refuse to operate when missing host or protocol",
this resulted in another host's credentials being leaked to the named
host.
Teach credential_from_url_gently to consider such a URL to be invalid
so that fsck can detect and block gitmodules files with such URLs,
allowing server operators to avoid serving them to downstream users
running older versions of Git.
This also means that when such URLs are passed on the command line, Git
will print a clearer error so affected users can switch to the simpler
URL that explicitly specifies the host and protocol they intend.
One subtlety: .gitmodules files can contain relative URLs, representing
a URL relative to the URL they were cloned from. The relative URL
resolver used for .gitmodules can follow ".." components out of the path
part and past the host part of a URL, meaning that such a relative URL
can be used to traverse from a https://foo.example.com/innocent
superproject to a https::attacker.example.com/exploit submodule.
Fortunately a leading ':' in the first path component after a series of
leading './' and '../' components is unlikely to show up in other
contexts, so we can catch this by detecting that pattern.
Reported-by: Jeff King <peff@peff.net>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Reviewed-by: Jeff King <peff@peff.net>
2020-04-19 03:54:13 +00:00
|
|
|
test_must_fail git remote-http http::/example.com/repo.git 2>stderr &&
|
|
|
|
test_i18ngrep "url has no scheme" stderr
|
2016-09-07 20:06:42 +00:00
|
|
|
'
|
|
|
|
|
2020-04-19 03:54:57 +00:00
|
|
|
# NEEDSWORK: Writing commands to git-remote-curl can race against the latter
|
|
|
|
# erroring out, producing SIGPIPE. Remove "ok=sigpipe" once transport-helper has
|
|
|
|
# learned to handle early remote helper failures more cleanly.
|
|
|
|
test_expect_success 'remote-http complains cleanly about empty scheme' '
|
|
|
|
test_must_fail ok=sigpipe git ls-remote \
|
|
|
|
http::${HTTPD_URL#http}/dumb/repo.git 2>stderr &&
|
|
|
|
test_i18ngrep "url has no scheme" stderr
|
2016-09-07 20:06:42 +00:00
|
|
|
'
|
|
|
|
|
http: make redirects more obvious
We instruct curl to always follow HTTP redirects. This is
convenient, but it creates opportunities for malicious
servers to create confusing situations. For instance,
imagine Alice is a git user with access to a private
repository on Bob's server. Mallory runs her own server and
wants to access objects from Bob's repository.
Mallory may try a few tricks that involve asking Alice to
clone from her, build on top, and then push the result:
1. Mallory may simply redirect all fetch requests to Bob's
server. Git will transparently follow those redirects
and fetch Bob's history, which Alice may believe she
got from Mallory. The subsequent push seems like it is
just feeding Mallory back her own objects, but is
actually leaking Bob's objects. There is nothing in
git's output to indicate that Bob's repository was
involved at all.
The downside (for Mallory) of this attack is that Alice
will have received Bob's entire repository, and is
likely to notice that when building on top of it.
2. If Mallory happens to know the sha1 of some object X in
Bob's repository, she can instead build her own history
that references that object. She then runs a dumb http
server, and Alice's client will fetch each object
individually. When it asks for X, Mallory redirects her
to Bob's server. The end result is that Alice obtains
objects from Bob, but they may be buried deep in
history. Alice is less likely to notice.
Both of these attacks are fairly hard to pull off. There's a
social component in getting Mallory to convince Alice to
work with her. Alice may be prompted for credentials in
accessing Bob's repository (but not always, if she is using
a credential helper that caches). Attack (1) requires a
certain amount of obliviousness on Alice's part while making
a new commit. Attack (2) requires that Mallory knows a sha1
in Bob's repository, that Bob's server supports dumb http,
and that the object in question is loose on Bob's server.
But we can probably make things a bit more obvious without
any loss of functionality. This patch does two things to
that end.
First, when we encounter a whole-repo redirect during the
initial ref discovery, we now inform the user on stderr,
making attack (1) much more obvious.
Second, the decision to follow redirects is now
configurable. The truly paranoid can set the new
http.followRedirects to false to avoid any redirection
entirely. But for a more practical default, we will disallow
redirects only after the initial ref discovery. This is
enough to thwart attacks similar to (2), while still
allowing the common use of redirects at the repository
level. Since c93c92f30 (http: update base URLs when we see
redirects, 2013-09-28) we re-root all further requests from
the redirect destination, which should generally mean that
no further redirection is necessary.
As an escape hatch, in case there really is a server that
needs to redirect individual requests, the user can set
http.followRedirects to "true" (and this can be done on a
per-server basis via http.*.followRedirects config).
Reported-by: Jann Horn <jannh@google.com>
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-12-06 18:24:41 +00:00
|
|
|
test_expect_success 'redirects can be forbidden/allowed' '
|
|
|
|
test_must_fail git -c http.followRedirects=false \
|
|
|
|
clone $HTTPD_URL/dumb-redir/repo.git dumb-redir &&
|
|
|
|
git -c http.followRedirects=true \
|
|
|
|
clone $HTTPD_URL/dumb-redir/repo.git dumb-redir 2>stderr
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'redirects are reported to stderr' '
|
|
|
|
# just look for a snippet of the redirected-to URL
|
|
|
|
test_i18ngrep /dumb/ stderr
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'non-initial redirects can be forbidden' '
|
|
|
|
test_must_fail git -c http.followRedirects=initial \
|
|
|
|
clone $HTTPD_URL/redir-objects/repo.git redir-objects &&
|
|
|
|
git -c http.followRedirects=true \
|
|
|
|
clone $HTTPD_URL/redir-objects/repo.git redir-objects
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'http.followRedirects defaults to "initial"' '
|
|
|
|
test_must_fail git clone $HTTPD_URL/redir-objects/repo.git default
|
|
|
|
'
|
|
|
|
|
http: treat http-alternates like redirects
The previous commit made HTTP redirects more obvious and
tightened up the default behavior. However, there's another
way for a server to ask a git client to fetch arbitrary
content: by having an http-alternates file (or a regular
alternates file, which is used as a backup).
Similar to the HTTP redirect case, a malicious server can
claim to have refs pointing at object X, return a 404 when
the client asks for X, but point to some other URL via
http-alternates, which the client will transparently fetch.
The end result is that it looks from the user's perspective
like the objects came from the malicious server, as the
other URL is not mentioned at all.
Worse, because we feed the new URL to curl ourselves, the
usual protocol restrictions do not kick in (neither curl's
default of disallowing file://, nor the protocol
whitelisting in f4113cac0 (http: limit redirection to
protocol-whitelist, 2015-09-22).
Let's apply the same rules here as we do for HTTP redirects.
Namely:
- unless http.followRedirects is set to "always", we will
not follow remote redirects from http-alternates (or
alternates) at all
- set CURLOPT_PROTOCOLS alongside CURLOPT_REDIR_PROTOCOLS
restrict ourselves to a known-safe set and respect any
user-provided whitelist.
- mention alternate object stores on stderr so that the
user is aware another source of objects may be involved
The first item may prove to be too restrictive. The most
common use of alternates is to point to another path on the
same server. While it's possible for a single-server
redirect to be an attack, it takes a fairly obscure setup
(victim and evil repository on the same host, host speaks
dumb http, and evil repository has access to edit its own
http-alternates file).
So we could make the checks more specific, and only cover
cross-server redirects. But that means parsing the URLs
ourselves, rather than letting curl handle them. This patch
goes for the simpler approach. Given that they are only used
with dumb http, http-alternates are probably pretty rare.
And there's an escape hatch: the user can allow redirects on
a specific server by setting http.<url>.followRedirects to
"always".
Reported-by: Jann Horn <jannh@google.com>
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-12-06 18:24:45 +00:00
|
|
|
# The goal is for a clone of the "evil" repository, which has no objects
|
|
|
|
# itself, to cause the client to fetch objects from the "victim" repository.
|
|
|
|
test_expect_success 'set up evil alternates scheme' '
|
|
|
|
victim=$HTTPD_DOCUMENT_ROOT_PATH/victim.git &&
|
|
|
|
git init --bare "$victim" &&
|
|
|
|
git -C "$victim" --work-tree=. commit --allow-empty -m secret &&
|
|
|
|
git -C "$victim" repack -ad &&
|
|
|
|
git -C "$victim" update-server-info &&
|
|
|
|
sha1=$(git -C "$victim" rev-parse HEAD) &&
|
|
|
|
|
|
|
|
evil=$HTTPD_DOCUMENT_ROOT_PATH/evil.git &&
|
|
|
|
git init --bare "$evil" &&
|
|
|
|
# do this by hand to avoid object existence check
|
2020-11-18 23:44:34 +00:00
|
|
|
printf "%s\\t%s\\n" $sha1 refs/heads/main >"$evil/info/refs"
|
http: treat http-alternates like redirects
The previous commit made HTTP redirects more obvious and
tightened up the default behavior. However, there's another
way for a server to ask a git client to fetch arbitrary
content: by having an http-alternates file (or a regular
alternates file, which is used as a backup).
Similar to the HTTP redirect case, a malicious server can
claim to have refs pointing at object X, return a 404 when
the client asks for X, but point to some other URL via
http-alternates, which the client will transparently fetch.
The end result is that it looks from the user's perspective
like the objects came from the malicious server, as the
other URL is not mentioned at all.
Worse, because we feed the new URL to curl ourselves, the
usual protocol restrictions do not kick in (neither curl's
default of disallowing file://, nor the protocol
whitelisting in f4113cac0 (http: limit redirection to
protocol-whitelist, 2015-09-22).
Let's apply the same rules here as we do for HTTP redirects.
Namely:
- unless http.followRedirects is set to "always", we will
not follow remote redirects from http-alternates (or
alternates) at all
- set CURLOPT_PROTOCOLS alongside CURLOPT_REDIR_PROTOCOLS
restrict ourselves to a known-safe set and respect any
user-provided whitelist.
- mention alternate object stores on stderr so that the
user is aware another source of objects may be involved
The first item may prove to be too restrictive. The most
common use of alternates is to point to another path on the
same server. While it's possible for a single-server
redirect to be an attack, it takes a fairly obscure setup
(victim and evil repository on the same host, host speaks
dumb http, and evil repository has access to edit its own
http-alternates file).
So we could make the checks more specific, and only cover
cross-server redirects. But that means parsing the URLs
ourselves, rather than letting curl handle them. This patch
goes for the simpler approach. Given that they are only used
with dumb http, http-alternates are probably pretty rare.
And there's an escape hatch: the user can allow redirects on
a specific server by setting http.<url>.followRedirects to
"always".
Reported-by: Jann Horn <jannh@google.com>
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-12-06 18:24:45 +00:00
|
|
|
'
|
|
|
|
|
|
|
|
# Here we'll just redirect via HTTP. In a real-world attack these would be on
|
|
|
|
# different servers, but we should reject it either way.
|
|
|
|
test_expect_success 'http-alternates is a non-initial redirect' '
|
|
|
|
echo "$HTTPD_URL/dumb/victim.git/objects" \
|
|
|
|
>"$evil/objects/info/http-alternates" &&
|
|
|
|
test_must_fail git -c http.followRedirects=initial \
|
|
|
|
clone $HTTPD_URL/dumb/evil.git evil-initial &&
|
|
|
|
git -c http.followRedirects=true \
|
|
|
|
clone $HTTPD_URL/dumb/evil.git evil-initial
|
|
|
|
'
|
|
|
|
|
|
|
|
# Curl supports a lot of protocols that we'd prefer not to allow
|
|
|
|
# http-alternates to use, but it's hard to test whether curl has
|
|
|
|
# accessed, say, the SMTP protocol, because we are not running an SMTP server.
|
|
|
|
# But we can check that it does not allow access to file://, which would
|
|
|
|
# otherwise allow this clone to complete.
|
|
|
|
test_expect_success 'http-alternates cannot point at funny protocols' '
|
|
|
|
echo "file://$victim/objects" >"$evil/objects/info/http-alternates" &&
|
|
|
|
test_must_fail git -c http.followRedirects=true \
|
|
|
|
clone "$HTTPD_URL/dumb/evil.git" evil-file
|
|
|
|
'
|
|
|
|
|
http: respect protocol.*.allow=user for http-alternates
The http-walker may fetch the http-alternates (or
alternates) file from a remote in order to find more
objects. This should count as a "not from the user" use of
the protocol. But because we implement the redirection
ourselves and feed the new URL to curl, it will use the
CURLOPT_PROTOCOLS rules, not the more restrictive
CURLOPT_REDIR_PROTOCOLS.
The ideal solution would be for each curl request we make to
know whether or not is directly from the user or part of an
alternates redirect, and then set CURLOPT_PROTOCOLS as
appropriate. However, that would require plumbing that
information through all of the various layers of the http
code.
Instead, let's check the protocol at the source: when we are
parsing the remote http-alternates file. The only downside
is that if there's any mismatch between what protocol we
think it is versus what curl thinks it is, it could violate
the policy.
To address this, we'll make the parsing err on the picky
side, and only allow protocols that it can parse
definitively. So for example, you can't elude the "http"
policy by asking for "HTTP://", even though curl might
handle it; we would reject it as unknown. The only unsafe
case would be if you have a URL that starts with "http://"
but curl interprets as another protocol. That seems like an
unlikely failure mode (and we are still protected by our
base CURLOPT_PROTOCOL setting, so the worst you could do is
trigger one of https, ftp, or ftps).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Brandon Williams <bmwill@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-12-14 22:39:55 +00:00
|
|
|
test_expect_success 'http-alternates triggers not-from-user protocol check' '
|
|
|
|
echo "$HTTPD_URL/dumb/victim.git/objects" \
|
|
|
|
>"$evil/objects/info/http-alternates" &&
|
|
|
|
test_config_global http.followRedirects true &&
|
|
|
|
test_must_fail git -c protocol.http.allow=user \
|
|
|
|
clone $HTTPD_URL/dumb/evil.git evil-user &&
|
|
|
|
git -c protocol.http.allow=always \
|
|
|
|
clone $HTTPD_URL/dumb/evil.git evil-user
|
|
|
|
'
|
|
|
|
|
http: attempt updating base URL only if no error
http.c supports HTTP redirects of the form
http://foo/info/refs?service=git-upload-pack
-> http://anything
-> http://bar/info/refs?service=git-upload-pack
(that is to say, as long as the Git part of the path and the query
string is preserved in the final redirect destination, the intermediate
steps can have any URL). However, if one of the intermediate steps
results in an HTTP exception, a confusing "unable to update url base
from redirection" message is printed instead of a Curl error message
with the HTTP exception code.
This was introduced by 2 commits. Commit c93c92f ("http: update base
URLs when we see redirects", 2013-09-28) introduced a best-effort
optimization that required checking if only the "base" part of the URL
differed between the initial request and the final redirect destination,
but it performed the check before any HTTP status checking was done. If
something went wrong, the normal code path was still followed, so this
did not cause any confusing error messages until commit 6628eb4 ("http:
always update the base URL for redirects", 2016-12-06), which taught
http to die if the non-"base" part of the URL differed.
Therefore, teach http to check the HTTP status before attempting to
check if only the "base" part of the URL differed. This commit teaches
http_request_reauth to return early without updating options->base_url
upon an error; the only invoker of this function that passes a non-NULL
"options" is remote-curl.c (through "http_get_strbuf"), which only uses
options->base_url for an informational message in the situations that
this commit cares about (that is, when the return value is not HTTP_OK).
The included test checks that the redirect scheme at the beginning of
this commit message works, and that returning a 502 in the middle of the
redirect scheme produces the correct result. Note that this is different
from the test in commit 6628eb4 ("http: always update the base URL for
redirects", 2016-12-06) in that this commit tests that a Git-shaped URL
(http://.../info/refs?service=git-upload-pack) works, whereas commit
6628eb4 tests that a non-Git-shaped URL
(http://.../info/refs/foo?service=git-upload-pack) does not work (even
though Git is processing that URL) and is an error that is fatal, not
silently swallowed.
Signed-off-by: Jonathan Tan <jonathantanmy@google.com>
Acked-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-28 02:53:11 +00:00
|
|
|
test_expect_success 'can redirect through non-"info/refs?service=git-upload-pack" URL' '
|
|
|
|
git clone "$HTTPD_URL/redir-to/dumb/repo.git"
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'print HTTP error when any intermediate redirect throws error' '
|
|
|
|
test_must_fail git clone "$HTTPD_URL/redir-to/502" 2> stderr &&
|
|
|
|
test_i18ngrep "unable to access.*/redir-to/502" stderr
|
|
|
|
'
|
|
|
|
|
http: normalize curl results for dumb loose and alternates fetches
If the dumb-http walker encounters a 404 when fetching a loose object,
it then looks at any http-alternates for the object. The 404 check is
implemented by missing_target(), which checks not only the http code,
but also that we got an http error from the CURLcode.
That broke when we stopped using CURLOPT_FAILONERROR in 17966c0a63
(http: avoid disconnecting on 404s for loose objects, 2016-07-11), since
our CURLcode will now be CURLE_OK. As a result, fetching over dumb-http
from a repository with alternates could result in Git printing "Unable
to find abcd1234..." and aborting.
We could probably fix this just by loosening missing_target(). However,
there's other code which looks at the curl result, and it would have to
be tweaked as well. Instead, let's just normalize the result the same
way the smart-http code does.
There's a similar case in processing the alternates (where we failover
from "info/http-alternates" to "info/alternates"). We'll give it the
same treatment.
After this patch, we should be hitting all code paths that need this
normalization (notably absent here is the http_pack_request path, but it
does not use FAILONERROR, nor missing_target()).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-03-24 12:09:46 +00:00
|
|
|
test_expect_success 'fetching via http alternates works' '
|
|
|
|
parent=$HTTPD_DOCUMENT_ROOT_PATH/alt-parent.git &&
|
|
|
|
git init --bare "$parent" &&
|
|
|
|
git -C "$parent" --work-tree=. commit --allow-empty -m foo &&
|
|
|
|
git -C "$parent" update-server-info &&
|
|
|
|
commit=$(git -C "$parent" rev-parse HEAD) &&
|
|
|
|
|
|
|
|
child=$HTTPD_DOCUMENT_ROOT_PATH/alt-child.git &&
|
|
|
|
git init --bare "$child" &&
|
|
|
|
echo "../../alt-parent.git/objects" >"$child/objects/info/alternates" &&
|
|
|
|
git -C "$child" update-ref HEAD $commit &&
|
|
|
|
git -C "$child" update-server-info &&
|
|
|
|
|
|
|
|
git -c http.followredirects=true clone "$HTTPD_URL/dumb/alt-child.git"
|
|
|
|
'
|
|
|
|
|
2009-02-25 08:32:09 +00:00
|
|
|
test_done
|