Skip to content

Commit 02cce1e

Browse files
fix(sync): fixed harbor authentication issues on _catalog endpoint
Signed-off-by: Petu Eusebiu <[email protected]>
1 parent b843799 commit 02cce1e

File tree

2 files changed

+34
-20
lines changed

2 files changed

+34
-20
lines changed

errors/errors.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,4 +174,5 @@ var (
174174
ErrInvalidSearchQuery = errors.New("invalid search query")
175175
ErrImageNotFound = errors.New("image not found")
176176
ErrAmbiguousInput = errors.New("input is not specific enough")
177+
ErrUnexpectedAuthHeader = errors.New("expected bearer auth header, received basic")
177178
)

pkg/extensions/sync/httpclient/client.go

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"time"
1414

1515
zerr "zotregistry.dev/zot/errors"
16+
"zotregistry.dev/zot/pkg/api/constants"
1617
"zotregistry.dev/zot/pkg/common"
1718
"zotregistry.dev/zot/pkg/log"
1819
)
@@ -165,7 +166,7 @@ func (httpClient *Client) Ping() bool {
165166
return false
166167
}
167168

168-
httpClient.getAuthType(resp)
169+
httpClient.authType = getAuthType(resp)
169170

170171
if resp.StatusCode >= http.StatusOK && resp.StatusCode <= http.StatusForbidden {
171172
return true
@@ -220,21 +221,6 @@ func (httpClient *Client) MakeGetRequest(ctx context.Context, resultPtr interfac
220221
return body, resp.Header, resp.StatusCode, err
221222
}
222223

223-
func (httpClient *Client) getAuthType(resp *http.Response) {
224-
authHeader := resp.Header.Get("www-authenticate")
225-
226-
authHeaderLower := strings.ToLower(authHeader)
227-
228-
//nolint: gocritic
229-
if strings.Contains(authHeaderLower, "bearer") {
230-
httpClient.authType = tokenAuth
231-
} else if strings.Contains(authHeaderLower, "basic") {
232-
httpClient.authType = basicAuth
233-
} else {
234-
httpClient.authType = noneAuth
235-
}
236-
}
237-
238224
func (httpClient *Client) setupAuth(req *http.Request, namespace string) error {
239225
if httpClient.authType == tokenAuth {
240226
token, err := httpClient.getToken(req.URL.String(), namespace)
@@ -298,7 +284,15 @@ func (httpClient *Client) makeAndDoRequest(method, mediaType, namespace, urlStr
298284
return nil, nil, err
299285
}
300286

301-
if err := httpClient.setupAuth(req, namespace); err != nil {
287+
err = httpClient.setupAuth(req, namespace)
288+
if err != nil {
289+
// harbor catalog requests return basicAuth by default, even if bearer is used on the rest of endpoints.
290+
if errors.Is(err, zerr.ErrUnexpectedAuthHeader) &&
291+
strings.Contains(urlStr, constants.ExtCatalogPrefix) {
292+
// try with basic auth
293+
return httpClient.get(context.Background(), urlStr, true)
294+
}
295+
302296
return nil, nil, err
303297
}
304298

@@ -371,7 +365,7 @@ func (httpClient *Client) getToken(urlStr, namespace string) (*bearerToken, erro
371365
return nil, err
372366
}
373367

374-
challengeParams, err := parseAuthHeader(resp)
368+
challengeParams, err := parseBearerAuthHeader(resp)
375369
if err != nil {
376370
return nil, err
377371
}
@@ -384,6 +378,21 @@ func (httpClient *Client) getToken(urlStr, namespace string) (*bearerToken, erro
384378
return httpClient.getTokenFromURL(tokenURL.String(), namespace)
385379
}
386380

381+
func getAuthType(resp *http.Response) authType {
382+
authHeader := resp.Header.Get("www-authenticate")
383+
384+
authHeaderLower := strings.ToLower(authHeader)
385+
386+
//nolint: gocritic
387+
if strings.Contains(authHeaderLower, "bearer") {
388+
return tokenAuth
389+
} else if strings.Contains(authHeaderLower, "basic") {
390+
return basicAuth
391+
} else {
392+
return noneAuth
393+
}
394+
}
395+
387396
func newBearerToken(blob []byte) (*bearerToken, error) {
388397
token := new(bearerToken)
389398
if err := json.Unmarshal(blob, &token); err != nil {
@@ -426,14 +435,18 @@ func getTokenURLFromChallengeParams(params challengeParams, account string) (*ur
426435
return parsedRealm, nil
427436
}
428437

429-
func parseAuthHeader(resp *http.Response) (challengeParams, error) {
438+
func parseBearerAuthHeader(resp *http.Response) (challengeParams, error) {
430439
authHeader := resp.Header.Get("www-authenticate")
431440

432441
authHeaderSlice := strings.Split(authHeader, ",")
433442

434443
params := challengeParams{}
435444

436445
for _, elem := range authHeaderSlice {
446+
if strings.Contains(strings.ToLower(elem), "basic") {
447+
return params, zerr.ErrUnexpectedAuthHeader
448+
}
449+
437450
if strings.Contains(strings.ToLower(elem), "bearer") {
438451
elem = strings.Split(elem, " ")[1]
439452
}
@@ -469,7 +482,7 @@ func parseAuthHeader(resp *http.Response) (challengeParams, error) {
469482
func needsRetryWithUpdatedScope(err error, resp *http.Response) (bool, challengeParams) {
470483
params := challengeParams{}
471484
if err == nil && resp.StatusCode == http.StatusUnauthorized {
472-
params, err = parseAuthHeader(resp)
485+
params, err = parseBearerAuthHeader(resp)
473486
if err != nil {
474487
return false, params
475488
}

0 commit comments

Comments
 (0)