diff --git a/command/cli.go b/command/cli.go index 63397bf920..9ca28765cc 100644 --- a/command/cli.go +++ b/command/cli.go @@ -64,6 +64,15 @@ func (cli *DockerCli) ConfigFile() *configfile.ConfigFile { return cli.configFile } +// CredentialsStore returns a new credentials store based +// on the settings provided in the configuration file. +func (cli *DockerCli) CredentialsStore() credentials.Store { + if cli.configFile.CredentialsStore != "" { + return credentials.NewNativeStore(cli.configFile) + } + return credentials.NewFileStore(cli.configFile) +} + // Initialize the dockerCli runs initialization that must happen after command // line flags are parsed. func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions) error { diff --git a/command/container/create.go b/command/container/create.go index b80b6e1e5a..7bd3856971 100644 --- a/command/container/create.go +++ b/command/container/create.go @@ -85,7 +85,7 @@ func pullImage(ctx context.Context, dockerCli *command.DockerCli, image string, return err } - authConfig := dockerCli.ResolveAuthConfig(ctx, repoInfo.Index) + authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index) encodedAuth, err := command.EncodeAuthToBase64(authConfig) if err != nil { return err diff --git a/command/credentials.go b/command/credentials.go deleted file mode 100644 index 06e9d1de20..0000000000 --- a/command/credentials.go +++ /dev/null @@ -1,44 +0,0 @@ -package command - -import ( - "github.com/docker/docker/api/types" - "github.com/docker/docker/cliconfig/configfile" - "github.com/docker/docker/cliconfig/credentials" -) - -// GetCredentials loads the user credentials from a credentials store. -// The store is determined by the config file settings. -func GetCredentials(c *configfile.ConfigFile, serverAddress string) (types.AuthConfig, error) { - s := LoadCredentialsStore(c) - return s.Get(serverAddress) -} - -// GetAllCredentials loads all credentials from a credentials store. -// The store is determined by the config file settings. -func GetAllCredentials(c *configfile.ConfigFile) (map[string]types.AuthConfig, error) { - s := LoadCredentialsStore(c) - return s.GetAll() -} - -// StoreCredentials saves the user credentials in a credentials store. -// The store is determined by the config file settings. -func StoreCredentials(c *configfile.ConfigFile, auth types.AuthConfig) error { - s := LoadCredentialsStore(c) - return s.Store(auth) -} - -// EraseCredentials removes the user credentials from a credentials store. -// The store is determined by the config file settings. -func EraseCredentials(c *configfile.ConfigFile, serverAddress string) error { - s := LoadCredentialsStore(c) - return s.Erase(serverAddress) -} - -// LoadCredentialsStore initializes a new credentials store based -// in the settings provided in the configuration file. -func LoadCredentialsStore(c *configfile.ConfigFile) credentials.Store { - if c.CredentialsStore != "" { - return credentials.NewNativeStore(c) - } - return credentials.NewFileStore(c) -} diff --git a/command/image/build.go b/command/image/build.go index 06ee32ba83..7f59b54136 100644 --- a/command/image/build.go +++ b/command/image/build.go @@ -266,6 +266,7 @@ func runBuild(dockerCli *command.DockerCli, options buildOptions) error { } } + authConfig, _ := dockerCli.CredentialsStore().GetAll() buildOptions := types.ImageBuildOptions{ Memory: memory, MemorySwap: memorySwap, @@ -286,7 +287,7 @@ func runBuild(dockerCli *command.DockerCli, options buildOptions) error { ShmSize: shmSize, Ulimits: options.ulimits.GetList(), BuildArgs: runconfigopts.ConvertKVStringsToMap(options.buildArgs.GetAll()), - AuthConfigs: dockerCli.RetrieveAuthConfigs(), + AuthConfigs: authConfig, Labels: runconfigopts.ConvertKVStringsToMap(options.labels), } diff --git a/command/image/pull.go b/command/image/pull.go index 3f3093a5d8..9116d45840 100644 --- a/command/image/pull.go +++ b/command/image/pull.go @@ -73,8 +73,8 @@ func runPull(dockerCli *command.DockerCli, opts pullOptions) error { ctx := context.Background() - authConfig := dockerCli.ResolveAuthConfig(ctx, repoInfo.Index) - requestPrivilege := dockerCli.RegistryAuthenticationPrivilegedFunc(repoInfo.Index, "pull") + authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index) + requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, "pull") if command.IsTrusted() && !registryRef.HasDigest() { // Check if tag is digest diff --git a/command/image/push.go b/command/image/push.go index a98de9e707..a8ce4945ec 100644 --- a/command/image/push.go +++ b/command/image/push.go @@ -44,8 +44,8 @@ func runPush(dockerCli *command.DockerCli, remote string) error { ctx := context.Background() // Resolve the Auth config relevant for this server - authConfig := dockerCli.ResolveAuthConfig(ctx, repoInfo.Index) - requestPrivilege := dockerCli.RegistryAuthenticationPrivilegedFunc(repoInfo.Index, "push") + authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index) + requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, "push") if command.IsTrusted() { return trustedPush(ctx, dockerCli, repoInfo, ref, authConfig, requestPrivilege) diff --git a/command/image/search.go b/command/image/search.go index 7c4ad03b96..6f8308af80 100644 --- a/command/image/search.go +++ b/command/image/search.go @@ -66,8 +66,8 @@ func runSearch(dockerCli *command.DockerCli, opts searchOptions) error { ctx := context.Background() - authConfig := dockerCli.ResolveAuthConfig(ctx, indexInfo) - requestPrivilege := dockerCli.RegistryAuthenticationPrivilegedFunc(indexInfo, "search") + authConfig := command.ResolveAuthConfig(ctx, dockerCli, indexInfo) + requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCli, indexInfo, "search") encodedAuth, err := command.EncodeAuthToBase64(authConfig) if err != nil { diff --git a/command/image/trust.go b/command/image/trust.go index f0948cc808..b08bd490cb 100644 --- a/command/image/trust.go +++ b/command/image/trust.go @@ -499,7 +499,7 @@ func TrustedReference(ctx context.Context, cli *command.DockerCli, ref reference } // Resolve the Auth config relevant for this server - authConfig := cli.ResolveAuthConfig(ctx, repoInfo.Index) + authConfig := command.ResolveAuthConfig(ctx, cli, repoInfo.Index) notaryRepo, err := GetNotaryRepository(cli, repoInfo, authConfig, "pull") if err != nil { diff --git a/command/plugin/install.go b/command/plugin/install.go index 2867247a84..e90e8d1224 100644 --- a/command/plugin/install.go +++ b/command/plugin/install.go @@ -61,14 +61,14 @@ func runInstall(dockerCli *command.DockerCli, opts pluginOptions) error { return err } - authConfig := dockerCli.ResolveAuthConfig(ctx, repoInfo.Index) + authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index) encodedAuth, err := command.EncodeAuthToBase64(authConfig) if err != nil { return err } - registryAuthFunc := dockerCli.RegistryAuthenticationPrivilegedFunc(repoInfo.Index, "plugin install") + registryAuthFunc := command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, "plugin install") options := types.PluginInstallOptions{ RegistryAuth: encodedAuth, diff --git a/command/plugin/push.go b/command/plugin/push.go index 5174828ea8..360830902e 100644 --- a/command/plugin/push.go +++ b/command/plugin/push.go @@ -45,7 +45,7 @@ func runPush(dockerCli *command.DockerCli, name string) error { if err != nil { return err } - authConfig := dockerCli.ResolveAuthConfig(ctx, repoInfo.Index) + authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index) encodedAuth, err := command.EncodeAuthToBase64(authConfig) if err != nil { diff --git a/command/registry.go b/command/registry.go index 4f72afa4a1..b70d6f444c 100644 --- a/command/registry.go +++ b/command/registry.go @@ -20,14 +20,14 @@ import ( ) // ElectAuthServer returns the default registry to use (by asking the daemon) -func (cli *DockerCli) ElectAuthServer(ctx context.Context) string { +func ElectAuthServer(ctx context.Context, cli *DockerCli) string { // The daemon `/info` endpoint informs us of the default registry being // used. This is essential in cross-platforms environment, where for // example a Linux client might be interacting with a Windows daemon, hence // the default registry URL might be Windows specific. serverAddress := registry.IndexServer - if info, err := cli.client.Info(ctx); err != nil { - fmt.Fprintf(cli.out, "Warning: failed to get default registry endpoint from daemon (%v). Using system default: %s\n", err, serverAddress) + if info, err := cli.Client().Info(ctx); err != nil { + fmt.Fprintf(cli.Out(), "Warning: failed to get default registry endpoint from daemon (%v). Using system default: %s\n", err, serverAddress) } else { serverAddress = info.IndexServerAddress } @@ -45,12 +45,12 @@ func EncodeAuthToBase64(authConfig types.AuthConfig) (string, error) { // RegistryAuthenticationPrivilegedFunc returns a RequestPrivilegeFunc from the specified registry index info // for the given command. -func (cli *DockerCli) RegistryAuthenticationPrivilegedFunc(index *registrytypes.IndexInfo, cmdName string) types.RequestPrivilegeFunc { +func RegistryAuthenticationPrivilegedFunc(cli *DockerCli, index *registrytypes.IndexInfo, cmdName string) types.RequestPrivilegeFunc { return func() (string, error) { - fmt.Fprintf(cli.out, "\nPlease login prior to %s:\n", cmdName) + fmt.Fprintf(cli.Out(), "\nPlease login prior to %s:\n", cmdName) indexServer := registry.GetAuthConfigKey(index) - isDefaultRegistry := indexServer == cli.ElectAuthServer(context.Background()) - authConfig, err := cli.ConfigureAuth("", "", indexServer, isDefaultRegistry) + isDefaultRegistry := indexServer == ElectAuthServer(context.Background(), cli) + authConfig, err := ConfigureAuth(cli, "", "", indexServer, isDefaultRegistry) if err != nil { return "", err } @@ -58,35 +58,21 @@ func (cli *DockerCli) RegistryAuthenticationPrivilegedFunc(index *registrytypes. } } -func (cli *DockerCli) promptWithDefault(prompt string, configDefault string) { - if configDefault == "" { - fmt.Fprintf(cli.out, "%s: ", prompt) - } else { - fmt.Fprintf(cli.out, "%s (%s): ", prompt, configDefault) - } -} - // ResolveAuthConfig is like registry.ResolveAuthConfig, but if using the // default index, it uses the default index name for the daemon's platform, // not the client's platform. -func (cli *DockerCli) ResolveAuthConfig(ctx context.Context, index *registrytypes.IndexInfo) types.AuthConfig { +func ResolveAuthConfig(ctx context.Context, cli *DockerCli, index *registrytypes.IndexInfo) types.AuthConfig { configKey := index.Name if index.Official { - configKey = cli.ElectAuthServer(ctx) + configKey = ElectAuthServer(ctx, cli) } - a, _ := GetCredentials(cli.configFile, configKey) + a, _ := cli.CredentialsStore().Get(configKey) return a } -// RetrieveAuthConfigs return all credentials. -func (cli *DockerCli) RetrieveAuthConfigs() map[string]types.AuthConfig { - acs, _ := GetAllCredentials(cli.configFile) - return acs -} - // ConfigureAuth returns an AuthConfig from the specified user, password and server. -func (cli *DockerCli) ConfigureAuth(flUser, flPassword, serverAddress string, isDefaultRegistry bool) (types.AuthConfig, error) { +func ConfigureAuth(cli *DockerCli, flUser, flPassword, serverAddress string, isDefaultRegistry bool) (types.AuthConfig, error) { // On Windows, force the use of the regular OS stdin stream. Fixes #14336/#14210 if runtime.GOOS == "windows" { cli.in = NewInStream(os.Stdin) @@ -96,7 +82,7 @@ func (cli *DockerCli) ConfigureAuth(flUser, flPassword, serverAddress string, is serverAddress = registry.ConvertToHostname(serverAddress) } - authconfig, err := GetCredentials(cli.configFile, serverAddress) + authconfig, err := cli.CredentialsStore().Get(serverAddress) if err != nil { return authconfig, err } @@ -117,10 +103,10 @@ func (cli *DockerCli) ConfigureAuth(flUser, flPassword, serverAddress string, is if flUser = strings.TrimSpace(flUser); flUser == "" { if isDefaultRegistry { // if this is a default registry (docker hub), then display the following message. - fmt.Fprintln(cli.out, "Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.") + fmt.Fprintln(cli.Out(), "Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.") } - cli.promptWithDefault("Username", authconfig.Username) - flUser = readInput(cli.in, cli.out) + promptWithDefault(cli.Out(), "Username", authconfig.Username) + flUser = readInput(cli.In(), cli.Out()) flUser = strings.TrimSpace(flUser) if flUser == "" { flUser = authconfig.Username @@ -134,11 +120,11 @@ func (cli *DockerCli) ConfigureAuth(flUser, flPassword, serverAddress string, is if err != nil { return authconfig, err } - fmt.Fprintf(cli.out, "Password: ") + fmt.Fprintf(cli.Out(), "Password: ") term.DisableEcho(cli.In().FD(), oldState) - flPassword = readInput(cli.in, cli.out) - fmt.Fprint(cli.out, "\n") + flPassword = readInput(cli.In(), cli.Out()) + fmt.Fprint(cli.Out(), "\n") term.RestoreTerminal(cli.In().FD(), oldState) if flPassword == "" { @@ -154,24 +140,28 @@ func (cli *DockerCli) ConfigureAuth(flUser, flPassword, serverAddress string, is return authconfig, nil } -// resolveAuthConfigFromImage retrieves that AuthConfig using the image string -func (cli *DockerCli) resolveAuthConfigFromImage(ctx context.Context, image string) (types.AuthConfig, error) { - registryRef, err := reference.ParseNamed(image) +func readInput(in io.Reader, out io.Writer) string { + reader := bufio.NewReader(in) + line, _, err := reader.ReadLine() if err != nil { - return types.AuthConfig{}, err + fmt.Fprintln(out, err.Error()) + os.Exit(1) } - repoInfo, err := registry.ParseRepositoryInfo(registryRef) - if err != nil { - return types.AuthConfig{}, err + return string(line) +} + +func promptWithDefault(out io.Writer, prompt string, configDefault string) { + if configDefault == "" { + fmt.Fprintf(out, "%s: ", prompt) + } else { + fmt.Fprintf(out, "%s (%s): ", prompt, configDefault) } - authConfig := cli.ResolveAuthConfig(ctx, repoInfo.Index) - return authConfig, nil } // RetrieveAuthTokenFromImage retrieves an encoded auth token given a complete image -func (cli *DockerCli) RetrieveAuthTokenFromImage(ctx context.Context, image string) (string, error) { +func RetrieveAuthTokenFromImage(ctx context.Context, cli *DockerCli, image string) (string, error) { // Retrieve encoded auth token from the image reference - authConfig, err := cli.resolveAuthConfigFromImage(ctx, image) + authConfig, err := resolveAuthConfigFromImage(ctx, cli, image) if err != nil { return "", err } @@ -182,12 +172,15 @@ func (cli *DockerCli) RetrieveAuthTokenFromImage(ctx context.Context, image stri return encodedAuth, nil } -func readInput(in io.Reader, out io.Writer) string { - reader := bufio.NewReader(in) - line, _, err := reader.ReadLine() +// resolveAuthConfigFromImage retrieves that AuthConfig using the image string +func resolveAuthConfigFromImage(ctx context.Context, cli *DockerCli, image string) (types.AuthConfig, error) { + registryRef, err := reference.ParseNamed(image) if err != nil { - fmt.Fprintln(out, err.Error()) - os.Exit(1) + return types.AuthConfig{}, err } - return string(line) + repoInfo, err := registry.ParseRepositoryInfo(registryRef) + if err != nil { + return types.AuthConfig{}, err + } + return ResolveAuthConfig(ctx, cli, repoInfo.Index), nil } diff --git a/command/registry/login.go b/command/registry/login.go index dccf538474..d6f7f8f1d1 100644 --- a/command/registry/login.go +++ b/command/registry/login.go @@ -52,7 +52,7 @@ func runLogin(dockerCli *command.DockerCli, opts loginOptions) error { var ( serverAddress string - authServer = dockerCli.ElectAuthServer(ctx) + authServer = command.ElectAuthServer(ctx, dockerCli) ) if opts.serverAddress != "" { serverAddress = opts.serverAddress @@ -62,7 +62,7 @@ func runLogin(dockerCli *command.DockerCli, opts loginOptions) error { isDefaultRegistry := serverAddress == authServer - authConfig, err := dockerCli.ConfigureAuth(opts.user, opts.password, serverAddress, isDefaultRegistry) + authConfig, err := command.ConfigureAuth(dockerCli, opts.user, opts.password, serverAddress, isDefaultRegistry) if err != nil { return err } @@ -74,7 +74,7 @@ func runLogin(dockerCli *command.DockerCli, opts loginOptions) error { authConfig.Password = "" authConfig.IdentityToken = response.IdentityToken } - if err := command.StoreCredentials(dockerCli.ConfigFile(), authConfig); err != nil { + if err := dockerCli.CredentialsStore().Store(authConfig); err != nil { return fmt.Errorf("Error saving credentials: %v", err) } diff --git a/command/registry/logout.go b/command/registry/logout.go index 1e0c5170a6..5d80595ff0 100644 --- a/command/registry/logout.go +++ b/command/registry/logout.go @@ -35,7 +35,7 @@ func runLogout(dockerCli *command.DockerCli, serverAddress string) error { var isDefaultRegistry bool if serverAddress == "" { - serverAddress = dockerCli.ElectAuthServer(ctx) + serverAddress = command.ElectAuthServer(ctx, dockerCli) isDefaultRegistry = true } @@ -68,7 +68,7 @@ func runLogout(dockerCli *command.DockerCli, serverAddress string) error { fmt.Fprintf(dockerCli.Out(), "Removing login credentials for %s\n", hostnameAddress) for _, r := range regsToLogout { - if err := command.EraseCredentials(dockerCli.ConfigFile(), r); err != nil { + if err := dockerCli.CredentialsStore().Erase(r); err != nil { fmt.Fprintf(dockerCli.Err(), "WARNING: could not erase credentials: %v\n", err) } } diff --git a/command/service/create.go b/command/service/create.go index 4ec8835b37..bc5576b1ad 100644 --- a/command/service/create.go +++ b/command/service/create.go @@ -55,7 +55,7 @@ func runCreate(dockerCli *command.DockerCli, opts *serviceOptions) error { // only send auth if flag was set if opts.registryAuth { // Retrieve encoded auth token from the image reference - encodedAuth, err := dockerCli.RetrieveAuthTokenFromImage(ctx, opts.image) + encodedAuth, err := command.RetrieveAuthTokenFromImage(ctx, dockerCli, opts.image) if err != nil { return err } diff --git a/command/service/update.go b/command/service/update.go index a86f20e585..be3218ed60 100644 --- a/command/service/update.go +++ b/command/service/update.go @@ -82,7 +82,7 @@ func runUpdate(dockerCli *command.DockerCli, flags *pflag.FlagSet, serviceID str // Retrieve encoded auth token from the image reference // This would be the old image if it didn't change in this update image := service.Spec.TaskTemplate.ContainerSpec.Image - encodedAuth, err := dockerCli.RetrieveAuthTokenFromImage(ctx, image) + encodedAuth, err := command.RetrieveAuthTokenFromImage(ctx, dockerCli, image) if err != nil { return err } diff --git a/command/stack/deploy.go b/command/stack/deploy.go index d72c2bd08f..6daf9500f0 100644 --- a/command/stack/deploy.go +++ b/command/stack/deploy.go @@ -197,7 +197,7 @@ func deployServices( if sendAuth { // Retrieve encoded auth token from the image reference image := serviceSpec.TaskTemplate.ContainerSpec.Image - encodedAuth, err = dockerCli.RetrieveAuthTokenFromImage(ctx, image) + encodedAuth, err = command.RetrieveAuthTokenFromImage(ctx, dockerCli, image) if err != nil { return err }