From a68530c1e895a553f4a03a70807688baaede0e63 Mon Sep 17 00:00:00 2001 From: Lantao Liu Date: Mon, 9 Apr 2018 18:27:39 +0000 Subject: [PATCH] Port containerd fix #2276 Signed-off-by: Lantao Liu --- pkg/containerd/resolver/resolver.go | 48 +++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/pkg/containerd/resolver/resolver.go b/pkg/containerd/resolver/resolver.go index 4bc0960c6..3130b7876 100644 --- a/pkg/containerd/resolver/resolver.go +++ b/pkg/containerd/resolver/resolver.go @@ -27,6 +27,7 @@ import ( "path" "strconv" "strings" + "sync" "time" "github.com/containerd/containerd/images" @@ -250,12 +251,12 @@ func (r *containerdResolver) Pusher(ctx context.Context, ref string) (remotes.Pu type dockerBase struct { refspec reference.Spec base []url.URL - token string - client *http.Client - useBasic bool - username string - secret string + client *http.Client + useBasic bool + username, secret string + token string + mu sync.Mutex } func (r *containerdResolver) base(refspec reference.Spec) (*dockerBase, error) { @@ -300,6 +301,23 @@ func (r *containerdResolver) base(refspec reference.Spec) (*dockerBase, error) { }, nil } +func (r *dockerBase) getToken() string { + r.mu.Lock() + defer r.mu.Unlock() + + return r.token +} + +func (r *dockerBase) setToken(token string) bool { + r.mu.Lock() + defer r.mu.Unlock() + + changed := r.token != token + r.token = token + + return changed +} + func (r *dockerBase) urls(ps ...string) []string { urls := []string{} for _, url := range r.base { @@ -310,10 +328,11 @@ func (r *dockerBase) urls(ps ...string) []string { } func (r *dockerBase) authorize(req *http.Request) { + token := r.getToken() if r.useBasic { req.SetBasicAuth(r.username, r.secret) - } else if r.token != "" { - req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", r.token)) + } else if token != "" { + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) } } @@ -361,7 +380,7 @@ func (r *dockerBase) retryRequest(ctx context.Context, req *http.Request, respon for _, c := range parseAuthHeader(last.Header) { if c.scheme == bearerAuth { if err := invalidAuthorization(c, responses); err != nil { - r.token = "" + r.setToken("") return nil, err } if err := r.setTokenAuth(ctx, c.parameters); err != nil { @@ -446,19 +465,22 @@ func (r *dockerBase) setTokenAuth(ctx context.Context, params map[string]string) if len(to.scopes) == 0 { return errors.New("no scope specified for token auth challenge") } + + var token string if r.secret != "" { // Credential information is provided, use oauth POST endpoint - r.token, err = r.fetchTokenWithOAuth(ctx, to) + token, err = r.fetchTokenWithOAuth(ctx, to) if err != nil { return errors.Wrap(err, "failed to fetch oauth token") } } else { // Do request anonymously - r.token, err = r.getToken(ctx, to) + token, err = r.fetchToken(ctx, to) if err != nil { return errors.Wrap(err, "failed to fetch anonymous token") } } + r.setToken(token) return nil } @@ -502,7 +524,7 @@ func (r *dockerBase) fetchTokenWithOAuth(ctx context.Context, to tokenOptions) ( // Registries without support for POST may return 404 for POST /v2/token. // As of September 2017, GCR is known to return 404. if (resp.StatusCode == 405 && r.username != "") || resp.StatusCode == 404 || resp.StatusCode == 401 { - return r.getToken(ctx, to) + return r.fetchToken(ctx, to) } else if resp.StatusCode < 200 || resp.StatusCode >= 400 { b, _ := ioutil.ReadAll(io.LimitReader(resp.Body, 64000)) // 64KB log.G(ctx).WithFields(logrus.Fields{ @@ -531,8 +553,8 @@ type getTokenResponse struct { RefreshToken string `json:"refresh_token"` } -// getToken fetches a token using a GET request -func (r *dockerBase) getToken(ctx context.Context, to tokenOptions) (string, error) { +// fetchToken fetches a token using a GET request +func (r *dockerBase) fetchToken(ctx context.Context, to tokenOptions) (string, error) { req, err := http.NewRequest("GET", to.realm, nil) if err != nil { return "", err