@@ -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,76 @@ func (a *AuthProvider) Credentials(ctx context.Context, req *auth.CredentialsReq
7883}
7984
8085func (a * AuthProvider ) FetchToken (ctx context.Context , req * auth.FetchTokenRequest ) (* auth.FetchTokenResponse , error ) {
86+ creds := a .findCredentials (req .Host )
87+ if creds == nil {
88+ return a .inner .FetchToken (ctx , req )
89+ }
90+
91+ to := authutil.TokenOptions {
92+ Realm : req .Realm ,
93+ Service : req .Service ,
94+ Scopes : req .Scopes ,
95+ Username : creds .Username ,
96+ Secret : creds .Password ,
97+ }
98+
99+ if to .Secret != "" {
100+ // Credential information is provided, try the OAuth POST endpoint first.
101+ resp , err := authutil .FetchTokenWithOAuth (ctx , http .DefaultClient , nil , "buildkit-client" , to )
102+ if err != nil {
103+ var errStatus remoteserrors.ErrUnexpectedStatus
104+ if errors .As (err , & errStatus ) {
105+ // Registries without support for POST may return 404 or 401.
106+ if (errStatus .StatusCode == 405 && to .Username != "" ) || errStatus .StatusCode == 404 || errStatus .StatusCode == 401 {
107+ getResp , err := authutil .FetchToken (ctx , http .DefaultClient , nil , to )
108+ if err != nil {
109+ return nil , err
110+ }
111+ return toFetchTokenResponse (getResp .Token , getResp .IssuedAt , getResp .ExpiresIn ), nil
112+ }
113+ }
114+ return nil , err
115+ }
116+ return toFetchTokenResponse (resp .AccessToken , resp .IssuedAt , resp .ExpiresIn ), nil
117+ }
118+
119+ // No secret, fall back to inner provider.
81120 return a .inner .FetchToken (ctx , req )
82121}
83122
123+ // findCredentials looks up decoded credentials for a host from the depot credential list.
124+ func (a * AuthProvider ) findCredentials (host string ) * types.AuthConfig {
125+ for _ , c := range a .credentials {
126+ if c .Host != host {
127+ continue
128+ }
129+ decoded , err := base64 .StdEncoding .DecodeString (c .Token )
130+ if err != nil {
131+ continue
132+ }
133+ parts := strings .SplitN (string (decoded ), ":" , 2 )
134+ if len (parts ) != 2 {
135+ continue
136+ }
137+ return & types.AuthConfig {
138+ Username : parts [0 ],
139+ Password : parts [1 ],
140+ }
141+ }
142+ return nil
143+ }
144+
145+ func toFetchTokenResponse (token string , issuedAt time.Time , expires int ) * auth.FetchTokenResponse {
146+ resp := & auth.FetchTokenResponse {
147+ Token : token ,
148+ ExpiresIn : int64 (expires ),
149+ }
150+ if ! issuedAt .IsZero () {
151+ resp .IssuedAt = issuedAt .Unix ()
152+ }
153+ return resp
154+ }
155+
84156func (a * AuthProvider ) GetTokenAuthority (ctx context.Context , req * auth.GetTokenAuthorityRequest ) (* auth.GetTokenAuthorityResponse , error ) {
85157 return a .inner .GetTokenAuthority (ctx , req )
86158}
@@ -124,6 +196,37 @@ func (a *DepotAuthProvider) Credentials(ctx context.Context, req *auth.Credentia
124196}
125197
126198func (a * DepotAuthProvider ) FetchToken (ctx context.Context , req * auth.FetchTokenRequest ) (* auth.FetchTokenResponse , error ) {
199+ creds := GetDepotAuthConfig ()
200+ if creds == nil {
201+ return a .inner .FetchToken (ctx , req )
202+ }
203+
204+ to := authutil.TokenOptions {
205+ Realm : req .Realm ,
206+ Service : req .Service ,
207+ Scopes : req .Scopes ,
208+ Username : creds .Username ,
209+ Secret : creds .Password ,
210+ }
211+
212+ if to .Secret != "" {
213+ resp , err := authutil .FetchTokenWithOAuth (ctx , http .DefaultClient , nil , "buildkit-client" , to )
214+ if err != nil {
215+ var errStatus remoteserrors.ErrUnexpectedStatus
216+ if errors .As (err , & errStatus ) {
217+ if (errStatus .StatusCode == 405 && to .Username != "" ) || errStatus .StatusCode == 404 || errStatus .StatusCode == 401 {
218+ getResp , err := authutil .FetchToken (ctx , http .DefaultClient , nil , to )
219+ if err != nil {
220+ return nil , err
221+ }
222+ return toFetchTokenResponse (getResp .Token , getResp .IssuedAt , getResp .ExpiresIn ), nil
223+ }
224+ }
225+ return nil , err
226+ }
227+ return toFetchTokenResponse (resp .AccessToken , resp .IssuedAt , resp .ExpiresIn ), nil
228+ }
229+
127230 return a .inner .FetchToken (ctx , req )
128231}
129232
0 commit comments