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>master
							parent
							
								
									7dcac52f18
								
							
						
					
					
						commit
						462bb55c3f
					
				|  | @ -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 | 	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 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -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) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue