Skip to content

Commit 62f38fe

Browse files
authored
Merge pull request #439 from depot/fix-www-authenticate-challenge
fix: fix buildkit www-authenticate challenges with depot registry
2 parents 4c155db + 337bfa3 commit 62f38fe

File tree

5 files changed

+96
-3
lines changed

5 files changed

+96
-3
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ go.work.sum
1212

1313
ralph.sh
1414
plans*
15+
.idea/

examples/go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,13 +132,13 @@ require (
132132
go.opentelemetry.io/otel/sdk v1.20.0 // indirect
133133
go.opentelemetry.io/otel/trace v1.20.0 // indirect
134134
go.opentelemetry.io/proto/otlp v0.12.0 // indirect
135-
golang.org/x/crypto v0.31.0 // indirect
135+
golang.org/x/crypto v0.33.0 // indirect
136136
golang.org/x/mod v0.17.0 // indirect
137137
golang.org/x/net v0.25.0 // indirect
138138
golang.org/x/oauth2 v0.11.0 // indirect
139139
golang.org/x/sync v0.12.0 // indirect
140140
golang.org/x/sys v0.31.0 // indirect
141-
golang.org/x/term v0.27.0 // indirect
141+
golang.org/x/term v0.29.0 // indirect
142142
golang.org/x/text v0.23.0 // indirect
143143
golang.org/x/time v0.3.0 // indirect
144144
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect

examples/go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,7 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm
624624
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
625625
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
626626
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
627+
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
627628
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
628629
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
629630
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -790,6 +791,7 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn
790791
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
791792
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
792793
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
794+
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
793795
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
794796
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
795797
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

pkg/buildx/build/build.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1010,7 +1010,6 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
10101010

10111011
ch, done := progress.NewChannel(pw)
10121012
defer func() { <-done }()
1013-
10141013
cc := c
10151014
var printRes map[string][]byte
10161015
// DEPOT: stop recording the build steps and traces on the server.

pkg/registry/auth.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@ import (
44
"context"
55
"encoding/base64"
66
"fmt"
7+
"net/http"
78
"os"
89
"strings"
10+
"time"
911

12+
authutil "github.com/containerd/containerd/remotes/docker/auth"
13+
remoteserrors "github.com/containerd/containerd/remotes/errors"
1014
"github.com/depot/cli/pkg/build"
1115
"github.com/docker/cli/cli/config"
1216
"github.com/docker/cli/cli/config/types"
1317
"github.com/moby/buildkit/session"
1418
"github.com/moby/buildkit/session/auth"
1519
"github.com/moby/buildkit/session/auth/authprovider"
20+
"github.com/pkg/errors"
1621
"google.golang.org/grpc"
1722
)
1823

@@ -78,9 +83,86 @@ func (a *AuthProvider) Credentials(ctx context.Context, req *auth.CredentialsReq
7883
}
7984

8085
func (a *AuthProvider) FetchToken(ctx context.Context, req *auth.FetchTokenRequest) (*auth.FetchTokenResponse, error) {
86+
creds, err := a.findCredentials(req.Host)
87+
if err != nil {
88+
return nil, err
89+
}
90+
if creds == nil {
91+
return a.inner.FetchToken(ctx, req)
92+
}
93+
94+
if creds.Password != "" {
95+
return fetchTokenWithFallback(ctx, req, creds)
96+
}
97+
98+
// No secret, fall back to inner provider.
8199
return a.inner.FetchToken(ctx, req)
82100
}
83101

102+
// findCredentials looks up decoded credentials for a host from the depot credential list.
103+
func (a *AuthProvider) findCredentials(host string) (*types.AuthConfig, error) {
104+
for _, c := range a.credentials {
105+
if c.Host != host {
106+
continue
107+
}
108+
decoded, err := base64.StdEncoding.DecodeString(c.Token)
109+
if err != nil {
110+
return nil, err
111+
}
112+
parts := strings.SplitN(string(decoded), ":", 2)
113+
if len(parts) != 2 {
114+
return nil, fmt.Errorf("invalid auth string")
115+
}
116+
return &types.AuthConfig{
117+
Username: parts[0],
118+
Password: parts[1],
119+
}, nil
120+
}
121+
return nil, nil
122+
}
123+
124+
// fetchTokenWithFallback attempts OAuth POST first, falling back to GET for registries
125+
// that don't support POST (e.g., GCR returns 404, JFrog returns 401, ACR returns 400).
126+
func fetchTokenWithFallback(ctx context.Context, req *auth.FetchTokenRequest, creds *types.AuthConfig) (*auth.FetchTokenResponse, error) {
127+
to := authutil.TokenOptions{
128+
Realm: req.Realm,
129+
Service: req.Service,
130+
Scopes: req.Scopes,
131+
Username: creds.Username,
132+
Secret: creds.Password,
133+
}
134+
135+
resp, err := authutil.FetchTokenWithOAuth(ctx, http.DefaultClient, nil, "buildkit-client", to)
136+
if err != nil {
137+
var errStatus remoteserrors.ErrUnexpectedStatus
138+
if errors.As(err, &errStatus) {
139+
// Registries without support for POST may return various error codes:
140+
// - GCR: 404
141+
// - JFrog Artifactory: 401
142+
// - ACR: 400
143+
// Fall back to GET for any unexpected status.
144+
getResp, err := authutil.FetchToken(ctx, http.DefaultClient, nil, to)
145+
if err != nil {
146+
return nil, err
147+
}
148+
return toFetchTokenResponse(getResp.Token, getResp.IssuedAt, getResp.ExpiresIn), nil
149+
}
150+
return nil, err
151+
}
152+
return toFetchTokenResponse(resp.AccessToken, resp.IssuedAt, resp.ExpiresIn), nil
153+
}
154+
155+
func toFetchTokenResponse(token string, issuedAt time.Time, expires int) *auth.FetchTokenResponse {
156+
resp := &auth.FetchTokenResponse{
157+
Token: token,
158+
ExpiresIn: int64(expires),
159+
}
160+
if !issuedAt.IsZero() {
161+
resp.IssuedAt = issuedAt.Unix()
162+
}
163+
return resp
164+
}
165+
84166
func (a *AuthProvider) GetTokenAuthority(ctx context.Context, req *auth.GetTokenAuthorityRequest) (*auth.GetTokenAuthorityResponse, error) {
85167
return a.inner.GetTokenAuthority(ctx, req)
86168
}
@@ -124,6 +206,15 @@ func (a *DepotAuthProvider) Credentials(ctx context.Context, req *auth.Credentia
124206
}
125207

126208
func (a *DepotAuthProvider) FetchToken(ctx context.Context, req *auth.FetchTokenRequest) (*auth.FetchTokenResponse, error) {
209+
creds := GetDepotAuthConfig()
210+
if creds == nil {
211+
return a.inner.FetchToken(ctx, req)
212+
}
213+
214+
if creds.Password != "" {
215+
return fetchTokenWithFallback(ctx, req, creds)
216+
}
217+
127218
return a.inner.FetchToken(ctx, req)
128219
}
129220

0 commit comments

Comments
 (0)