Browse Source

Refactor cliconfig so that the default constructor can exist in the package.

Signed-off-by: Daniel Nephin <dnephin@docker.com>
Daniel Nephin 9 years ago
parent
commit
30e3620eae

+ 2 - 1
api/client/cli.go

@@ -11,6 +11,7 @@ import (
 	"github.com/docker/docker/api"
 	"github.com/docker/docker/api"
 	cliflags "github.com/docker/docker/cli/flags"
 	cliflags "github.com/docker/docker/cli/flags"
 	"github.com/docker/docker/cliconfig"
 	"github.com/docker/docker/cliconfig"
+	"github.com/docker/docker/cliconfig/configfile"
 	"github.com/docker/docker/cliconfig/credentials"
 	"github.com/docker/docker/cliconfig/credentials"
 	"github.com/docker/docker/dockerversion"
 	"github.com/docker/docker/dockerversion"
 	"github.com/docker/docker/opts"
 	"github.com/docker/docker/opts"
@@ -27,7 +28,7 @@ type DockerCli struct {
 	init func() error
 	init func() error
 
 
 	// configFile has the client configuration file
 	// configFile has the client configuration file
-	configFile *cliconfig.ConfigFile
+	configFile *configfile.ConfigFile
 	// in holds the input stream and closer (io.ReadCloser) for the client.
 	// in holds the input stream and closer (io.ReadCloser) for the client.
 	in io.ReadCloser
 	in io.ReadCloser
 	// out holds the output stream (io.Writer) for the client.
 	// out holds the output stream (io.Writer) for the client.

+ 6 - 6
api/client/login.go

@@ -11,7 +11,7 @@ import (
 	"golang.org/x/net/context"
 	"golang.org/x/net/context"
 
 
 	Cli "github.com/docker/docker/cli"
 	Cli "github.com/docker/docker/cli"
-	"github.com/docker/docker/cliconfig"
+	"github.com/docker/docker/cliconfig/configfile"
 	"github.com/docker/docker/cliconfig/credentials"
 	"github.com/docker/docker/cliconfig/credentials"
 	flag "github.com/docker/docker/pkg/mflag"
 	flag "github.com/docker/docker/pkg/mflag"
 	"github.com/docker/docker/pkg/term"
 	"github.com/docker/docker/pkg/term"
@@ -143,33 +143,33 @@ func readInput(in io.Reader, out io.Writer) string {
 
 
 // getCredentials loads the user credentials from a credentials store.
 // getCredentials loads the user credentials from a credentials store.
 // The store is determined by the config file settings.
 // The store is determined by the config file settings.
-func getCredentials(c *cliconfig.ConfigFile, serverAddress string) (types.AuthConfig, error) {
+func getCredentials(c *configfile.ConfigFile, serverAddress string) (types.AuthConfig, error) {
 	s := loadCredentialsStore(c)
 	s := loadCredentialsStore(c)
 	return s.Get(serverAddress)
 	return s.Get(serverAddress)
 }
 }
 
 
-func getAllCredentials(c *cliconfig.ConfigFile) (map[string]types.AuthConfig, error) {
+func getAllCredentials(c *configfile.ConfigFile) (map[string]types.AuthConfig, error) {
 	s := loadCredentialsStore(c)
 	s := loadCredentialsStore(c)
 	return s.GetAll()
 	return s.GetAll()
 }
 }
 
 
 // storeCredentials saves the user credentials in a credentials store.
 // storeCredentials saves the user credentials in a credentials store.
 // The store is determined by the config file settings.
 // The store is determined by the config file settings.
-func storeCredentials(c *cliconfig.ConfigFile, auth types.AuthConfig) error {
+func storeCredentials(c *configfile.ConfigFile, auth types.AuthConfig) error {
 	s := loadCredentialsStore(c)
 	s := loadCredentialsStore(c)
 	return s.Store(auth)
 	return s.Store(auth)
 }
 }
 
 
 // eraseCredentials removes the user credentials from a credentials store.
 // eraseCredentials removes the user credentials from a credentials store.
 // The store is determined by the config file settings.
 // The store is determined by the config file settings.
-func eraseCredentials(c *cliconfig.ConfigFile, serverAddress string) error {
+func eraseCredentials(c *configfile.ConfigFile, serverAddress string) error {
 	s := loadCredentialsStore(c)
 	s := loadCredentialsStore(c)
 	return s.Erase(serverAddress)
 	return s.Erase(serverAddress)
 }
 }
 
 
 // loadCredentialsStore initializes a new credentials store based
 // loadCredentialsStore initializes a new credentials store based
 // in the settings provided in the configuration file.
 // in the settings provided in the configuration file.
-func loadCredentialsStore(c *cliconfig.ConfigFile) credentials.Store {
+func loadCredentialsStore(c *configfile.ConfigFile) credentials.Store {
 	if c.CredentialsStore != "" {
 	if c.CredentialsStore != "" {
 		return credentials.NewNativeStore(c)
 		return credentials.NewNativeStore(c)
 	}
 	}

+ 16 - 180
cliconfig/config.go

@@ -1,15 +1,12 @@
 package cliconfig
 package cliconfig
 
 
 import (
 import (
-	"encoding/base64"
-	"encoding/json"
 	"fmt"
 	"fmt"
 	"io"
 	"io"
-	"io/ioutil"
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
-	"strings"
 
 
+	"github.com/docker/docker/cliconfig/configfile"
 	"github.com/docker/docker/pkg/homedir"
 	"github.com/docker/docker/pkg/homedir"
 	"github.com/docker/engine-api/types"
 	"github.com/docker/engine-api/types"
 )
 )
@@ -46,94 +43,19 @@ func SetConfigDir(dir string) {
 	configDir = dir
 	configDir = dir
 }
 }
 
 
-// ConfigFile ~/.docker/config.json file info
-type ConfigFile struct {
-	AuthConfigs      map[string]types.AuthConfig `json:"auths"`
-	HTTPHeaders      map[string]string           `json:"HttpHeaders,omitempty"`
-	PsFormat         string                      `json:"psFormat,omitempty"`
-	ImagesFormat     string                      `json:"imagesFormat,omitempty"`
-	DetachKeys       string                      `json:"detachKeys,omitempty"`
-	CredentialsStore string                      `json:"credsStore,omitempty"`
-	filename         string                      // Note: not serialized - for internal use only
-}
-
 // NewConfigFile initializes an empty configuration file for the given filename 'fn'
 // NewConfigFile initializes an empty configuration file for the given filename 'fn'
-func NewConfigFile(fn string) *ConfigFile {
-	return &ConfigFile{
+func NewConfigFile(fn string) *configfile.ConfigFile {
+	return &configfile.ConfigFile{
 		AuthConfigs: make(map[string]types.AuthConfig),
 		AuthConfigs: make(map[string]types.AuthConfig),
 		HTTPHeaders: make(map[string]string),
 		HTTPHeaders: make(map[string]string),
-		filename:    fn,
-	}
-}
-
-// LegacyLoadFromReader reads the non-nested configuration data given and sets up the
-// auth config information with given directory and populates the receiver object
-func (configFile *ConfigFile) LegacyLoadFromReader(configData io.Reader) error {
-	b, err := ioutil.ReadAll(configData)
-	if err != nil {
-		return err
-	}
-
-	if err := json.Unmarshal(b, &configFile.AuthConfigs); err != nil {
-		arr := strings.Split(string(b), "\n")
-		if len(arr) < 2 {
-			return fmt.Errorf("The Auth config file is empty")
-		}
-		authConfig := types.AuthConfig{}
-		origAuth := strings.Split(arr[0], " = ")
-		if len(origAuth) != 2 {
-			return fmt.Errorf("Invalid Auth config file")
-		}
-		authConfig.Username, authConfig.Password, err = decodeAuth(origAuth[1])
-		if err != nil {
-			return err
-		}
-		authConfig.ServerAddress = defaultIndexserver
-		configFile.AuthConfigs[defaultIndexserver] = authConfig
-	} else {
-		for k, authConfig := range configFile.AuthConfigs {
-			authConfig.Username, authConfig.Password, err = decodeAuth(authConfig.Auth)
-			if err != nil {
-				return err
-			}
-			authConfig.Auth = ""
-			authConfig.ServerAddress = k
-			configFile.AuthConfigs[k] = authConfig
-		}
+		Filename:    fn,
 	}
 	}
-	return nil
-}
-
-// LoadFromReader reads the configuration data given and sets up the auth config
-// information with given directory and populates the receiver object
-func (configFile *ConfigFile) LoadFromReader(configData io.Reader) error {
-	if err := json.NewDecoder(configData).Decode(&configFile); err != nil {
-		return err
-	}
-	var err error
-	for addr, ac := range configFile.AuthConfigs {
-		ac.Username, ac.Password, err = decodeAuth(ac.Auth)
-		if err != nil {
-			return err
-		}
-		ac.Auth = ""
-		ac.ServerAddress = addr
-		configFile.AuthConfigs[addr] = ac
-	}
-	return nil
-}
-
-// ContainsAuth returns whether there is authentication configured
-// in this file or not.
-func (configFile *ConfigFile) ContainsAuth() bool {
-	return configFile.CredentialsStore != "" ||
-		(configFile.AuthConfigs != nil && len(configFile.AuthConfigs) > 0)
 }
 }
 
 
 // LegacyLoadFromReader is a convenience function that creates a ConfigFile object from
 // LegacyLoadFromReader is a convenience function that creates a ConfigFile object from
 // a non-nested reader
 // a non-nested reader
-func LegacyLoadFromReader(configData io.Reader) (*ConfigFile, error) {
-	configFile := ConfigFile{
+func LegacyLoadFromReader(configData io.Reader) (*configfile.ConfigFile, error) {
+	configFile := configfile.ConfigFile{
 		AuthConfigs: make(map[string]types.AuthConfig),
 		AuthConfigs: make(map[string]types.AuthConfig),
 	}
 	}
 	err := configFile.LegacyLoadFromReader(configData)
 	err := configFile.LegacyLoadFromReader(configData)
@@ -142,8 +64,8 @@ func LegacyLoadFromReader(configData io.Reader) (*ConfigFile, error) {
 
 
 // LoadFromReader is a convenience function that creates a ConfigFile object from
 // LoadFromReader is a convenience function that creates a ConfigFile object from
 // a reader
 // a reader
-func LoadFromReader(configData io.Reader) (*ConfigFile, error) {
-	configFile := ConfigFile{
+func LoadFromReader(configData io.Reader) (*configfile.ConfigFile, error) {
+	configFile := configfile.ConfigFile{
 		AuthConfigs: make(map[string]types.AuthConfig),
 		AuthConfigs: make(map[string]types.AuthConfig),
 	}
 	}
 	err := configFile.LoadFromReader(configData)
 	err := configFile.LoadFromReader(configData)
@@ -153,32 +75,32 @@ func LoadFromReader(configData io.Reader) (*ConfigFile, error) {
 // Load reads the configuration files in the given directory, and sets up
 // Load reads the configuration files in the given directory, and sets up
 // the auth config information and returns values.
 // the auth config information and returns values.
 // FIXME: use the internal golang config parser
 // FIXME: use the internal golang config parser
-func Load(configDir string) (*ConfigFile, error) {
+func Load(configDir string) (*configfile.ConfigFile, error) {
 	if configDir == "" {
 	if configDir == "" {
 		configDir = ConfigDir()
 		configDir = ConfigDir()
 	}
 	}
 
 
-	configFile := ConfigFile{
+	configFile := configfile.ConfigFile{
 		AuthConfigs: make(map[string]types.AuthConfig),
 		AuthConfigs: make(map[string]types.AuthConfig),
-		filename:    filepath.Join(configDir, ConfigFileName),
+		Filename:    filepath.Join(configDir, ConfigFileName),
 	}
 	}
 
 
 	// Try happy path first - latest config file
 	// Try happy path first - latest config file
-	if _, err := os.Stat(configFile.filename); err == nil {
-		file, err := os.Open(configFile.filename)
+	if _, err := os.Stat(configFile.Filename); err == nil {
+		file, err := os.Open(configFile.Filename)
 		if err != nil {
 		if err != nil {
-			return &configFile, fmt.Errorf("%s - %v", configFile.filename, err)
+			return &configFile, fmt.Errorf("%s - %v", configFile.Filename, err)
 		}
 		}
 		defer file.Close()
 		defer file.Close()
 		err = configFile.LoadFromReader(file)
 		err = configFile.LoadFromReader(file)
 		if err != nil {
 		if err != nil {
-			err = fmt.Errorf("%s - %v", configFile.filename, err)
+			err = fmt.Errorf("%s - %v", configFile.Filename, err)
 		}
 		}
 		return &configFile, err
 		return &configFile, err
 	} else if !os.IsNotExist(err) {
 	} else if !os.IsNotExist(err) {
 		// if file is there but we can't stat it for any reason other
 		// if file is there but we can't stat it for any reason other
 		// than it doesn't exist then stop
 		// than it doesn't exist then stop
-		return &configFile, fmt.Errorf("%s - %v", configFile.filename, err)
+		return &configFile, fmt.Errorf("%s - %v", configFile.Filename, err)
 	}
 	}
 
 
 	// Can't find latest config file so check for the old one
 	// Can't find latest config file so check for the old one
@@ -201,89 +123,3 @@ func Load(configDir string) (*ConfigFile, error) {
 	}
 	}
 	return &configFile, nil
 	return &configFile, nil
 }
 }
-
-// SaveToWriter encodes and writes out all the authorization information to
-// the given writer
-func (configFile *ConfigFile) SaveToWriter(writer io.Writer) error {
-	// Encode sensitive data into a new/temp struct
-	tmpAuthConfigs := make(map[string]types.AuthConfig, len(configFile.AuthConfigs))
-	for k, authConfig := range configFile.AuthConfigs {
-		authCopy := authConfig
-		// encode and save the authstring, while blanking out the original fields
-		authCopy.Auth = encodeAuth(&authCopy)
-		authCopy.Username = ""
-		authCopy.Password = ""
-		authCopy.ServerAddress = ""
-		tmpAuthConfigs[k] = authCopy
-	}
-
-	saveAuthConfigs := configFile.AuthConfigs
-	configFile.AuthConfigs = tmpAuthConfigs
-	defer func() { configFile.AuthConfigs = saveAuthConfigs }()
-
-	data, err := json.MarshalIndent(configFile, "", "\t")
-	if err != nil {
-		return err
-	}
-	_, err = writer.Write(data)
-	return err
-}
-
-// Save encodes and writes out all the authorization information
-func (configFile *ConfigFile) Save() error {
-	if configFile.Filename() == "" {
-		return fmt.Errorf("Can't save config with empty filename")
-	}
-
-	if err := os.MkdirAll(filepath.Dir(configFile.filename), 0700); err != nil {
-		return err
-	}
-	f, err := os.OpenFile(configFile.filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
-	if err != nil {
-		return err
-	}
-	defer f.Close()
-	return configFile.SaveToWriter(f)
-}
-
-// Filename returns the name of the configuration file
-func (configFile *ConfigFile) Filename() string {
-	return configFile.filename
-}
-
-// encodeAuth creates a base64 encoded string to containing authorization information
-func encodeAuth(authConfig *types.AuthConfig) string {
-	if authConfig.Username == "" && authConfig.Password == "" {
-		return ""
-	}
-
-	authStr := authConfig.Username + ":" + authConfig.Password
-	msg := []byte(authStr)
-	encoded := make([]byte, base64.StdEncoding.EncodedLen(len(msg)))
-	base64.StdEncoding.Encode(encoded, msg)
-	return string(encoded)
-}
-
-// decodeAuth decodes a base64 encoded string and returns username and password
-func decodeAuth(authStr string) (string, string, error) {
-	if authStr == "" {
-		return "", "", nil
-	}
-
-	decLen := base64.StdEncoding.DecodedLen(len(authStr))
-	decoded := make([]byte, decLen)
-	authByte := []byte(authStr)
-	n, err := base64.StdEncoding.Decode(decoded, authByte)
-	if err != nil {
-		return "", "", err
-	}
-	if n > decLen {
-		return "", "", fmt.Errorf("Something went wrong decoding auth config")
-	}
-	arr := strings.SplitN(string(decoded), ":", 2)
-	if len(arr) != 2 {
-		return "", "", fmt.Errorf("Invalid auth configuration file")
-	}
-	password := strings.Trim(arr[1], "\x00")
-	return arr[0], password, nil
-}

+ 6 - 26
cliconfig/config_test.go

@@ -7,8 +7,8 @@ import (
 	"strings"
 	"strings"
 	"testing"
 	"testing"
 
 
+	"github.com/docker/docker/cliconfig/configfile"
 	"github.com/docker/docker/pkg/homedir"
 	"github.com/docker/docker/pkg/homedir"
-	"github.com/docker/engine-api/types"
 )
 )
 
 
 func TestEmptyConfigDir(t *testing.T) {
 func TestEmptyConfigDir(t *testing.T) {
@@ -26,8 +26,8 @@ func TestEmptyConfigDir(t *testing.T) {
 	}
 	}
 
 
 	expectedConfigFilename := filepath.Join(tmpHome, ConfigFileName)
 	expectedConfigFilename := filepath.Join(tmpHome, ConfigFileName)
-	if config.Filename() != expectedConfigFilename {
-		t.Fatalf("Expected config filename %s, got %s", expectedConfigFilename, config.Filename())
+	if config.Filename != expectedConfigFilename {
+		t.Fatalf("Expected config filename %s, got %s", expectedConfigFilename, config.Filename)
 	}
 	}
 
 
 	// Now save it and make sure it shows up in new form
 	// Now save it and make sure it shows up in new form
@@ -377,7 +377,7 @@ func TestJsonWithPsFormat(t *testing.T) {
 }
 }
 
 
 // Save it and make sure it shows up in new form
 // Save it and make sure it shows up in new form
-func saveConfigAndValidateNewFormat(t *testing.T, config *ConfigFile, homeFolder string) string {
+func saveConfigAndValidateNewFormat(t *testing.T, config *configfile.ConfigFile, homeFolder string) string {
 	if err := config.Save(); err != nil {
 	if err := config.Save(); err != nil {
 		t.Fatalf("Failed to save: %q", err)
 		t.Fatalf("Failed to save: %q", err)
 	}
 	}
@@ -415,8 +415,8 @@ func TestConfigFile(t *testing.T) {
 	configFilename := "configFilename"
 	configFilename := "configFilename"
 	configFile := NewConfigFile(configFilename)
 	configFile := NewConfigFile(configFilename)
 
 
-	if configFile.Filename() != configFilename {
-		t.Fatalf("Expected %s, got %s", configFilename, configFile.Filename())
+	if configFile.Filename != configFilename {
+		t.Fatalf("Expected %s, got %s", configFilename, configFile.Filename)
 	}
 	}
 }
 }
 
 
@@ -543,23 +543,3 @@ func TestLegacyJsonSaveWithNoFile(t *testing.T) {
 		t.Fatalf("Should have save in new form: \n%s\n not \n%s", string(buf), expConfStr)
 		t.Fatalf("Should have save in new form: \n%s\n not \n%s", string(buf), expConfStr)
 	}
 	}
 }
 }
-
-func TestEncodeAuth(t *testing.T) {
-	newAuthConfig := &types.AuthConfig{Username: "ken", Password: "test"}
-	authStr := encodeAuth(newAuthConfig)
-	decAuthConfig := &types.AuthConfig{}
-	var err error
-	decAuthConfig.Username, decAuthConfig.Password, err = decodeAuth(authStr)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if newAuthConfig.Username != decAuthConfig.Username {
-		t.Fatal("Encode Username doesn't match decoded Username")
-	}
-	if newAuthConfig.Password != decAuthConfig.Password {
-		t.Fatal("Encode Password doesn't match decoded Password")
-	}
-	if authStr != "a2VuOnRlc3Q=" {
-		t.Fatal("AuthString encoding isn't correct.")
-	}
-}

+ 177 - 0
cliconfig/configfile/file.go

@@ -0,0 +1,177 @@
+package configfile
+
+import (
+	"encoding/base64"
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"github.com/docker/engine-api/types"
+)
+
+const (
+	// This constant is only used for really old config files when the
+	// URL wasn't saved as part of the config file and it was just
+	// assumed to be this value.
+	defaultIndexserver = "https://index.docker.io/v1/"
+)
+
+// ConfigFile ~/.docker/config.json file info
+type ConfigFile struct {
+	AuthConfigs      map[string]types.AuthConfig `json:"auths"`
+	HTTPHeaders      map[string]string           `json:"HttpHeaders,omitempty"`
+	PsFormat         string                      `json:"psFormat,omitempty"`
+	ImagesFormat     string                      `json:"imagesFormat,omitempty"`
+	DetachKeys       string                      `json:"detachKeys,omitempty"`
+	CredentialsStore string                      `json:"credsStore,omitempty"`
+	Filename         string                      `json:"-"` // Note: for internal use only
+}
+
+// LegacyLoadFromReader reads the non-nested configuration data given and sets up the
+// auth config information with given directory and populates the receiver object
+func (configFile *ConfigFile) LegacyLoadFromReader(configData io.Reader) error {
+	b, err := ioutil.ReadAll(configData)
+	if err != nil {
+		return err
+	}
+
+	if err := json.Unmarshal(b, &configFile.AuthConfigs); err != nil {
+		arr := strings.Split(string(b), "\n")
+		if len(arr) < 2 {
+			return fmt.Errorf("The Auth config file is empty")
+		}
+		authConfig := types.AuthConfig{}
+		origAuth := strings.Split(arr[0], " = ")
+		if len(origAuth) != 2 {
+			return fmt.Errorf("Invalid Auth config file")
+		}
+		authConfig.Username, authConfig.Password, err = decodeAuth(origAuth[1])
+		if err != nil {
+			return err
+		}
+		authConfig.ServerAddress = defaultIndexserver
+		configFile.AuthConfigs[defaultIndexserver] = authConfig
+	} else {
+		for k, authConfig := range configFile.AuthConfigs {
+			authConfig.Username, authConfig.Password, err = decodeAuth(authConfig.Auth)
+			if err != nil {
+				return err
+			}
+			authConfig.Auth = ""
+			authConfig.ServerAddress = k
+			configFile.AuthConfigs[k] = authConfig
+		}
+	}
+	return nil
+}
+
+// LoadFromReader reads the configuration data given and sets up the auth config
+// information with given directory and populates the receiver object
+func (configFile *ConfigFile) LoadFromReader(configData io.Reader) error {
+	if err := json.NewDecoder(configData).Decode(&configFile); err != nil {
+		return err
+	}
+	var err error
+	for addr, ac := range configFile.AuthConfigs {
+		ac.Username, ac.Password, err = decodeAuth(ac.Auth)
+		if err != nil {
+			return err
+		}
+		ac.Auth = ""
+		ac.ServerAddress = addr
+		configFile.AuthConfigs[addr] = ac
+	}
+	return nil
+}
+
+// ContainsAuth returns whether there is authentication configured
+// in this file or not.
+func (configFile *ConfigFile) ContainsAuth() bool {
+	return configFile.CredentialsStore != "" ||
+		(configFile.AuthConfigs != nil && len(configFile.AuthConfigs) > 0)
+}
+
+// SaveToWriter encodes and writes out all the authorization information to
+// the given writer
+func (configFile *ConfigFile) SaveToWriter(writer io.Writer) error {
+	// Encode sensitive data into a new/temp struct
+	tmpAuthConfigs := make(map[string]types.AuthConfig, len(configFile.AuthConfigs))
+	for k, authConfig := range configFile.AuthConfigs {
+		authCopy := authConfig
+		// encode and save the authstring, while blanking out the original fields
+		authCopy.Auth = encodeAuth(&authCopy)
+		authCopy.Username = ""
+		authCopy.Password = ""
+		authCopy.ServerAddress = ""
+		tmpAuthConfigs[k] = authCopy
+	}
+
+	saveAuthConfigs := configFile.AuthConfigs
+	configFile.AuthConfigs = tmpAuthConfigs
+	defer func() { configFile.AuthConfigs = saveAuthConfigs }()
+
+	data, err := json.MarshalIndent(configFile, "", "\t")
+	if err != nil {
+		return err
+	}
+	_, err = writer.Write(data)
+	return err
+}
+
+// Save encodes and writes out all the authorization information
+func (configFile *ConfigFile) Save() error {
+	if configFile.Filename == "" {
+		return fmt.Errorf("Can't save config with empty filename")
+	}
+
+	if err := os.MkdirAll(filepath.Dir(configFile.Filename), 0700); err != nil {
+		return err
+	}
+	f, err := os.OpenFile(configFile.Filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+	return configFile.SaveToWriter(f)
+}
+
+// encodeAuth creates a base64 encoded string to containing authorization information
+func encodeAuth(authConfig *types.AuthConfig) string {
+	if authConfig.Username == "" && authConfig.Password == "" {
+		return ""
+	}
+
+	authStr := authConfig.Username + ":" + authConfig.Password
+	msg := []byte(authStr)
+	encoded := make([]byte, base64.StdEncoding.EncodedLen(len(msg)))
+	base64.StdEncoding.Encode(encoded, msg)
+	return string(encoded)
+}
+
+// decodeAuth decodes a base64 encoded string and returns username and password
+func decodeAuth(authStr string) (string, string, error) {
+	if authStr == "" {
+		return "", "", nil
+	}
+
+	decLen := base64.StdEncoding.DecodedLen(len(authStr))
+	decoded := make([]byte, decLen)
+	authByte := []byte(authStr)
+	n, err := base64.StdEncoding.Decode(decoded, authByte)
+	if err != nil {
+		return "", "", err
+	}
+	if n > decLen {
+		return "", "", fmt.Errorf("Something went wrong decoding auth config")
+	}
+	arr := strings.SplitN(string(decoded), ":", 2)
+	if len(arr) != 2 {
+		return "", "", fmt.Errorf("Invalid auth configuration file")
+	}
+	password := strings.Trim(arr[1], "\x00")
+	return arr[0], password, nil
+}

+ 27 - 0
cliconfig/configfile/file_test.go

@@ -0,0 +1,27 @@
+package configfile
+
+import (
+	"testing"
+
+	"github.com/docker/engine-api/types"
+)
+
+func TestEncodeAuth(t *testing.T) {
+	newAuthConfig := &types.AuthConfig{Username: "ken", Password: "test"}
+	authStr := encodeAuth(newAuthConfig)
+	decAuthConfig := &types.AuthConfig{}
+	var err error
+	decAuthConfig.Username, decAuthConfig.Password, err = decodeAuth(authStr)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if newAuthConfig.Username != decAuthConfig.Username {
+		t.Fatal("Encode Username doesn't match decoded Username")
+	}
+	if newAuthConfig.Password != decAuthConfig.Password {
+		t.Fatal("Encode Password doesn't match decoded Password")
+	}
+	if authStr != "a2VuOnRlc3Q=" {
+		t.Fatal("AuthString encoding isn't correct.")
+	}
+}

+ 2 - 2
cliconfig/credentials/default_store.go

@@ -3,12 +3,12 @@ package credentials
 import (
 import (
 	"os/exec"
 	"os/exec"
 
 
-	"github.com/docker/docker/cliconfig"
+	"github.com/docker/docker/cliconfig/configfile"
 )
 )
 
 
 // DetectDefaultStore sets the default credentials store
 // DetectDefaultStore sets the default credentials store
 // if the host includes the default store helper program.
 // if the host includes the default store helper program.
-func DetectDefaultStore(c *cliconfig.ConfigFile) {
+func DetectDefaultStore(c *configfile.ConfigFile) {
 	if c.CredentialsStore != "" {
 	if c.CredentialsStore != "" {
 		// user defined
 		// user defined
 		return
 		return

+ 3 - 3
cliconfig/credentials/file_store.go

@@ -3,18 +3,18 @@ package credentials
 import (
 import (
 	"strings"
 	"strings"
 
 
-	"github.com/docker/docker/cliconfig"
+	"github.com/docker/docker/cliconfig/configfile"
 	"github.com/docker/engine-api/types"
 	"github.com/docker/engine-api/types"
 )
 )
 
 
 // fileStore implements a credentials store using
 // fileStore implements a credentials store using
 // the docker configuration file to keep the credentials in plain text.
 // the docker configuration file to keep the credentials in plain text.
 type fileStore struct {
 type fileStore struct {
-	file *cliconfig.ConfigFile
+	file *configfile.ConfigFile
 }
 }
 
 
 // NewFileStore creates a new file credentials store.
 // NewFileStore creates a new file credentials store.
-func NewFileStore(file *cliconfig.ConfigFile) Store {
+func NewFileStore(file *configfile.ConfigFile) Store {
 	return &fileStore{
 	return &fileStore{
 		file: file,
 		file: file,
 	}
 	}

+ 2 - 1
cliconfig/credentials/file_store_test.go

@@ -5,10 +5,11 @@ import (
 	"testing"
 	"testing"
 
 
 	"github.com/docker/docker/cliconfig"
 	"github.com/docker/docker/cliconfig"
+	"github.com/docker/docker/cliconfig/configfile"
 	"github.com/docker/engine-api/types"
 	"github.com/docker/engine-api/types"
 )
 )
 
 
-func newConfigFile(auths map[string]types.AuthConfig) *cliconfig.ConfigFile {
+func newConfigFile(auths map[string]types.AuthConfig) *configfile.ConfigFile {
 	tmp, _ := ioutil.TempFile("", "docker-test")
 	tmp, _ := ioutil.TempFile("", "docker-test")
 	name := tmp.Name()
 	name := tmp.Name()
 	tmp.Close()
 	tmp.Close()

+ 2 - 2
cliconfig/credentials/native_store.go

@@ -9,7 +9,7 @@ import (
 	"strings"
 	"strings"
 
 
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
-	"github.com/docker/docker/cliconfig"
+	"github.com/docker/docker/cliconfig/configfile"
 	"github.com/docker/engine-api/types"
 	"github.com/docker/engine-api/types"
 )
 )
 
 
@@ -52,7 +52,7 @@ type nativeStore struct {
 
 
 // NewNativeStore creates a new native store that
 // NewNativeStore creates a new native store that
 // uses a remote helper program to manage credentials.
 // uses a remote helper program to manage credentials.
-func NewNativeStore(file *cliconfig.ConfigFile) Store {
+func NewNativeStore(file *configfile.ConfigFile) Store {
 	return &nativeStore{
 	return &nativeStore{
 		commandFn: shellCommandFn(file.CredentialsStore),
 		commandFn: shellCommandFn(file.CredentialsStore),
 		fileStore: NewFileStore(file),
 		fileStore: NewFileStore(file),