@@ -83,63 +83,73 @@ func (a *AuthProvider) Credentials(ctx context.Context, req *auth.CredentialsReq
8383}
8484
8585func (a * AuthProvider ) FetchToken (ctx context.Context , req * auth.FetchTokenRequest ) (* auth.FetchTokenResponse , error ) {
86- creds := a .findCredentials (req .Host )
86+ creds , err := a .findCredentials (req .Host )
87+ if err != nil {
88+ return nil , err
89+ }
8790 if creds == nil {
8891 return a .inner .FetchToken (ctx , req )
8992 }
9093
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
94+ if creds .Password != "" {
95+ return fetchTokenWithFallback (ctx , req , creds )
11796 }
11897
11998 // No secret, fall back to inner provider.
12099 return a .inner .FetchToken (ctx , req )
121100}
122101
123102// findCredentials looks up decoded credentials for a host from the depot credential list.
124- func (a * AuthProvider ) findCredentials (host string ) * types.AuthConfig {
103+ func (a * AuthProvider ) findCredentials (host string ) ( * types.AuthConfig , error ) {
125104 for _ , c := range a .credentials {
126105 if c .Host != host {
127106 continue
128107 }
129108 decoded , err := base64 .StdEncoding .DecodeString (c .Token )
130109 if err != nil {
131- continue
110+ return nil , err
132111 }
133112 parts := strings .SplitN (string (decoded ), ":" , 2 )
134113 if len (parts ) != 2 {
135- continue
114+ return nil , fmt . Errorf ( "invalid auth string" )
136115 }
137116 return & types.AuthConfig {
138117 Username : parts [0 ],
139118 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
140149 }
150+ return nil , err
141151 }
142- return nil
152+ return toFetchTokenResponse ( resp . AccessToken , resp . IssuedAt , resp . ExpiresIn ), nil
143153}
144154
145155func toFetchTokenResponse (token string , issuedAt time.Time , expires int ) * auth.FetchTokenResponse {
@@ -201,30 +211,8 @@ func (a *DepotAuthProvider) FetchToken(ctx context.Context, req *auth.FetchToken
201211 return a .inner .FetchToken (ctx , req )
202212 }
203213
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
214+ if creds .Password != "" {
215+ return fetchTokenWithFallback (ctx , req , creds )
228216 }
229217
230218 return a .inner .FetchToken (ctx , req )
0 commit comments