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:
parent
7dcac52f18
commit
462bb55c3f
3 changed files with 37 additions and 2 deletions
27
registry/client/auth/addr.go
Normal file
27
registry/client/auth/addr.go
Normal 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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue