Merge branch 'jc/gnu-hurd-lets-fread-read-dirs'
[git] / t / t0300-credentials.sh
1 #!/bin/sh
2
3 test_description='basic credential helper tests'
4 . ./test-lib.sh
5 . "$TEST_DIRECTORY"/lib-credential.sh
6
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
19
20         write_script git-credential-useless <<-\EOF &&
21         . ./dump
22         exit 0
23         EOF
24
25         write_script git-credential-quit <<-\EOF &&
26         . ./dump
27         echo quit=1
28         EOF
29
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
37
38         PATH="$PWD:$PATH"
39 '
40
41 test_expect_success 'credential_fill invokes helper' '
42         check fill "verbatim foo bar" <<-\EOF
43         protocol=http
44         host=example.com
45         --
46         protocol=http
47         host=example.com
48         username=foo
49         password=bar
50         --
51         verbatim: get
52         verbatim: protocol=http
53         verbatim: host=example.com
54         EOF
55 '
56
57 test_expect_success 'credential_fill invokes multiple helpers' '
58         check fill useless "verbatim foo bar" <<-\EOF
59         protocol=http
60         host=example.com
61         --
62         protocol=http
63         host=example.com
64         username=foo
65         password=bar
66         --
67         useless: get
68         useless: protocol=http
69         useless: host=example.com
70         verbatim: get
71         verbatim: protocol=http
72         verbatim: host=example.com
73         EOF
74 '
75
76 test_expect_success 'credential_fill stops when we get a full response' '
77         check fill "verbatim one two" "verbatim three four" <<-\EOF
78         protocol=http
79         host=example.com
80         --
81         protocol=http
82         host=example.com
83         username=one
84         password=two
85         --
86         verbatim: get
87         verbatim: protocol=http
88         verbatim: host=example.com
89         EOF
90 '
91
92 test_expect_success 'credential_fill continues through partial response' '
93         check fill "verbatim one \"\"" "verbatim two three" <<-\EOF
94         protocol=http
95         host=example.com
96         --
97         protocol=http
98         host=example.com
99         username=two
100         password=three
101         --
102         verbatim: get
103         verbatim: protocol=http
104         verbatim: host=example.com
105         verbatim: get
106         verbatim: protocol=http
107         verbatim: host=example.com
108         verbatim: username=one
109         EOF
110 '
111
112 test_expect_success 'credential_fill passes along metadata' '
113         check fill "verbatim one two" <<-\EOF
114         protocol=ftp
115         host=example.com
116         path=foo.git
117         --
118         protocol=ftp
119         host=example.com
120         path=foo.git
121         username=one
122         password=two
123         --
124         verbatim: get
125         verbatim: protocol=ftp
126         verbatim: host=example.com
127         verbatim: path=foo.git
128         EOF
129 '
130
131 test_expect_success 'credential_approve calls all helpers' '
132         check approve useless "verbatim one two" <<-\EOF
133         protocol=http
134         host=example.com
135         username=foo
136         password=bar
137         --
138         --
139         useless: store
140         useless: protocol=http
141         useless: host=example.com
142         useless: username=foo
143         useless: password=bar
144         verbatim: store
145         verbatim: protocol=http
146         verbatim: host=example.com
147         verbatim: username=foo
148         verbatim: password=bar
149         EOF
150 '
151
152 test_expect_success 'do not bother storing password-less credential' '
153         check approve useless <<-\EOF
154         protocol=http
155         host=example.com
156         username=foo
157         --
158         --
159         EOF
160 '
161
162
163 test_expect_success 'credential_reject calls all helpers' '
164         check reject useless "verbatim one two" <<-\EOF
165         protocol=http
166         host=example.com
167         username=foo
168         password=bar
169         --
170         --
171         useless: erase
172         useless: protocol=http
173         useless: host=example.com
174         useless: username=foo
175         useless: password=bar
176         verbatim: erase
177         verbatim: protocol=http
178         verbatim: host=example.com
179         verbatim: username=foo
180         verbatim: password=bar
181         EOF
182 '
183
184 test_expect_success 'usernames can be preserved' '
185         check fill "verbatim \"\" three" <<-\EOF
186         protocol=http
187         host=example.com
188         username=one
189         --
190         protocol=http
191         host=example.com
192         username=one
193         password=three
194         --
195         verbatim: get
196         verbatim: protocol=http
197         verbatim: host=example.com
198         verbatim: username=one
199         EOF
200 '
201
202 test_expect_success 'usernames can be overridden' '
203         check fill "verbatim two three" <<-\EOF
204         protocol=http
205         host=example.com
206         username=one
207         --
208         protocol=http
209         host=example.com
210         username=two
211         password=three
212         --
213         verbatim: get
214         verbatim: protocol=http
215         verbatim: host=example.com
216         verbatim: username=one
217         EOF
218 '
219
220 test_expect_success 'do not bother completing already-full credential' '
221         check fill "verbatim three four" <<-\EOF
222         protocol=http
223         host=example.com
224         username=one
225         password=two
226         --
227         protocol=http
228         host=example.com
229         username=one
230         password=two
231         --
232         EOF
233 '
234
235 # We can't test the basic terminal password prompt here because
236 # getpass() tries too hard to find the real terminal. But if our
237 # askpass helper is run, we know the internal getpass is working.
238 test_expect_success 'empty helper list falls back to internal getpass' '
239         check fill <<-\EOF
240         protocol=http
241         host=example.com
242         --
243         protocol=http
244         host=example.com
245         username=askpass-username
246         password=askpass-password
247         --
248         askpass: Username for '\''http://example.com'\'':
249         askpass: Password for '\''http://askpass-username@example.com'\'':
250         EOF
251 '
252
253 test_expect_success 'internal getpass does not ask for known username' '
254         check fill <<-\EOF
255         protocol=http
256         host=example.com
257         username=foo
258         --
259         protocol=http
260         host=example.com
261         username=foo
262         password=askpass-password
263         --
264         askpass: Password for '\''http://foo@example.com'\'':
265         EOF
266 '
267
268 HELPER="!f() {
269                 cat >/dev/null
270                 echo username=foo
271                 echo password=bar
272         }; f"
273 test_expect_success 'respect configured credentials' '
274         test_config credential.helper "$HELPER" &&
275         check fill <<-\EOF
276         protocol=http
277         host=example.com
278         --
279         protocol=http
280         host=example.com
281         username=foo
282         password=bar
283         --
284         EOF
285 '
286
287 test_expect_success 'match configured credential' '
288         test_config credential.https://example.com.helper "$HELPER" &&
289         check fill <<-\EOF
290         protocol=https
291         host=example.com
292         path=repo.git
293         --
294         protocol=https
295         host=example.com
296         username=foo
297         password=bar
298         --
299         EOF
300 '
301
302 test_expect_success 'do not match configured credential' '
303         test_config credential.https://foo.helper "$HELPER" &&
304         check fill <<-\EOF
305         protocol=https
306         host=bar
307         --
308         protocol=https
309         host=bar
310         username=askpass-username
311         password=askpass-password
312         --
313         askpass: Username for '\''https://bar'\'':
314         askpass: Password for '\''https://askpass-username@bar'\'':
315         EOF
316 '
317
318 test_expect_success 'match multiple configured helpers' '
319         test_config credential.helper "verbatim \"\" \"\"" &&
320         test_config credential.https://example.com.helper "$HELPER" &&
321         check fill <<-\EOF
322         protocol=https
323         host=example.com
324         path=repo.git
325         --
326         protocol=https
327         host=example.com
328         username=foo
329         password=bar
330         --
331         verbatim: get
332         verbatim: protocol=https
333         verbatim: host=example.com
334         EOF
335 '
336
337 test_expect_success 'match multiple configured helpers with URLs' '
338         test_config credential.https://example.com/repo.git.helper "verbatim \"\" \"\"" &&
339         test_config credential.https://example.com.helper "$HELPER" &&
340         check fill <<-\EOF
341         protocol=https
342         host=example.com
343         path=repo.git
344         --
345         protocol=https
346         host=example.com
347         username=foo
348         password=bar
349         --
350         verbatim: get
351         verbatim: protocol=https
352         verbatim: host=example.com
353         EOF
354 '
355
356 test_expect_success 'match percent-encoded values' '
357         test_config credential.https://example.com/%2566.git.helper "$HELPER" &&
358         check fill <<-\EOF
359         url=https://example.com/%2566.git
360         --
361         protocol=https
362         host=example.com
363         username=foo
364         password=bar
365         --
366         EOF
367 '
368
369 test_expect_success 'pull username from config' '
370         test_config credential.https://example.com.username foo &&
371         check fill <<-\EOF
372         protocol=https
373         host=example.com
374         --
375         protocol=https
376         host=example.com
377         username=foo
378         password=askpass-password
379         --
380         askpass: Password for '\''https://foo@example.com'\'':
381         EOF
382 '
383
384 test_expect_success 'honors username from URL over helper (URL)' '
385         test_config credential.https://example.com.username bob &&
386         test_config credential.https://example.com.helper "verbatim \"\" bar" &&
387         check fill <<-\EOF
388         url=https://alice@example.com
389         --
390         protocol=https
391         host=example.com
392         username=alice
393         password=bar
394         --
395         verbatim: get
396         verbatim: protocol=https
397         verbatim: host=example.com
398         verbatim: username=alice
399         EOF
400 '
401
402 test_expect_success 'honors username from URL over helper (components)' '
403         test_config credential.https://example.com.username bob &&
404         test_config credential.https://example.com.helper "verbatim \"\" bar" &&
405         check fill <<-\EOF
406         protocol=https
407         host=example.com
408         username=alice
409         --
410         protocol=https
411         host=example.com
412         username=alice
413         password=bar
414         --
415         verbatim: get
416         verbatim: protocol=https
417         verbatim: host=example.com
418         verbatim: username=alice
419         EOF
420 '
421
422 test_expect_success 'last matching username wins' '
423         test_config credential.https://example.com/path.git.username bob &&
424         test_config credential.https://example.com.username alice &&
425         test_config credential.https://example.com.helper "verbatim \"\" bar" &&
426         check fill <<-\EOF
427         url=https://example.com/path.git
428         --
429         protocol=https
430         host=example.com
431         username=alice
432         password=bar
433         --
434         verbatim: get
435         verbatim: protocol=https
436         verbatim: host=example.com
437         verbatim: username=alice
438         EOF
439 '
440
441 test_expect_success 'http paths can be part of context' '
442         check fill "verbatim foo bar" <<-\EOF &&
443         protocol=https
444         host=example.com
445         path=foo.git
446         --
447         protocol=https
448         host=example.com
449         username=foo
450         password=bar
451         --
452         verbatim: get
453         verbatim: protocol=https
454         verbatim: host=example.com
455         EOF
456         test_config credential.https://example.com.useHttpPath true &&
457         check fill "verbatim foo bar" <<-\EOF
458         protocol=https
459         host=example.com
460         path=foo.git
461         --
462         protocol=https
463         host=example.com
464         path=foo.git
465         username=foo
466         password=bar
467         --
468         verbatim: get
469         verbatim: protocol=https
470         verbatim: host=example.com
471         verbatim: path=foo.git
472         EOF
473 '
474
475 test_expect_success 'context uses urlmatch' '
476         test_config "credential.https://*.org.useHttpPath" true &&
477         check fill "verbatim foo bar" <<-\EOF
478         protocol=https
479         host=example.org
480         path=foo.git
481         --
482         protocol=https
483         host=example.org
484         path=foo.git
485         username=foo
486         password=bar
487         --
488         verbatim: get
489         verbatim: protocol=https
490         verbatim: host=example.org
491         verbatim: path=foo.git
492         EOF
493 '
494
495 test_expect_success 'helpers can abort the process' '
496         test_must_fail git \
497                 -c credential.helper=quit \
498                 -c credential.helper="verbatim foo bar" \
499                 credential fill >stdout 2>stderr <<-\EOF &&
500         protocol=http
501         host=example.com
502         EOF
503         test_must_be_empty stdout &&
504         cat >expect <<-\EOF &&
505         quit: get
506         quit: protocol=http
507         quit: host=example.com
508         fatal: credential helper '\''quit'\'' told us to quit
509         EOF
510         test_i18ncmp expect stderr
511 '
512
513 test_expect_success 'empty helper spec resets helper list' '
514         test_config credential.helper "verbatim file file" &&
515         check fill "" "verbatim cmdline cmdline" <<-\EOF
516         protocol=http
517         host=example.com
518         --
519         protocol=http
520         host=example.com
521         username=cmdline
522         password=cmdline
523         --
524         verbatim: get
525         verbatim: protocol=http
526         verbatim: host=example.com
527         EOF
528 '
529
530 test_expect_success 'url parser rejects embedded newlines' '
531         test_must_fail git credential fill 2>stderr <<-\EOF &&
532         url=https://one.example.com?%0ahost=two.example.com/
533         EOF
534         cat >expect <<-\EOF &&
535         warning: url contains a newline in its path component: https://one.example.com?%0ahost=two.example.com/
536         fatal: credential url cannot be parsed: https://one.example.com?%0ahost=two.example.com/
537         EOF
538         test_i18ncmp expect stderr
539 '
540
541 test_expect_success 'host-less URLs are parsed as empty host' '
542         check fill "verbatim foo bar" <<-\EOF
543         url=cert:///path/to/cert.pem
544         --
545         protocol=cert
546         host=
547         path=path/to/cert.pem
548         username=foo
549         password=bar
550         --
551         verbatim: get
552         verbatim: protocol=cert
553         verbatim: host=
554         verbatim: path=path/to/cert.pem
555         EOF
556 '
557
558 test_expect_success 'credential system refuses to work with missing host' '
559         test_must_fail git credential fill 2>stderr <<-\EOF &&
560         protocol=http
561         EOF
562         cat >expect <<-\EOF &&
563         fatal: refusing to work with credential missing host field
564         EOF
565         test_i18ncmp expect stderr
566 '
567
568 test_expect_success 'credential system refuses to work with missing protocol' '
569         test_must_fail git credential fill 2>stderr <<-\EOF &&
570         host=example.com
571         EOF
572         cat >expect <<-\EOF &&
573         fatal: refusing to work with credential missing protocol field
574         EOF
575         test_i18ncmp expect stderr
576 '
577
578 # usage: check_host_and_path <url> <expected-host> <expected-path>
579 check_host_and_path () {
580         # we always parse the path component, but we need this to make sure it
581         # is passed to the helper
582         test_config credential.useHTTPPath true &&
583         check fill "verbatim user pass" <<-EOF
584         url=$1
585         --
586         protocol=https
587         host=$2
588         path=$3
589         username=user
590         password=pass
591         --
592         verbatim: get
593         verbatim: protocol=https
594         verbatim: host=$2
595         verbatim: path=$3
596         EOF
597 }
598
599 test_expect_success 'url parser handles bare query marker' '
600         check_host_and_path https://example.com?foo.git example.com ?foo.git
601 '
602
603 test_expect_success 'url parser handles bare fragment marker' '
604         check_host_and_path https://example.com#foo.git example.com "#foo.git"
605 '
606
607 test_expect_success 'url parser not confused by encoded markers' '
608         check_host_and_path https://example.com%23%3f%2f/foo.git \
609                 "example.com#?/" foo.git
610 '
611
612 test_done