Merge pull request #9294 from dmcgowan/push-match-request-scheme

Check scheme and host of request on push redirect
This commit is contained in:
Samuel Karp 2023-10-25 22:13:48 +00:00 committed by GitHub
commit 90f1638e72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 57 additions and 6 deletions

View File

@ -245,13 +245,16 @@ func (p dockerPusher) push(ctx context.Context, desc ocispec.Descriptor, ref str
} }
if lurl.Host != lhost.Host || lhost.Scheme != lurl.Scheme { if lurl.Host != lhost.Host || lhost.Scheme != lurl.Scheme {
lhost.Scheme = lurl.Scheme lhost.Scheme = lurl.Scheme
lhost.Host = lurl.Host lhost.Host = lurl.Host
log.G(ctx).WithField("host", lhost.Host).WithField("scheme", lhost.Scheme).Debug("upload changed destination")
// Strip authorizer if change to host or scheme // Check if different than what was requested, accounting for fallback in the transport layer
lhost.Authorizer = nil requested := resp.Request.URL
if requested.Host != lhost.Host || requested.Scheme != lhost.Scheme {
// Strip authorizer if change to host or scheme
lhost.Authorizer = nil
log.G(ctx).WithField("host", lhost.Host).WithField("scheme", lhost.Scheme).Debug("upload changed destination, authorizer removed")
}
} }
} }
q := lurl.Query() q := lurl.Query()

View File

@ -33,6 +33,7 @@ import (
"github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/reference" "github.com/containerd/containerd/reference"
"github.com/containerd/containerd/remotes" "github.com/containerd/containerd/remotes"
"github.com/containerd/log/logtest"
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1" ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -86,6 +87,42 @@ func TestPusherErrClosedRetry(t *testing.T) {
} }
} }
func TestPusherHTTPFallback(t *testing.T) {
ctx := logtest.WithT(context.Background(), t)
p, reg, _, done := samplePusher(t)
defer done()
reg.uploadable = true
reg.username = "testuser"
reg.secret = "testsecret"
reg.locationPrefix = p.hosts[0].Scheme + "://" + p.hosts[0].Host
p.hosts[0].Scheme = "https"
client := p.hosts[0].Client
if client == nil {
clientC := *http.DefaultClient
client = &clientC
}
if client.Transport == nil {
client.Transport = http.DefaultTransport
}
client.Transport = HTTPFallback{client.Transport}
p.hosts[0].Client = client
phost := p.hosts[0].Host
p.hosts[0].Authorizer = NewDockerAuthorizer(WithAuthCreds(func(host string) (string, string, error) {
if host == phost {
return "testuser", "testsecret", nil
}
return "", "", nil
}))
layerContent := []byte("test")
if err := tryUpload(ctx, t, p, layerContent); err != nil {
t.Errorf("upload failed: %v", err)
}
}
// TestPusherErrReset tests the push method if the request needs to be retried // TestPusherErrReset tests the push method if the request needs to be retried
// i.e when ErrReset occurs // i.e when ErrReset occurs
func TestPusherErrReset(t *testing.T) { func TestPusherErrReset(t *testing.T) {
@ -189,9 +226,20 @@ type uploadableMockRegistry struct {
availableContents []string availableContents []string
uploadable bool uploadable bool
putHandlerFunc func(w http.ResponseWriter, r *http.Request) bool putHandlerFunc func(w http.ResponseWriter, r *http.Request) bool
locationPrefix string
username string
secret string
} }
func (u *uploadableMockRegistry) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (u *uploadableMockRegistry) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if u.secret != "" {
user, pass, ok := r.BasicAuth()
if !ok || user != u.username || pass != u.secret {
w.Header().Add("WWW-Authenticate", "basic realm=test")
w.WriteHeader(http.StatusUnauthorized)
return
}
}
if r.Method == http.MethodPut && u.putHandlerFunc != nil { if r.Method == http.MethodPut && u.putHandlerFunc != nil {
// if true return the response witout calling default handler // if true return the response witout calling default handler
if u.putHandlerFunc(w, r) { if u.putHandlerFunc(w, r) {
@ -205,9 +253,9 @@ func (u *uploadableMockRegistry) defaultHandler(w http.ResponseWriter, r *http.R
if r.Method == http.MethodPost { if r.Method == http.MethodPost {
if matches := blobUploadRegexp.FindStringSubmatch(r.URL.Path); len(matches) != 0 { if matches := blobUploadRegexp.FindStringSubmatch(r.URL.Path); len(matches) != 0 {
if u.uploadable { if u.uploadable {
w.Header().Set("Location", "/upload") w.Header().Set("Location", u.locationPrefix+"/upload")
} else { } else {
w.Header().Set("Location", "/cannotupload") w.Header().Set("Location", u.locationPrefix+"/cannotupload")
} }
dgstr := digest.Canonical.Digester() dgstr := digest.Canonical.Digester()