Skip to content

Commit 4d74466

Browse files
committed
feat: add default auth provider, that uses the same config as the docker cli
1 parent 025a8cb commit 4d74466

File tree

5 files changed

+133
-6
lines changed

5 files changed

+133
-6
lines changed

examples/pull/main.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,22 @@ package main
33
import (
44
"context"
55
"docker-wrapper/pkg/client"
6+
"docker-wrapper/pkg/client/auth"
67
"github.com/distribution/reference"
78
client2 "github.com/docker/docker/client"
9+
"time"
810
)
911

1012
func main() {
11-
cli, err := client.New(client2.FromEnv)
13+
authProvider, err := auth.NewDefaultProvider()
14+
if err != nil {
15+
panic(err)
16+
}
17+
cli, err := client.NewWithOpts(
18+
client.WithAuthProvider(authProvider),
19+
client.FromEnv,
20+
client.WithDockerOpts(client2.WithTimeout(time.Second*10)),
21+
)
1222
if err != nil {
1323
panic(err)
1424
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ require (
1313
require (
1414
github.com/Microsoft/go-winio v0.6.2 // indirect
1515
github.com/containerd/log v0.1.0 // indirect
16+
github.com/cpuguy83/dockercfg v0.3.2 // indirect
1617
github.com/docker/go-connections v0.5.0 // indirect
1718
github.com/felixge/httpsnoop v1.0.4 // indirect
1819
github.com/go-logr/logr v1.4.3 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG
88
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
99
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
1010
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
11+
github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA=
12+
github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
1113
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
1214
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
1315
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=

pkg/client/auth/default.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package auth
2+
3+
import (
4+
"encoding/base64"
5+
"errors"
6+
"fmt"
7+
"github.com/cpuguy83/dockercfg"
8+
"github.com/distribution/reference"
9+
"github.com/docker/docker/api/types/registry"
10+
"log"
11+
"os"
12+
)
13+
14+
type DefaultAuthProvider struct {
15+
authConfigs map[string]*registry.AuthConfig
16+
}
17+
18+
func (d *DefaultAuthProvider) AuthConfig(ref reference.Named) registry.AuthConfig {
19+
domain := reference.Domain(ref)
20+
if ac, ok := d.authConfigs[domain]; ok {
21+
log.Printf("using auth config for %s", domain)
22+
return *ac
23+
}
24+
log.Printf("no auth config for %s", domain)
25+
return registry.AuthConfig{}
26+
}
27+
28+
func NewDefaultProvider() (*DefaultAuthProvider, error) {
29+
authConfigs := map[string]*registry.AuthConfig{}
30+
31+
cfg, err := dockercfg.LoadDefaultConfig()
32+
if err != nil && !errors.Is(err, os.ErrNotExist) {
33+
log.Printf("failed to load docker config: %v", err)
34+
return nil, err
35+
} else if errors.Is(err, os.ErrNotExist) {
36+
log.Printf("docker config not found, using empty config")
37+
return &DefaultAuthProvider{authConfigs}, nil
38+
}
39+
40+
for k, v := range cfg.AuthConfigs {
41+
ac := &registry.AuthConfig{
42+
Username: v.Username,
43+
Password: v.Password,
44+
Email: v.Email,
45+
Auth: v.Auth,
46+
IdentityToken: v.IdentityToken,
47+
RegistryToken: v.RegistryToken,
48+
ServerAddress: v.ServerAddress,
49+
}
50+
if ac.Username == "" && ac.Password == "" {
51+
err := getCredentials(k, &cfg, ac)
52+
if err != nil {
53+
log.Printf("failed to get credentials for registry %s: %v", k, err)
54+
continue
55+
}
56+
}
57+
if ac.Auth == "" {
58+
ac.Auth = base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", ac.Username, ac.Password)))
59+
}
60+
authConfigs[k] = ac
61+
}
62+
63+
for k := range cfg.CredentialHelpers {
64+
err := getCredentials(k, &cfg, authConfigs[k])
65+
if err != nil {
66+
log.Printf("failed to get credentials for registry %s: %v", k, err)
67+
}
68+
}
69+
return &DefaultAuthProvider{authConfigs}, nil
70+
}
71+
72+
func getCredentials(registryHost string, cfg *dockercfg.Config, ac *registry.AuthConfig) error {
73+
u, p, err := cfg.GetRegistryCredentials(registryHost)
74+
if err != nil {
75+
return err
76+
}
77+
if u == "" {
78+
ac.IdentityToken = p
79+
} else {
80+
ac.Username = u
81+
ac.Password = p
82+
}
83+
84+
return nil
85+
}

pkg/client/client.go

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"github.com/distribution/reference"
55
"github.com/docker/docker/api/types/registry"
66
"github.com/docker/docker/client"
7+
"slices"
78
)
89

910
type AuthProvider interface {
@@ -12,19 +13,47 @@ type AuthProvider interface {
1213

1314
type Client struct {
1415
*client.Client
16+
dockerOpts []client.Opt
1517
authProvider AuthProvider
1618
}
1719

18-
func New(opts ...client.Opt) (*Client, error) {
19-
cli, err := client.NewClientWithOpts(opts...)
20+
type Opt func(*Client) error
21+
22+
func NewWithOpts(opts ...Opt) (*Client, error) {
23+
c := &Client{}
24+
for _, opt := range opts {
25+
err := opt(c)
26+
if err != nil {
27+
return nil, err
28+
}
29+
}
30+
cli, err := client.NewClientWithOpts(c.dockerOpts...)
2031
if err != nil {
2132
return nil, err
2233
}
23-
return &Client{
24-
Client: cli,
25-
}, nil
34+
c.Client = cli
35+
return c, nil
2636
}
2737

2838
func (c *Client) Close() error {
2939
return c.Client.Close()
3040
}
41+
42+
func WithAuthProvider(authProvider AuthProvider) Opt {
43+
return func(c *Client) error {
44+
c.authProvider = authProvider
45+
return nil
46+
}
47+
}
48+
49+
func WithDockerOpts(opts ...client.Opt) Opt {
50+
return func(c *Client) error {
51+
c.dockerOpts = slices.Concat(c.dockerOpts, opts)
52+
return nil
53+
}
54+
}
55+
56+
func FromEnv(c *Client) error {
57+
c.dockerOpts = append(c.dockerOpts, client.FromEnv)
58+
return nil
59+
}

0 commit comments

Comments
 (0)