From 504645849200304ea4257efee027e70276cf11c9 Mon Sep 17 00:00:00 2001 From: Ioannis Sermetziadis <142409669+sermio-te@users.noreply.github.com> Date: Wed, 29 Nov 2023 18:51:18 +0200 Subject: [PATCH] fix: fallback matching of registry authentication config (#1927) --- docker_auth.go | 23 +++++++++++++++++++- docker_auth_test.go | 52 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 69 insertions(+), 6 deletions(-) diff --git a/docker_auth.go b/docker_auth.go index a8c32bf46f..cada63870e 100644 --- a/docker_auth.go +++ b/docker_auth.go @@ -4,6 +4,7 @@ import ( "context" "encoding/base64" "encoding/json" + "net/url" "os" "github.com/cpuguy83/dockercfg" @@ -24,13 +25,33 @@ func DockerImageAuth(ctx context.Context, image string) (string, registry.AuthCo return reg, registry.AuthConfig{}, err } - if cfg, ok := cfgs[reg]; ok { + if cfg, ok := getRegistryAuth(reg, cfgs); ok { return reg, cfg, nil } return reg, registry.AuthConfig{}, dockercfg.ErrCredentialsNotFound } +func getRegistryAuth(reg string, cfgs map[string]registry.AuthConfig) (registry.AuthConfig, bool) { + if cfg, ok := cfgs[reg]; ok { + return cfg, true + } + + // fallback match using authentication key host + for k, cfg := range cfgs { + keyURL, err := url.Parse(k) + if err != nil { + continue + } + + if keyURL.Host == reg { + return cfg, true + } + } + + return registry.AuthConfig{}, false +} + // defaultRegistry returns the default registry to use when pulling images // It will use the docker daemon to get the default registry, returning "https://index.docker.io/v1/" if // it fails to get the information from the daemon diff --git a/docker_auth_test.go b/docker_auth_test.go index d6352bdecc..d4ce9f1af5 100644 --- a/docker_auth_test.go +++ b/docker_auth_test.go @@ -30,14 +30,14 @@ func TestGetDockerConfig(t *testing.T) { // Then, we can safely run the tests that rely on it. defaultCfg, err := dockercfg.LoadDefaultConfig() require.Nil(t, err) - require.NotNil(t, defaultCfg) + require.NotEmpty(t, defaultCfg) t.Run("without DOCKER_CONFIG env var retrieves default", func(t *testing.T) { t.Setenv("DOCKER_CONFIG", "") cfg, err := getDockerConfig() require.Nil(t, err) - require.NotNil(t, cfg) + require.NotEmpty(t, cfg) assert.Equal(t, defaultCfg, cfg) }) @@ -55,7 +55,7 @@ func TestGetDockerConfig(t *testing.T) { cfg, err := getDockerConfig() require.Nil(t, err) - require.NotNil(t, cfg) + require.NotEmpty(t, cfg) assert.Equal(t, 3, len(cfg.AuthConfigs)) @@ -83,7 +83,7 @@ func TestGetDockerConfig(t *testing.T) { cfg, err := getDockerConfig() require.Nil(t, err) - require.NotNil(t, cfg) + require.NotEmpty(t, cfg) assert.Equal(t, 1, len(cfg.AuthConfigs)) @@ -109,13 +109,55 @@ func TestGetDockerConfig(t *testing.T) { registry, cfg, err := DockerImageAuth(context.Background(), exampleAuth+"/my/image:latest") require.Nil(t, err) - require.NotNil(t, cfg) + require.NotEmpty(t, cfg) assert.Equal(t, exampleAuth, registry) assert.Equal(t, "gopher", cfg.Username) assert.Equal(t, "secret", cfg.Password) assert.Equal(t, base64, cfg.Auth) }) + + t.Run("match registry authentication by host", func(t *testing.T) { + base64 := "Z29waGVyOnNlY3JldA==" // gopher:secret + imageReg := "example-auth.com" + imagePath := "/my/image:latest" + + t.Setenv("DOCKER_AUTH_CONFIG", `{ + "auths": { + "`+exampleAuth+`": { "username": "gopher", "password": "secret", "auth": "`+base64+`" } + }, + "credsStore": "desktop" + }`) + + registry, cfg, err := DockerImageAuth(context.Background(), imageReg+imagePath) + require.Nil(t, err) + require.NotEmpty(t, cfg) + + assert.Equal(t, imageReg, registry) + assert.Equal(t, "gopher", cfg.Username) + assert.Equal(t, "secret", cfg.Password) + assert.Equal(t, base64, cfg.Auth) + }) + + t.Run("fail to match registry authentication due to invalid host", func(t *testing.T) { + base64 := "Z29waGVyOnNlY3JldA==" // gopher:secret + imageReg := "example-auth.com" + imagePath := "/my/image:latest" + invalidRegistryURL := "://invalid-host" + + t.Setenv("DOCKER_AUTH_CONFIG", `{ + "auths": { + "`+invalidRegistryURL+`": { "username": "gopher", "password": "secret", "auth": "`+base64+`" } + }, + "credsStore": "desktop" + }`) + + registry, cfg, err := DockerImageAuth(context.Background(), imageReg+imagePath) + require.Equal(t, err, dockercfg.ErrCredentialsNotFound) + require.Empty(t, cfg) + + assert.Equal(t, imageReg, registry) + }) } func TestBuildContainerFromDockerfile(t *testing.T) {