@matheusbsbs / matheus-bagliano / commits / 12294990c9
Fork 0

credential: handle `credential.<partial-URL>.<key>` again

In the patches for CVE-2020-11008, the ability to specify credential settings in the config for partial URLs got lost. For example, it used to be possible to specify a credential helper for a specific protocol: [credential "https://"] helper = my-https-helper Likewise, it used to be possible to configure settings for a specific host, e.g.: [credential "dev.azure.com"] useHTTPPath = true Let's reinstate this behavior. While at it, increase the test coverage to document and verify the behavior with a couple other categories of partial URLs. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Johannes Schindelin committed Apr 24, 2020 at 22:35 UTC 12294990c90e043862be9eb7eb22c3784b526340
4 files changed +77 -3
credential.c
+27
@@ -37,6 +37,10 @@ int credential_match(const struct credential *want,
37 #undef CHECK
38 }
39
40 +
41 +static int credential_from_potentially_partial_url(struct credential *c,
42 + const char *url);
43 +
44 static int credential_config_callback(const char *var, const char *value,
45 void *data)
46 {
@@ -82,6 +86,22 @@ static int select_all(const struct urlmatch_item *a,
86 return 0;
87 }
88
89 +static int match_partial_url(const char *url, void *cb)
90 +{
91 + struct credential *c = cb;
92 + struct credential want = CREDENTIAL_INIT;
93 + int matches = 0;
94 +
95 + if (credential_from_potentially_partial_url(&want, url) < 0)
96 + warning(_("skipping credential lookup for key: credential.%s"),
97 + url);
98 + else
99 + matches = credential_match(&want, c);
100 + credential_clear(&want);
101 +
102 + return matches;
103 +}
104 +
105 static void credential_apply_config(struct credential *c)
106 {
107 char *normalized_url;
@@ -101,6 +121,7 @@ static void credential_apply_config(struct credential *c)
121 config.collect_fn = credential_config_callback;
122 config.cascade_fn = NULL;
123 config.select_fn = select_all;
124 + config.fallback_match_fn = match_partial_url;
125 config.cb = c;
126
127 credential_format(c, &url);
@@ -468,6 +489,12 @@ static int credential_from_url_1(struct credential *c, const char *url,
489 return 0;
490 }
491
492 +static int credential_from_potentially_partial_url(struct credential *c,
493 + const char *url)
494 +{
495 + return credential_from_url_1(c, url, 1, 0);
496 +}
497 +
498 int credential_from_url_gently(struct credential *c, const char *url, int quiet)
499 {
500 return credential_from_url_1(c, url, 0, quiet);
t/t0300-credentials.sh
+38
@@ -575,4 +575,42 @@ test_expect_success 'credential system refuses to work with missing protocol' '
575 test_i18ncmp expect stderr
576 '
577
578 +test_expect_success 'credential config with partial URLs' '
579 + echo "echo password=yep" | write_script git-credential-yep &&
580 + test_write_lines url=https://user@example.com/repo.git >stdin &&
581 + for partial in \
582 + example.com \
583 + user@example.com \
584 + https:// \
585 + https://example.com \
586 + https://example.com/ \
587 + https://user@example.com \
588 + https://user@example.com/ \
589 + https://example.com/repo.git \
590 + https://user@example.com/repo.git \
591 + /repo.git
592 + do
593 + git -c credential.$partial.helper=yep \
594 + credential fill <stdin >stdout &&
595 + grep yep stdout ||
596 + return 1
597 + done &&
598 +
599 + for partial in \
600 + dont.use.this \
601 + http:// \
602 + /repo
603 + do
604 + git -c credential.$partial.helper=yep \
605 + credential fill <stdin >stdout &&
606 + ! grep yep stdout ||
607 + return 1
608 + done &&
609 +
610 + git -c credential.$partial.helper=yep \
611 + -c credential.with%0anewline.username=uh-oh \
612 + credential fill <stdin >stdout 2>stderr &&
613 + test_i18ngrep "skipping credential lookup for key" stderr
614 +'
615 +
616 test_done
urlmatch.c
+7 -3
@@ -572,10 +572,14 @@ int urlmatch_config_entry(const char *var, const char *value, void *cb)
572
573 config_url = xmemdupz(key, dot - key);
574 norm_url = url_normalize_1(config_url, &norm_info, 1);
575 + if (norm_url)
576 + retval = match_urls(url, &norm_info, &matched);
577 + else if (collect->fallback_match_fn)
578 + retval = collect->fallback_match_fn(config_url,
579 + collect->cb);
580 + else
581 + retval = 0;
582 free(config_url);
576 - if (!norm_url)
577 - return 0;
578 - retval = match_urls(url, &norm_info, &matched);
583 free(norm_url);
584 if (!retval)
585 return 0;
urlmatch.h
+5
@@ -59,6 +59,11 @@ struct urlmatch_config {
59 * specificity rules) than existing.
60 */
61 int (*select_fn)(const struct urlmatch_item *found, const struct urlmatch_item *existing);
62 + /*
63 + * An optional callback to allow e.g. for partial URLs; it shall
64 + * return 1 or 0 depending whether `url` matches or not.
65 + */
66 + int (*fallback_match_fn)(const char *url, void *cb);
67 };
68
69 int urlmatch_config_entry(const char *var, const char *value, void *cb);