From 462bb55c3f05def7f4ddee3c3965f08a25777df9 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Thu, 1 Sep 2016 14:46:31 -0700 Subject: [PATCH 1/2] Fix missing auth headers with PATCH HTTP request when pushing to default port If a user specifies `mydomain.com:443` in the `Host` configuration, the PATCH request for the layer upload will fail because the challenge does not appear to be in the map. To fix this, we normalize the map keys to always use the Host:Port combination. Closes https://github.com/docker/docker/issues/18469 Signed-off-by: Stan Hu --- registry/client/auth/addr.go | 27 ++++++++++++++++++++++ registry/client/auth/authchallenge.go | 10 ++++++-- registry/client/auth/authchallenge_test.go | 2 ++ 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 registry/client/auth/addr.go diff --git a/registry/client/auth/addr.go b/registry/client/auth/addr.go new file mode 100644 index 00000000..ca987f34 --- /dev/null +++ b/registry/client/auth/addr.go @@ -0,0 +1,27 @@ +package auth + +import ( + "net/url" + "strings" +) + +// FROM: http://golang.org/src/net/http/client.go +// Given a string of the form "host", "host:port", or "[ipv6::address]:port", +// return true if the string includes a port. +func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") } + +// FROM: http://golang.org/src/net/http/transport.go +var portMap = map[string]string{ + "http": "80", + "https": "443", +} + +// CanonicalAddr returns url.Host but always with a ":port" suffix +// FROM: http://golang.org/src/net/http/transport.go +func CanonicalAddr(url *url.URL) string { + addr := url.Host + if !hasPort(addr) { + return addr + ":" + portMap[url.Scheme] + } + return addr +} diff --git a/registry/client/auth/authchallenge.go b/registry/client/auth/authchallenge.go index e8cdef7f..a208ec6b 100644 --- a/registry/client/auth/authchallenge.go +++ b/registry/client/auth/authchallenge.go @@ -54,8 +54,13 @@ type simpleChallengeManager struct { Challanges map[string][]Challenge } -func (m *simpleChallengeManager) GetChallenges(endpoint url.URL) ([]Challenge, error) { +func normalizeURL(endpoint *url.URL) { endpoint.Host = strings.ToLower(endpoint.Host) + endpoint.Host = CanonicalAddr(endpoint) +} + +func (m *simpleChallengeManager) GetChallenges(endpoint url.URL) ([]Challenge, error) { + normalizeURL(&endpoint) m.RLock() defer m.RUnlock() @@ -70,11 +75,12 @@ func (m *simpleChallengeManager) AddResponse(resp *http.Response) error { } urlCopy := url.URL{ Path: resp.Request.URL.Path, - Host: strings.ToLower(resp.Request.URL.Host), + Host: resp.Request.URL.Host, Scheme: resp.Request.URL.Scheme, } m.Lock() defer m.Unlock() + normalizeURL(&urlCopy) m.Challanges[urlCopy.String()] = challenges return nil } diff --git a/registry/client/auth/authchallenge_test.go b/registry/client/auth/authchallenge_test.go index e767ed74..ef26ba76 100644 --- a/registry/client/auth/authchallenge_test.go +++ b/registry/client/auth/authchallenge_test.go @@ -44,6 +44,7 @@ func TestAuthChallengeParse(t *testing.T) { func TestAuthChallengeNormalization(t *testing.T) { testAuthChallengeNormalization(t, "reg.EXAMPLE.com") testAuthChallengeNormalization(t, "bɿɒʜɔiɿ-ɿɘƚƨim-ƚol-ɒ-ƨʞnɒʜƚ.com") + testAuthChallengeNormalization(t, "reg.example.com:80") testAuthChallengeConcurrent(t, "reg.EXAMPLE.com") } @@ -72,6 +73,7 @@ func testAuthChallengeNormalization(t *testing.T, host string) { lowered := *url lowered.Host = strings.ToLower(lowered.Host) + lowered.Host = CanonicalAddr(&lowered) c, err := scm.GetChallenges(lowered) if err != nil { t.Fatal(err) From 6d952c92cfe69b7958abae22be93c06bc0099409 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Mon, 19 Sep 2016 14:14:07 -0700 Subject: [PATCH 2/2] Rename CanonicalAddr -> canonicalAddr Update comment for hasPort Signed-off-by: Stan Hu --- registry/client/auth/addr.go | 6 +++--- registry/client/auth/authchallenge.go | 5 +++-- registry/client/auth/authchallenge_test.go | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/registry/client/auth/addr.go b/registry/client/auth/addr.go index ca987f34..6e777528 100644 --- a/registry/client/auth/addr.go +++ b/registry/client/auth/addr.go @@ -5,7 +5,7 @@ import ( "strings" ) -// FROM: http://golang.org/src/net/http/client.go +// FROM: https://golang.org/src/net/http/http.go // Given a string of the form "host", "host:port", or "[ipv6::address]:port", // return true if the string includes a port. func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") } @@ -16,9 +16,9 @@ var portMap = map[string]string{ "https": "443", } -// CanonicalAddr returns url.Host but always with a ":port" suffix +// canonicalAddr returns url.Host but always with a ":port" suffix // FROM: http://golang.org/src/net/http/transport.go -func CanonicalAddr(url *url.URL) string { +func canonicalAddr(url *url.URL) string { addr := url.Host if !hasPort(addr) { return addr + ":" + portMap[url.Scheme] diff --git a/registry/client/auth/authchallenge.go b/registry/client/auth/authchallenge.go index a208ec6b..69d9d6fe 100644 --- a/registry/client/auth/authchallenge.go +++ b/registry/client/auth/authchallenge.go @@ -56,7 +56,7 @@ type simpleChallengeManager struct { func normalizeURL(endpoint *url.URL) { endpoint.Host = strings.ToLower(endpoint.Host) - endpoint.Host = CanonicalAddr(endpoint) + endpoint.Host = canonicalAddr(endpoint) } func (m *simpleChallengeManager) GetChallenges(endpoint url.URL) ([]Challenge, error) { @@ -78,9 +78,10 @@ func (m *simpleChallengeManager) AddResponse(resp *http.Response) error { Host: resp.Request.URL.Host, Scheme: resp.Request.URL.Scheme, } + normalizeURL(&urlCopy) + m.Lock() defer m.Unlock() - normalizeURL(&urlCopy) m.Challanges[urlCopy.String()] = challenges return nil } diff --git a/registry/client/auth/authchallenge_test.go b/registry/client/auth/authchallenge_test.go index ef26ba76..2716fba5 100644 --- a/registry/client/auth/authchallenge_test.go +++ b/registry/client/auth/authchallenge_test.go @@ -73,7 +73,7 @@ func testAuthChallengeNormalization(t *testing.T, host string) { lowered := *url lowered.Host = strings.ToLower(lowered.Host) - lowered.Host = CanonicalAddr(&lowered) + lowered.Host = canonicalAddr(&lowered) c, err := scm.GetChallenges(lowered) if err != nil { t.Fatal(err)