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 <stanhu@gmail.com>
This commit is contained in:
Stan Hu 2016-09-01 14:46:31 -07:00
parent 7dcac52f18
commit 462bb55c3f
3 changed files with 37 additions and 2 deletions

View file

@ -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
}

View file

@ -54,8 +54,13 @@ type simpleChallengeManager struct {
Challanges map[string][]Challenge 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 = strings.ToLower(endpoint.Host)
endpoint.Host = CanonicalAddr(endpoint)
}
func (m *simpleChallengeManager) GetChallenges(endpoint url.URL) ([]Challenge, error) {
normalizeURL(&endpoint)
m.RLock() m.RLock()
defer m.RUnlock() defer m.RUnlock()
@ -70,11 +75,12 @@ func (m *simpleChallengeManager) AddResponse(resp *http.Response) error {
} }
urlCopy := url.URL{ urlCopy := url.URL{
Path: resp.Request.URL.Path, Path: resp.Request.URL.Path,
Host: strings.ToLower(resp.Request.URL.Host), Host: resp.Request.URL.Host,
Scheme: resp.Request.URL.Scheme, Scheme: resp.Request.URL.Scheme,
} }
m.Lock() m.Lock()
defer m.Unlock() defer m.Unlock()
normalizeURL(&urlCopy)
m.Challanges[urlCopy.String()] = challenges m.Challanges[urlCopy.String()] = challenges
return nil return nil
} }

View file

@ -44,6 +44,7 @@ func TestAuthChallengeParse(t *testing.T) {
func TestAuthChallengeNormalization(t *testing.T) { func TestAuthChallengeNormalization(t *testing.T) {
testAuthChallengeNormalization(t, "reg.EXAMPLE.com") testAuthChallengeNormalization(t, "reg.EXAMPLE.com")
testAuthChallengeNormalization(t, "bɿɒʜɔiɿ-ɿɘƚƨim-ƚol-ɒ-ƨʞnɒʜƚ.com") testAuthChallengeNormalization(t, "bɿɒʜɔiɿ-ɿɘƚƨim-ƚol-ɒ-ƨʞnɒʜƚ.com")
testAuthChallengeNormalization(t, "reg.example.com:80")
testAuthChallengeConcurrent(t, "reg.EXAMPLE.com") testAuthChallengeConcurrent(t, "reg.EXAMPLE.com")
} }
@ -72,6 +73,7 @@ func testAuthChallengeNormalization(t *testing.T, host string) {
lowered := *url lowered := *url
lowered.Host = strings.ToLower(lowered.Host) lowered.Host = strings.ToLower(lowered.Host)
lowered.Host = CanonicalAddr(&lowered)
c, err := scm.GetChallenges(lowered) c, err := scm.GetChallenges(lowered)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)