Fix #1403: sslCAInfo config lookup when host in config doesn't have a trailing slash

appendRootCAsForHostFromGitconfig() modified to check hosts with and without a trailing slash.

Cert unit tests made "table driven" and extended to cover this case.
This commit is contained in:
Dakota Hawkins 2016-07-28 15:32:18 -04:00
parent d0028c6e03
commit 24cab8ad99
2 changed files with 58 additions and 40 deletions

@ -51,10 +51,14 @@ func appendRootCAsForHostFromGitconfig(pool *x509.CertPool, host string) *x509.C
if cafile := config.Config.Getenv("GIT_SSL_CAINFO"); len(cafile) > 0 { if cafile := config.Config.Getenv("GIT_SSL_CAINFO"); len(cafile) > 0 {
return appendCertsFromFile(pool, cafile) return appendCertsFromFile(pool, cafile)
} }
// http.<url>.sslcainfo // http.<url>/.sslcainfo or http.<url>.sslcainfo
// we know we have simply "host" or "host:port" // we know we have simply "host" or "host:port"
key := fmt.Sprintf("http.https://%v/.sslcainfo", host) hostKeyWithSlash := fmt.Sprintf("http.https://%v/.sslcainfo", host)
if cafile, ok := config.Config.GitConfig(key); ok { if cafile, ok := config.Config.GitConfig(hostKeyWithSlash); ok {
return appendCertsFromFile(pool, cafile)
}
hostKeyWithoutSlash := fmt.Sprintf("http.https://%v.sslcainfo", host)
if cafile, ok := config.Config.GitConfig(hostKeyWithoutSlash); ok {
return appendCertsFromFile(pool, cafile) return appendCertsFromFile(pool, cafile)
} }
// http.sslcainfo // http.sslcainfo

@ -1,6 +1,7 @@
package httputil package httputil
import ( import (
"fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
@ -34,6 +35,19 @@ aW6vZwkA+ccj/pDTx8LBe2lnpatrFeIt6znAUJW3G8r6SFHKVBWHwmESZS4kxhjx
NpW5Hh0w4/5iIetCkJ0= NpW5Hh0w4/5iIetCkJ0=
-----END CERTIFICATE-----` -----END CERTIFICATE-----`
var sslCAInfoConfigHostNames = []string{
"git-lfs.local",
"git-lfs.local/",
}
var sslCAInfoMatchedHostTests = []struct {
hostName string
shouldMatch bool
}{
{"git-lfs.local", true},
{"git-lfs.local:8443", false},
{"wronghost.com", false},
}
func TestCertFromSSLCAInfoConfig(t *testing.T) { func TestCertFromSSLCAInfoConfig(t *testing.T) {
defer config.Config.ResetConfig() defer config.Config.ResetConfig()
@ -45,32 +59,38 @@ func TestCertFromSSLCAInfoConfig(t *testing.T) {
assert.Nil(t, err, "Error writing temp cert file") assert.Nil(t, err, "Error writing temp cert file")
tempfile.Close() tempfile.Close()
config.Config.ClearConfig() // Test http.<url>.sslcainfo
config.Config.SetConfig("http.https://git-lfs.local/.sslcainfo", tempfile.Name()) for _, hostName := range sslCAInfoConfigHostNames {
config.Config.ClearConfig()
// Should match hostKey := fmt.Sprintf("http.https://%v.sslcainfo", hostName)
pool := getRootCAsForHost("git-lfs.local") config.Config.SetConfig(hostKey, tempfile.Name())
assert.NotNil(t, pool)
// Shouldn't match for _, matchedHostTest := range sslCAInfoMatchedHostTests {
pool = getRootCAsForHost("wronghost.com") pool := getRootCAsForHost(matchedHostTest.hostName)
assert.Nil(t, pool)
// Ports have to match var shouldOrShouldnt string
pool = getRootCAsForHost("git-lfs.local:8443") if matchedHostTest.shouldMatch {
assert.Nil(t, pool) shouldOrShouldnt = "should"
} else {
shouldOrShouldnt = "should not"
}
// Now use global sslcainfo assert.Equal(t, matchedHostTest.shouldMatch, pool != nil,
"Cert lookup for \"%v\" %v have succeeded with \"%v\"",
matchedHostTest.hostName, shouldOrShouldnt, hostKey)
}
}
// Test http.sslcainfo
config.Config.ClearConfig() config.Config.ClearConfig()
config.Config.SetConfig("http.sslcainfo", tempfile.Name()) config.Config.SetConfig("http.sslcainfo", tempfile.Name())
// Should match anything // Should match any host at all
pool = getRootCAsForHost("git-lfs.local") for _, matchedHostTest := range sslCAInfoMatchedHostTests {
assert.NotNil(t, pool) pool := getRootCAsForHost(matchedHostTest.hostName)
pool = getRootCAsForHost("wronghost.com") assert.NotNil(t, pool)
assert.NotNil(t, pool) }
pool = getRootCAsForHost("git-lfs.local:8443")
assert.NotNil(t, pool)
} }
@ -91,12 +111,10 @@ func TestCertFromSSLCAInfoEnv(t *testing.T) {
config.Config.SetAllEnv(map[string]string{"GIT_SSL_CAINFO": tempfile.Name()}) config.Config.SetAllEnv(map[string]string{"GIT_SSL_CAINFO": tempfile.Name()})
// Should match any host at all // Should match any host at all
pool := getRootCAsForHost("git-lfs.local") for _, matchedHostTest := range sslCAInfoMatchedHostTests {
assert.NotNil(t, pool) pool := getRootCAsForHost(matchedHostTest.hostName)
pool = getRootCAsForHost("wronghost.com") assert.NotNil(t, pool)
assert.NotNil(t, pool) }
pool = getRootCAsForHost("notthisone.com:8888")
assert.NotNil(t, pool)
} }
@ -114,12 +132,10 @@ func TestCertFromSSLCAPathConfig(t *testing.T) {
config.Config.SetConfig("http.sslcapath", tempdir) config.Config.SetConfig("http.sslcapath", tempdir)
// Should match any host at all // Should match any host at all
pool := getRootCAsForHost("git-lfs.local") for _, matchedHostTest := range sslCAInfoMatchedHostTests {
assert.NotNil(t, pool) pool := getRootCAsForHost(matchedHostTest.hostName)
pool = getRootCAsForHost("wronghost.com") assert.NotNil(t, pool)
assert.NotNil(t, pool) }
pool = getRootCAsForHost("notthisone.com:8888")
assert.NotNil(t, pool)
} }
@ -139,12 +155,10 @@ func TestCertFromSSLCAPathEnv(t *testing.T) {
config.Config.SetAllEnv(map[string]string{"GIT_SSL_CAPATH": tempdir}) config.Config.SetAllEnv(map[string]string{"GIT_SSL_CAPATH": tempdir})
// Should match any host at all // Should match any host at all
pool := getRootCAsForHost("git-lfs.local") for _, matchedHostTest := range sslCAInfoMatchedHostTests {
assert.NotNil(t, pool) pool := getRootCAsForHost(matchedHostTest.hostName)
pool = getRootCAsForHost("wronghost.com") assert.NotNil(t, pool)
assert.NotNil(t, pool) }
pool = getRootCAsForHost("notthisone.com:8888")
assert.NotNil(t, pool)
} }