Skip to content

Commit

Permalink
feat: Support Docker credential helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanilves committed Apr 15, 2019
1 parent f4029c8 commit 0394344
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 20 deletions.
2 changes: 1 addition & 1 deletion API_VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.1
1.2
47 changes: 28 additions & 19 deletions docker/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"os"
"strings"

"github.com/ivanilves/lstags/docker/config/credhelper"

"github.com/ivanilves/lstags/util/fix"
)

Expand All @@ -16,9 +18,11 @@ var DefaultDockerJSON = "~/.docker/config.json"

// Config encapsulates configuration loaded from Docker 'config.json' file
type Config struct {
Auths map[string]Auth `json:"auths"`
usernames map[string]string
passwords map[string]string
Auths map[string]Auth `json:"auths"`
usernames map[string]string
passwords map[string]string
CredsStore string `json:"credsStore,omitempty"`
CredHelpers map[string]string `json:"credHelpers,omitempty"`
}

// Auth contains Docker registry username and password in base64-encoded form
Expand All @@ -34,7 +38,9 @@ func (c *Config) IsEmpty() bool {
// GetCredentials gets per-registry credentials from loaded Docker config
func (c *Config) GetCredentials(registry string) (string, string, bool) {
if _, defined := c.usernames[registry]; !defined {
return "", "", false
username, password, _ := credhelper.GetCredentials(registry, c.CredsStore, c.CredHelpers)

return username, password, false
}

return c.usernames[registry], c.passwords[registry], true
Expand Down Expand Up @@ -79,25 +85,28 @@ func Load(fileName string) (*Config, error) {
authenticationToken := string(b)
usernameAndPassword := strings.Split(authenticationToken, ":")

if len(usernameAndPassword) != 2 {
if fileName != DefaultDockerJSON {
errStr := "Invalid auth for Docker registry: %s\nBase64-encoded string is wrong: %s (%s)\n"

return nil, errors.New(
fmt.Sprint(
errStr,
registry,
a.B64Auth,
authenticationToken,
),
)
}
if len(usernameAndPassword) == 2 {
c.usernames[registry] = usernameAndPassword[0]
c.passwords[registry] = usernameAndPassword[1]
continue
}

if len(usernameAndPassword) == 1 && len(usernameAndPassword[0]) == 0 {
// Defined but empty auth string means we will use credsStore or CredHelpers
continue
}

c.usernames[registry] = usernameAndPassword[0]
c.passwords[registry] = usernameAndPassword[1]
if fileName != DefaultDockerJSON {
errStr := "Invalid auth for Docker registry: %s\nBase64-encoded string is wrong: %s (%s)\n"
return nil, errors.New(
fmt.Sprint(
errStr,
registry,
a.B64Auth,
authenticationToken,
),
)
}
}

return c, nil
Expand Down
60 changes: 60 additions & 0 deletions docker/config/credhelper/credhelper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package credhelper

import (
"bytes"
"encoding/json"
"errors"
"os"
"os/exec"
)

type storedCredentials struct {
Username string
Secret string
}

// GetCredentials gets Docker registry credentials either from "credsStore" or "credHelpers"
func GetCredentials(registry, credsStore string, credHelpers map[string]string) (string, string, error) {
if credsStore != "" {
c, err := getCredentials(registry, credsStore)

if err == nil {
return c.Username, c.Secret, nil
}

os.Stderr.WriteString("[credhelper][credsStore] Error: " + err.Error() + "\n")
}

provider, defined := credHelpers[registry]
if defined {
c, err := getCredentials(registry, provider)

if err == nil {
return c.Username, c.Secret, nil
}

os.Stderr.WriteString("[credhelper][credHelpers] Error: " + err.Error() + "\n")
}

return "", "", errors.New("No working credential helpers found for this registry: " + registry)
}

func getCredentials(registry, provider string) (*storedCredentials, error) {
cmd := exec.Command("docker-credential-"+provider, "get")

var stdout bytes.Buffer

cmd.Stdin = bytes.NewBuffer([]byte(registry))
cmd.Stdout = &stdout

if err := cmd.Run(); err != nil {
return nil, err
}

var c storedCredentials
if err := json.NewDecoder(&stdout).Decode(&c); err != nil {
return nil, err
}

return &c, nil
}
2 changes: 2 additions & 0 deletions fixtures/docker/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
},
"registry.hub.docker.com": {
"auth": "dXNlcjI6cGFzczI="
},
"registry.credhelper.com": {
}
}
}

0 comments on commit 0394344

Please sign in to comment.