Skip to content

Commit 839b56d

Browse files
committed
Move creation of bearerToken to obtainBearerToken
Instead of having getBearerToken* construct a new bearerToken object, have the caller provide one. This will allow us to record that a token is being obtained, so that others can wait for it. Should not change behavior. Signed-off-by: Miloslav Trmač <[email protected]>
1 parent c387ab8 commit 839b56d

File tree

2 files changed

+37
-33
lines changed

2 files changed

+37
-33
lines changed

image/docker/docker_client.go

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -764,20 +764,18 @@ func (c *dockerClient) obtainBearerToken(ctx context.Context, challenge challeng
764764
token, inCache = c.tokenCache[cacheKey]
765765
}()
766766
if !inCache || time.Now().After(token.expirationTime) {
767-
var (
768-
t *bearerToken
769-
err error
770-
)
767+
token = &bearerToken{}
768+
769+
var err error
771770
if c.auth.IdentityToken != "" {
772-
t, err = c.getBearerTokenOAuth2(ctx, challenge, scopes)
771+
err = c.getBearerTokenOAuth2(ctx, token, challenge, scopes)
773772
} else {
774-
t, err = c.getBearerToken(ctx, challenge, scopes)
773+
err = c.getBearerToken(ctx, token, challenge, scopes)
775774
}
776775
if err != nil {
777776
return "", err
778777
}
779778

780-
token = t
781779
func() { // A scope for defer
782780
c.tokenCacheLock.Lock()
783781
defer c.tokenCacheLock.Unlock()
@@ -787,16 +785,19 @@ func (c *dockerClient) obtainBearerToken(ctx context.Context, challenge challeng
787785
return token.token, nil
788786
}
789787

790-
func (c *dockerClient) getBearerTokenOAuth2(ctx context.Context, challenge challenge,
791-
scopes []authScope) (*bearerToken, error) {
788+
// getBearerTokenOAuth2 obtains an "Authorization: Bearer" token using a pre-existing identity token per
789+
// https://github.com/distribution/distribution/blob/main/docs/spec/auth/oauth.md for challenge and scopes,
790+
// and writes it into dest.
791+
func (c *dockerClient) getBearerTokenOAuth2(ctx context.Context, dest *bearerToken, challenge challenge,
792+
scopes []authScope) error {
792793
realm, ok := challenge.Parameters["realm"]
793794
if !ok {
794-
return nil, errors.New("missing realm in bearer auth challenge")
795+
return errors.New("missing realm in bearer auth challenge")
795796
}
796797

797798
authReq, err := http.NewRequestWithContext(ctx, http.MethodPost, realm, nil)
798799
if err != nil {
799-
return nil, err
800+
return err
800801
}
801802

802803
// Make the form data required against the oauth2 authentication
@@ -821,26 +822,29 @@ func (c *dockerClient) getBearerTokenOAuth2(ctx context.Context, challenge chall
821822
logrus.Debugf("%s %s", authReq.Method, authReq.URL.Redacted())
822823
res, err := c.client.Do(authReq)
823824
if err != nil {
824-
return nil, err
825+
return err
825826
}
826827
defer res.Body.Close()
827828
if err := httpResponseToError(res, "Trying to obtain access token"); err != nil {
828-
return nil, err
829+
return err
829830
}
830831

831-
return newBearerTokenFromHTTPResponseBody(res)
832+
return dest.readFromHTTPResponseBody(res)
832833
}
833834

834-
func (c *dockerClient) getBearerToken(ctx context.Context, challenge challenge,
835-
scopes []authScope) (*bearerToken, error) {
835+
// getBearerToken obtains an "Authorization: Bearer" token using a GET request, per
836+
// https://github.com/distribution/distribution/blob/main/docs/spec/auth/token.md for challenge and scopes,
837+
// and writes it into dest.
838+
func (c *dockerClient) getBearerToken(ctx context.Context, dest *bearerToken, challenge challenge,
839+
scopes []authScope) error {
836840
realm, ok := challenge.Parameters["realm"]
837841
if !ok {
838-
return nil, errors.New("missing realm in bearer auth challenge")
842+
return errors.New("missing realm in bearer auth challenge")
839843
}
840844

841845
authReq, err := http.NewRequestWithContext(ctx, http.MethodGet, realm, nil)
842846
if err != nil {
843-
return nil, err
847+
return err
844848
}
845849

846850
params := authReq.URL.Query()
@@ -868,22 +872,22 @@ func (c *dockerClient) getBearerToken(ctx context.Context, challenge challenge,
868872
logrus.Debugf("%s %s", authReq.Method, authReq.URL.Redacted())
869873
res, err := c.client.Do(authReq)
870874
if err != nil {
871-
return nil, err
875+
return err
872876
}
873877
defer res.Body.Close()
874878
if err := httpResponseToError(res, "Requesting bearer token"); err != nil {
875-
return nil, err
879+
return err
876880
}
877881

878-
return newBearerTokenFromHTTPResponseBody(res)
882+
return dest.readFromHTTPResponseBody(res)
879883
}
880884

881-
// newBearerTokenFromHTTPResponseBody parses a http.Response to obtain a bearerToken.
885+
// readFromHTTPResponseBody sets token data by parsing a http.Response.
882886
// The caller is still responsible for ensuring res.Body is closed.
883-
func newBearerTokenFromHTTPResponseBody(res *http.Response) (*bearerToken, error) {
887+
func (bt *bearerToken) readFromHTTPResponseBody(res *http.Response) error {
884888
blob, err := iolimits.ReadAtMost(res.Body, iolimits.MaxAuthTokenBodySize)
885889
if err != nil {
886-
return nil, err
890+
return err
887891
}
888892

889893
var token struct {
@@ -899,12 +903,10 @@ func newBearerTokenFromHTTPResponseBody(res *http.Response) (*bearerToken, error
899903
if len(bodySample) > bodySampleLength {
900904
bodySample = bodySample[:bodySampleLength]
901905
}
902-
return nil, fmt.Errorf("decoding bearer token (last URL %q, body start %q): %w", res.Request.URL.Redacted(), string(bodySample), err)
906+
return fmt.Errorf("decoding bearer token (last URL %q, body start %q): %w", res.Request.URL.Redacted(), string(bodySample), err)
903907
}
904908

905-
bt := &bearerToken{
906-
token: token.Token,
907-
}
909+
bt.token = token.Token
908910
if bt.token == "" {
909911
bt.token = token.AccessToken
910912
}
@@ -917,7 +919,7 @@ func newBearerTokenFromHTTPResponseBody(res *http.Response) (*bearerToken, error
917919
token.IssuedAt = time.Now().UTC()
918920
}
919921
bt.expirationTime = token.IssuedAt.Add(time.Duration(token.ExpiresIn) * time.Second)
920-
return bt, nil
922+
return nil
921923
}
922924

923925
// detectPropertiesHelper performs the work of detectProperties which executes

image/docker/docker_client_test.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ func testTokenHTTPResponse(t *testing.T, body string) *http.Response {
106106
}
107107
}
108108

109-
func TestNewBearerTokenFromHTTPResponseBody(t *testing.T) {
109+
func TestBearerTokenReadFromHTTPResponseBody(t *testing.T) {
110110
for _, c := range []struct {
111111
input string
112112
expected *bearerToken // or nil if a failure is expected
@@ -128,7 +128,8 @@ func TestNewBearerTokenFromHTTPResponseBody(t *testing.T) {
128128
expected: &bearerToken{token: "IAmAToken", expirationTime: time.Unix(1514800802+60, 0)},
129129
},
130130
} {
131-
token, err := newBearerTokenFromHTTPResponseBody(testTokenHTTPResponse(t, c.input))
131+
token := &bearerToken{}
132+
err := token.readFromHTTPResponseBody(testTokenHTTPResponse(t, c.input))
132133
if c.expected == nil {
133134
assert.Error(t, err, c.input)
134135
} else {
@@ -140,11 +141,12 @@ func TestNewBearerTokenFromHTTPResponseBody(t *testing.T) {
140141
}
141142
}
142143

143-
func TestNewBearerTokenFromHTTPResponseBodyIssuedAtZero(t *testing.T) {
144+
func TestBearerTokenReadFromHTTPResponseBodyIssuedAtZero(t *testing.T) {
144145
zeroTime := time.Time{}.Format(time.RFC3339)
145146
now := time.Now()
146147
tokenBlob := fmt.Sprintf(`{"token":"IAmAToken","expires_in":100,"issued_at":"%s"}`, zeroTime)
147-
token, err := newBearerTokenFromHTTPResponseBody(testTokenHTTPResponse(t, tokenBlob))
148+
token := &bearerToken{}
149+
err := token.readFromHTTPResponseBody(testTokenHTTPResponse(t, tokenBlob))
148150
require.NoError(t, err)
149151
expectedExpiration := now.Add(time.Duration(100) * time.Second)
150152
require.False(t, token.expirationTime.Before(expectedExpiration),

0 commit comments

Comments
 (0)