diff --git a/pkg/authn/keychain.go b/pkg/authn/keychain.go index 6e8814d80..db0dc2131 100644 --- a/pkg/authn/keychain.go +++ b/pkg/authn/keychain.go @@ -95,9 +95,13 @@ func (dk *defaultKeychain) ResolveContext(_ context.Context, target Resource) (A // First, check $HOME/.docker/config.json foundDockerConfig := false + configHome := os.Getenv("XDG_CONFIG_HOME") home, err := homedir.Dir() if err == nil { foundDockerConfig = fileExists(filepath.Join(home, ".docker/config.json")) + if configHome == "" { + configHome = filepath.Join(home, ".config") + } } // If $HOME/.docker/config.json isn't found, check $DOCKER_CONFIG (if set) if !foundDockerConfig && os.Getenv("DOCKER_CONFIG") != "" { @@ -107,7 +111,8 @@ func (dk *defaultKeychain) ResolveContext(_ context.Context, target Resource) (A // config.Load, which may fail if the config can't be parsed. // // If neither was found, look for Podman's auth at - // $REGISTRY_AUTH_FILE or $XDG_RUNTIME_DIR/containers/auth.json + // $REGISTRY_AUTH_FILE, $XDG_RUNTIME_DIR/containers/auth.json, + // $XDG_CONFIG_HOME/containers/auth.json, or ~/.config/containers/auth.json // and attempt to load it as a Docker config. // // If neither are found, fallback to Anonymous. @@ -137,6 +142,16 @@ func (dk *defaultKeychain) ResolveContext(_ context.Context, target Resource) (A if err != nil { return nil, err } + } else if configHome != "" && fileExists(filepath.Join(configHome, "containers/auth.json")) { + f, err := os.Open(filepath.Join(configHome, "containers/auth.json")) + if err != nil { + return nil, err + } + defer f.Close() + cf, err = config.LoadFromReader(f) + if err != nil { + return nil, err + } } else { return Anonymous, nil } diff --git a/pkg/authn/keychain_test.go b/pkg/authn/keychain_test.go index 5a79db9bf..0fcc262f6 100644 --- a/pkg/authn/keychain_test.go +++ b/pkg/authn/keychain_test.go @@ -110,13 +110,15 @@ func TestPodmanConfig(t *testing.T) { os.Unsetenv("DOCKER_CONFIG") // At first, $DOCKER_CONFIG is unset and $HOME/.docker/config.json isn't - // found, but Podman auth $XDG_RUNTIME_DIR/containers/auth.json is configured. - // This should return Podman's auth $XDG_RUNTIME_DIR/containers/auth.json. + // found, but Podman auth $XDG_CONFIG_HOME/containers/auth.json is configured. + // This should return Podman's auth $XDG_CONFIG_HOME/containers/auth.json. + // Note: on non-Linux platforms, $XDG_CONFIG_HOME usually won't be defined, + // and the path resolution should fall back to ~/.config in this case. p := filepath.Join(tmpdir, fmt.Sprintf("%d", fresh)) - t.Setenv("XDG_RUNTIME_DIR", p) + t.Setenv("XDG_CONFIG_HOME", p) writeConfig(t, filepath.Join(p, "containers"), "auth.json", fmt.Sprintf(`{"auths": {"test.io": {"auth": %q}}}`, - encode("XDG_RUNTIME_DIR-foo", "XDG_RUNTIME_DIR-bar"))) + encode("XDG_CONFIG_HOME-foo", "XDG_CONFIG_HOME-bar"))) auth, err := DefaultKeychain.Resolve(testRegistry) if err != nil { t.Fatalf("Resolve() = %v", err) @@ -126,6 +128,31 @@ func TestPodmanConfig(t *testing.T) { t.Fatal(err) } want := &AuthConfig{ + Username: "XDG_CONFIG_HOME-foo", + Password: "XDG_CONFIG_HOME-bar", + } + if !reflect.DeepEqual(got, want) { + t.Errorf("got %+v, want %+v", got, want) + } + + // Then, configure $XDG_RUNTIME_DIR/containers/auth.json. This should take + // precedence over $XDG_CONFIG_HOME/containers/auth.json, as it does in + // podman. + fresh++ + p = filepath.Join(tmpdir, fmt.Sprintf("%d", fresh)) + t.Setenv("XDG_RUNTIME_DIR", p) + writeConfig(t, filepath.Join(p, "containers"), "auth.json", + fmt.Sprintf(`{"auths": {"test.io": {"auth": %q}}}`, + encode("XDG_RUNTIME_DIR-foo", "XDG_RUNTIME_DIR-bar"))) + auth, err = DefaultKeychain.Resolve(testRegistry) + if err != nil { + t.Fatalf("Resolve() = %v", err) + } + got, err = auth.Authorization() + if err != nil { + t.Fatal(err) + } + want = &AuthConfig{ Username: "XDG_RUNTIME_DIR-foo", Password: "XDG_RUNTIME_DIR-bar", }