]> git.ipfire.org Git - thirdparty/git.git/blame - t/t0300-credentials.sh
credential: new attribute password_expiry_utc
[thirdparty/git.git] / t / t0300-credentials.sh
CommitLineData
abca927d
JK
1#!/bin/sh
2
3test_description='basic credential helper tests'
4. ./test-lib.sh
5. "$TEST_DIRECTORY"/lib-credential.sh
6
7test_expect_success 'setup helper scripts' '
8 cat >dump <<-\EOF &&
dd64267f 9 whoami=$(echo $0 | sed s/.*git-credential-//)
abca927d 10 echo >&2 "$whoami: $*"
78ed1d2d
MG
11 OIFS=$IFS
12 IFS==
13 while read key value; do
abca927d
JK
14 echo >&2 "$whoami: $key=$value"
15 eval "$key=$value"
16 done
78ed1d2d 17 IFS=$OIFS
abca927d
JK
18 EOF
19
3d9f5b67 20 write_script git-credential-useless <<-\EOF &&
abca927d
JK
21 . ./dump
22 exit 0
23 EOF
abca927d 24
a88dbd2f
JK
25 write_script git-credential-quit <<-\EOF &&
26 . ./dump
27 echo quit=1
28 EOF
29
3d9f5b67 30 write_script git-credential-verbatim <<-\EOF &&
abca927d
JK
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
abca927d 37
d208bfdf
H
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
47
abca927d
JK
48 PATH="$PWD:$PATH"
49'
50
51test_expect_success 'credential_fill invokes helper' '
52 check fill "verbatim foo bar" <<-\EOF
73aafe9b
JK
53 protocol=http
54 host=example.com
abca927d 55 --
73aafe9b
JK
56 protocol=http
57 host=example.com
abca927d
JK
58 username=foo
59 password=bar
60 --
61 verbatim: get
73aafe9b
JK
62 verbatim: protocol=http
63 verbatim: host=example.com
abca927d
JK
64 EOF
65'
66
67test_expect_success 'credential_fill invokes multiple helpers' '
68 check fill useless "verbatim foo bar" <<-\EOF
73aafe9b
JK
69 protocol=http
70 host=example.com
abca927d 71 --
73aafe9b
JK
72 protocol=http
73 host=example.com
abca927d
JK
74 username=foo
75 password=bar
76 --
77 useless: get
73aafe9b
JK
78 useless: protocol=http
79 useless: host=example.com
abca927d 80 verbatim: get
73aafe9b
JK
81 verbatim: protocol=http
82 verbatim: host=example.com
abca927d
JK
83 EOF
84'
85
86test_expect_success 'credential_fill stops when we get a full response' '
87 check fill "verbatim one two" "verbatim three four" <<-\EOF
73aafe9b
JK
88 protocol=http
89 host=example.com
abca927d 90 --
73aafe9b
JK
91 protocol=http
92 host=example.com
abca927d
JK
93 username=one
94 password=two
95 --
96 verbatim: get
73aafe9b
JK
97 verbatim: protocol=http
98 verbatim: host=example.com
abca927d
JK
99 EOF
100'
101
102test_expect_success 'credential_fill continues through partial response' '
103 check fill "verbatim one \"\"" "verbatim two three" <<-\EOF
73aafe9b
JK
104 protocol=http
105 host=example.com
abca927d 106 --
73aafe9b
JK
107 protocol=http
108 host=example.com
abca927d
JK
109 username=two
110 password=three
111 --
112 verbatim: get
73aafe9b
JK
113 verbatim: protocol=http
114 verbatim: host=example.com
abca927d 115 verbatim: get
73aafe9b
JK
116 verbatim: protocol=http
117 verbatim: host=example.com
abca927d
JK
118 verbatim: username=one
119 EOF
120'
121
d208bfdf
H
122test_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
126 --
127 protocol=http
128 host=example.com
129 username=one
130 password=two
131 password_expiry_utc=9999999999
132 --
133 verbatim-with-expiry: get
134 verbatim-with-expiry: protocol=http
135 verbatim-with-expiry: host=example.com
136 EOF
137'
138
139test_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
143 --
144 protocol=http
145 host=example.com
146 username=three
147 password=four
148 --
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
156 EOF
157'
158
abca927d
JK
159test_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
164 --
2d6dc182
MM
165 protocol=ftp
166 host=example.com
167 path=foo.git
abca927d
JK
168 username=one
169 password=two
170 --
171 verbatim: get
172 verbatim: protocol=ftp
173 verbatim: host=example.com
174 verbatim: path=foo.git
175 EOF
176'
177
178test_expect_success 'credential_approve calls all helpers' '
179 check approve useless "verbatim one two" <<-\EOF
73aafe9b
JK
180 protocol=http
181 host=example.com
abca927d
JK
182 username=foo
183 password=bar
184 --
185 --
186 useless: store
73aafe9b
JK
187 useless: protocol=http
188 useless: host=example.com
abca927d
JK
189 useless: username=foo
190 useless: password=bar
191 verbatim: store
73aafe9b
JK
192 verbatim: protocol=http
193 verbatim: host=example.com
abca927d
JK
194 verbatim: username=foo
195 verbatim: password=bar
196 EOF
197'
198
d208bfdf
H
199test_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
206 --
207 --
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
214 EOF
215'
216
abca927d
JK
217test_expect_success 'do not bother storing password-less credential' '
218 check approve useless <<-\EOF
73aafe9b
JK
219 protocol=http
220 host=example.com
abca927d
JK
221 username=foo
222 --
223 --
224 EOF
225'
226
d208bfdf
H
227test_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
234 --
235 --
236 EOF
237'
abca927d
JK
238
239test_expect_success 'credential_reject calls all helpers' '
240 check reject useless "verbatim one two" <<-\EOF
73aafe9b
JK
241 protocol=http
242 host=example.com
abca927d
JK
243 username=foo
244 password=bar
245 --
246 --
247 useless: erase
73aafe9b
JK
248 useless: protocol=http
249 useless: host=example.com
abca927d
JK
250 useless: username=foo
251 useless: password=bar
252 verbatim: erase
73aafe9b
JK
253 verbatim: protocol=http
254 verbatim: host=example.com
abca927d
JK
255 verbatim: username=foo
256 verbatim: password=bar
257 EOF
258'
259
d208bfdf
H
260test_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
267 --
268 --
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
275 EOF
276'
277
abca927d
JK
278test_expect_success 'usernames can be preserved' '
279 check fill "verbatim \"\" three" <<-\EOF
73aafe9b
JK
280 protocol=http
281 host=example.com
abca927d
JK
282 username=one
283 --
73aafe9b
JK
284 protocol=http
285 host=example.com
abca927d
JK
286 username=one
287 password=three
288 --
289 verbatim: get
73aafe9b
JK
290 verbatim: protocol=http
291 verbatim: host=example.com
abca927d
JK
292 verbatim: username=one
293 EOF
294'
295
296test_expect_success 'usernames can be overridden' '
297 check fill "verbatim two three" <<-\EOF
73aafe9b
JK
298 protocol=http
299 host=example.com
abca927d
JK
300 username=one
301 --
73aafe9b
JK
302 protocol=http
303 host=example.com
abca927d
JK
304 username=two
305 password=three
306 --
307 verbatim: get
73aafe9b
JK
308 verbatim: protocol=http
309 verbatim: host=example.com
abca927d
JK
310 verbatim: username=one
311 EOF
312'
313
314test_expect_success 'do not bother completing already-full credential' '
315 check fill "verbatim three four" <<-\EOF
73aafe9b
JK
316 protocol=http
317 host=example.com
abca927d
JK
318 username=one
319 password=two
320 --
73aafe9b
JK
321 protocol=http
322 host=example.com
abca927d
JK
323 username=one
324 password=two
325 --
326 EOF
327'
328
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.
332test_expect_success 'empty helper list falls back to internal getpass' '
333 check fill <<-\EOF
73aafe9b
JK
334 protocol=http
335 host=example.com
abca927d 336 --
73aafe9b
JK
337 protocol=http
338 host=example.com
abca927d
JK
339 username=askpass-username
340 password=askpass-password
341 --
73aafe9b
JK
342 askpass: Username for '\''http://example.com'\'':
343 askpass: Password for '\''http://askpass-username@example.com'\'':
abca927d
JK
344 EOF
345'
346
347test_expect_success 'internal getpass does not ask for known username' '
348 check fill <<-\EOF
73aafe9b
JK
349 protocol=http
350 host=example.com
abca927d
JK
351 username=foo
352 --
73aafe9b
JK
353 protocol=http
354 host=example.com
abca927d
JK
355 username=foo
356 password=askpass-password
357 --
73aafe9b 358 askpass: Password for '\''http://foo@example.com'\'':
abca927d
JK
359 EOF
360'
361
567ad2c0
TK
362test_expect_success 'git-credential respects core.askPass' '
363 write_script alternate-askpass <<-\EOF &&
364 echo >&2 "alternate askpass invoked"
365 echo alternate-value
366 EOF
367 test_config core.askpass "$PWD/alternate-askpass" &&
368 (
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
376 --
377 protocol=http
378 host=example.com
379 username=alternate-value
380 password=alternate-value
381 --
382 alternate askpass invoked
383 alternate askpass invoked
384 EOF
385 )
386'
387
11825072
JK
388HELPER="!f() {
389 cat >/dev/null
390 echo username=foo
391 echo password=bar
392 }; f"
393test_expect_success 'respect configured credentials' '
394 test_config credential.helper "$HELPER" &&
395 check fill <<-\EOF
73aafe9b
JK
396 protocol=http
397 host=example.com
11825072 398 --
73aafe9b
JK
399 protocol=http
400 host=example.com
11825072
JK
401 username=foo
402 password=bar
403 --
404 EOF
405'
406
407test_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
413 --
2d6dc182
MM
414 protocol=https
415 host=example.com
11825072
JK
416 username=foo
417 password=bar
418 --
419 EOF
420'
421
422test_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
427 --
2d6dc182
MM
428 protocol=https
429 host=bar
11825072
JK
430 username=askpass-username
431 password=askpass-password
432 --
433 askpass: Username for '\''https://bar'\'':
434 askpass: Password for '\''https://askpass-username@bar'\'':
435 EOF
436'
437
588c70e1 438test_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
445 --
446 protocol=https
447 host=example.com
448 username=foo
449 password=bar
450 --
451 verbatim: get
452 verbatim: protocol=https
453 verbatim: host=example.com
454 EOF
455'
456
457test_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
464 --
465 protocol=https
466 host=example.com
467 username=foo
468 password=bar
469 --
470 verbatim: get
471 verbatim: protocol=https
472 verbatim: host=example.com
473 EOF
474'
475
476test_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
480 --
481 protocol=https
482 host=example.com
483 username=foo
484 password=bar
485 --
486 EOF
487'
488
b44d0118 489test_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
494 --
495 protocol=https
496 host=example.com
497 path=perú.git
498 username=foo
499 password=bar
500 --
501 EOF
502'
503
504test_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
508 --
509 protocol=https
510 host=example.com
511 username=foo
512 password=bar
513 --
514 EOF
515'
516
517test_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
522 --
523 protocol=https
524 host=example.com
525 username=foo
526 password=bar
527 --
528 verbatim: get
529 verbatim: protocol=https
530 verbatim: host=example.com
531 EOF
532'
533
d5742425
JK
534test_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
539 --
2d6dc182
MM
540 protocol=https
541 host=example.com
d5742425
JK
542 username=foo
543 password=askpass-password
544 --
545 askpass: Password for '\''https://foo@example.com'\'':
546 EOF
547'
548
588c70e1 549test_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
554 --
555 protocol=https
556 host=example.com
557 username=alice
558 password=bar
559 --
560 verbatim: get
561 verbatim: protocol=https
562 verbatim: host=example.com
563 verbatim: username=alice
564 EOF
565'
566
567test_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
574 --
575 protocol=https
576 host=example.com
577 username=alice
578 password=bar
579 --
580 verbatim: get
581 verbatim: protocol=https
582 verbatim: host=example.com
583 verbatim: username=alice
584 EOF
585'
586
82eb2498 587test_expect_success 'last matching username wins' '
588c70e1 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
593 --
594 protocol=https
595 host=example.com
596 username=alice
597 password=bar
598 --
599 verbatim: get
600 verbatim: protocol=https
601 verbatim: host=example.com
602 verbatim: username=alice
603 EOF
604'
605
a78fbb4f
JK
606test_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
611 --
2d6dc182
MM
612 protocol=https
613 host=example.com
a78fbb4f
JK
614 username=foo
615 password=bar
616 --
617 verbatim: get
618 verbatim: protocol=https
619 verbatim: host=example.com
620 EOF
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
626 --
2d6dc182
MM
627 protocol=https
628 host=example.com
629 path=foo.git
a78fbb4f
JK
630 username=foo
631 password=bar
632 --
633 verbatim: get
634 verbatim: protocol=https
635 verbatim: host=example.com
636 verbatim: path=foo.git
637 EOF
638'
639
46fd7b39 640test_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
646 --
647 protocol=https
648 host=example.org
649 path=foo.git
650 username=foo
651 password=bar
652 --
653 verbatim: get
654 verbatim: protocol=https
655 verbatim: host=example.org
656 verbatim: path=foo.git
657 EOF
658'
659
59b38652
JK
660test_expect_success 'helpers can abort the process' '
661 test_must_fail git \
a88dbd2f 662 -c credential.helper=quit \
59b38652 663 -c credential.helper="verbatim foo bar" \
73aafe9b
JK
664 credential fill >stdout 2>stderr <<-\EOF &&
665 protocol=http
666 host=example.com
667 EOF
76b54ee9 668 test_must_be_empty stdout &&
a88dbd2f
JK
669 cat >expect <<-\EOF &&
670 quit: get
73aafe9b
JK
671 quit: protocol=http
672 quit: host=example.com
a88dbd2f
JK
673 fatal: credential helper '\''quit'\'' told us to quit
674 EOF
1108cea7 675 test_cmp expect stderr
59b38652
JK
676'
677
24321375
JK
678test_expect_success 'empty helper spec resets helper list' '
679 test_config credential.helper "verbatim file file" &&
680 check fill "" "verbatim cmdline cmdline" <<-\EOF
73aafe9b
JK
681 protocol=http
682 host=example.com
24321375 683 --
73aafe9b
JK
684 protocol=http
685 host=example.com
24321375
JK
686 username=cmdline
687 password=cmdline
688 --
689 verbatim: get
73aafe9b
JK
690 verbatim: protocol=http
691 verbatim: host=example.com
24321375
JK
692 EOF
693'
694
8ba8ed56
JK
695test_expect_success 'url parser rejects embedded newlines' '
696 test_must_fail git credential fill 2>stderr <<-\EOF &&
9a6bbee8 697 url=https://one.example.com?%0ahost=two.example.com/
8ba8ed56
JK
698 EOF
699 cat >expect <<-\EOF &&
a397e9c2 700 warning: url contains a newline in its path component: https://one.example.com?%0ahost=two.example.com/
fe29a9b7 701 fatal: credential url cannot be parsed: https://one.example.com?%0ahost=two.example.com/
9a6bbee8 702 EOF
1108cea7 703 test_cmp expect stderr
9a6bbee8
JK
704'
705
24036686
JK
706test_expect_success 'host-less URLs are parsed as empty host' '
707 check fill "verbatim foo bar" <<-\EOF
708 url=cert:///path/to/cert.pem
c716fe4b 709 --
24036686
JK
710 protocol=cert
711 host=
712 path=path/to/cert.pem
713 username=foo
714 password=bar
c716fe4b 715 --
24036686
JK
716 verbatim: get
717 verbatim: protocol=cert
718 verbatim: host=
719 verbatim: path=path/to/cert.pem
720 EOF
721'
722
8ba8ed56
JK
723test_expect_success 'credential system refuses to work with missing host' '
724 test_must_fail git credential fill 2>stderr <<-\EOF &&
725 protocol=http
726 EOF
727 cat >expect <<-\EOF &&
728 fatal: refusing to work with credential missing host field
729 EOF
1108cea7 730 test_cmp expect stderr
8ba8ed56
JK
731'
732
733test_expect_success 'credential system refuses to work with missing protocol' '
734 test_must_fail git credential fill 2>stderr <<-\EOF &&
735 host=example.com
736 EOF
737 cat >expect <<-\EOF &&
738 fatal: refusing to work with credential missing protocol field
9a6bbee8 739 EOF
1108cea7 740 test_cmp expect stderr
9a6bbee8
JK
741'
742
4c5971e1
JK
743# usage: check_host_and_path <url> <expected-host> <expected-path>
744check_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
750 --
751 protocol=https
752 host=$2
753 path=$3
754 username=user
755 password=pass
756 --
757 verbatim: get
758 verbatim: protocol=https
759 verbatim: host=$2
760 verbatim: path=$3
761 EOF
762}
763
764test_expect_success 'url parser handles bare query marker' '
765 check_host_and_path https://example.com?foo.git example.com ?foo.git
766'
767
768test_expect_success 'url parser handles bare fragment marker' '
769 check_host_and_path https://example.com#foo.git example.com "#foo.git"
770'
771
772test_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
775'
776
9a121b0d
JS
777test_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
791 do
792 git -c credential.$partial.helper=yep \
793 credential fill <stdin >stdout &&
794 grep yep stdout ||
795 return 1
796 done &&
797
798 for partial in \
799 dont.use.this \
800 http:// \
801 /repo
802 do
803 git -c credential.$partial.helper=yep \
804 credential fill <stdin >stdout &&
805 ! grep yep stdout ||
806 return 1
807 done &&
808
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
813'
814
abca927d 815test_done