Skip to content

Commit

Permalink
remote/transport: Make bearer transport go-routine-safe (#1806)
Browse files Browse the repository at this point in the history
  • Loading branch information
2opremio authored Aug 10, 2024
1 parent c195f15 commit b8e87ed
Showing 1 changed file with 18 additions and 2 deletions.
20 changes: 18 additions & 2 deletions pkg/v1/remote/transport/bearer.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ import (
"net/http"
"net/url"
"strings"
"sync"

authchallenge "github.com/docker/distribution/registry/client/auth/challenge"

"github.com/google/go-containerregistry/internal/redact"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/logs"
Expand Down Expand Up @@ -98,6 +100,7 @@ func fromChallenge(reg name.Registry, auth authn.Authenticator, t http.RoundTrip
}

type bearerTransport struct {
mx sync.RWMutex
// Wrapped by bearerTransport.
inner http.RoundTripper
// Basic credentials that we exchange for bearer tokens.
Expand Down Expand Up @@ -139,7 +142,10 @@ func (bt *bearerTransport) RoundTrip(in *http.Request) (*http.Response, error) {
// the registry with which we are interacting.
// In case of redirect http.Client can use an empty Host, check URL too.
if matchesHost(bt.registry.RegistryStr(), in, bt.scheme) {
hdr := fmt.Sprintf("Bearer %s", bt.bearer.RegistryToken)
bt.mx.RLock()
localToken := bt.bearer.RegistryToken
bt.mx.RUnlock()
hdr := fmt.Sprintf("Bearer %s", localToken)
in.Header.Set("Authorization", hdr)
}
return bt.inner.RoundTrip(in)
Expand All @@ -156,11 +162,12 @@ func (bt *bearerTransport) RoundTrip(in *http.Request) (*http.Response, error) {
res.Body.Close()

newScopes := []string{}
bt.mx.Lock()
got := stringSet(bt.scopes)
for _, wac := range challenges {
// TODO(jonjohnsonjr): Should we also update "realm" or "service"?
if want, ok := wac.Parameters["scope"]; ok {
// Add any scopes that we don't already request.
got := stringSet(bt.scopes)
if _, ok := got[want]; !ok {
newScopes = append(newScopes, want)
}
Expand All @@ -172,6 +179,7 @@ func (bt *bearerTransport) RoundTrip(in *http.Request) (*http.Response, error) {
// otherwise the registry might just ignore it :/
newScopes = append(newScopes, bt.scopes...)
bt.scopes = newScopes
bt.mx.Unlock()

// TODO(jonjohnsonjr): Teach transport.Error about "error" and "error_description" from challenge.

Expand All @@ -196,7 +204,9 @@ func (bt *bearerTransport) refresh(ctx context.Context) error {
}

if auth.RegistryToken != "" {
bt.mx.Lock()
bt.bearer.RegistryToken = auth.RegistryToken
bt.mx.Unlock()
return nil
}

Expand All @@ -212,7 +222,9 @@ func (bt *bearerTransport) refresh(ctx context.Context) error {

// Find a token to turn into a Bearer authenticator
if response.Token != "" {
bt.mx.Lock()
bt.bearer.RegistryToken = response.Token
bt.mx.Unlock()
}

// If we obtained a refresh token from the oauth flow, use that for refresh() now.
Expand Down Expand Up @@ -306,7 +318,9 @@ func (bt *bearerTransport) refreshOauth(ctx context.Context) ([]byte, error) {
}

v := url.Values{}
bt.mx.RLock()
v.Set("scope", strings.Join(bt.scopes, " "))
bt.mx.RUnlock()
if bt.service != "" {
v.Set("service", bt.service)
}
Expand Down Expand Up @@ -362,7 +376,9 @@ func (bt *bearerTransport) refreshBasic(ctx context.Context) ([]byte, error) {
client := http.Client{Transport: b}

v := u.Query()
bt.mx.RLock()
v["scope"] = bt.scopes
bt.mx.RUnlock()
v.Set("service", bt.service)
u.RawQuery = v.Encode()

Expand Down

0 comments on commit b8e87ed

Please sign in to comment.