registry: treat basic-auth 401 as unauthorized

Client-side login (daemon down) was wrapping a 401 as a plain error, so
Auth() moved on to the next endpoint. That can print Login Succeeded if
the HTTP fallback happens to answer 200.

Fixes #7237

Signed-off-by: Dean Chen <862469039@qq.com>
This commit is contained in:
Dean Chen
2026-08-28 14:53:19 +05:00
parent ff3273f3e4
commit 5e0fdb3f6e
2 changed files with 45 additions and 1 deletions
+5 -1
View File
@@ -67,7 +67,11 @@ func loginV2(ctx context.Context, authConfig *registry.AuthConfig, endpoint APIE
if resp.StatusCode != http.StatusOK {
// TODO(dmcgowan): Attempt to further interpret result, status code and error code string
return "", fmt.Errorf("login attempt to %s failed with status: %d %s", endpointStr, resp.StatusCode, http.StatusText(resp.StatusCode))
err := fmt.Errorf("login attempt to %s failed with status: %d %s", endpointStr, resp.StatusCode, http.StatusText(resp.StatusCode))
if resp.StatusCode == http.StatusUnauthorized {
return "", unauthorizedErr{err}
}
return "", err
}
return credentialAuthConfig.IdentityToken, nil
+40
View File
@@ -0,0 +1,40 @@
package registry
import (
"context"
"net/http"
"net/http/httptest"
"net/url"
"testing"
"github.com/containerd/errdefs"
"github.com/moby/moby/api/types/registry"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
func TestLoginV2BasicAuthUnauthorized(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
user, pass, ok := r.BasicAuth()
if !ok || user != "alice" || pass != "secret" {
w.Header().Set("WWW-Authenticate", `Basic realm="test"`)
http.Error(w, "401 Unauthorized", http.StatusUnauthorized)
return
}
w.WriteHeader(http.StatusOK)
}))
t.Cleanup(srv.Close)
u, err := url.Parse(srv.URL)
assert.NilError(t, err)
endpoint := APIEndpoint{URL: u}
ctx := context.Background()
_, err = loginV2(ctx, &registry.AuthConfig{Username: "alice", Password: "wrong"}, endpoint, "docker-test")
assert.ErrorContains(t, err, "401")
assert.Check(t, errdefs.IsUnauthorized(err))
token, err := loginV2(ctx, &registry.AuthConfig{Username: "alice", Password: "secret"}, endpoint, "docker-test")
assert.NilError(t, err)
assert.Check(t, is.Equal("", token))
}