unicode: update the width tables to Unicode 15.1
[git.git] / t / t0300-credentials.sh
blobc66d91e82d8bc737bc6b909c9427f163aef5dfea
1 #!/bin/sh
3 test_description='basic credential helper tests'
4 . ./test-lib.sh
5 . "$TEST_DIRECTORY"/lib-credential.sh
7 test_expect_success 'setup helper scripts' '
8 cat >dump <<-\EOF &&
9 whoami=$(echo $0 | sed s/.*git-credential-//)
10 echo >&2 "$whoami: $*"
11 OIFS=$IFS
12 IFS==
13 while read key value; do
14 echo >&2 "$whoami: $key=$value"
15 eval "$key=$value"
16 done
17 IFS=$OIFS
18 EOF
20 write_script git-credential-useless <<-\EOF &&
21 . ./dump
22 exit 0
23 EOF
25 write_script git-credential-quit <<-\EOF &&
26 . ./dump
27 echo quit=1
28 EOF
30 write_script git-credential-verbatim <<-\EOF &&
31 user=$1; shift
32 pass=$1; shift
33 . ./dump
34 test -z "$user" || echo username=$user
35 test -z "$pass" || echo password=$pass
36 EOF
38 write_script git-credential-verbatim-with-expiry <<-\EOF &&
39 user=$1; shift
40 pass=$1; shift
41 pexpiry=$1; shift
42 . ./dump
43 test -z "$user" || echo username=$user
44 test -z "$pass" || echo password=$pass
45 test -z "$pexpiry" || echo password_expiry_utc=$pexpiry
46 EOF
48 PATH="$PWD:$PATH"
51 test_expect_success 'credential_fill invokes helper' '
52 check fill "verbatim foo bar" <<-\EOF
53 protocol=http
54 host=example.com
56 protocol=http
57 host=example.com
58 username=foo
59 password=bar
61 verbatim: get
62 verbatim: protocol=http
63 verbatim: host=example.com
64 EOF
67 test_expect_success 'credential_fill invokes multiple helpers' '
68 check fill useless "verbatim foo bar" <<-\EOF
69 protocol=http
70 host=example.com
72 protocol=http
73 host=example.com
74 username=foo
75 password=bar
77 useless: get
78 useless: protocol=http
79 useless: host=example.com
80 verbatim: get
81 verbatim: protocol=http
82 verbatim: host=example.com
83 EOF
86 test_expect_success 'credential_fill stops when we get a full response' '
87 check fill "verbatim one two" "verbatim three four" <<-\EOF
88 protocol=http
89 host=example.com
91 protocol=http
92 host=example.com
93 username=one
94 password=two
96 verbatim: get
97 verbatim: protocol=http
98 verbatim: host=example.com
99 EOF
102 test_expect_success 'credential_fill continues through partial response' '
103 check fill "verbatim one \"\"" "verbatim two three" <<-\EOF
104 protocol=http
105 host=example.com
107 protocol=http
108 host=example.com
109 username=two
110 password=three
112 verbatim: get
113 verbatim: protocol=http
114 verbatim: host=example.com
115 verbatim: get
116 verbatim: protocol=http
117 verbatim: host=example.com
118 verbatim: username=one
122 test_expect_success 'credential_fill populates password_expiry_utc' '
123 check fill "verbatim-with-expiry one two 9999999999" <<-\EOF
124 protocol=http
125 host=example.com
127 protocol=http
128 host=example.com
129 username=one
130 password=two
131 password_expiry_utc=9999999999
133 verbatim-with-expiry: get
134 verbatim-with-expiry: protocol=http
135 verbatim-with-expiry: host=example.com
139 test_expect_success 'credential_fill ignores expired password' '
140 check fill "verbatim-with-expiry one two 5" "verbatim three four" <<-\EOF
141 protocol=http
142 host=example.com
144 protocol=http
145 host=example.com
146 username=three
147 password=four
149 verbatim-with-expiry: get
150 verbatim-with-expiry: protocol=http
151 verbatim-with-expiry: host=example.com
152 verbatim: get
153 verbatim: protocol=http
154 verbatim: host=example.com
155 verbatim: username=one
159 test_expect_success 'credential_fill passes along metadata' '
160 check fill "verbatim one two" <<-\EOF
161 protocol=ftp
162 host=example.com
163 path=foo.git
165 protocol=ftp
166 host=example.com
167 path=foo.git
168 username=one
169 password=two
171 verbatim: get
172 verbatim: protocol=ftp
173 verbatim: host=example.com
174 verbatim: path=foo.git
178 test_expect_success 'credential_approve calls all helpers' '
179 check approve useless "verbatim one two" <<-\EOF
180 protocol=http
181 host=example.com
182 username=foo
183 password=bar
186 useless: store
187 useless: protocol=http
188 useless: host=example.com
189 useless: username=foo
190 useless: password=bar
191 verbatim: store
192 verbatim: protocol=http
193 verbatim: host=example.com
194 verbatim: username=foo
195 verbatim: password=bar
199 test_expect_success 'credential_approve stores password expiry' '
200 check approve useless <<-\EOF
201 protocol=http
202 host=example.com
203 username=foo
204 password=bar
205 password_expiry_utc=9999999999
208 useless: store
209 useless: protocol=http
210 useless: host=example.com
211 useless: username=foo
212 useless: password=bar
213 useless: password_expiry_utc=9999999999
217 test_expect_success 'do not bother storing password-less credential' '
218 check approve useless <<-\EOF
219 protocol=http
220 host=example.com
221 username=foo
227 test_expect_success 'credential_approve does not store expired password' '
228 check approve useless <<-\EOF
229 protocol=http
230 host=example.com
231 username=foo
232 password=bar
233 password_expiry_utc=5
239 test_expect_success 'credential_reject calls all helpers' '
240 check reject useless "verbatim one two" <<-\EOF
241 protocol=http
242 host=example.com
243 username=foo
244 password=bar
247 useless: erase
248 useless: protocol=http
249 useless: host=example.com
250 useless: username=foo
251 useless: password=bar
252 verbatim: erase
253 verbatim: protocol=http
254 verbatim: host=example.com
255 verbatim: username=foo
256 verbatim: password=bar
260 test_expect_success 'credential_reject erases credential regardless of expiry' '
261 check reject useless <<-\EOF
262 protocol=http
263 host=example.com
264 username=foo
265 password=bar
266 password_expiry_utc=5
269 useless: erase
270 useless: protocol=http
271 useless: host=example.com
272 useless: username=foo
273 useless: password=bar
274 useless: password_expiry_utc=5
278 test_expect_success 'usernames can be preserved' '
279 check fill "verbatim \"\" three" <<-\EOF
280 protocol=http
281 host=example.com
282 username=one
284 protocol=http
285 host=example.com
286 username=one
287 password=three
289 verbatim: get
290 verbatim: protocol=http
291 verbatim: host=example.com
292 verbatim: username=one
296 test_expect_success 'usernames can be overridden' '
297 check fill "verbatim two three" <<-\EOF
298 protocol=http
299 host=example.com
300 username=one
302 protocol=http
303 host=example.com
304 username=two
305 password=three
307 verbatim: get
308 verbatim: protocol=http
309 verbatim: host=example.com
310 verbatim: username=one
314 test_expect_success 'do not bother completing already-full credential' '
315 check fill "verbatim three four" <<-\EOF
316 protocol=http
317 host=example.com
318 username=one
319 password=two
321 protocol=http
322 host=example.com
323 username=one
324 password=two
329 # We can't test the basic terminal password prompt here because
330 # getpass() tries too hard to find the real terminal. But if our
331 # askpass helper is run, we know the internal getpass is working.
332 test_expect_success 'empty helper list falls back to internal getpass' '
333 check fill <<-\EOF
334 protocol=http
335 host=example.com
337 protocol=http
338 host=example.com
339 username=askpass-username
340 password=askpass-password
342 askpass: Username for '\''http://example.com'\'':
343 askpass: Password for '\''http://askpass-username@example.com'\'':
347 test_expect_success 'internal getpass does not ask for known username' '
348 check fill <<-\EOF
349 protocol=http
350 host=example.com
351 username=foo
353 protocol=http
354 host=example.com
355 username=foo
356 password=askpass-password
358 askpass: Password for '\''http://foo@example.com'\'':
362 test_expect_success 'git-credential respects core.askPass' '
363 write_script alternate-askpass <<-\EOF &&
364 echo >&2 "alternate askpass invoked"
365 echo alternate-value
367 test_config core.askpass "$PWD/alternate-askpass" &&
369 # unset GIT_ASKPASS set by lib-credential.sh which would
370 # override our config, but do so in a subshell so that we do
371 # not interfere with other tests
372 sane_unset GIT_ASKPASS &&
373 check fill <<-\EOF
374 protocol=http
375 host=example.com
377 protocol=http
378 host=example.com
379 username=alternate-value
380 password=alternate-value
382 alternate askpass invoked
383 alternate askpass invoked
388 HELPER="!f() {
389 cat >/dev/null
390 echo username=foo
391 echo password=bar
392 }; f"
393 test_expect_success 'respect configured credentials' '
394 test_config credential.helper "$HELPER" &&
395 check fill <<-\EOF
396 protocol=http
397 host=example.com
399 protocol=http
400 host=example.com
401 username=foo
402 password=bar
407 test_expect_success 'match configured credential' '
408 test_config credential.https://example.com.helper "$HELPER" &&
409 check fill <<-\EOF
410 protocol=https
411 host=example.com
412 path=repo.git
414 protocol=https
415 host=example.com
416 username=foo
417 password=bar
422 test_expect_success 'do not match configured credential' '
423 test_config credential.https://foo.helper "$HELPER" &&
424 check fill <<-\EOF
425 protocol=https
426 host=bar
428 protocol=https
429 host=bar
430 username=askpass-username
431 password=askpass-password
433 askpass: Username for '\''https://bar'\'':
434 askpass: Password for '\''https://askpass-username@bar'\'':
438 test_expect_success 'match multiple configured helpers' '
439 test_config credential.helper "verbatim \"\" \"\"" &&
440 test_config credential.https://example.com.helper "$HELPER" &&
441 check fill <<-\EOF
442 protocol=https
443 host=example.com
444 path=repo.git
446 protocol=https
447 host=example.com
448 username=foo
449 password=bar
451 verbatim: get
452 verbatim: protocol=https
453 verbatim: host=example.com
457 test_expect_success 'match multiple configured helpers with URLs' '
458 test_config credential.https://example.com/repo.git.helper "verbatim \"\" \"\"" &&
459 test_config credential.https://example.com.helper "$HELPER" &&
460 check fill <<-\EOF
461 protocol=https
462 host=example.com
463 path=repo.git
465 protocol=https
466 host=example.com
467 username=foo
468 password=bar
470 verbatim: get
471 verbatim: protocol=https
472 verbatim: host=example.com
476 test_expect_success 'match percent-encoded values' '
477 test_config credential.https://example.com/%2566.git.helper "$HELPER" &&
478 check fill <<-\EOF
479 url=https://example.com/%2566.git
481 protocol=https
482 host=example.com
483 username=foo
484 password=bar
489 test_expect_success 'match percent-encoded UTF-8 values in path' '
490 test_config credential.https://example.com.useHttpPath true &&
491 test_config credential.https://example.com/perú.git.helper "$HELPER" &&
492 check fill <<-\EOF
493 url=https://example.com/per%C3%BA.git
495 protocol=https
496 host=example.com
497 path=perú.git
498 username=foo
499 password=bar
504 test_expect_success 'match percent-encoded values in username' '
505 test_config credential.https://user%2fname@example.com/foo/bar.git.helper "$HELPER" &&
506 check fill <<-\EOF
507 url=https://user%2fname@example.com/foo/bar.git
509 protocol=https
510 host=example.com
511 username=foo
512 password=bar
517 test_expect_success 'fetch with multiple path components' '
518 test_unconfig credential.helper &&
519 test_config credential.https://example.com/foo/repo.git.helper "verbatim foo bar" &&
520 check fill <<-\EOF
521 url=https://example.com/foo/repo.git
523 protocol=https
524 host=example.com
525 username=foo
526 password=bar
528 verbatim: get
529 verbatim: protocol=https
530 verbatim: host=example.com
534 test_expect_success 'pull username from config' '
535 test_config credential.https://example.com.username foo &&
536 check fill <<-\EOF
537 protocol=https
538 host=example.com
540 protocol=https
541 host=example.com
542 username=foo
543 password=askpass-password
545 askpass: Password for '\''https://foo@example.com'\'':
549 test_expect_success 'honors username from URL over helper (URL)' '
550 test_config credential.https://example.com.username bob &&
551 test_config credential.https://example.com.helper "verbatim \"\" bar" &&
552 check fill <<-\EOF
553 url=https://alice@example.com
555 protocol=https
556 host=example.com
557 username=alice
558 password=bar
560 verbatim: get
561 verbatim: protocol=https
562 verbatim: host=example.com
563 verbatim: username=alice
567 test_expect_success 'honors username from URL over helper (components)' '
568 test_config credential.https://example.com.username bob &&
569 test_config credential.https://example.com.helper "verbatim \"\" bar" &&
570 check fill <<-\EOF
571 protocol=https
572 host=example.com
573 username=alice
575 protocol=https
576 host=example.com
577 username=alice
578 password=bar
580 verbatim: get
581 verbatim: protocol=https
582 verbatim: host=example.com
583 verbatim: username=alice
587 test_expect_success 'last matching username wins' '
588 test_config credential.https://example.com/path.git.username bob &&
589 test_config credential.https://example.com.username alice &&
590 test_config credential.https://example.com.helper "verbatim \"\" bar" &&
591 check fill <<-\EOF
592 url=https://example.com/path.git
594 protocol=https
595 host=example.com
596 username=alice
597 password=bar
599 verbatim: get
600 verbatim: protocol=https
601 verbatim: host=example.com
602 verbatim: username=alice
606 test_expect_success 'http paths can be part of context' '
607 check fill "verbatim foo bar" <<-\EOF &&
608 protocol=https
609 host=example.com
610 path=foo.git
612 protocol=https
613 host=example.com
614 username=foo
615 password=bar
617 verbatim: get
618 verbatim: protocol=https
619 verbatim: host=example.com
621 test_config credential.https://example.com.useHttpPath true &&
622 check fill "verbatim foo bar" <<-\EOF
623 protocol=https
624 host=example.com
625 path=foo.git
627 protocol=https
628 host=example.com
629 path=foo.git
630 username=foo
631 password=bar
633 verbatim: get
634 verbatim: protocol=https
635 verbatim: host=example.com
636 verbatim: path=foo.git
640 test_expect_success 'context uses urlmatch' '
641 test_config "credential.https://*.org.useHttpPath" true &&
642 check fill "verbatim foo bar" <<-\EOF
643 protocol=https
644 host=example.org
645 path=foo.git
647 protocol=https
648 host=example.org
649 path=foo.git
650 username=foo
651 password=bar
653 verbatim: get
654 verbatim: protocol=https
655 verbatim: host=example.org
656 verbatim: path=foo.git
660 test_expect_success 'helpers can abort the process' '
661 test_must_fail git \
662 -c credential.helper=quit \
663 -c credential.helper="verbatim foo bar" \
664 credential fill >stdout 2>stderr <<-\EOF &&
665 protocol=http
666 host=example.com
668 test_must_be_empty stdout &&
669 cat >expect <<-\EOF &&
670 quit: get
671 quit: protocol=http
672 quit: host=example.com
673 fatal: credential helper '\''quit'\'' told us to quit
675 test_cmp expect stderr
678 test_expect_success 'empty helper spec resets helper list' '
679 test_config credential.helper "verbatim file file" &&
680 check fill "" "verbatim cmdline cmdline" <<-\EOF
681 protocol=http
682 host=example.com
684 protocol=http
685 host=example.com
686 username=cmdline
687 password=cmdline
689 verbatim: get
690 verbatim: protocol=http
691 verbatim: host=example.com
695 test_expect_success 'url parser rejects embedded newlines' '
696 test_must_fail git credential fill 2>stderr <<-\EOF &&
697 url=https://one.example.com?%0ahost=two.example.com/
699 cat >expect <<-\EOF &&
700 warning: url contains a newline in its path component: https://one.example.com?%0ahost=two.example.com/
701 fatal: credential url cannot be parsed: https://one.example.com?%0ahost=two.example.com/
703 test_cmp expect stderr
706 test_expect_success 'host-less URLs are parsed as empty host' '
707 check fill "verbatim foo bar" <<-\EOF
708 url=cert:///path/to/cert.pem
710 protocol=cert
711 host=
712 path=path/to/cert.pem
713 username=foo
714 password=bar
716 verbatim: get
717 verbatim: protocol=cert
718 verbatim: host=
719 verbatim: path=path/to/cert.pem
723 test_expect_success 'credential system refuses to work with missing host' '
724 test_must_fail git credential fill 2>stderr <<-\EOF &&
725 protocol=http
727 cat >expect <<-\EOF &&
728 fatal: refusing to work with credential missing host field
730 test_cmp expect stderr
733 test_expect_success 'credential system refuses to work with missing protocol' '
734 test_must_fail git credential fill 2>stderr <<-\EOF &&
735 host=example.com
737 cat >expect <<-\EOF &&
738 fatal: refusing to work with credential missing protocol field
740 test_cmp expect stderr
743 # usage: check_host_and_path <url> <expected-host> <expected-path>
744 check_host_and_path () {
745 # we always parse the path component, but we need this to make sure it
746 # is passed to the helper
747 test_config credential.useHTTPPath true &&
748 check fill "verbatim user pass" <<-EOF
749 url=$1
751 protocol=https
752 host=$2
753 path=$3
754 username=user
755 password=pass
757 verbatim: get
758 verbatim: protocol=https
759 verbatim: host=$2
760 verbatim: path=$3
764 test_expect_success 'url parser handles bare query marker' '
765 check_host_and_path https://example.com?foo.git example.com ?foo.git
768 test_expect_success 'url parser handles bare fragment marker' '
769 check_host_and_path https://example.com#foo.git example.com "#foo.git"
772 test_expect_success 'url parser not confused by encoded markers' '
773 check_host_and_path https://example.com%23%3f%2f/foo.git \
774 "example.com#?/" foo.git
777 test_expect_success 'credential config with partial URLs' '
778 echo "echo password=yep" | write_script git-credential-yep &&
779 test_write_lines url=https://user@example.com/repo.git >stdin &&
780 for partial in \
781 example.com \
782 user@example.com \
783 https:// \
784 https://example.com \
785 https://example.com/ \
786 https://user@example.com \
787 https://user@example.com/ \
788 https://example.com/repo.git \
789 https://user@example.com/repo.git \
790 /repo.git
792 git -c credential.$partial.helper=yep \
793 credential fill <stdin >stdout &&
794 grep yep stdout ||
795 return 1
796 done &&
798 for partial in \
799 dont.use.this \
800 http:// \
801 /repo
803 git -c credential.$partial.helper=yep \
804 credential fill <stdin >stdout &&
805 ! grep yep stdout ||
806 return 1
807 done &&
809 git -c credential.$partial.helper=yep \
810 -c credential.with%0anewline.username=uh-oh \
811 credential fill <stdin >stdout 2>stderr &&
812 test_i18ngrep "skipping credential lookup for key" stderr
815 test_done