Skip to content

Commit

Permalink
Support podman auth file REGISTRY_AUTH_FILE. (#1914)
Browse files Browse the repository at this point in the history
  • Loading branch information
zhaoyonghe authored Apr 18, 2024
1 parent 051d642 commit 98dd3e9
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 29 deletions.
20 changes: 16 additions & 4 deletions pkg/authn/keychain.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ func (dk *defaultKeychain) Resolve(target Resource) (Authenticator, error) {
// config.Load, which may fail if the config can't be parsed.
//
// If neither was found, look for Podman's auth at
// $XDG_RUNTIME_DIR/containers/auth.json and attempt to load it as a
// Docker config.
// $REGISTRY_AUTH_FILE or $XDG_RUNTIME_DIR/containers/auth.json
// and attempt to load it as a Docker config.
//
// If neither are found, fallback to Anonymous.
var cf *configfile.ConfigFile
Expand All @@ -96,16 +96,28 @@ func (dk *defaultKeychain) Resolve(target Resource) (Authenticator, error) {
if err != nil {
return nil, err
}
} else {
} else if fileExists(os.Getenv("REGISTRY_AUTH_FILE")) {
f, err := os.Open(os.Getenv("REGISTRY_AUTH_FILE"))
if err != nil {
return nil, err
}
defer f.Close()
cf, err = config.LoadFromReader(f)
if err != nil {
return nil, err
}
} else if fileExists(filepath.Join(os.Getenv("XDG_RUNTIME_DIR"), "containers/auth.json")) {
f, err := os.Open(filepath.Join(os.Getenv("XDG_RUNTIME_DIR"), "containers/auth.json"))
if err != nil {
return Anonymous, nil
return nil, err
}
defer f.Close()
cf, err = config.LoadFromReader(f)
if err != nil {
return nil, err
}
} else {
return Anonymous, nil
}

// See:
Expand Down
70 changes: 45 additions & 25 deletions pkg/authn/keychain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,27 +92,31 @@ func TestNoConfig(t *testing.T) {
}
}

func writeConfig(t *testing.T, dir, file, content string) {
if err := os.MkdirAll(dir, 0777); err != nil {
t.Fatalf("mkdir %s: %v", dir, err)
}
if err := os.WriteFile(filepath.Join(dir, file), []byte(content), 0600); err != nil {
t.Fatalf("write %q: %v", file, err)
}
}

func TestPodmanConfig(t *testing.T) {
tmpdir := os.Getenv("TEST_TMPDIR")
if tmpdir == "" {
tmpdir = t.TempDir()
}
fresh++
p := filepath.Join(tmpdir, fmt.Sprintf("%d", fresh))
t.Setenv("XDG_RUNTIME_DIR", p)
os.Unsetenv("DOCKER_CONFIG")
if err := os.MkdirAll(filepath.Join(p, "containers"), 0777); err != nil {
t.Fatalf("mkdir %s/containers: %v", p, err)
}
cfg := filepath.Join(p, "containers/auth.json")
content := fmt.Sprintf(`{"auths": {"test.io": {"auth": %q}}}`, encode("foo", "bar"))
if err := os.WriteFile(cfg, []byte(content), 0600); err != nil {
t.Fatalf("write %q: %v", cfg, err)
}

os.Unsetenv("DOCKER_CONFIG")
// At first, $DOCKER_CONFIG is unset and $HOME/.docker/config.json isn't
// found, but Podman auth is configured. This should return Podman's
// auth.
// found, but Podman auth $XDG_RUNTIME_DIR/containers/auth.json is configured.
// This should return Podman's auth $XDG_RUNTIME_DIR/containers/auth.json.
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)
Expand All @@ -122,24 +126,40 @@ func TestPodmanConfig(t *testing.T) {
t.Fatal(err)
}
want := &AuthConfig{
Username: "foo",
Password: "bar",
Username: "XDG_RUNTIME_DIR-foo",
Password: "XDG_RUNTIME_DIR-bar",
}
if !reflect.DeepEqual(got, want) {
t.Errorf("got %+v, want %+v", got, want)
}

// Now, configure $HOME/.docker/config.json, which should override
// Podman auth and be used.
if err := os.MkdirAll(filepath.Join(os.Getenv("HOME"), ".docker"), 0777); err != nil {
t.Fatalf("mkdir $HOME/.docker: %v", err)
// Then, configure Podman auth $REGISTRY_AUTH_FILE.
// This demonstrates that $REGISTRY_AUTH_FILE is preferred over $XDG_RUNTIME_DIR/containers/auth.json.
t.Setenv("REGISTRY_AUTH_FILE", filepath.Join(p, "auth.json"))
writeConfig(t, p, "auth.json",
fmt.Sprintf(`{"auths": {"test.io": {"auth": %q}}}`,
encode("REGISTRY_AUTH_FILE-foo", "REGISTRY_AUTH_FILE-bar")))
auth, err = DefaultKeychain.Resolve(testRegistry)
if err != nil {
t.Fatalf("Resolve() = %v", err)
}
got, err = auth.Authorization()
if err != nil {
t.Fatal(err)
}
cfg = filepath.Join(os.Getenv("HOME"), ".docker/config.json")
content = fmt.Sprintf(`{"auths": {"test.io": {"auth": %q}}}`, encode("home-foo", "home-bar"))
if err := os.WriteFile(cfg, []byte(content), 0600); err != nil {
t.Fatalf("write %q: %v", cfg, err)
want = &AuthConfig{
Username: "REGISTRY_AUTH_FILE-foo",
Password: "REGISTRY_AUTH_FILE-bar",
}
if !reflect.DeepEqual(got, want) {
t.Errorf("got %+v, want %+v", got, want)
}
defer func() { os.Remove(cfg) }()

// Now, configure $HOME/.docker/config.json, which should override
// Podman auth and be used.
writeConfig(t, filepath.Join(os.Getenv("HOME"), ".docker"), "config.json",
fmt.Sprintf(`{"auths": {"test.io": {"auth": %q}}}`, encode("home-foo", "home-bar")))
defer func() { os.Remove(filepath.Join(os.Getenv("HOME"), ".docker/config.json")) }()
auth, err = DefaultKeychain.Resolve(testRegistry)
if err != nil {
t.Fatalf("Resolve() = %v", err)
Expand All @@ -160,7 +180,7 @@ func TestPodmanConfig(t *testing.T) {
// auth configured.
// This demonstrates that DOCKER_CONFIG is preferred over Podman auth
// and $HOME/.docker/config.json.
content = fmt.Sprintf(`{"auths": {"test.io": {"auth": %q}}}`, encode("another-foo", "another-bar"))
content := fmt.Sprintf(`{"auths": {"test.io": {"auth": %q}}}`, encode("another-foo", "another-bar"))
cd := setupConfigFile(t, content)
defer os.RemoveAll(filepath.Dir(cd))

Expand Down

0 comments on commit 98dd3e9

Please sign in to comment.